RS485 MODBUS ARDUINO: Print multiple response data frame from soil sensor

Well that didn't go as planned :confused:

OK, might as well go back to 20mS for now then. Do you have a 'scope? Can you capture a shot of the TX request message and the RX message from the module? I'm quite confused by the timing.

This is the OUTPUT with 20ms:
Msg: 01030E000000F100000045000000000000FC2E
Humidity....: 0.0%
Temperature.: 24.1oC
Conductivity: 0us/cm
pH..........: 6.90
Nitrogen....: 0mg/kg?
Phosphorus..: 0mg/kg
Potassium...: 0mg/kg
Message Timeout
Msg: 01030E003300F1000000470000000000009BDD
Humidity....: 5.1%
Temperature.: 24.1oC
Conductivity: 0us/cm
pH..........: 7.10
Nitrogen....: 0mg/kg?
Phosphorus..: 0mg/kg
Potassium...: 0mg/kg
Msg: 01030E009900F400000046000000000000027A
Humidity....: 15.3%
Temperature.: 24.4oC
Conductivity: 0us/cm
pH..........: 7.00
Nitrogen....: 0mg/kg?
Phosphorus..: 0mg/kg
Potassium...: 0mg/kg
Message Timeout
Msg: 01030E000000F900000046000000000000E54E
Humidity....: 0.0%
Temperature.: 24.9oC
Conductivity: 0us/cm
pH..........: 7.00
Nitrogen....: 0mg/kg?
Phosphorus..: 0mg/kg
Potassium...: 0mg/kg
Message Timeout
Message Timeout
Msg: 01030E000000FA00000045000000000000D90A
DELAY TIME
FROM DE and RE HIGH to DE and RE LOW:
Delay time 1: 3001
Msg: 01030E000000F100000046000000000000CF2E
Humidity....: 0.0%
Temperature.: 24.1oC
Conductivity: 0us/cm
pH..........: 7.00
Nitrogen....: 0mg/kg
Phosphorus..: 0mg/kg
Potassium...: 0mg/kg

Can you try;
a) Increase the serial monitor baud rate to 115200 to allow for faster debug messages:

void setup() 
{
    Serial.begin(115200); //<-- change

b) Changing the receive switch contents to the following (adds some serial prints to give an idea of the time elapsing between the request transmission and the receipt of parts of reply from the module (you can copy-paste or just add the lines with the comment "added"...):

        case    ST_RXDATA:            
            if( mod.available() )            
            {   
                ch = mod.read();                             
                switch( rxIdx )
                {
                    case    0:  //address code
                        //an attempt to filter leading zeros in reply
                        //look for 0x01 address code
                        if( ch == 0x01 )
                        {
                            Serial.print( "Time to address code: " ); // added
                            Serial.println( tNow - tFrameTimeout ); // added
                            //got the address code
                            values[rxIdx++] = ch;
                            
                        }//if
                    break;
                        
                    case    1:  //function code
                        //if function code is not 0x03, we're misaligned
                        if( ch != 0x03 )
                            rxIdx = 0;
                        else
                        {
                            Serial.print( "Time to function code: " ); // added
                            Serial.println( tNow - tFrameTimeout ); // added
                            values[rxIdx++] = ch;
                        }//else
                    break;

                    case    2:
                        //number of data + CRC bytes to follow
                        dataLen = ch;
                        values[rxIdx++] = ch;
                    break;

                    default:
                        //RX data and CRC
                        values[rxIdx++] = ch;
                        if( rxIdx == RX_BUFF_SIZE )
                            rxIdx--;
                            
                        dataLen--;
                        if( dataLen == 0 )
                        {
                            Serial.print( "Time to end of message: " ); // added
                            Serial.println( tNow - tFrameTimeout ); // added
                            
                            state = ST_CHECKDATA;
                            
                        }//if                        
                    break;
                                            
                }//switch rx index

            }//if available
            
            //if we haven't completed the message after 1.5-seconds just return to idle state
            if( (tNow - tFrameTimeout) >= 1500ul )
            {
                Serial.println( "Message Timeout" );
                state = ST_IDLE;
                
            }//if
            
        break;

        case    ST_CHECKDATA:
            //show RXed message
            //Serial.print( "Msg: " );
            //for( crc=0; crc<rxIdx; crc++ ) 
            //{
            //    sprintf( szStr, "%02X", values[crc] );
            //    Serial.print( szStr );
            //    
            //}//for
            //Serial.println();
            
            //check the CRC                
            crc = CRC16_Modbus( values, values[2]+3 );
            if( ((uint8_t)(crc & 0x0ff) == values[rxIdx-2]) && ((uint8_t)((crc>>8) & 0x0ff) == values[rxIdx-1]) )
            {
                //msg is good; print results
                PrintData();                                
                    
            }//if
            else
            {
                Serial.println( "Bad CRC" );
                
            }//else

            state = ST_IDLE;
            
        break;

With the time to address OUTPUT:

Time to address code: 30
Time to function code: 33
Time to end of message: 52
Humidity....: 0.0%
Temperature.: 23.4oC
Conductivity: 0us/cm
pH..........: 7.00
Nitrogen....: 0mg/kg
Phosphorus..: 0mg/kg
Potassium...: 0mg/kg
Time to address code: 31
Time to function code: 33
Time to end of message: 50
Humidity....: 0.0%
Temperature.: 23.4oC
Conductivity: 0us/cm
pH..........: 6.90
Nitrogen....: 0mg/kg
Phosphorus..: 0mg/kg
Potassium...: 0mg/kg
Time to address code: 31
Time to function code: 33
Time to end of message: 50
Humidity....: 0.0%
Temperature.: 23.4oC
Conductivity: 0us/cm
pH..........: 7.00
Nitrogen....: 0mg/kg
Phosphorus..: 0mg/kg
Potassium...: 0mg/kg
Message Timeout
Time to address code: 31
Message Timeout
Message Timeout
Time to address code: 30
Time to function code: 33
Time to end of message: 51
Humidity....: 0.0%
Temperature.: 23.5oC
Conductivity: 0us/cm
pH..........: 7.00
Nitrogen....: 0mg/kg
Phosphorus..: 0mg/kg
Potassium...: 0mg/kg

Well, more oddity: When it is successful the return message completes in just ~50mS. But there are enough cases where it seems to exceed 1500mS (resulting in the time-out.)

I don't have a soil NPK sensor so I can't do much more debugging for you. I'd like to scope the signals to check for timing consistency and integrity to better understand the timeouts being seen and to experiment more with frequency of requests etc. But I won't be buying a sensor to do this testing myself. If you find out the reason why please post back and let us know.

1 Like

Thank you so much @Blackfin. You help me a lot :handshake:

I'm not sure this will help you out some more, but back in post #1 you had a screenshot of a PC application talking to the sensor. Therefore I assume that you have a way of generating RS485 from the PC - maybe a USB-RS485 dongle or the like.

Whilst trying to get the code to work on the Arduino, you can also use your PC as a serial monitor on the RS485 bus to see what messages are being sent out and what replies you get in return (if any). Just wire your RS485 dongle into the bus and you should be able to see the messages.

There are several PC apps that can display serial data as hex bytes. I happen to like using Hercules for this task, but use whatever you are familiar with as long as it can display binary data as hex bytes.

1 Like