Go Down

Topic: Arduino and RS485 communication (Read 2881 times) previous topic - next topic

Etienne1805

Hello everybody,

Currently in Vietnam for an intership I'm trying to communicate with a PLC from Ditel and my Arduino nano. here is the datasheet of the PLC :  ftp://ftp.cmdl.noaa.gov/aerosol/ugr/etc/Ditel_PID_SZ48-SZ49_Modbus.pdf

I have to use an Half-duplex RS485 modbus protocol, so I'm using a MAX485 in order to adjust the voltage level of my frame.

I'm trying to send the frame on page 33 of the datasheet.

Code: [Select]

// Pin 2 of tharduino connected to pins RE&DE of MAX485
#include <SoftwareSerial.h>


SoftwareSerial mySerial(10, 11); //RX, TX

#define switchPin 2

#define rxPin 10
#define txPin 11
 


byte req[]= {0x02, 0x04, 0x00, 0x00, 0x00, 0x01, 0x31, 0xCA}; // Frame to send in order to read the PV value of the PLC
 

byte RS485Byte = 0;
 
void setup() {
 
  // Communication at 9600 b/s
  Serial.begin(9600);
// pin tx to send data
  pinMode(txPin, OUTPUT);
  // pin rx to receive data
  pinMode(rxPin, INPUT);
 
 
  pinMode(switchPin, OUTPUT);
  mySerial.begin(9600);
  digitalWrite(switchPin, HIGH); // Pin 2 High level in order to send data
  mySerial.write(req, sizeof(req));
  mySerial.flush();
  digitalWrite(switchPin, LOW);// Pin 2 Low level in order to receive data
   
   
   
 
 
 
}
 
void loop() {
 

     if( mySerial.available()>0)
     {
        RS485Byte = mySerial.read();
        Serial.print("incoming Bytes : "); Serial.println(byte(RS485Byte), HEX);
      } 
}


And the anwser I have on the monitor is incoming Bytes : 0. 

I was wondering if I have to use the Modbus master library to send data or if anything was wrong in my code ...

( sorry for my bad english..)

Thanks for your help !

Have a nice day


chucktodd

You are sending an invalid CRC, the Slave device is rejecting the command message because of the CRC failure.

Read and Implement a CRC calculating function.

  You copied the example command sequence from the reference manual, BUT changed one byte.  This change of the Station ID from 0x01 to 0x02 invalidated the CRC value 0x31, 0xCA. The calculated CRC is 0x31 0xF9.

  Since the command's CRC does not match the calculated CRC, the device discards the command because it thinks there was a data transmission error. 
 
  This is documented in the PDF as the response to a CRC failure.

  Try sending one of the examples exactly as listed in the PDF. 

Code: [Select]
byte req[]= {0x02, 0x04, 0x00, 0x00, 0x00, 0x01, 0x31, 0xCA}; // Frame to send in order to read the PV value of the PLC


Here is a CRC Function that matches the examples.  I had to reverse the highByte, lowByte order to match the examples from the PDF.  The Manual may be in error, or the implementation may have changed without updating the manual.  If the device does not respond, reverse the order of my example, send the highByte first.


Code: [Select]
// Ditel Modbus CRC calculation
// Chuck Todd <ctodd@cableone.net>


uint16_t CalcCRC(byte * data, uint8_t datlen){
uint16_t CRC=0xFFFF; // Init CRC
uint8_t xor_flag;
for(uint8_t n=0; n<datlen;n++){
  CRC = CRC ^ data[n];
  for(uint8_t i=0;i<8;i++){
    if(CRC & 0x0001) {
      xor_flag = 1;
      }
    else {
      xor_flag = 0;
      }
    CRC = CRC >> 1;
    if (xor_flag) {
      CRC = CRC ^ 0xA001;
      }
    }
  }
return CRC;
}

void SendCmd( byte * data, uint8_t datlen){ // this is just a test routine to send results Serial Monitor.
uint16_t CRC=CalcCRC(data, datlen);
for(uint8_t i=0;i<datlen;i++){ // set TX mode, use the correct Serial (softSerial?)
  Serial.print(data[i],HEX);
  Serial.print(' ');
  }
Serial.print(lowByte(CRC),HEX); // This does not match the Example. It could be an error in the manual.
Serial.print(' ');              // If the device does not respond, reverse the order byte order the CRC 
Serial.println(highByte(CRC),HEX); // is sent.  Send highbyte then lowByte.
}

byte
 req[] = {0x02, 0x04, 0x00, 0x00, 0x00, 0x01},
 req1[]= {0x02, 0x03, 0x03, 0xF9, 0x00, 0x02}, // CRC= 0x14 0x4D pg 31 command
 req2[]= {0x02, 0x03, 0x04, 0x00, 0x00, 0x01, 0x90}, // CRC= 0xC8 0xCF pg 31 response
 req3[]= {0x01, 0x04, 0x00, 0x00, 0x00, 0x01}, // CRC= 0x31 0xCA pg 33 command
 req4[]= {0x01, 0x04, 0x02, 0x03, 0x46};       // CRC= 0x38 0x32 pg 33 response
void setup(){
Serial.begin(9600);
SendCmd(req,6);
Serial.println("CRC != 0x31 0xCA");
SendCmd(req1,6);
Serial.println("CRC= 0x14 0x4D pg 31 command");
SendCmd(req2,7);
Serial.println("CRC= 0xC8 0xCF pg 31 response");
SendCmd(req3,6);
Serial.println("CRC= 0x31 0xCA pg 33 command");
SendCmd(req4,5);
Serial.println("CRC= 0x38 0x32 pg 33 response");

}

void loop(){
}




Chuck.
-----------------------
check out my Kickstarter project. Memory Panes
Currently built mega http server, Now converting it to ESP32.

Etienne1805

Thanks you very much Chuck very helpful ! But I still have no answer from the PLC... I really don't uderstand why because I'm sending the right frame ... I should have a response !

chucktodd

Thanks you very much Chuck very helpful ! But I still have no answer from the PLC... I really don't uderstand why because I'm sending the right frame ... I should have a response !
Have you added the correct CRC for your messages?  Post your updated code, I'll look thru it.

Is the PLC configured correctly?  

Can you just put your Arduino into receive mode (_T/R=R) and monitor communications on the RS485 net?

Have you verified the baud rate is correct?

Can you cause the PLC to transmit something on the RS485 net?  Make it think it has a remote sensor It needs to query?

You are at square one:
 1. Have you connected A-A, B-B, and Ground?
 2. Are the Baud rates correct? Both Arduino and PLC.
 3. Does the PLC know to monitor the RS485 net?
 4. Have you verified the Terminal number (address) of the PLC?
 5. Do you have a Scope to check that you have activity on the RS485 net?
     
Many, many questions.  You need some answers.

Chuck.


Check out my Kickstarter Project Memory Panes an expansion RAM Shield for Mega2560's.  It adds 1MB of RAM for those projects where 8KB is not enough.
Currently built mega http server, Now converting it to ESP32.

Etienne1805

I've checked every questions you tell me everything is ok , only the fact of the same ground. I thought that on a RS485 there was no need of same ground and the fact is that on the PLC there is no ground output... Also I don't have any scope to check the activity on the line...

Go Up