Trouble using Modbus Protocol for RS485-based Sensor

Hi All,

I am attempting to parse the data received from an absolute position encoder using RS485. I have attached a few relevant snippets from the datasheet as images. Note it is translated from another language, so it's not the most coherent.

I had purchased a USB to RS485 converted to monitor the data being received. Per the datasheet, I received a steady stream of HEX data in the format of:

AA BB 01 X1 X2 X3 X4 X5 X6 X7 X8 CS

In my project I am only concerned with the position of the absolute encoder, and per the datasheet this is obtained using X7+X8. I am able to see this clearly using a serial monitor debugger. The only error I was receiving at this point was a consistent CRC error.

Since I would like this to run on an MCU (Arduino Mega2560), I attempted to use the modbus protocol. Despite providing the correct Slave ID and albeit a random register address (wasn't clear which to choose from datasheet), I had continuously received the error "Invalid response function". Upon further research, it seems the standardised functions of Modbus do not match what the sensor is using.

I am new to using the RS485 standard, but it seems the only way to obtain this data is via Modbus. Any suggestions on how to properly receive this data would be greatly appreciated! And please let me know if I am missing any info, thanks.

  #include<ModbusMaster.h>

  #define MAX485_DE      3
  #define MAX485_RE_NEG  2
  
  ModbusMaster node;

  void preTransmission()
  {
    digitalWrite(MAX485_RE_NEG, 1);
    digitalWrite(MAX485_DE, 1);
  }

  void postTransmission()
  {
    digitalWrite(MAX485_RE_NEG, 0);
    digitalWrite(MAX485_DE, 0);
  }

  void setup() {
    pinMode(MAX485_RE_NEG, OUTPUT);
    pinMode(MAX485_DE, OUTPUT);
    
    // Init in receive mode 
    digitalWrite(MAX485_RE_NEG, 0);  
    digitalWrite(MAX485_DE, 0);  
  
    Serial.begin(115200);  
    Serial1.begin(115200);  

    //slave ID 170  
    node.begin(0xAA, Serial1);  

    Serial.println("----------------------------");  
    Serial.println("Starting Modbus Transaction:");  
    node.preTransmission(preTransmission);  
    node.postTransmission(postTransmission);  
  }

  void loop() {
    static uint32_t i;
    uint8_t j, result;
    uint16_t data[10];

    i++;
    
    result = node.readHoldingRegisters(0x01,8);
    

    Serial.println("");
  
    if (result == node.ku8MBSuccess) {
      Serial.print("Success, Received data: ");
      for (j = 0; j < 2; j++) {
        data[j] = node.getResponseBuffer(j);
        Serial.print(data[j], HEX);
        Serial.print(" ");
      }
      Serial.println("");
    } else {
      Serial.print("Failed, Response Code: ");
      Serial.print(result, HEX);
      Serial.println("");
      delay(5000); 
    }
    delay(1000);
  }

I also attempted a straight read from serial and print but this had resulted in random characters being printed such as reverse question marks.

const unsigned int MAX_MESSAGE_LENGTH = 12;
//Create a place to hold the incoming message
char message[MAX_MESSAGE_LENGTH];
unsigned int message_pos = 0;

void setup() {
 Serial.begin(115200);
 Serial1.begin(115200);
}

void loop() {
 //Check to see if anything is available in the serial receive buffer
 while (Serial1.available() > 0)
 {

   //Read the next available byte in the serial receive buffer
   char inByte = Serial1.read();


   //Message coming in (check not terminating character) and guard for over message size
   if ( inByte != '\n' && (message_pos < MAX_MESSAGE_LENGTH - 1) )
   {
     //Add the incoming byte to our message
     message[message_pos] = inByte;
     message_pos++;
   }
   
   //Full message received...
   else
   {
     //Add null character to string
     message[message_pos] = '\0';

     for (int cnt = 0; cnt < strlen(message); cnt++)
     {
      Serial.print(message[cnt], HEX);
     }
     
     //Print the message (or do other things)
     Serial.println();

     //Reset for the next message
     message_pos = 0;
  }
 }
}

Datasheet Screenshots
https://ibb.co/Gs0N1Pv
https://ibb.co/Qr6Q6Nf

RS485 to TTL Converter:

USB to RS485 Converter:

Reading the second file you uploaded, I don't think the sensor is using Modbus. The text suggests that the sensor sends the information continuously, rather than wait to be asked for the information.

There is a basic serial handling tutorial here in the forums:

You don't appear to have start and end markers as such. However, it seems that your returned data message will always begin with 0xAA 0xBB and will be 12 bytes long. If you had a buffer 12 bytes long, and stored the received bytes, shifting out the oldest byte when the buffer fills, you can check for the first 2 bytes matching 0xAA & 0xBB. If you get a match, then calculate the checksum and compare it with the 12th byte. If you get a match, then you have a complete message and can extract the data bytes as needed.

Additionally, the text file suggests that the data is transferred as ASCII hex and that possibly each message may be terminated by a CR LF - as it seems to say that you can view this data using a serial port monitor. You should be able to easily determine this for yourself.

1 Like

By using example 6 of the Serial Input Basics along with your suggestions I am now able to receive the data from my sensor. Thank you very much @markd833!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.