June 15, 20224 yr Dear *, for my Sunsynk 8k inverter I am looking for a RS485 Modbus connection for my data logger. I only need the pure data, no charts or user interface. So I need the absolute basic bytes to send a read request 0x03 via RS485. I am using an Atmel chip, programmed with C++. No windows, no raspberry, no USB. I allready knoow the pinning of the RJ45, I set the ModBus address to 01 and I know too, the speed 9600bps, 8N1. What is the absolute minimum string to get an answer: byte[0] = 0x01 = address index of the meter byte[1] = 0x03 = function "read" byte[2+3] 0x00 0x01 = read parameter #17 byte[5] = 0x04 = read 4 bytes byte[6+7] = crc16 MODBUS Just one valid bytes string would help ! Thank you for any hint, Arno
June 17, 20224 yr /* * g++ -std=c++17 -o read_registers read_registers.cpp * Author: system32 * Date: 17 Jun 2022 * Version: 0.1 * Copyright: public domain * * See: * https://modbus.org/specs.php * https://modbus.org/docs/PI_MBUS_300.pdf * https://github.com/LacobusVentura/MODBUS-CRC16 * https://www.cmrr.umn.edu/~strupp/serial.html */ #include <string> #include <unistd.h> #include <fcntl.h> #include <termios.h> /* POSIX terminal control definitions */ #include <iostream> // macro version https://www.microchip.com/forums/m393549.aspx #define GET_LO_BYTE(a) *((uint8_t *)&a) #define GET_HI_BYTE(a) *(((uint8_t *)&a) + 1) using namespace std; // https://github.com/LacobusVentura/MODBUS-CRC16 static uint16_t MODBUS_CRC16_v3(const unsigned char *buf, unsigned int len) { static const uint16_t table[256] = { 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 }; uint8_t Xor = 0; uint16_t crc = 0xFFFF; while (len--) { Xor = (*buf++) ^ crc; crc >>= 8; crc ^= table[Xor]; } return crc; } // https://www.cmrr.umn.edu/~strupp/serial.html int open_serial(const std::string& port, const speed_t baud) { // open a serial port and return fd int fd = open(port.c_str(), O_RDWR | O_NOCTTY | O_NDELAY); if (fd == -1) { perror(("open_serial: unable to open " + port).c_str()); exit(1); } // fcntl(fd, F_SETFL, FNDELAY); // no delay read fcntl(fd, F_SETFL, 0); // blocked read struct termios options; tcgetattr(fd, &options); // Get the current options for the port... cfsetspeed(&options, baud); // Set the baud rates cfmakeraw(&options); // Enable Raw Mode options.c_cc[VMIN] = 0; options.c_cc[VTIME] = 10; // 1 second timeout tcsetattr(fd, TCSANOW, &options); // Set the new options for the port... return fd; } void print_buffer(const char* msg, const uint8_t buffer[], int count) { printf(msg); for (int i=0; i<count; i++) if (i+1 < count) printf("0x%.2x, ", buffer[i]); else printf("0x%.2x\n", buffer[i]); } // https://modbus.org/docs/PI_MBUS_300.pdf int read_registers(int fd, uint8_t slave, uint16_t registeraddress, uint16_t number_of_registers) { // See Data and Control Functions - Page 19 // PI_MBUS_300.pdf - Figure 7 Master Query with ASCII/RTU Framing // send cmd buffer to slave uint8_t cmd_buffer[8] = {0}; cmd_buffer[0] = slave; cmd_buffer[1] = 3; // READ REGISTERS cmd_buffer[2] = GET_HI_BYTE(registeraddress); cmd_buffer[3] = GET_LO_BYTE(registeraddress); cmd_buffer[4] = GET_HI_BYTE(number_of_registers); cmd_buffer[5] = GET_LO_BYTE(number_of_registers); uint16_t crc = MODBUS_CRC16_v3(cmd_buffer, 6); cmd_buffer[6] = GET_LO_BYTE(crc); cmd_buffer[7] = GET_HI_BYTE(crc); print_buffer("cmd_buffer=",cmd_buffer,sizeof(cmd_buffer)); write(fd, cmd_buffer, sizeof(cmd_buffer)); sleep(1); // read the result // See PI_MBUS_300.pdf - Figure 8 Slave Response with ASCII/RTU Framing uint8_t result_buffer[64] = {0}; int expect = 5 + number_of_registers * 2; size_t rc = read(fd, result_buffer, expect); print_buffer("result_buffer=",result_buffer,expect); return 0; } int main(int argc, char** argv) { int fd = open_serial("/dev/ttyUSB0", B9600); int slave = 1; int registeraddress = 182; int count = 3; read_registers(fd, slave, registeraddress, count); close(fd); return 0; } Tested on RPI3 attached to SunSynk 8k cmd_buffer=0x01, 0x03, 0x00, 0xb6, 0x00, 0x03, 0xe4, 0x2d result_buffer=0x01, 0x03, 0x06, 0x04, 0xbc, 0x14, 0x6d, 0x00, 0x5c, 0xe5, 0x3e Register 182 (Temperature) = 0x04bc = (1212 - 1000)/10 = 21.2C Register 183 (Volts) = 0x146d = 5229 / 100 = 52.29V Register 184 (SoC) = 0x005c = 92% Edited June 18, 20224 yr by system32
June 20, 20224 yr Author Dear system32, a very big thank you for your support ! You are the first I met, who could help me with my basic RS485 problem. I understand your source code and I tried your example ( write 0x01, 0x03, 0x00, 0xb6, 0x00, 0x03, 0xe4, 0x2d) but my Sunsynk 8k did not reply any thing. I used 9600baude, 8N1, the ModBuus SN is 01. I am using Pin 1 and Pin 2 of the RJ45 plug. I even have an osciloscope and can see the outgoing code on the RS485 A/B lines. Is there any special timing I have to do? How long do I have to wait for an answer? Is any initialisation necessary? Thank you a lot ! Arno
June 20, 20224 yr 3 hours ago, Arno Uhlmann said: Dear system32, a very big thank you for your support ! You are the first I met, who could help me with my basic RS485 problem. I understand your source code and I tried your example ( write 0x01, 0x03, 0x00, 0xb6, 0x00, 0x03, 0xe4, 0x2d) but my Sunsynk 8k did not reply any thing. I used 9600baude, 8N1, the ModBuus SN is 01. I am using Pin 1 and Pin 2 of the RJ45 plug. I even have an osciloscope and can see the outgoing code on the RS485 A/B lines. Is there any special timing I have to do? How long do I have to wait for an answer? Is any initialisation necessary? Thank you a lot ! Arno 1) Make sure you set the Modbus ID for SunSynk as per this post: https://powerforum.co.za/topic/8451-sunsynk-inverter-monitoring/page/21/#comment-124091 Mine reset itself to ID=0 after a firmware upgrade. 2) The serial side of "open_serial / read / write" probably needs some work On my tests, the read seems to return incorrectly every other time - may be because the ttyUSB0 has another app running on it. I've attached a simple python3 app to test with: #!/usr/bin/python3 # Simple test app for reading SunSynk 8k via Modbus # pip3 install minimalmodbus import minimalmodbus device = minimalmodbus.Instrument("/dev/ttyUSB0", slaveaddress=1, debug=True) device.serial.baudrate = 9600 # Baud device.serial.timeout = 1.0 # seconds print(device) result = device.read_registers(registeraddress=182, number_of_registers=3) print(result) ######################################################### $ python3 test1.py MinimalModbus debug mode. Create serial port /dev/ttyUSB0 minimalmodbus.Instrument<id=0x768304d0, address=1, mode=rtu, close_port_after_each_call=False, precalculate_read_size=True, clear_buffers_before_each_transaction=True, handle_local_echo=False, debug=True, serial=Serial<id=0x768304f0, open=True>(port='/dev/ttyUSB0', baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=1.0, xonxoff=False, rtscts=False, dsrdtr=False)> MinimalModbus debug mode. Will write to instrument (expecting 11 bytes back): 01 03 00 B6 00 03 E4 2D (8 bytes) MinimalModbus debug mode. Clearing serial buffers for port /dev/ttyUSB0 MinimalModbus debug mode. No sleep required before write. Time since previous read: 1413018911.60 ms, minimum silent period: 4.01 ms. MinimalModbus debug mode. Response from instrument: 01 03 06 04 C8 14 EE 00 63 E4 CD (11 bytes), roundtrip time: 0.1 ms. Timeout for reading: 1000.0 ms. [1224, 5358, 99] Edited June 20, 20224 yr by system32
June 21, 20224 yr Author Dear system32, the ModBusSN index is set to 01, the inverter is defined as "slave" and not in parallel. Thank you for your link to the property menu, the ModBus settings are well hidden. But there is still no response to my small 8 bytes request. I tested the signal just to the RJ45 plug sitting inside the inverter. I am using 9600,8N1 with my atmel ATMega324 and my RS485 circuit works fine together with our Lumel power meter. If there is nothing else to check, I will try to do it with your Python script ... Thank you for your support, Arno
April 19, 20233 yr On 2022/06/20 at 4:04 PM, system32 said: I've attached a simple python3 app to test with: Sorry to revive an old topic.. root@cm4-can:~/src# python3 test.py MinimalModbus debug mode. Create serial port /dev/ttySC0 minimalmodbus.Instrument<id=0x7fb5ac3d90, address=1, mode=rtu, close_port_after_each_call=False, precalculate_read_size=True, clear_buffers_before_each_transaction=True, handle_local_echo=False, debug=True, serial=Serial<id=0x7fb5ac3d00, open=True>(port='/dev/ttySC0', baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=1.0, xonxoff=False, rtscts=False, dsrdtr=False)> MinimalModbus debug mode. Will write to instrument (expecting 11 bytes back): 01 03 00 B6 00 03 E4 2D (8 bytes) MinimalModbus debug mode. Clearing serial buffers for port /dev/ttySC0 MinimalModbus debug mode. No sleep required before write. Time since previous read: 5780045.46 ms, minimum silent period: 4.01 ms. MinimalModbus debug mode. Response from instrument: 0D 11 C5 2C 0E 04 10 00 00 17 B4 (11 bytes), roundtrip time: 0.7 ms. Timeout for reading: 1000.0 ms. Traceback (most recent call last): File "/root/src/test.py", line 13, in <module> result = device.read_registers(registeraddress=182, number_of_registers=3) File "/usr/local/lib/python3.9/dist-packages/minimalmodbus.py", line 904, in read_registers returnvalue = self._generic_command( File "/usr/local/lib/python3.9/dist-packages/minimalmodbus.py", line 1245, in _generic_command payload_from_slave = self._perform_command(functioncode, payload_to_slave) File "/usr/local/lib/python3.9/dist-packages/minimalmodbus.py", line 1329, in _perform_command payload_from_slave = _extract_payload( File "/usr/local/lib/python3.9/dist-packages/minimalmodbus.py", line 1867, in _extract_payload raise InvalidResponseError(text) minimalmodbus.InvalidResponseError: Checksum error in rtu mode: '\x17´' instead of 'i4' . The response is: '\r\x11Å,\x0e\x04\x10\x00\x00\x17´' (plain response: '\r\x11Å,\x0e\x04\x10\x00\x00\x17´') Not sure why, but it seems that the CRC Validation is failing?
April 19, 20233 yr Sorted root@cm4-can:~/src# modbus -s 1 -b 9600 -p 1 -P n -v /dev/ttySC0 183 Parsed 0 registers definitions from 1 files Serial port /dev/ttySC0. Parameters: 9600 baud, 1 stop bit(s), parity: N, timeout 5.0s. → < 01 03 00 b7 00 01 34 2c > ← < 01 03 02 14 de 37 1c > 7 bytes ← [5342] 183: 5342 0x14de root@cm4-can:~/src# python3 test.py MinimalModbus debug mode. Create serial port /dev/ttySC0 minimalmodbus.Instrument<id=0x7f9b27dd90, address=1, mode=rtu, close_port_after_each_call=False, precalculate_read_size=True, clear_buffers_before_each_transaction=True, handle_local_echo=False, debug=True, serial=Serial<id=0x7f9b27dd00, open=True>(port='/dev/ttySC0', baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=1.0, xonxoff=False, rtscts=False, dsrdtr=False)> MinimalModbus debug mode. Will write to instrument (expecting 11 bytes back): 01 03 00 B7 00 03 B5 ED (8 bytes) MinimalModbus debug mode. Clearing serial buffers for port /dev/ttySC0 MinimalModbus debug mode. No sleep required before write. Time since previous read: 6868903.28 ms, minimum silent period: 4.01 ms. MinimalModbus debug mode. Response from instrument: 01 03 06 14 DC 00 62 03 12 D2 91 (11 bytes), roundtrip time: 0.0 ms. Timeout for reading: 1000.0 ms. [5340, 98, 786] Edited April 19, 20233 yr by Chris Knipe
September 16, 20241 yr @system32 Just had to pop in and say thank you for sharing this information. I appreciate it more than you know. I translated this into arduino code for an ESP32 and it seem to work just fine. The documentation I have on how to read the inverter via Rs232 does not include the CRC bytes. To give some back , Incase anyone is interested in example code, see below. The ESP32 runs a web server and the second serial RX,TX pins GPIO 16 & 17 is connected to the inverter's RS232 port using a TTL converter. You can send a request for any register you want and it will read 3 of them at a time starting with the one you requested. and it will save the RAW hex to a log file on the ESP32's flash memory. Special Note: Most TTL converters that comes with a DB 9 is a female port and my Sunsynk 5Kw inverter's port is also female. A gender changer does not work for some reason. (Unless the one i have is faulty , I did check the pins with a multimeter and it looks fine, or my brain is too small to visualize where the RX TX pins has to go 🙂 ) I created a temporary Frankenstein board that allows me to tap into the TX/RX lines along with a 5V voltage regulator to bring down 12V to 5V for the VIN pin on the ESP32. Warning an LM7805 becomes extremely hot and will most probably give up if you use it for long periods, this was just a proof of concept. Once the server is up, you can request any value you want. http://ipaddress/send?registeraddress=182 and then retrieve the response like this http://ipaddress/log #include "LittleFS.h" #include <WiFi.h> #include <WiFiClient.h> #include <WebServer.h> const char* ssid = "SSID"; const char* password = "PASSWORD"; WebServer server(80); //Define Serial Port 2 #define RXD2 16 #define TXD2 17 int incomingBytePort2=0; void setup() { pinMode(2, OUTPUT); digitalWrite(2, LOW); Serial.begin(9600); // opens serial port, sets data rate to 9600 bps Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2); LittleFS.begin(); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); Serial.print("Connecting "); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.print("Connected to "); Serial.println(ssid); Serial.print("IP address: "); Serial.println(WiFi.localIP()); server.on("/", handleRoot); server.on("/log",ServeLog); server.on("/deletelog", DeleteLog); server.on("/formatfs",FormatFS); server.on("/send",SendCMD); server.begin(); } void loop() { server.handleClient(); // Read Serial Port 2 if (Serial2.available() > 0) { // read the incoming byte: incomingBytePort2 = Serial2.read(); Serial.print(incomingBytePort2, HEX); Serial.print(","); File file = LittleFS.open("/log.txt", FILE_APPEND); file.print(String(incomingBytePort2,HEX)); file.print(","); file.close(); } } void ServeLog(){ File file = LittleFS.open("/log.txt", "r"); size_t sent = server.streamFile(file, "text/plain"); file.close(); } void handleRoot() { String MainPage=""; MainPage = MainPage + "<a href=""/formatfs"">Format Filesystem</a><br><br><br>"; MainPage = MainPage + "<a href=""/deletelog"">Delete Log</a><br><br><br>"; MainPage = MainPage + "<a href=""/log"">View Log</a><br><br><br>"; MainPage = MainPage + "URL Example /send?registeraddress=184<br><br>"; MainPage = MainPage + "<a href=""/send?registeraddress=182"">Send CMD 182, Batt Temp, Batt Voltage, Batt Capacity </a><br><br><br>"; server.send(200, "text/html", MainPage); } void DeleteLog(){ LittleFS.remove("/log.txt"); server.send(200, "text/plain", "log.txt deleted"); } void FormatFS(){ LittleFS.format(); server.send(200, "text/plain", "FS Formatted"); } void SendCMD(){ int registeraddress=0; String strRegisterAddress=""; for (uint8_t i = 0; i < server.args(); i++) { //Serial.println(server.argName(i)); if(server.argName(i)=="registeraddress") { Serial.println(""); Serial.print("Reading Register:"); Serial.print(server.arg(i)); strRegisterAddress = server.arg(i); registeraddress=strRegisterAddress.toInt(); } } Serial.println(""); Serial.println("Sending Read Request...."); int slave = 1; int count = 3; read_registers(slave, registeraddress, count); server.send(200, "text/plain", "cmd sent"); } // https://github.com/LacobusVentura/MODBUS-CRC16 static uint16_t MODBUS_CRC16_v3(const unsigned char *buf, unsigned int len) { static const uint16_t table[256] = { 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 }; uint8_t Xor = 0; uint16_t crc = 0xFFFF; while (len--) { Xor = (*buf++) ^ crc; crc >>= 8; crc ^= table[Xor]; } return crc; } // https://modbus.org/docs/PI_MBUS_300.pdf int read_registers(uint8_t slave, uint16_t registeraddress, uint16_t number_of_registers) { // See Data and Control Functions - Page 19 // PI_MBUS_300.pdf - Figure 7 Master Query with ASCII/RTU Framing // send cmd buffer to slave byte cmd_buffer[8] = {0}; cmd_buffer[0] = slave; cmd_buffer[1] = 3; // READ REGISTERS cmd_buffer[2] = highByte(registeraddress); cmd_buffer[3] = lowByte(registeraddress); cmd_buffer[4] = highByte(number_of_registers); cmd_buffer[5] = lowByte(number_of_registers); uint16_t crc = MODBUS_CRC16_v3(cmd_buffer, 6); cmd_buffer[6] = lowByte(crc); cmd_buffer[7] = highByte(crc); //Serial.print("cmd_buffer="); //Serial.print(cmd_buffer); //Serial.println(sizeof(cmd_buffer)); Serial2.write(cmd_buffer, sizeof(cmd_buffer)); return 0; } Edited September 16, 20241 yr by MartinViljoen
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.