-1

I am a novice to Arduino. I came across an article on rs 485 and currently trying to implement the same between 2 arduino unos. I copied code from internet which is pretty simple but I am unable to make communication work properly. Here is the code for master arduino with explanation of what I am trying to do.

**Master Arduino Code** 
/* 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 
                                                             //function  
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();    // wiat 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);
}

This is the slave arduino code

#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 
                 }
             }
             
        }
    }

  }
}

This is screen shot of proteous simulation showing Master unable to read slave1's sensor data enter image description here

I assessed that problem arose because of master and slave both being in transmission mode so I attached a not gate between master's enable pin and slave's enable pin and then master is working fine. but practically attaching a not gate wont be possible. that's why I want to know how to ensure that enable of both master and slave is not high simultaneously. I have tried a couple of strategies and introduced delays at different locations in the code but nothing seems to work. by hit and trial it starts to work sometimes but I want to know the correct way of doing so.

This is screen shot of proteous simulation which shows master reading correctly slave1 data only after I attach a not gate between master Enable pin and Slave's Enable pin. Code for both master and slave and circuit is exactly the same as before. only a not gate has been used between master's enable pin and slave's enable pin.

enter image description here

I tried another library madleech/Auto485 but that i also showing the same problem. have tried a couple of times adding delays at different locations in master code but to no use. i know problem is because of enable pins of both MAX 485 modules connected to 2 arduinos going high simultaneously but i am unable to figure out how to address this issue.

1 Answers1

0

You need to wait for each byte to be available before reading the serial port.

In your code:

if(Serial.available())  // you wait 
{ 
   if(Serial.read()=='I')  // all slaves will detect I on rs 485 bus which //means master has started commmunication. 
   {    
       // parseInt() does wait for a byte to be availeble, so that works...

       int Slave = Serial.parseInt();bus 
       if(Slave == SlaveNumber)
       {   
           // Here serial.read() will most likely return -1, since it is very 
           // unlikely that a byte is already available at this point.

           char command = Serial.read();
      
       // ...   

You should wait for the serial port to have received bytes before reading them.

You can try inserting a loop before calling read(), as in:

 while (!Serial.available()) {} // wait for something to read
 char byteRead = Serial.read(); 

This blocking code should help fix the code as you have it now. You should probably explore non-blocking ways of reading serial commands, such as using some sort of finite state machine algorithm. As a rule of thumb, embedded software should avoid blocking.

Michaël Roy
  • 6,338
  • 1
  • 15
  • 19
  • Maybe try putting a few ms delay after setting 'Enable' high on the slave side so it could be fully on before printing anything. It could be that using the not gate sets it high sooner than without the not gate so it has a tiny bit more time before printing back. – Roman Feb 15 '23 at 21:09
  • @Roman RS485 chips are usually fairly quick to enable (< 75 ns, or less than 2 cycles @16MHz). Note that this signal only goes to the RS485 transceiver, and not al the way to the master. No delay would be necessary on a 16MHz Arduino, but a few milliseconds would be too long on faster devices. – Michaël Roy Feb 15 '23 at 21:33
  • @MichaëlRoy Thanks for your suggestion. I made both master and slave wait for something to be available ( by putting while ( !Serial.available() ) {} ) on serial port before invoking Serial.read() on both master and slave but it didnt work. Mysteriously adding a small delay of 1 ms before slave starts to send data back to the master worked. I dont know why. ``` if(Serial.read()=='F'){ delay(1); int AnalogValue = analogRead(0); digitalWrite(Enable, HIGH); Serial.print("i"); ``` – mohsin ali Feb 16 '23 at 16:09
  • There is nothing mysterious about adding a small delay, t=you'll notice there is also one in the original master code. Sometimes you must give time for the hardware to respond. Physics. If you plan on doing more embedded programming, you should *always* consult the datasheets of the hardware you are using. Timing delays are usually listed as AC characteristics. – Michaël Roy Feb 16 '23 at 16:14