基于红外的Arduino双板通信故障排查求助
Arduino红外通信故障排查与修复方案
核心问题梳理
你的代码存在多处导致通信失效的问题,逐一拆解如下:
- 串口波特率不匹配:主控代码
Serial.begin(9600),从控代码Serial.begin(19200),波特率不一致会导致接收数据乱码。 - 数据格式完全不兼容:主控发送的是完整字符串(如
"0x1",包含'0'、'x'、'1'和换行符),但从控用char val = Serial.read()读取单个字符,还试图匹配case '0x1'——单个字符不可能等于4字符的字符串,完全无法触发对应逻辑。 - 红外通信实现误解:你直接使用硬件Serial通信,但普通红外收发模块并非直接对接硬件串口,需要用专用的红外编码/解码库(如IRremote)通过数字引脚实现通信,而非复用USB串口。
- 从控代码语法错误:
else stop();的位置错误,属于if(Serial.available())的分支,但代码括号嵌套错误,会导致编译或逻辑异常。 - 硬件引脚冲突:从控中
E1=5、E2=6,同时将舵机servo_0绑定到引脚5,servo_1绑定到引脚6,同一引脚同时被电机PWM和舵机占用,会导致硬件功能异常。 - 主控重复发送数据:多个
if条件无互斥逻辑,可能同时触发多条指令发送(比如摇杆处于边界时),导致从控接收数据混乱。
修正方案与代码
1. 硬件调整
- 主控:将红外发射模块的数据引脚连接到数字引脚3,电源接5V/GND。
- 从控:将红外接收模块的数据引脚连接到数字引脚2,电源接5V/GND;调整舵机引脚到空闲引脚(如9、10),避免和电机引脚冲突。
2. 主控修正代码(使用IRremote库发送指令)
首先在Arduino库管理器中搜索安装IRremote库:
#include <IRremote.h> IRsend irsend; // 摇杆引脚 const int joystickX = A0; const int joystickY = A1; const int joystickS1 = A2; const int joystickS2 = A3; // 定义指令码(用单个字节代替字符串,避免格式问题) const byte CMD_STOP = 0x00; const byte CMD_FORWARD = 0x01; const byte CMD_BACKWARD = 0x02; const byte CMD_LEFT = 0x03; const byte CMD_RIGHT = 0x04; const byte CMD_SERVO1_UP = 0x05; const byte CMD_SERVO1_DOWN = 0x06; const byte CMD_SERVO2_UP = 0x07; const byte CMD_SERVO2_DOWN = 0x08; void setup() { pinMode(joystickX, INPUT); pinMode(joystickY, INPUT); pinMode(joystickS1, INPUT); pinMode(joystickS2, INPUT); Serial.begin(9600); // 仅用于调试,红外通信不需要这个 } void loop() { int xVal = analogRead(joystickX); int yVal = analogRead(joystickY); int s1Val = analogRead(joystickS1); int s2Val = analogRead(joystickS2); byte cmd = CMD_STOP; // 优先判断摇杆指令(互斥逻辑) if (xVal > 522) { cmd = CMD_FORWARD; } else if (xVal < 500) { cmd = CMD_BACKWARD; } else if (yVal > 522) { cmd = CMD_RIGHT; } else if (yVal < 500) { cmd = CMD_LEFT; } else if (s1Val > 522) { cmd = CMD_SERVO1_UP; } else if (s1Val < 500) { cmd = CMD_SERVO1_DOWN; } else if (s2Val > 522) { cmd = CMD_SERVO2_UP; } else if (s2Val < 500) { cmd = CMD_SERVO2_DOWN; } else { cmd = CMD_STOP; } irsend.sendNEC(cmd, 8); // 发送NEC格式的8位指令 delay(50); // 避免发送过于频繁 }
3. 从控修正代码(使用IRremote库接收指令)
同样安装IRremote库,调整引脚冲突:
#include <Servo.h> #include <IRremote.h> // 电机引脚(避免和舵机冲突) const int E1 = 5; // M1 Speed Control const int E2 = 6; // M2 Speed Control const int M1 = 4; // M1 Direction Control const int M2 = 7; // M2 Direction Control // 舵机引脚调整到空闲引脚 Servo servo_0; Servo servo_1; const int SERVO_PIN1 = 9; const int SERVO_PIN2 = 10; int sr1 = 90; // 初始角度设为中间值 int sr2 = 90; // 红外接收引脚 const int IR_RECEIVE_PIN = 2; IRrecv irrecv(IR_RECEIVE_PIN); decode_results results; // 指令码和主控保持一致 const byte CMD_STOP = 0x00; const byte CMD_FORWARD = 0x01; const byte CMD_BACKWARD = 0x02; const byte CMD_LEFT = 0x03; const byte CMD_RIGHT = 0x04; const byte CMD_SERVO1_UP = 0x05; const byte CMD_SERVO1_DOWN = 0x06; const byte CMD_SERVO2_UP = 0x07; const byte CMD_SERVO2_DOWN = 0x08; void stop(void) { digitalWrite(E1, LOW); digitalWrite(E2, LOW); } void advance(char a, char b) { analogWrite(E1, a); digitalWrite(M1, HIGH); analogWrite(E2, b); digitalWrite(M2, HIGH); } void back_off(char a, char b) { analogWrite(E1, a); digitalWrite(M1, LOW); analogWrite(E2, b); digitalWrite(M2, LOW); } void turn_L(char a, char b) { analogWrite(E1, a); digitalWrite(M1, LOW); analogWrite(E2, b); digitalWrite(M2, HIGH); } void turn_R(char a, char b) { analogWrite(E1, a); digitalWrite(M1, HIGH); analogWrite(E2, b); digitalWrite(M2, LOW); } void setup(void) { servo_0.attach(SERVO_PIN1, 500, 2500); servo_1.attach(SERVO_PIN2, 500, 2500); // 初始化电机引脚 for (int i = 4; i <= 7; i++) { pinMode(i, OUTPUT); } // 初始化红外接收 irrecv.enableIRIn(); Serial.begin(9600); // 用于调试 Serial.println("IR control ready"); } void loop(void) { servo_0.write(sr1); servo_1.write(sr2); if (irrecv.decode(&results)) { byte cmd = results.value; irrecv.resume(); // 准备接收下一个指令 switch (cmd) { case CMD_FORWARD: advance(255, 255); break; case CMD_BACKWARD: back_off(255, 255); break; case CMD_LEFT: turn_L(100, 100); break; case CMD_RIGHT: turn_R(100, 100); break; case CMD_STOP: stop(); break; case CMD_SERVO1_UP: sr1 = constrain(sr1 + 10, 0, 180); // 限制角度在0-180 break; case CMD_SERVO1_DOWN: sr1 = constrain(sr1 - 10, 0, 180); break; case CMD_SERVO2_UP: sr2 = constrain(sr2 + 10, 0, 180); break; case CMD_SERVO2_DOWN: sr2 = constrain(sr2 - 10, 0, 180); break; default: stop(); // 未知指令停止 break; } } }
额外注意事项
- 确保红外模块的发射和接收头正对,避免遮挡,在有效通信距离内测试。
- 舵机角度添加
constrain限制,避免超出舵机物理范围损坏硬件。 - 若使用的是带串口的红外模块(如HC-12转红外),则需要调整波特率一致,且发送单个字节而非字符串。
内容的提问来源于stack exchange,提问作者Kyle_3_1415
相关产品推荐
相关产品推荐

