两台Arduino Uno的RS485通信Enable引脚冲突问题求助
Arduino Uno RS485主从通信故障解决方法
问题背景
本人是Arduino新手,尝试在两台Arduino Uno间实现RS485通信,复制网上的主从代码后无法正常通信。分析发现问题源于主从设备的MAX485 Enable引脚同时处于高电平导致总线冲突。在Proteus仿真中给Enable引脚添加非门后通信恢复正常,但实际场景无法使用非门。尝试过添加延迟、使用madleech/Auto485库均未解决问题,现求助正确的解决方法。
仿真现象
- 未加非门:主设备无法读取从设备数据
- 添加非门后:通信恢复正常
原代码
主设备代码
/* master will send a message I1LF where I shows start of master message by master. * 1 shows the slave device No. from whom data is to be fetched and L * shows that master wants to read slave's sensor data * and F indicates finish of message by master. * slave will respond by sending Serial.println(i1) where i is slave no and 1 is to let master know that * correct slave is sending data. then slave would send sensor_value and then f indicates end of slave message. * master will display data read from rs 485 bus. */ #include<LiquidCrystal.h> //Library for LCD display LiquidCrystal lcd(4, 5, 6, 7, 8, 9); const int Enable = 2; int value1=0; void setup() { Serial.begin(9600); pinMode(Enable, OUTPUT); digitalWrite(Enable, HIGH); // put master arduino into transmission mode. lcd.begin(16,2); lcd.clear(); } void loop() { Serial.print('I'); // I indicates master has started communication. Serial.print('1'); // this is the address of slave from whom data is to be fetched. Serial.print('L'); // this means master wants to read sensor data. Serial.print('F'); // this means end of message. Serial.flush(); // wait untill all data has been pushed to the serial. digitalWrite(Enable, LOW); // put master into receiving mode. if(Serial.find('i')) // i will be sent (to indicate start of slave //message , by the slave that was prompted by //master. { int slave = Serial.parseInt(); // check which slave is sending //data. value1 = Serial.parseInt(); if(Serial.read() == 'f' && slave == 1) // f indicates end of message //sent by slave and 1 is the //address of the slave sent by // the slave so that master can //recognize which slave is this. { lcd.setCursor(0,0); lcd.print("Slave : "); lcd.setCursor(11,0); lcd.print(value1); } } digitalWrite(Enable, HIGH); delay(300); }
从设备代码
#include<LiquidCrystal.h> LiquidCrystal lcd(4, 5, 6, 7, 8, 9); const int Enable = 2; const int SlaveNumber = 1; void setup() { Serial.begin(9600); pinMode(Enable, OUTPUT); digitalWrite(Enable, LOW); // initially put slave in receiving mode pinMode(A0, INPUT); lcd.begin(16,2); lcd.clear(); } void loop() { if(Serial.available()) { if(Serial.read()=='I') // all slaves will detect I on rs 485 bus which means master has started commmunication. { int Slave = Serial.parseInt(); // read next character on rs 485 bus //which would definitely be a digit //indicating slave no to whom master //wishes to communicate. if(Slave == SlaveNumber) // check if master wants to commnucate //with you. { char command = Serial.read(); // read next character in //serial buffer which would be //command L delay(100); if(command == 'L') { if(Serial.read()=='F') // if master's message has //finished. { int AnalogValue = analogRead(0); // read sensor digitalWrite(Enable, HIGH); // put slave in //transmission mode. Serial.print("i"); // i indicates start of //slave message Serial.println(SlaveNumber); // send slave no so that //master can identify which //slave he is receiving //data from. Serial.print(AnalogValue); Serial.print("f"); // indicates end of message by the //slave. Serial.flush(); digitalWrite(Enable, LOW); // put slave in //listening ( receivig ) mode } } } } } }
解决方案
核心问题分析
你的代码存在两个关键问题:
- MAX485引脚控制逻辑错误:MAX485的
RE和DE引脚通常短接使用,高电平为发送模式,低电平为接收模式。仿真加非门能工作,说明硬件接线或代码电平逻辑搞反了。 - 从设备串口读取时序混乱:
Serial.parseInt()会跳过非数字字符,导致后续读取内容不符预期,额外添加的delay(100)完全没必要,反而打乱通信节奏。
修改后的代码
主设备代码(修正版)
#include<LiquidCrystal.h> LiquidCrystal lcd(4, 5, 6, 7, 8, 9); const int RS485_EN = 2; int value1 = 0; void setup() { Serial.begin(9600); pinMode(RS485_EN, OUTPUT); digitalWrite(RS485_EN, LOW); // 初始设为接收模式 lcd.begin(16,2); lcd.clear(); } void loop() { // 切换到发送模式,发送完整指令 digitalWrite(RS485_EN, HIGH); Serial.print("I1LF"); Serial.flush(); // 等待串口发送完成,再切回接收模式 while(Serial.availableForWrite() > 0); digitalWrite(RS485_EN, LOW); // 1秒超时等待从设备响应 unsigned long timeout = millis(); while(millis() - timeout < 1000) { if(Serial.find('i')) { int slave = Serial.parseInt(); value1 = Serial.parseInt(); if(Serial.read() == 'f' && slave == 1) { lcd.setCursor(0,0); lcd.print("Slave : "); lcd.setCursor(11,0); lcd.print(value1); } break; } } digitalWrite(RS485_EN, LOW); delay(300); }
从设备代码(修正版)
#include<LiquidCrystal.h> LiquidCrystal lcd(4, 5, 6, 7, 8, 9); const int RS485_EN = 2; const int SlaveNumber = 1; char buffer[10]; // 用缓冲区存储完整指令 int bufIndex = 0; void setup() { Serial.begin(9600); pinMode(RS485_EN, OUTPUT); digitalWrite(RS485_EN, LOW); // 初始接收模式 pinMode(A0, INPUT); lcd.begin(16,2); lcd.clear(); } void loop() { while(Serial.available()) { char c = Serial.read(); if(c == 'F') { // 以F作为指令结束标志 buffer[bufIndex] = '\0'; // 解析指令格式:I1LF if(buffer[0] == 'I' && atoi(&buffer[1]) == SlaveNumber && buffer[2] == 'L') { int AnalogValue = analogRead(A0); // 切换到发送模式 digitalWrite(RS485_EN, HIGH); Serial.print("i"); Serial.print(SlaveNumber); Serial.print(AnalogValue); Serial.print("f"); Serial.flush(); // 等待发送完成再切回接收 while(Serial.availableForWrite() > 0); digitalWrite(RS485_EN, LOW); // 更新从设备LCD显示 lcd.setCursor(0,0); lcd.print("Sent: "); lcd.print(AnalogValue); } bufIndex = 0; // 重置缓冲区索引 } else { if(bufIndex < sizeof(buffer)-1) { buffer[bufIndex++] = c; } } } }
额外硬件注意事项
- MAX485接线:务必将
RE和DE引脚短接后接到Arduino的Enable引脚(如引脚2),A端接总线A,B端接总线B,总线两端需各加120Ω终端电阻。 - 电平逻辑适配:如果修正代码后仍无法通信,尝试反转Enable引脚的电平逻辑(高电平接收,低电平发送),这可能是因为你的MAX485模块引脚接线反相了。
内容的提问来源于stack exchange,提问作者mohsin ali
相关产品推荐
相关产品推荐

