You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

两台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 
                 }
             }
             
        }
    }

  }
}

解决方案

核心问题分析

你的代码存在两个关键问题:

  1. MAX485引脚控制逻辑错误:MAX485的RE和DE引脚通常短接使用,高电平为发送模式,低电平为接收模式。仿真加非门能工作,说明硬件接线或代码电平逻辑搞反了。
  2. 从设备串口读取时序混乱: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;
      }
    }
  }
}

额外硬件注意事项

  1. MAX485接线:务必将RE和DE引脚短接后接到Arduino的Enable引脚(如引脚2),A端接总线A,B端接总线B,总线两端需各加120Ω终端电阻。
  2. 电平逻辑适配:如果修正代码后仍无法通信,尝试反转Enable引脚的电平逻辑(高电平接收,低电平发送),这可能是因为你的MAX485模块引脚接线反相了。

内容的提问来源于stack exchange,提问作者mohsin ali

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 22:45:45