Invalid CRC
libmodbus version
3.1.10
OS and/or distribution
Ubuntu 22.04.4 Jammy release
Environment
Raspberry Pi 4B Arc
Description
Hello, I'm trying to connect and get datas from specific registers that is on a slave connected to raspbery pi from /dev/ttyUSB0 port. Connecting and opening port are okay but here is the problem whenever I tried to read registers which is starting 30001 and up to 30004 it says invalid crc. But if I start with 0 I got these different datas from expected
Actual behavior if applicable
int rc=modbus_read_registers(ctx,30001,3,tab_reg); Opening /dev/ttyUSB0 at 9600 bauds (O, 8, 1) [21][03][75][30][00][04][59][6A] Sending request using RTS signal Waiting for a confirmation... <21><00><00><00><00> ERROR CRC received 0x0 != CRC calculated 0x21CA Invalid CRC
int rc=modbus_read_registers(ctx,0,3,tab_reg); Opening /dev/ttyUSB0 at 9600 bauds (O, 8, 1) [21][03][00][00][00][03][02][AB] Sending request using RTS signal Waiting for a confirmation... <21><03><06><00><00><00><00><00><21><78><AC> reg[0]=0 (0x0) reg[1]=0 (0x0) reg[2]=33 (0x21) reg[3]=0 (0x0)
Expected behavior or suggestion
Steps to reproduce the behavior (commands or source code)
#include <stdio.h>
#include <modbus.h>
#include <cerrno>
#include <iostream>
int main(){
const int REMOTE_ID = 33;
modbus_t *ctx;
uint16_t tab_reg[4];
ctx = modbus_new_rtu("/dev/ttyUSB0", 9600, 'O', 8, 1);
modbus_set_slave(ctx, 33);
modbus_rtu_set_serial_mode(ctx, MODBUS_RTU_RS485);
modbus_rtu_set_rts(ctx, MODBUS_RTU_RTS_UP);
modbus_rtu_set_rts_delay(ctx, 3);
modbus_set_debug(ctx, 1);
if (ctx == NULL) {
fprintf(stderr, "Unable to create the libmodbus context\n");
return -1;
}
if (modbus_connect(ctx) == -1) {
fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
modbus_free(ctx);
return -1;
}
int rc=modbus_read_registers(ctx,30001,3,tab_reg);
if(rc==-1){
fprintf(stderr,"%s\n",modbus_strerror(errno));
std::cout<<"Reading register error";
return -1;
}
for (int i=0;i<sizeof(tab_reg)/sizeof(tab_reg[0]);i++){
printf("reg[%d]=%d (0x%X)\n",i,tab_reg[i],tab_reg[i]);
}
modbus_close(ctx);
modbus_free(ctx);
}
libmodbus output with debug mode enabled
<...>
Correct. Welcome to the wonderful world of modbus. "30000" just means "registers" and 20000 and 40000 just mean "input registers" and "coils"
it's kinda like "modbus_opration(3000x)" will automatically do a read_registers(x) and "modbus_operation(4000x)" will automatically do a "read_holding_registers(x)"
libmodbus doesn't support the 30000 style, just the "full" style.
How can I solve this problem and read these datas as I expected on top?Btw tried to start with 40001. I already wrote a code snippet which is working with termios but here too, the datas are not resolvable.
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <cstdint>
#define DEVICE_PATH "/dev/ttyUSB0" // Update the serial port path appropriately
#define REMOTE_ID 33 // Device's slave ID
#define START_ADDRESS 30001 // Start register address
#define NUM_REGISTERS 4 // Number of registers to read
int main() {
int fd;
struct termios serial;
uint16_t tab_reg[NUM_REGISTERS];
// Open the serial port
fd = open(DEVICE_PATH, O_RDWR | O_NOCTTY);
if (fd == -1) {
perror("open");
return -1;
}
// Configure the serial port settings
tcgetattr(fd, &serial);
cfsetispeed(&serial, B9600); // Set input baud rate
cfsetospeed(&serial, B9600); // Set output baud rate
serial.c_cflag |= (CLOCAL | CREAD); // Enable port for local and reading capabilities
serial.c_cflag &= ~PARENB; // Disable parity
serial.c_cflag |= PARODD;
serial.c_cflag &= ~CSTOPB; // Use 1 stop bit
serial.c_cflag &= ~CSIZE; // Clear data bits
serial.c_cflag |= CS8; // Use 8 data bits
serial.c_cc[VMIN] = 0; // Set minimum character count to 0
serial.c_cc[VTIME] = 10; // Set timeout to 1 second
// Apply the serial port settings
tcsetattr(fd, TCSANOW, &serial);
// Modbus read operation
if (write(fd, "\x21\x03\x75\x31\x00\x04\x49\x68", 8) != 8) {
perror("write");
return -1;
}
sleep(3); // Wait for 0.5 seconds
int rc = read(fd, tab_reg, sizeof(tab_reg));
if (rc == -1) {
perror("read");
return -1;
}
// Print the read register values
for (int i = 0; i < NUM_REGISTERS; i++) {
printf("reg[%d]=%d (0x%X)\n", i, tab_reg[i], tab_reg[i]);
}
// Close the serial port
close(fd);
return 0;
}
output: reg[0]=45936 (0xB370) reg[1]=51248 (0xC830) reg[2]=65535 (0xFFFF) reg[3]=0 (0x0)
You simply don't. libmodbus (much as many other tools) simply doens't use the 300xx / 400xx addressing. If you want to read 30013, you do a "read regs 13" if you want 40013, you do a "read holding regs 13" (or vice versa, I never remember which is holding and which is input)
Thank you @karlp for your comments.