Arduino蓝牙与红外冲突问题求助:发送蓝牙消息后无法接收红外码
嘿,作为一个经常折腾Arduino蓝牙和红外组合的开发者,我来帮你拆解这个问题~
首先,你的核心需求是:蓝牙收到字符或红外接收器收到信号时,发送指定红外码channel;但实际操作中,蓝牙发送a触发红外发送后,再也抓不到新的红外消息。这种情况大概率不是蓝牙和红外的硬件冲突,而是红外发送过程中中断资源的处理问题,下面详细分析:
可能的核心原因:红外发送时中断被禁用未恢复
大多数红外库(比如常用的IRremote)在执行sendRaw这类发送函数时,会暂时关闭全局中断(cli())——目的是保证红外信号的时序精度不被其他中断打断。但如果库的版本较旧,或者某些场景下没有正确重新开启中断(sei()),就会导致依赖外部中断的红外接收器(引脚2是Arduino Uno的外部中断0)无法触发接收,自然捕获不到新的红外信号。
另外,还有一个容易忽略的点:如果你的红外接收代码里没有调用irrecv.resume(),那接收器在捕获一次信号后就会停止工作,但你说的是发送蓝牙a后才失效,所以这个可能性稍小,但也要检查。
排查与解决步骤
1. 先单独验证红外收发的独立性
先断开蓝牙模块,写一个极简测试程序:
#include <IRremote.h> IRrecv irrecv(2); IRsend irsend; decode_results results; void setup() { Serial.begin(9600); irrecv.enableIRIn(); } void loop() { // 用串口触发红外发送 if (Serial.available() && Serial.read() == 'a') { sendChannelIR(); } // 接收红外信号 if (irrecv.decode(&results)) { Serial.println("收到红外信号"); sendChannelIR(); irrecv.resume(); // 必须调用,恢复下一次接收 } } void sendChannelIR() { // 替换成你自己的channel raw码数组 unsigned int rawData[] = {9000, 4500, 560, 1690, ...}; irsend.sendRaw(rawData, sizeof(rawData)/sizeof(rawData[0]), 38); sei(); // 手动强制开启全局中断 }
如果发送后依然无法接收新红外信号,那可以确定是IRsend的中断恢复问题,直接用上面代码里的sei()解决即可。
2. 排查蓝牙与红外的资源冲突
如果单独测试红外正常,那再看蓝牙的软串口(SoftwareSerial)是否和红外库占用了相同的定时器资源:
- Arduino Uno上,
SoftwareSerial默认使用Timer2,IRremote默认使用Timer1,理论上不冲突;但如果你的板型是其他型号(比如Nano),或者修改过库的定时器配置,可能会有冲突。 - 可以临时把蓝牙换成硬串口(引脚0、1)测试,但注意这时候不能用USB串口调试,只能用蓝牙终端发送指令,看是否还会出现接收失效的问题。
3. 优化你的代码结构
确保代码里没有阻塞式操作(比如delay()),并且在红外接收后必须调用irrecv.resume(),蓝牙接收的处理也要是非阻塞的(就像上面示例那样)。
最终修复后的完整代码示例
#include <IRremote.h> #include <SoftwareSerial.h> // 蓝牙引脚:12为RX,13为TX SoftwareSerial bluetooth(12, 13); IRrecv irrecv(2); IRsend irsend; decode_results results; // 替换成你实际的channel红外raw码 unsigned int channelRaw[] = {9000, 4500, 560, 1690, 560, 560, 560, 560, 560, 1690, 560, 1690, 560, 1690, 560, 1690, 560, 1690, 560, 560, 560, 560, 560, 560, 560, 560, 560, 1690, 560, 1690, 560, 1690, 560, 1690, 560, 39800}; const int rawLength = sizeof(channelRaw)/sizeof(channelRaw[0]); void setup() { Serial.begin(9600); bluetooth.begin(9600); irrecv.enableIRIn(); // 启动红外接收 } void loop() { // 处理蓝牙接收 if (bluetooth.available()) { char receivedChar = bluetooth.read(); if (receivedChar == 'a') { sendChannelIR(); } } // 处理红外接收 if (irrecv.decode(&results)) { Serial.println("捕获到红外遥控器信号"); sendChannelIR(); irrecv.resume(); // 关键:恢复接收下一个红外信号 } } void sendChannelIR() { irsend.sendRaw(channelRaw, rawLength, 38); // 38kHz为常见红外载波频率 sei(); // 手动开启全局中断,确保红外接收中断正常工作 }
总结
你的问题本质是红外发送过程中全局中断被禁用后未正确恢复,导致依赖外部中断的红外接收器无法工作,和蓝牙本身的冲突关系不大。按照上面的步骤排查和修改代码,应该就能解决问题啦~
内容的提问来源于stack exchange,提问作者Pulgayo

