MODBUS协议是一种主从式协议,即主站发起通讯,从站响应。主设备可以与一个或多个从设备通信。
当MODBUS主设备想要从一台从设备请求数据的时候,这个主设备会发送一条包含该从设备地址、请求数据以及一个用于检测错误的校验码的数据帧。网络上的所有其它设备都可以看到这一条信息,但是只有指定地址的设备才会做出反应。数据帧结构如下:
AliOS Things的MODBUS主协议是针对物联网RTOS系统特点而专门设计的。协议在实现时分为四层,整体架构如下:

API层主要用于提供用户接口。PDU层用于封装数据包PDU部分,ADU层用于封装数据包ADU部分,PHY用于通信链路初始化及数据发送与接收。
API列表
mbmaster_rtu_init() | 初始化基于RTU的MODBUS主协议通信 |
mbmaster_rtu_uninit() | 释放基于RTU的modbus主协议通信 |
mbmaster_read_coils() | 读线圈,功能码0x01 |
mbmaster_read_discrete_inputs() | 读离散输入,功能码0x02 |
mbmaster_read_holding_registers() | 读保持寄存器,功能码0x03 |
mbmaster_read_input_registers() | 读输入寄存器,功能码0x04 |
mbmaster_write_single_coil() | 写单个线圈,功能码0x05 |
mbmaster_write_single_register() | 写单个寄存器,功能码0x06 |
mbmaster_write_multiple_coils() | 写多个线圈,功能码0x0F |
mbmaster_write_multiple_registers() | 写多个寄存器,功能码0x10 |
使用
添加该组件
在调用该组件的其它组件aos.mk中增加
$(NAME)_COMPONENTS += mbmaster
#include "mbmaster.h"
包含头文件
#include "mbmaster.h"
使用示例
#include "modbus/mbmaster.h"
/* 定义串口通讯参数 */
#define SERIAL_PORT 2 /* 用于MODBUS通讯的uart端口号 */
#define SERIAL_BAUD_RATE 9600 /* 波特率 */
/* 定义从设备参数 */
#define DEVICE1_SLAVE_ADDR 0x1 /* 从设备地址 */
/* 定义请求参数 */
#define DEVICE1_REG1_ADDR 0x0 /* 待读寄存器地址 */
#define RECV_LEN_MAX 20 /* 数据缓存长度, 必须大于等于 (REQ_REGISTER_NUMBER * 2) */
#define REQ_REGISTER_NUMBER 2 /* 读寄存器的个数 */
void mb_main(void)
{
uint8_t buf[RECV_LEN_MAX];
uint8_t len;
mb_status_t status;
uint16_t simulator1 = 0, simulator2 = 0;
uint16_t data_write = 0, data_resp = 0;
uint16_t *register_buf;
/* 定义一个指针,调用mbmaster_rtu_init函数进行初始化 */
mb_handler_t *mb_handler;
/**
* 初始化通信端口。用户需根据实际使用的串口参数进行配置
*/
status = mbmaster_rtu_init(&mb_handler, SERIAL_PORT, SERIAL_BAUD_RATE, MB_PAR_NONE);
if (status != MB_SUCCESS) {
LOGE(MODBUSM_APP, "mbmaster init error");
return;
}
/* 该用例每隔2秒循环一次,首先发起一个写请求,然后再发起一个读请求。*/
while (1) {
/**
* 发起写寄存器请求。
* data_resp是从设备返回的写结果,如果写成功,则该值等于写入值data_write。
*/
status = mbmaster_write_single_register(mb_handler, DEVICE1_SLAVE_ADDR, DEVICE1_REG1_ADDR,
data_write, NULL, &data_resp, NULL, AOS_WAIT_FOREVER);
if (status == MB_SUCCESS) {
if (data_write != data_resp) {
LOGE(MODBUSM_APP, "write single register error");
} else {
LOGI(MODBUSM_APP, "write single register ok");
}
} else {
LOGE(MODBUSM_APP, "write single register error");
}
data_write++; /* 生成一个新的待写值 */
aos_msleep(1000);
memset(buf, 0, RECV_LEN_MAX);
/**
* 发起一个读寄存器请求。
* 缓存长度必须大于等于 (REQ_REGISTER_NUMBER * 2)
*/
status = mbmaster_read_holding_registers(mb_handler, DEVICE1_SLAVE_ADDR, DEVICE1_REG1_ADDR,
REQ_REGISTER_NUMBER, buf, &len, AOS_WAIT_FOREVER);
if (status == MB_SUCCESS) {
/*寄存器长度为16位 */
register_buf = buf;
simulator1 = register_buf[0];
simulator2 = register_buf[1];
LOGI(MODBUSM_APP, "read holding register simulator1: %d,simulator2: %d", simulator1, simulator2);
} else {
LOGE(MODBUSM_APP, "read holding register error");
}
aos_msleep(1000);
}
}
API详情
modbus的应用层API说明请参考include/bus/modbus/mbmaster.h。
aos_mbmaster_rtu_init()
初始化基于RTU的MODBUS主协议通信。
函数原型
mb_status_t mbmaster_rtu_init(mb_handler_t **handler, uint8_t port, uint32_t baud_rate, mb_parity_t parity);
输入参数
handler |
modbus句柄,用户定义一个mb_handler_t类型指针,将该指针的地址传入,调用成功后该指针指向新分配的句柄结构体 | |
port |
用于通信的串口端口号 | 2 |
baud_rate |
串口波特率 | 9600 |
parity |
串行通信校验方式,MB_PAR_NONE不校验,MB_PAR_ODD奇校验,MB_PAR_EVEN偶校验 | MB_PAR_NONE |
返回参数
返回参数宏定义见include/bus/modbus/mbmaster.h文件
调用示例
mb_status_t status;
mb_handler_t *mb_handler;
status = mbmaster_rtu_init(&mb_handler, SERIAL_PORT, SERIAL_BAUD_RATE, MB_PAR_NONE);
if (status != MB_SUCCESS) {
LOGE(MODBUSM_APP, "mbmaster init error");
return;
}
aos_mbmaster_rtu_uninit()
释放基于RTU的modbus主协议通信。
函数原型
mb_status_t mbmaster_rtu_uninit(mb_handler_t *req_handler);
输入参数
req_handler |
modbus句柄 |
返回参数
返回参数宏定义见include/bus/modbus/mbmaster.h文件
调用示例
mb_status_t status;
mb_handler_t *mb_handler;
status = mbmaster_rtu_init(&mb_handler, SERIAL_PORT, SERIAL_BAUD_RATE, MB_PAR_NONE);
if (status != MB_SUCCESS) {
LOGE(MODBUSM_APP, "mbmaster init error");
return;
}
……
mbmaster_rtu_uninit(&mb_handler);
mbmaster_read_coils()
读线圈,功能码0x01。线圈是位码形式,每个线圈长度为1 bit。
函数原型
mb_status_t mbmaster_read_coils(mb_handler_t *req_handler, uint8_t slave_addr, uint16_t start_addr,
uint16_t quantity, uint8_t *respond_buf, uint8_t *respond_count,
uint32_t timeout);
输入参数
req_handler |
modbus句柄 | |
slave_addr |
从设备地址 | 0x01 |
start_addr |
待读线圈起始地址 | 0x0 |
quantity |
待读线圈数量 | 10 |
respond_buf |
用于接收从设备响应数据的缓存,该缓存长度必须大于等于quantity/8字节(若不能整除需再增加1字节 | |
respond_count |
从设备实际返回的数据长度,单位为字节) | |
timeout |
请求超时时间,单位ms | 100 |
返回参数
返回参数宏定义见include/bus/modbus/mbmaster.h文件
调用示例
#define DEVICE1_SLAVE_ADDR 0x1
#define DEVICE1_COILS_ADDR 0x0
#define RECV_LEN_MAX 20
#define REQ_BIT_NUMBER 13
mb_status_t status;
mb_handler_t *mb_handler;
uint8_t buf[RECV_LEN_MAX];
uint8_t len;
status = mbmaster_rtu_init(&mb_handler, 2, 9600, MB_PAR_NONE);
if (status != MB_SUCCESS) {
LOGE(MODBUSM_APP, "mbmaster init error");
return;
}
status = mbmaster_read_coils(mb_handler, DEVICE1_SLAVE_ADDR, DEVICE1_COILS_ADDR,
REQ_BIT_NUMBER, buf, &len, AOS_WAIT_FOREVER);
mbmaster_read_discrete_inputs()
读离散输入,功能码0x02。离散输入是位码形式,每个离散输入长度为1 bit。
函数原型
mb_status_t mbmaster_read_discrete_inputs(mb_handler_t *req_handler, uint8_t slave_addr, uint16_t start_addr,
uint16_t quantity, uint8_t *respond_buf, uint8_t *respond_count,
uint32_t timeout);
输入参数
req_handler |
modbus句柄 | |
slave_addr |
从设备地址 | 0x01 |
start_addr |
待读离散输入的起始地址 | 0x0 |
quantity |
待读离散输入的数量 | 10 |
respond_buf |
用于接收从设备响应数据的缓存,该缓存长度必须大于等于quantity/8 字节(若不能整除需再增加1字节) | |
respond_count |
从设备实际返回的数据长度,单位为字节 | |
timeout |
请求超时时间,单位ms | 100 |
返回参数
返回参数宏定义见include/bus/modbus/mbmaster.h文件
调用示例
#define DEVICE1_SLAVE_ADDR 0x1
#define DEVICE1_COILS_ADDR 0x0
#define RECV_LEN_MAX 20
#define REQ_BIT_NUMBER 13
mb_status_t status;
mb_handler_t *mb_handler;
uint8_t buf[RECV_LEN_MAX];
uint8_t len;
status = mbmaster_rtu_init(&mb_handler, 2, 9600, MB_PAR_NONE);
if (status != MB_SUCCESS) {
LOGE(MODBUSM_APP, "mbmaster init error");
return;
}
status = mbmaster_read_discrete_inputs(mb_handler, DEVICE1_SLAVE_ADDR, DEVICE1_COILS_ADDR,
REQ_BIT_NUMBER, buf, &len, AOS_WAIT_FOREVER);
mbmaster_read_holding_registers()
读保持寄存器,功能码0x03。每个寄存器长度为16位。
函数原型
mb_status_t mbmaster_read_holding_registers(mb_handler_t *req_handler, uint8_t slave_addr,
uint16_t start_addr, uint16_t quantity,
uint8_t *respond_buf, uint8_t *respond_count, uint32_t timeout);
输入参数
req_handler |
modbus句柄 | |
slave_addr |
从设备地址 | 0x01 |
start_addr |
待读寄存器的起始地址 | 0x0 |
quantity |
待读寄存器的数量 | 2 |
respond_buf |
用于接收从设备响应数据的缓存,该缓存长度必须大于等于quantity *2 字节 | |
respondcount |
从设备实际返回的数据长度,单位为字节 | |
timeout |
请求超时时间,单位ms | 100 |
返回参数
返回参数宏定义见include/bus/modbus/mbmaster.h文件
调用示例
#define DEVICE1_SLAVE_ADDR 0x1
#define DEVICE1_REG1_ADDR 0x0
#define RECV_LEN_MAX 20
#define REQ_REGISTER_NUMBER 2
mb_status_t status;
mb_handler_t *mb_handler;
uint8_t buf[RECV_LEN_MAX];
uint8_t len;
status = mbmaster_rtu_init(&mb_handler, 2, 9600, MB_PAR_NONE);
if (status != MB_SUCCESS) {
LOGE(MODBUSM_APP, "mbmaster init error");
return;
}
status = mbmaster_read_holding_registers(mb_handler, DEVICE1_SLAVE_ADDR, DEVICE1_REG1_ADDR,
REQ_REGISTER_NUMBER, buf, &len, AOS_WAIT_FOREVER);
mbmaster_read_input_registers()
读输入寄存器,功能码0x04。每个寄存器长度为16位。
函数原型
mb_status_t mbmaster_read_input_registers(mb_handler_t *req_handler, uint8_t slave_addr,
uint16_t start_addr, uint16_t quantity,
uint8_t *respond_buf, uint8_t *respond_count, uint32_t timeout);
输入参数
req_handler |
modbus句柄 | |
slave_addr |
从设备地址 | 0x01 |
start_addr |
待读寄存器的起始地址 | 0x0 |
quantity |
待读寄存器的数量 | 2 |
respond_buf |
用于接收从设备响应数据的缓存,该缓存长度必须大于等于quantity *2 字节 | |
respondcount |
从设备实际返回的数据长度,单位为字节 | |
timeout |
请求超时时间,单位ms | 100 |
返回参数
返回参数宏定义见include/bus/modbus/mbmaster.h文件
调用示例
#define DEVICE1_SLAVE_ADDR 0x1
#define DEVICE1_REG1_ADDR 0x0
#define RECV_LEN_MAX 20
#define REQ_REGISTER_NUMBER 2
mb_status_t status;
mb_handler_t *mb_handler;
uint8_t buf[RECV_LEN_MAX];
uint8_t len;
status = mbmaster_rtu_init(&mb_handler, 2, 9600, MB_PAR_NONE);
if (status != MB_SUCCESS) {
LOGE(MODBUSM_APP, "mbmaster init error");
return;
}
status = mbmaster_read_input_registers(mb_handler, DEVICE1_SLAVE_ADDR, DEVICE1_REG1_ADDR,
REQ_REGISTER_NUMBER, buf, &len, AOS_WAIT_FOREVER);
mbmaster_write_single_coil()
写单个线圈,功能码0x05。线圈是位码形式,每个线圈长度为1 bit。
函数原型
mb_status_t mbmaster_write_single_coil(mb_handler_t *req_handler, uint8_t slave_addr, uint16_t coil_addr,
uint16_t coil_value, uint16_t *resp_addr, uint16_t *resp_value,
uint8_t *exception_code, uint32_t timeout);
输入参数
req_handler |
modbus句柄 | |
slave_addr |
从设备地址 | 0x01 |
coil_addr |
待写线圈地址 | 0x0 |
coil_value |
待写的值,0x0000表示off即写0,0xFF00表示ON即写1 | 0xFF00 |
resp_addr |
从设备返回的实际写的地址,写成功时等于coil_addr | |
resp_value |
从设备返回的实际写的值,写成功时等于coil_value | |
exception_code |
异常码,当写异常时有效 | |
timeout |
请求超时时间,单位ms | 100 |
返回参数
返回参数宏定义见include/bus/modbus/mbmaster.h文件
调用示例
#define DEVICE1_SLAVE_ADDR 0x1
#define DEVICE1_COILS_ADDR 0x0
#define RECV_LEN_MAX 20
#define REQ_BIT_NUMBER 13
mb_status_t status;
mb_handler_t *mb_handler;
uint8_t buf[RECV_LEN_MAX];
uint8_t len;
uint16_t data_resp = 0;
status = mbmaster_rtu_init(&mb_handler, 2, 9600, MB_PAR_NONE);
if (status != MB_SUCCESS) {
LOGE(MODBUSM_APP, "mbmaster init error");
return;
}
status = mbmaster_write_single_coil(mb_handler, DEVICE1_SLAVE_ADDR, DEVICE1_COILS_ADDR ,
0xFF00, NULL, &data_resp, NULL, AOS_WAIT_FOREVER);
mbmaster_write_single_register()
写单个寄存器,功能码0x06。寄存器长度16位。
函数原型
mb_status_t mbmaster_write_single_register(mb_handler_t *req_handler, uint8_t slave_addr, uint16_t register_addr,
uint16_t register_value, uint16_t *resp_addr, uint16_t *resp_value,
uint8_t *exception_code, uint32_t timeout);
输入参数
req_handler |
modbus句柄 | |
slave_addr |
从设备地址 | 0x01 |
register_addr |
待写寄存器地址 | 0x0 |
register_value |
待写的值 | 0x03 |
resp_addr |
从设备返回的实际写的地址,写成功时等于register_addr | |
resp_value |
从设备返回的实际写的值,写成功时等于register_value | |
exception_code |
异常码,当写异常时有效 | |
timeout |
请求超时时间,单位ms | 100 |
返回参数
返回参数宏定义见include/bus/modbus/mbmaster.h文件
调用示例
#define DEVICE1_SLAVE_ADDR 0x1
#define DEVICE1_REG1_ADDR 0x0
#define RECV_LEN_MAX 20
#define REQ_REGISTER_NUMBER 2
mb_status_t status;
mb_handler_t *mb_handler;
uint8_t buf[RECV_LEN_MAX];
uint8_t len;
uint16_t data_resp = 0;
status = mbmaster_rtu_init(&mb_handler, 2, 9600, MB_PAR_NONE);
if (status != MB_SUCCESS) {
LOGE(MODBUSM_APP, "mbmaster init error");
return;
}
status = mbmaster_write_single_register(mb_handler, DEVICE1_SLAVE_ADDR, DEVICE1_REG1_ADDR,
0x03, NULL, &data_resp, NULL, AOS_WAIT_FOREVER);
mbmaster_write_multiple_coils()
写多个线圈,功能码0x0F。线圈是位码形式,每个线圈长度为1 bit。
函数原型
mb_status_t mbmaster_write_multiple_coils(mb_handler_t *req_handler, uint8_t slave_addr, uint16_t start_addr,
uint16_t quantity, uint8_t *outputs_buf, uint16_t *resp_addr,
uint16_t *resp_quantity, uint8_t *exception_code, uint32_t timeout);
输入参数
req_handler |
modbus句柄 | |
slave_addr |
从设备地址 | 0x01 |
start_addr |
待写线圈起始地址 | 0x0 |
quantity |
写的数量 | 10 |
outputs_buf |
输出缓存,里面保存了待写的值,位码形式1位对应1个线圈 | |
resp_addr |
从设备返回的实际写的地址,写成功时等于start_addr | |
resp_quantity |
从设备返回的实际写的数量,写成功时等于quantity | |
exception_code |
异常码,当写异常时有效 | |
timeout |
请求超时时间,单位ms | 100 |
返回参数
返回参数宏定义见include/bus/modbus/mbmaster.h文件
调用示例
#define DEVICE1_SLAVE_ADDR 0x1
#define DEVICE1_COILS_ADDR 0x0
#define RECV_LEN_MAX 20
#define REQ_BIT_NUMBER 13
mb_status_t status;
mb_handler_t *mb_handler;
uint8_t buf[RECV_LEN_MAX];
uint8_t len;
status = mbmaster_rtu_init(&mb_handler, 2, 9600, MB_PAR_NONE);
if (status != MB_SUCCESS) {
LOGE(MODBUSM_APP, "mbmaster init error");
return;
}
buf[0] = 0x55;
buf[1] = 0x3c;
status = mbmaster_write_multiple_coils(mb_handler, DEVICE1_SLAVE_ADDR, DEVICE1_COILS_ADDR, REQ_BIT_NUMBER,
buf, NULL, NULL, NULL, AOS_WAIT_FOREVER);
mbmaster_write_multiple_registers()
写多个寄存器,功能码0x10。寄存器长度为16位。
函数原型
mb_status_t mbmaster_write_multiple_registers(mb_handler_t *req_handler, uint8_t slave_addr, uint16_t start_addr,
uint16_t quantity, uint8_t *outputs_buf, uint16_t *resp_addr,
uint16_t *resp_quantity, uint8_t *exception_code, uint32_t timeout);
输入参数
req_handler |
modbus句柄 | |
slave_addr |
从设备地址 | 0x01 |
start_addr |
待写寄存器的起始地址 | 0x0 |
quantity |
写的数量 | 10 |
outputs_buf |
输出缓存,里面保存了待写的值 | |
resp_addr |
从设备返回的实际写的地址,写成功时等于start_addr | |
resp_quantity |
从设备返回的实际写的数量,写成功时等于quantity | |
exception_code |
异常码,当写异常时有效 | |
timeout |
请求超时时间,单位ms | 100 |
返回参数
返回参数宏定义见include/bus/modbus/mbmaster.h文件
调用示例
#define DEVICE1_SLAVE_ADDR 0x1
#define DEVICE1_REG1_ADDR 0x0
#define RECV_LEN_MAX 20
#define REQ_REGISTER_NUMBER 2
mb_status_t status;
mb_handler_t *mb_handler;
uint8_t register_buf[RECV_LEN_MAX];
uint8_t len;
status = mbmaster_rtu_init(&mb_handler, 2, 9600, MB_PAR_NONE);
if (status != MB_SUCCESS) {
LOGE(MODBUSM_APP, "mbmaster init error");
return;
}
register_buf[0] = 0x03;
register_buf[1] = 0x04;
status = mbmaster_write_multiple_registers(mb_handler, DEVICE1_SLAVE_ADDR, DEVICE1_REG1_ADDR, REQ_REGISTER_NUMBER,
register_buf, NULL, NULL, NULL, AOS_WAIT_FOREVER);
配置说明
aos make menuconfig
命令即可进入到menuconfig配置界面中,依次选择Middleware
-> Modbus Master Support
即可进入到MODBUS主协议组件的配置界面: 
配置项说明
--- Key-value Storage
--- Modbus Master Support
[*] Enable the rtu transmission mode (NEW) #使能RTU传输,默认使能
(1) The max number of handler resources (NEW) #modbus句柄结构体的数量,默认为1
移植说明
MODBUS主协议RTU方式基于串口HAL层接口,完成串口适配后即可使用。
其他
返回参数定义
返回参数定义在include/bus/modbus/mbmaster.h文件中。
typedef enum mb_status {
MB_SUCCESS = 0u,
MB_MUTEX_ERROR, /* 请求互斥信号量失败,MODBUS协议栈内部通过互斥信号量保护临界资源 */
MB_INVALID_SLAVE_ADDR, /* 无效的从设备地址 */
MB_INVALID_PARAM, /* 无效的参数 */
MB_RESPOND_EXCEPTION, /* 远程设备响应异常 */
MB_RESPOND_LENGTH_ERR, /* 远程设备响应的数据帧长度错误 */
MB_RESPOND_FRAME_ERR, /* 远程设备响应的帧错误,比如校验和错误 */
MB_RESPOND_TIMEOUT, /* 请求超时 */
MB_CANNOT_GET_HANDLER, /*分配句柄失败,可能是配置的资源不足引起的 */
MB_SLAVE_NO_RESPOND, /* 从设备无响应 */
MB_FRAME_SEND_ERR, /* 帧发送错误 */
MB_SERIAL_INIT_FAILED, /* 串行通信链路初始化失败 */
MB_SERIAL_UNINIT_FAILED, /* 串行通信链路逆初始化失败 */
MB_FUNCTION_CODE_NOT_SUPPORT, /* 不支持的功能码 */
} mb_status_t;
使用注意事项
在调用mbmaster_read_coils()、mbmaster_read_discrete_inputs()、mbmaster_read_holding_registers()、mbmaster_read_input_registers
函数时,需确保传入的用户缓存足够大,若为读寄存器类型则至少为2*quantity字节,若为读位码类型,则至少为quantity/8字节(若无法整除还需再增加1)。
在文档使用中是否遇到以下问题
更多建议
匿名提交