How to set up simple Modbus communication?
How to set up simple Modbus communication?
Hello together,
I'm working at an Modbus project in the ESP IDF 4.1.
Where do I find the documentation how to Write Single Registers and Read Holding Registers?
I have already tested it with example Master code, but it didn't work. I were not able to find how to write Single Registers.
For example I want to do the following:
- Device 1
- Write Single Register
- Address 0
- Value 3000
How do I set it up correctly?
I'm working at an Modbus project in the ESP IDF 4.1.
Where do I find the documentation how to Write Single Registers and Read Holding Registers?
I have already tested it with example Master code, but it didn't work. I were not able to find how to write Single Registers.
For example I want to do the following:
- Device 1
- Write Single Register
- Address 0
- Value 3000
How do I set it up correctly?
Re: How to set up simple Modbus communication?
After testing different code over the weekend, I'm still not able to communicate with my device.
Either reading registers nor writing ones.
- How do I set the stop bit to 2? I didn't find any option for this like in uart.
For write input registers I've tried the following:
Here is my problem how to set the cid right to write to register. Here are only variables for reading registers.
Here I also have the problem that I don't now wich is the right command for writing registers. (Referring to the modbus protocol and the datasheet form my device i tried 3 (Read Holding Register) and 6 (Write Single Register))
I've also connected my logic analyzer and see that my devices answers. But I'm not able to decode the binary code wich is send over Modbus.
Maybe with this information someone is now able to help me with my Problem?
EDIT: Small update:
I found out that i have set my Logic analyzer wrong. After changing the variable value from "float" to "int" im able to set the register.
Either reading registers nor writing ones.
- How do I set the stop bit to 2? I didn't find any option for this like in uart.
For write input registers I've tried the following:
Code: Select all
mbc_master_set_parameter(uint16_t cid, char *name, uint8_t *value, uint8_t *type)
Code: Select all
const mb_param_request_t setparam = {1,6,0,1}; //slave adr, command, start reg, number of registers
float value = 5000;
err = mbc_master_send_request(&setparam, &value);
I've also connected my logic analyzer and see that my devices answers. But I'm not able to decode the binary code wich is send over Modbus.
Maybe with this information someone is now able to help me with my Problem?
EDIT: Small update:
I found out that i have set my Logic analyzer wrong. After changing the variable value from "float" to "int" im able to set the register.
-
- Posts: 211
- Joined: Fri Feb 01, 2019 4:02 pm
- Contact:
Re: How to set up simple Modbus communication?
Hi @waterfox,
examples\protocols\modbus\serial\mb_master\main\master.c:master_operation_func()
The function below is used to read registers into value parameter:
This one is used to write registers:
Before start of communication you need to create the data dictionary (see the device_parameters in the example) for your device which maps the CID to actual modbus registers.
The parameter structures which contain instances for parameters can be assigned in the object dictionary for each CID using HOLD_OFFSET(holding_data2) macro as example (one macro per register area type). See the examples\protocols\modbus\serial\mb_example_common\modbus_params.c::holding_reg_params for example parameters.
The modbus stack uses modbus command 16 (Write Multiple Holding Registers) to write registers as more universal. The 6 (Write Single Register) command support can also be added into stack if required.
Let me know if you need more help with Modbus implementation in ESP-IDF.
The modbus master supports UART_STOP_BITS_1 option set in the serial port components\freemodbus\port\portserial_m.c:xMBMasterPortSerialInit(). However it should not cause any communication issues.- How do I set the stop bit to 2? I didn't find any option for this like in uart.
The master operation function located in the example can explain how to read and write modbus registers:Here I also have the problem that I don't now wich is the right command for writing registers. (Referring to the modbus protocol and the datasheet form my device i tried 3 (Read Holding Register) and 6 (Write Single Register))
examples\protocols\modbus\serial\mb_master\main\master.c:master_operation_func()
The function below is used to read registers into value parameter:
Code: Select all
// Read modbus parameter described by object dictionary CID into value parameter
err = mbc_master_get_parameter(cid, (char*)param_descriptor->param_key,
(uint8_t*)value, &type);
Code: Select all
// Write value into characteristic defined as cid mapped to corresponded modbus parameter
err = mbc_master_set_parameter(cid, (char*)param_descriptor->param_key,
(uint8_t*)value, &type);
The parameter structures which contain instances for parameters can be assigned in the object dictionary for each CID using HOLD_OFFSET(holding_data2) macro as example (one macro per register area type). See the examples\protocols\modbus\serial\mb_example_common\modbus_params.c::holding_reg_params for example parameters.
The modbus stack uses modbus command 16 (Write Multiple Holding Registers) to write registers as more universal. The 6 (Write Single Register) command support can also be added into stack if required.
Let me know if you need more help with Modbus implementation in ESP-IDF.
Re: How to set up simple Modbus communication?
Hello ESP_alisitsyn,
What do you mean it can be added to the stack if required? Is there a way for me to customize the underlying stack, or was that an offer to extend the existing library?The modbus stack uses modbus command 16 (Write Multiple Holding Registers) to write registers as more universal. The 6 (Write Single Register) command support can also be added into stack if required.
Re: How to set up simple Modbus communication?
What I'm using for reading and writing registers now is this function.
Have a look at mb_param_request_t at the docs.
At the moment I havn't spend enough time on it to figure out how to work with CID'S.
Code: Select all
esp_err_t err = ESP_OK;
mb_param_request_t setparam = {1, 6, 0, 1}; //Device Adress, Func code (3 Read Holding Reg, 6 Write Input Reg), start Adr, reg length
int value = 3000; //Value to set or Variable for Output
err = mbc_master_send_request(&setparam, value);
switch (err)
{
case ESP_OK:
ESP_LOGI(TAG, "Set to Value = %d", Value);
break;
case ESP_ERR_INVALID_ARG:
ESP_LOGE(TAG, "invalid Argument");
break;
default:
break;
}
At the moment I havn't spend enough time on it to figure out how to work with CID'S.
Re: How to set up simple Modbus communication?
Many thanks for the clarification. I find the section of the documentation about Modbus quite cryptic, and in fact I don't think it describes the content of the structure `mb_param_request_t`. The source code is quite simple however, so I think I got it!
Since I'm here, are you aware of any way get the exact error response if the function requested could not be completed (e.g. if I try to write a register outside of its allowed range)?
Since I'm here, are you aware of any way get the exact error response if the function requested could not be completed (e.g. if I try to write a register outside of its allowed range)?
Re: How to set up simple Modbus communication?
I think that depends on your device. My device will return a value which is out of range. But I'm not sure if this is modbus standard.
-
- Posts: 211
- Joined: Fri Feb 01, 2019 4:02 pm
- Contact:
Re: How to set up simple Modbus communication?
Hello waterfox,
Per your request to read rite holding register:
- Device 1
- Write Single Register
- Address 0
- Value 3000
The device address, reg type, start address of register, number of registers defined as: `MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0, 1,`
```
// Example Data (Object) Dictionary for Modbus parameters
const mb_parameter_descriptor_t device_parameters[] = {
// CID, Name, Units, Modbus addr, register type, Modbus Reg Start Addr, Modbus Reg read length,
// Instance offset (NA), Instance type, Instance length (bytes), Options (NA), Permissions
{ CID_DEV_REG0, STR("MB_hold_reg-0"), STR("Data"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0, 1,
0, PARAM_TYPE_U16, 2, OPTS( 0,0,0 ), PAR_PERMS_READ_WRITE_TRIGGER },
...
```
To write register you can use a call:
```
register_data = 3000;
err = write_modbus_parameter(CID_DEV_REG0, ®ister_data);
err = read_modbus_parameter(CID_DEV_REG0, ®ister_data);
```
You don't need to extend library. In order to read registers from your device you can use command "Read Holding Registers 0x03", and "Write Multiple Holding Registers 0x10". The modbus controller is the common interface above Modbus API for all ports which allows to read and write any parameters of your slave device. Additionally it allows to integrate this functionality with other components or networks adding abstraction object "characteristic" with its CID - characteristic iD. So you do not need to go deeper to lower layer of Modbus port and read description of its parameters (`mb_param_request_t`). I prepared the simplified example to read and write two holding registers of the device. The example has just one file and I removed as much as possible from there. Hope it will help you to understand API and read your device data.What do you mean it can be added to the stack if required? Is there a way for me to customize the underlying stack, or was that an offer to extend the existing library?
Per your request to read rite holding register:
- Device 1
- Write Single Register
- Address 0
- Value 3000
The device address, reg type, start address of register, number of registers defined as: `MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0, 1,`
```
// Example Data (Object) Dictionary for Modbus parameters
const mb_parameter_descriptor_t device_parameters[] = {
// CID, Name, Units, Modbus addr, register type, Modbus Reg Start Addr, Modbus Reg read length,
// Instance offset (NA), Instance type, Instance length (bytes), Options (NA), Permissions
{ CID_DEV_REG0, STR("MB_hold_reg-0"), STR("Data"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0, 1,
0, PARAM_TYPE_U16, 2, OPTS( 0,0,0 ), PAR_PERMS_READ_WRITE_TRIGGER },
...
```
To write register you can use a call:
```
register_data = 3000;
err = write_modbus_parameter(CID_DEV_REG0, ®ister_data);
err = read_modbus_parameter(CID_DEV_REG0, ®ister_data);
```
- Attachments
-
- simple_modbus_example.zip
- Simple example to read and write holding registers of slave.
- (12.13 KiB) Downloaded 771 times
-
- Posts: 211
- Joined: Fri Feb 01, 2019 4:02 pm
- Contact:
Re: How to set up simple Modbus communication?
There are two possible situations:
1. Read/write the register outside of supported address space: the Modbus stack returns exception response back with the most significant bit set to 1 in the command field of PDU (0x80 + send command). The register space supported by device is described in its protocol (memory map) provided with device.
2. Read/write register from the middle of complex parameter of the device: Modbus stack returns the correct answer with value which may be out of range (depends on memory map of concrete device). Usually the parameters are stored in the device memory using different types (like: float, uint16_t, uint8_t and etc.). These complex values are mapped to Modbus register space according to memory map of the device which is defined in the documentation for device. The parameter description table in the modbus_master example can describe complex parameters of device as well as register values from each register space (input registers, holding registers, coils, disrete inputs) to allow read and write parameters and registers using api calls. See simple example.
Who is online
Users browsing this forum: andy_wharton_uk and 84 guests