0

I am reading data from RS485 which is in the following format:

void sendkwh()
{
  RS485Serial.write((byte)0x01); // Meter Address
  RS485Serial.write((byte)0x03); // Read Function Code
  RS485Serial.write((byte)0x40); // Register Address Variable (Start address high bit)
  RS485Serial.write((byte)0x34); // Register Address Variable (Start address low bit)
  RS485Serial.write((byte)0x00); // Register Quantity (High Bit)
  RS485Serial.write((byte)0x02); // Register Quantity (Low Bit)
  RS485Serial.write((byte)0x90); // CRC check code (CRC code Low bit)
  RS485Serial.write((byte)0x05); // CRC check code (CRC code High bit)
}

and I need to read only the 4th and 5th frame of the packet. I am doing it the following way:

RS485Serial.listen();            
  if (RS485Serial.available() > 0)  
   {

    if(RS485Serial.read() == 0x01)
    {
    for(int i=0; i<4; i++) {

   byte discard = RS485Serial.read();

   }
    byteReceived = RS485Serial.read(); // 4th frame
    byteReceived2 = RS485Serial.read(); // 5th frame

which is working fine. I wanted to know if there is a method to discard the packets without loop?

As in I have changed the sendkwh() as below:

byte SendKWh[] = { 0x01, 0x03, 0x40, 0x34, 0x00, 0x02, 0x90, 0x05 };
RS485Serial.write(SendKWh, sizeof(SendKWh));

But don't know how to proceed with tapping the 4th and the 5th frame. Your help is appreciated.

  • What are the significance of the other bytes in the packet? – Majenko May 23 '17 at 10:29
  • But the 4th and 5th frame actually needs to be sent to a server later in the code – Ashish K May 23 '17 at 10:31
  • If there was no significance they wouldn't exist. What do they all mean? As in - is there a packet header? A checksum? A packet length? What? – Majenko May 23 '17 at 10:31
  • In a nutshell: your current reading methodology is seriously flawed and you're lucky it works at all. – Majenko May 23 '17 at 10:32
  • Ok, sorry I didn't get your question at first. The other bytes have significance, as in Meter Address, Function Code, CRC code , etc – Ashish K May 23 '17 at 10:35
2

Your reading methodology is flawed from the start and you need to completely change how you do things. First off, you wait until there is at least one byte in the incoming buffer, then if that byte is 0x01 you then try and read 5 more bytes - even if there is only (say) 2 bytes in the buffer.

Instead you need to set up a sliding window for receiving the data. A sliding window is basically an array that is the same size as the data you are receiving, and as bytes become available they work their way down from the "top" to the "bottom" of the array. When the contents of the array match a certain pattern you know it is a "good" packet and you can use the data form it.

For example, you may have something like:

uint8_t window[8];

void loop() {
    if (RS485Serial.available()) {
        uint8_t b = RS485Serial.read();
        // Slide the contents of the array down
        for (uint8_t i = 0; i < 7; i++) {
            window[i] = window[i+1];
        }
        // Insert at the top
        window[7] = b;

        // If the array starts with 0x01,0x03,0x40,0x34...
        if ((window[0] == 0x01) && (window[1] == 0x03) &&
            (window[2] == 0x40) && (window[3] == 0x34)) {
            // Do something with window[4] and window[5]
        }
    }
}

You could also add checking the CRC to that by comparing the calculated CRC for the incoming packet (however that is done in this protocol) with the last two bytes of the array.

  • Just one quick question, What is the need to slide the contents of the array down ? – Ashish K May 23 '17 at 10:58
  • To make room for the new incoming byte. Yes, you could wrap around instead, using a circular buffer, but that gets more complicated to both code and understand. Think of the data as socks on a washing line. You are only interested in the 8 socks that begin with the sequence red, blue, green, yellow. The "window" is the gap between your hands held out in front of you (fingers up, palms away from you, thumb tips touching). You move the "window" (slide it) along the socks until you see just 8 starting with the right sequence. – Majenko May 23 '17 at 11:00
  • If I give the condition as (window[0] == 0x01) && (window[1] == 0x03) && (window[2] == 0x40) && (window[3] == 0x34) to (window[0] == 0x01) && (window[7] == 0x05) to confirm the window is covering the complete frame, then will I go wrong? – Ashish K May 23 '17 at 11:27
  • 1
    Yes, because window[6] and window[7] are the CRC and will change from packet to packet. You should, as I say in the last line of my answer, calculate the CRC and compare that to windows 6 and 7. – Majenko May 23 '17 at 11:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.