philippedc / arduino-esp8266-rs485-modbus-anemometer Goto Github PK
View Code? Open in Web Editor NEWHere is a way to setup an anemometer that works with RS485 MODBUS communication protocol
License: GNU General Public License v3.0
Here is a way to setup an anemometer that works with RS485 MODBUS communication protocol
License: GNU General Public License v3.0
Hi Philippe, what needs to be changed in the code for ESP8266 v3.5 so that a DS3231 can be used instead of the DS1307?
Also: there seem to be compiling issues near line 223: i and imax should not be defined as byte at the start?
Philip
Here's another issue I've been working on:
I see that you're testing the 2nd byte in Anenometer_buff[] for RS485 trasmission errors:
while( Anemometer_buf[1] != 0x03 ) { // if received message has an error
I found that wasn't sufficient to trap all the errors.
I've implemented code to do a full CRC-16/MODBUS checksum calculation.
I found reference to it on stackoverflow.com and slightly modified it for C++ (Arduino/ESP8266 IDE) data types. The linked article refers to two methods of calculation. The bytewise version is much faster and that's the one I used. It uses 512 bytes of ROM which shouldn't be a problem on the ESP8266.
I've attached the code I'm using. It works very reliably for me. Perhaps you might want to incorporate it into your code.
Here's the function, CRC16, that calculates the checksum:
// CRC-16/MODBUS calc function
uint16_t CRC16 (const byte *nData, uint16_t wLength)
{
static const uint16_t wCRCTable[] = {
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 };
byte nTemp;
uint16_t wCRCWord = 0xFFFF;
while (wLength--)
{
nTemp = *nData++ ^ wCRCWord;
wCRCWord >>= 8;
wCRCWord ^= wCRCTable[(nTemp & 0xFF)];
}
return wCRCWord;
} // End: CRC16
And here's the code that calls the CRC16 function. It passes the first 5 bytes from responseFrameBuff[] to the CRC16 function, which returns the 2 byte CRC. This is tested against the CRC in responseFrameBuff[] (last 2 bytes). The code will loop until an Inquiry returns data with a valid checksum. (In my code the receive buffer is called responseFrameBuff[] rather than Anenometer_buff[] because I use it for both Anenometer and Wind Direction sensors):
#define rtsPin D5 // RS485 RTS direction control
#define transmit HIGH
#define receive LOW
byte responseFrameBuff[7] = {}; // buffer for receiving response frame from sensors
const byte anemometerInquiryFrame[] = {0x03, 0x03, 0x00, 0x00, 0x00, 0x01, 0x85, 0xE8}; // Wind Speed Sensor Inquiry frame
const byte windDirectionInquiryFrame[] = {0x02, 0x03, 0x00, 0x00, 0x00, 0x01, 0x84, 0x39}; // Wind Direction Sensor Inquiry frame
word checksum;
word crc;
do
{
digitalWrite(rtsPin, transmit); // init transmission
RS485.write(anemometerInquiryFrame, sizeof(anemometerInquiryFrame)); // send the Inquiry
RS485.flush(); // Wait for the transmission to complete
digitalWrite(rtsPin, receive); // init receive
RS485.readBytes(responseFrameBuff, 7); // read the data
checksum = CRC16 (responseFrameBuff, 5); // calculate CRC-16/MODBUS checksum
crc = responseFrameBuff[6] * 256 + responseFrameBuff[5]; // get checksum from buffer
}
while (checksum != crc); // test if checksum is ok
Why are you allocating and reading 8 bytes to Anemometer_buff[]
? The Response Frame only has 7 bytes.
Reading 8 bytes limits the response time to > 1 second, perhaps hitting the Serial.setTimeout()
default of 1 second on the 8th byte.
Your test output to the serial monitor is reading 7 bytes.
You can check the return value of RS485Serial.readBytes(anemometerBuff, 8)
which will return the number of bytes placed in the buffer (7).
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.