DEV Community

Cover image for IRRemote 程式庫搭配 Adafruit_NeoPoxel 程式庫的問題
codemee
codemee

Posted on

IRRemote 程式庫搭配 Adafruit_NeoPoxel 程式庫的問題

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();
  }
}
Enter fullscreen mode Exit fullscreen mode

由於呼吸燈效果每隔一小段時間(本例是 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
Enter fullscreen mode Exit fullscreen mode

中間出現的未知協定(0)的解碼(0)就是錯誤解碼的結果,根據 IRRemote 的〈Problems with Neopixels, FastLed etc.〉建議,最好只在紅外線接收器閒置的時候傳輸 WS2812B 的資料,以下就是依此修改 loop 中顯示呼吸燈效果的地方:

...
void loop() {
  if(IrReceiver.isIdle()) {
    // 只有沒有在接收紅外線指令時才顯示進行特效
    // 否則傳輸燈條資料的時間會擾亂紅外線接收訊號
    breathe();
  }
...
Enter fullscreen mode Exit fullscreen mode

修改完成後,就可以看到不會再出現奇怪的解碼 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
Enter fullscreen mode Exit fullscreen mode

最後,還是要提醒大家,使用 IRRemote 程式庫一定要注意,只要 IrReceiver.decode() 傳回結果,就一定要叫用 IrReceiver.resume() 恢復等待接收狀態,否則就再也不會解碼,因此你的程式架構一定是長這樣:

void loop() {
  ...
  if (IrReceiver.decode()) {
    // 有成功收到訊號
    ...
    // 恢復紅外線接收功能
    IrReceiver.resume();
  }
}
Enter fullscreen mode Exit fullscreen mode

如果 IrReceiver.resume() 擺錯地方,就有可能不會被執行到,我自己就犯過低級錯誤,還想了老半天為什麼紅外線接收突然就失靈了。

Top comments (0)