Thanks for your answer. I have implemented the code you provided me and the result:
I don't understand... What could be wrong?
Thanks for your answer. I have implemented the code you provided me and the result:
Thank for reply @markd833. The circuit is like the image and without the LCD and instead arduino nano I working with Arduino UNO
Initialising the state the output are those:
I see the response frame apparently starting after two other characters on your first line there. Perhaps it would be worth emptying the serial input buffer before you send the request frame.
Give this a try (compiles, lightly tested with Uno emulating your sensor...)
Uses CRC checks to verify packets.
#include <Wire.h>
#include <SoftwareSerial.h>
#define RE 8
#define DE 7
#define RX_BUFF_SIZE 30
enum RS485States
{
ST_IDLE = 0,
ST_RXDATA,
ST_CHECKDATA
};
const uint16_t crc16_tab[] PROGMEM =
{
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
};
const byte requestframe[] = { 0x01, 0x03, 0x00, 0x00, 0x00, 0x07 }; //CRC is added in TX logic
uint8_t values[RX_BUFF_SIZE];
SoftwareSerial mod(2,3); // RX, TX ( Creates a new SoftwareSerial object ) (for Uno)
//SoftwareSerial mod(10,3); // RX, TX ( Creates a new SoftwareSerial object ) (for Mega2560)
void setup()
{
Serial.begin(4800);
mod.begin(4800);
pinMode(RE, OUTPUT);
pinMode(DE, OUTPUT);
}//setup
void loop()
{
ModSM();
}//loop
void ModSM( void )
{
static uint32_t
tFrame = 0ul,
tSM = 0ul;
static uint8_t
dataLen,
rxIdx,
state = ST_IDLE;
uint16_t
crc;
uint32_t
tNow = millis();
uint8_t
ch;
switch( state )
{
case ST_IDLE:
if( (tNow - tSM) >= 3000ul )
{
//flush any stray characters from RX buffer
while( mod.available() )
mod.read();
tSM = tNow;
digitalWrite(DE, HIGH);
digitalWrite(RE, HIGH);
delayMicroseconds(100);
crc = CRC16_Modbus( requestframe, sizeof( requestframe ) );
mod.write( requestframe, sizeof(requestframe) );
mod.write( crc & 0xff );
mod.write( (crc >> 8) & 0xff );
delayMicroseconds(100);
digitalWrite(DE, LOW);
digitalWrite(RE, LOW);
rxIdx = 0;
dataLen = 0;
state = ST_RXDATA;
}//if
break;
case ST_RXDATA:
if( mod.available() )
{
ch = mod.read();
switch( rxIdx )
{
case 0: //address code
case 1: //function code
//do nothing but store these
values[rxIdx++] = ch;
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 )
state = ST_CHECKDATA;
break;
}//switch rx index
}//if available
break;
case ST_CHECKDATA:
//data done; check the CRC
crc = CRC16_Modbus( values, values[2]+1 ); //-2 for CRC, +2 for header, +1 for value[2] itself
if( ((uint8_t)(crc & 0x0ff) == values[rxIdx-2]) && ((uint8_t)((crc>>8) & 0x0ff) == values[rxIdx-1]) )
{
//msg is good; print results
PrintData();
}//if
state = ST_IDLE;
break;
}//switch
}//ModSM
uint16_t CRC16_Modbus( uint8_t *pData, uint8_t Len )
{
//CRC16 calculation
uint16_t crc = 0xFFFF;
while( Len-- )
crc = (crc >> 8) ^ (pgm_read_word(&crc16_tab[(crc ^ *pData++)&0xFF]) );
return crc;
}//CRC16_Modbus
void PrintData( void )
{
int16_t
val;
//0 index 3 moisture content
val = (values[3] << 8) + values[4];
Serial.print( "Humidity....: " ); Serial.print( (float)val/10.0, 1 ); Serial.println("%");
//1 index 5 temperature
val = (values[5] << 8) + values[6];
Serial.print( "Temperature.: " ); Serial.print( (float)val/10.0, 1 ); Serial.println("oC");
//2 index 7 conductivity
val = (values[7] << 8) + values[8];
Serial.print( "Conductivity: " ); Serial.print( val ); Serial.println("us/cm");
//3 index 9 PH
val = (values[9] << 8) + values[10];
Serial.print( "pH..........: " ); Serial.print( (float)val/10.0 ); Serial.println("");
//4 index 11 nitrogen content
val = (values[11] << 8) + values[12];
Serial.print( "Nitrogen....: " ); Serial.print( val ); Serial.println("units?");
//5 index 13 phosphorus content
val = (values[13] << 8) + values[14];
Serial.print( "Phosphorus..: " ); Serial.print( val ); Serial.println("units?");
//6 index 15 potassium content
val = (values[15] << 8) + values[16];
Serial.print( "Potassium...: " ); Serial.print( val ); Serial.println("units?");
}//PrintData
Dear @Blackfin. I appreciate your time and response. It does not print within seconds of execution.
Parameters
Temperature:
UNITS VALUES:
HUMIDITY: % percentage
TEMPERATURE: ºC Celsius
EC: us/cm
PH: As far as I know pH-value is a dimensionless quantity and therefore has no unit.
Nitrogen: mg/kg
Phosphorus: mg/kg
Potassium: mg/kg
And I need your help. I'll leave this forum when the output values are correct.
Can you add the following lines to print the received data in the ST_CHECKDATA state:
case ST_CHECKDATA:
//data done; check the CRC
for( crc=0; crc<rxIdx; crc++ ) //<--- add
Serial.print( values[crc], HEX ); //<--- add
Serial.println(); // <-- add
crc = CRC16_Modbus( values, values[2]+1 ); //-2 for CRC, +2 for header, +1 for value[2] itself
if( ((uint8_t)(crc & 0x0ff) == values[rxIdx-2]) && ((uint8_t)((crc>>8) & 0x0ff) == values[rxIdx-1]) )
{
//msg is good; print results
PrintData();
}//if
else //<--- add from here...
{
Serial.println( "Bad CRC" );
}//else //<--- to here
The CRC must be okay if it's printing the data but the numbers don't make sense. It should update once every 3 seconds; if it's only updating once in a while the CRC may be bad.
Can you also copy the serial monitor contents and paste it within code tags instead of taking screen pics?
Now the output prints:
Bad CRC
0013
every second
As a follow up to my earlier question regarding the correct wiring of the A & B wires, I believe that you have the sensor wired correctly. In your screenshot in #21, you are receiving a valid message - but only once, and it's out of sync with the query.
Are those few bytes at the top left of your screenshot the very first bytes printed out when your sketch runs?
Not wanting to make things worse for you, but have you tried another software serial implementation? I've used AltSoftSerial in the past with good results. You will have to adjust your wiring if you want to try this library as it has to use pin 9 for Tx and pin 8 for Rx on an UNO.
Every second?
That was the first line output that seems ok. I'll try with AltSoftSerial...
Yes. Every second...
Interesting. When I run it on my Uno with my 2650 emulating your sensor I see:
138292FF9B03836A3Humidity....: 65.8%
Temperature.: -10.1oC
Conductivity: 56us/cm
pH..........: 1398.70
Nitrogen....: 0units?
Phosphorus..: 0units?
Potassium...: 0units?
138292FF9B03836A3Humidity....: 65.8%
Temperature.: -10.1oC
Conductivity: 56us/cm
pH..........: 1398.70
Nitrogen....: 0units?
Phosphorus..: 0units?
Potassium...: 0units?
138292FF9B03836A3Humidity....: 65.8%
Temperature.: -10.1oC
Conductivity: 56us/cm
.
.
.
The 2560 sends this canned message:
buffTX[] = { 0x01, 0x03, 0x08, 0x02, 0x92, 0xff, 0x9b, 0x00, 0x38, 0x36, 0xa3 };
This is the message from the datasheet (page 16) though with a different CRC (0xa336 vs 0xb657; I couldn't get the CRC16 generator nor an online resource to produce 0xb657 for that message...)
Is there nothing more being printed to your serial monitor than the two lines you showed (i.e.
Bad CRC
0013
?
No. Only in new line every second
Bad CRC
0013 ...
OK. Please try changing the delayMicroseconds() after the last CRC byte is sent to this:
.
.
.
crc = CRC16_Modbus( requestframe, sizeof( requestframe ) );
mod.write( requestframe, sizeof(requestframe) );
mod.write( crc & 0xff );
mod.write( (crc >> 8) & 0xff );
delay(20); //<--- change to 20mS
.
.
.
Now prints every ms:
Bad CRC
00000C0000000C00C00000000000000C0
Are you still using SoftwareSerial or did you change to AltSoftSerial? Are the serial connections correct?
I tried with AltSoftSerial library:
// RS485 module wired up as:
// RS485 DI signal to pin 9
// RS485 RO signal to pin 8
// RS485 RE signal to pin 7
// RS485 DE signal to pin 6
Output:
0 0 C0 C0 0 C0 C0 C0 C0 0 C0 C0 C0 C0 0 C0 C0 C0 | hum: -1619.20 %, temp: 19.20 º, ec: -1619.20, ph: -1638.40, n: -1619.20, p: -1619.20, k: 19.20
C0 0 C0 C0 C0 C0 0 C0 C0 C0 C0 0 C0 C0 C0 C0 0 C0 | hum: -1619.20 %, temp: -1619.20 º, ec: 19.20, ph: -1619.20, n: -1638.40, p: -1619.20, k: -1619.20
C0 C0 C0 0 C0 C0 C0 C0 0 C0 E0 70 B6 6B 0 4B 83 37 | hum: -1638.40 %, temp: -1619.20 º, ec: -1619.20, ph: 19.20, n: -808.00, p: -1883.70, k: 7.50
4B 6B 4B 0 4B 3 7B 94 6B 6B 3 6B B 6B 4B 6B 6B 3 | hum: 1920.00 %, temp: 1920.30 º, ec: 3163.60, ph: 2749.90, n: 87.50, p: 292.30, k: 1930.70
4B B 8B B4 4B 4B B 4B B 4B B4 4B 4B 3 4B B CB 4B | hum: -2977.20 %, temp: 1927.50 º, ec: 289.10, ph: 289.10, n: -1938.10, p: 1920.30, k: 1921.10
4B 4B 3 4B B 3B 4B 0 7C FF F0 40 0 4B B B 4B 9B | hum: 84.30 %, temp: 287.50 º, ec: 1920.00, ph: 3199.90, n: -403.20, p: 7.50, k: 282.70
For the code that I gave you can you revert to SoftwareSerial and pins 2 and 3?
I'll keep checking in on your progress, but for now i'll back off as we're providing you with two alternate solutions which can only lead to confusion.
I tried with AltSoftSerial library:
// RS485 module wired up as:
// RS485 DI signal to pin 9
// RS485 RO signal to pin 8
// RS485 RE signal to pin 7
// RS485 DE signal to pin 6
With your code the provide me prints every 10 ms:
Bad CRC
9280FF8306B6BB6B6B6B696B6B16B6B6996696934BB6BB44B4B0