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)