DEV Community

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

Posted on • Edited 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() 擺錯地方,就有可能不會被執行到,我自己就犯過低級錯誤,還想了老半天為什麼紅外線接收突然就失靈了。

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

Top comments (0)

AWS Security LIVE!

Tune in for AWS Security LIVE!

Join AWS Security LIVE! for expert insights and actionable tips to protect your organization and keep security teams prepared.

Learn More

👋 Kindness is contagious

Engage with a sea of insights in this enlightening article, highly esteemed within the encouraging DEV Community. Programmers of every skill level are invited to participate and enrich our shared knowledge.

A simple "thank you" can uplift someone's spirits. Express your appreciation in the comments section!

On DEV, sharing knowledge smooths our journey and strengthens our community bonds. Found this useful? A brief thank you to the author can mean a lot.

Okay