任大奇++謝作如
最近,在教學(xué)《Arduino創(chuàng)意機(jī)器人》的過程中碰到了一個(gè)奇怪的問題。
故障描述
學(xué)生在學(xué)習(xí)了《換擋風(fēng)扇》一課后,做了一個(gè)用三個(gè)按鈕控制的“換擋風(fēng)扇”。如圖1所示,學(xué)生將三個(gè)按鈕模塊分別接在Arduino的數(shù)字口2、3、4上,風(fēng)扇接在數(shù)字口11上。接好硬件后,學(xué)生用米思齊(Mixly)軟件編寫了如圖2所示的程序,編譯并下載到Arduino中。學(xué)生按下按鈕2,風(fēng)扇開始慢速轉(zhuǎn)動(dòng),再按下按鈕3,風(fēng)扇加速轉(zhuǎn)動(dòng),按下按鈕1后,風(fēng)扇停止了轉(zhuǎn)動(dòng)。
一切都很順利,于是筆者提議給這個(gè)作品增加遙控功能。學(xué)生們馬上興致勃勃地動(dòng)手找到紅外遙控模塊,沒幾下就把硬件連接好了(在9號(hào)數(shù)字口上增加了紅外接收模塊),如圖3所示。
使用遙控器上的“1”“2”“3”鍵分別控制風(fēng)扇“停止轉(zhuǎn)動(dòng)”“慢速轉(zhuǎn)動(dòng)”“快速轉(zhuǎn)動(dòng)”,程序并不復(fù)雜,很快便寫好了,如下頁圖4所示。
當(dāng)學(xué)生按下遙控器上的“3”鍵時(shí),風(fēng)扇快速旋轉(zhuǎn)起來。但當(dāng)按下“2”鍵時(shí),預(yù)期的慢速旋轉(zhuǎn)并沒有出現(xiàn),風(fēng)扇直接停止了轉(zhuǎn)動(dòng)。學(xué)生又按了幾次“2”鍵,可是風(fēng)扇仍然紋絲不動(dòng),再按“3”鍵,風(fēng)扇也不動(dòng)了。這時(shí),學(xué)生趕緊檢查剛才寫的程序,再三檢查后確定程序沒有問題。那難道是硬件連接出問題了?仔細(xì)檢查后也沒有問題。一臉茫然的學(xué)生只好來求助筆者。于是,筆者查找遙控失效的原因。
首先,可以確定的是,風(fēng)扇不能工作在慢速狀態(tài)下的故障和加入了紅外線遙控有關(guān),因?yàn)楸緛硎钦5?。但它們之間會(huì)有什么關(guān)系呢?然后,筆者開始從它們的工作原理入手查找線索,考慮到遙控器遵循NEC協(xié)議,所以不論發(fā)送還是接收命令都需要產(chǎn)生38kHz的脈沖,于是便很自然地想到,紅外接收模塊工作時(shí)會(huì)使用到Arduino板的定時(shí)器,同時(shí)風(fēng)扇轉(zhuǎn)速的改變也是靠Arduino板定時(shí)器產(chǎn)生的PWM輸出實(shí)現(xiàn)的,那會(huì)不會(huì)是它們在使用定時(shí)器資源時(shí)產(chǎn)生了沖突呢?帶著這一疑問,筆者開始求證自己的推測。
技術(shù)分析
為了更好地理解求證過程,筆者先來解釋一下Arduino UNO的主芯片(Atmage328P)中的定時(shí)器。所謂的定時(shí)器類似于生活中的鬧鐘,只要開啟這個(gè)鬧鐘它就會(huì)根據(jù)設(shè)定的時(shí)間不斷去提醒。提醒的方式有兩種:一種是給CPU發(fā)送定時(shí)器中斷,另一種是直接在管腳上輸出脈沖電壓(PWM)。只是在同一個(gè)時(shí)間內(nèi)這個(gè)“小鬧鐘”只能設(shè)定一個(gè)定時(shí)時(shí)間,以一種方式工作,不能既當(dāng)“鬧鐘”,又輸出PWM。這種定時(shí)器在Atmage328P中共需要三個(gè),分別是Timer0(0號(hào)定時(shí)器)、Timer1(1號(hào)定時(shí)器)和Timer2(2號(hào)定時(shí)器)。
為了確認(rèn)紅外遙控和風(fēng)扇PWM輸出在使用定時(shí)器資源上是否有沖突,首先,要確定風(fēng)扇PWM輸出所使用的是幾號(hào)定時(shí)器。查看Arduino UNO的原理圖,可以知道風(fēng)扇所接的11口是從Arduino主芯片(Atmage328P)的17號(hào)管腳引出的(如上頁圖5),筆者順藤摸瓜,查閱Atmage328P的數(shù)據(jù)手冊,得知此管腳(OC2A)正是2號(hào)定時(shí)器在PWM模式下輸出脈沖的管腳(如上頁圖6),也就是說要想風(fēng)扇慢速轉(zhuǎn),必須讓2號(hào)定時(shí)器工作在PWM模式下。接著,需要確認(rèn)紅外接收模塊使用的是幾號(hào)定時(shí)器。分析Mixly軟件中的Arduino代碼,可以看到程序加載了一個(gè)外部庫“IRremote.h”,在“Mixly0.97\arduino1.7.9\hardware\arduino\avr\libraries\IRremote”文件夾中找到該庫文件。打開該庫文件,發(fā)現(xiàn)其又引用了一個(gè)用于設(shè)置中斷的庫文件“IRremoteInt.h”,在這個(gè)文件的72行中發(fā)現(xiàn)了“#define IR_USE_TIMER2”這一句(如上頁圖7)。因此可知,針對Atmage328P芯片,紅外遙控模塊使用了2號(hào)定時(shí)器,至此可以確定問題的原因就是這兩個(gè)功能同時(shí)使用了2號(hào)定時(shí)器。
解決方案
問題的原因找到了,那怎么解決呢?筆者想到了兩種方法:
第一種方法是修改紅外遙控模塊使用的定時(shí)器。將“IRremoteInt.h”中的72行修改成“#define IR_USE_TIMER1”,強(qiáng)制紅外遙控使用1號(hào)定時(shí)器。保存庫文件后,筆者重新編譯下載,試著按下了遙控器上的“2”鍵,風(fēng)扇慢速地轉(zhuǎn)了起來,成功了!
但是,這種方法對沒有學(xué)習(xí)過類C語言的學(xué)生來說,有一定困難,而且改變了默認(rèn)庫中定時(shí)器的設(shè)置,可能會(huì)產(chǎn)生與其他模塊的沖突,所以這種方式只適合于硬件連接無法改變的情況使用。有沒有簡單點(diǎn)的方法呢?
還有一種方法就是更換風(fēng)扇連接的數(shù)字口。查看資料,筆者可以得知,Arduino UNO的各個(gè)具備PWM輸出功能的數(shù)字口及其定時(shí)器的對應(yīng)關(guān)系如上頁表所示。筆者將風(fēng)扇換到使用0號(hào)定時(shí)器的6號(hào)口上,修改程序中的端口,重新編譯下載后,測試也一切正常。學(xué)生覺得這種處理定時(shí)沖突的方式更簡單,只要記住6個(gè)可以輸出PWM的數(shù)字口對應(yīng)的定時(shí)器,換一下連接數(shù)字口就可以解決定時(shí)器資源沖突問題。
結(jié)語
至此,故障得到了很好的解決。通過這個(gè)過程,筆者總結(jié)了在進(jìn)行Arduino制作時(shí)需要注意的幾點(diǎn):
①用Arduino UNO實(shí)現(xiàn)一些簡單的互動(dòng)功能的確很方便,但作品的功能一旦復(fù)雜,就容易出現(xiàn)各種資源沖突的問題。所以,應(yīng)用比較復(fù)雜的作品,最好選用硬件資源更加豐富的板子,如Arduino 2560、Arduino DUE等。
②如果作品中多處用到定時(shí)器,要合理分配定時(shí)器的使用。
③在使用數(shù)字口5、6的PWM功能時(shí),盡量不要使用delay()延時(shí)函數(shù),因?yàn)檫@個(gè)函數(shù)是使用定時(shí)器0來產(chǎn)生延時(shí)。
④像紅外遙控模塊這樣需要用到定時(shí)器的模塊,盡量不要接在具有PWM功能的數(shù)字口上,以免造成干擾。
⑤將PWM輸出寫在不同程序段,能減少互相干擾的概率。
此外,筆者深刻體會(huì)到,創(chuàng)客教師和學(xué)生還應(yīng)該多了解一些單片機(jī)的原理、知識(shí),才能“造”出更多有趣的作品,遇到問題也能得到有效解決。