Skip to content
View in the app

A better way to browse. Learn more.

Power Forum - Renewable Energy Discussion

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

Sunsynk RS485 Modbus RTU request, bytes level

Featured Replies

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

/*
 * 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 by system32

  • 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

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 by system32

  • 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

  • 9 months later...
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?

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 by Chris Knipe

  • 1 year later...

@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.

spacer.png
 

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 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.

Guest
Reply to this topic...

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.