IRremote 是大家使用紅外線遙控實驗最常用的程式庫,由於接收紅外線遙控器訊號與時間極度相關,如果你的程式中有耗時較久的動作,就可能會影響到紅外線訊號接收的正確性。舉例來說,像是大家愛用的 WS2812B 燈串,串接越多顆燈,傳輸所有燈顏色的資料所耗的時間就越久,以底下這個採用 Adafruit_NeoPixel 程式庫顯示呼吸燈效果的程式為例:
#include <Arduino.h> #include <IRremote.hpp> #include<Adafruit_NeoPixel.h> #define DECODE_NEC Adafruit_NeoPixel leds=Adafruit_NeoPixel(16, 7); void setup() { Serial.begin(115200); leds.begin(); leds.setBrightness(32); IrReceiver.begin(2); } void breathe() { static unsigned long lastTime = 0; static uint32_t color = 0; static int step = 1; if(millis() - lastTime > 10) { leds.fill(color << 16 | color << 8 | color); leds.show(); color += step; if(color == 80) step = -1; if(color == 0) step = 1; lastTime = millis(); } } void loop() { breathe(); if (IrReceiver.decode()) { // 有成功收到訊號 if(IrReceiver.decodedIRData.protocol == NEC) { // 只處理 NEC 編碼的訊號 Serial.println(IrReceiver.decodedIRData.command, HEX); } else { Serial.print("Non-NEC code:"); Serial.print(IrReceiver.decodedIRData.protocol); Serial.print(","); Serial.println(IrReceiver.decodedIRData.command, HEX); } // 恢復紅外線接收功能 IrReceiver.resume(); } }
由於呼吸燈效果每隔一小段時間(本例是 10ms)就要更新一次 16 顆 WS2812B 的顏色,實際執行時就會發現接收紅外線訊號會有不穩的現象:
18:25:32.318 -> 1C 18:25:32.866 -> 52 18:25:32.913 -> Non-NEC code:0,0 18:25:33.004 -> Non-NEC code:0,0 18:25:34.794 -> 52 18:25:34.840 -> 52 18:25:37.052 -> 8 18:25:37.098 -> 8 18:25:37.646 -> 1C 18:25:37.691 -> 1C 18:25:38.613 -> 42 18:25:38.650 -> 42
中間出現的未知協定(0)的解碼(0)就是錯誤解碼的結果,根據 IRRemote 的〈Problems with Neopixels, FastLed etc.〉建議,最好只在紅外線接收器閒置的時候傳輸 WS2812B 的資料,以下就是依此修改 loop
中顯示呼吸燈效果的地方:
... void loop() { if(IrReceiver.isIdle()) { // 只有沒有在接收紅外線指令時才顯示進行特效 // 否則傳輸燈條資料的時間會擾亂紅外線接收訊號 breathe(); } ...
修改完成後,就可以看到不會再出現奇怪的解碼 0 了:
18:29:19.866 -> 43 18:29:19.952 -> 43 18:29:20.675 -> 44 18:29:20.754 -> 44 18:29:21.257 -> 7 18:29:21.350 -> 7 18:29:21.440 -> 7 18:29:21.936 -> 15 18:29:22.021 -> 15 18:29:22.574 -> 9 18:29:22.621 -> 9
最後,還是要提醒大家,使用 IRRemote 程式庫一定要注意,只要 IrReceiver.decode()
傳回結果,就一定要叫用 IrReceiver.resume()
恢復等待接收狀態,否則就再也不會解碼,因此你的程式架構一定是長這樣:
void loop() { ... if (IrReceiver.decode()) { // 有成功收到訊號 ... // 恢復紅外線接收功能 IrReceiver.resume(); } }
如果 IrReceiver.resume()
擺錯地方,就有可能不會被執行到,我自己就犯過低級錯誤,還想了老半天為什麼紅外線接收突然就失靈了。
Top comments (0)