本教程手把手教你实现Agile Modbus,照抄就能成。
并且会解读函数功能含义。
1. 引言
Agile Modbus 是一个轻量级的 Modbus 协议栈,可以满足用户在任何场景下的需求。
功能
- 支持 rtu 和 tcp 协议,使用纯 C 语言开发,不涉及任何硬件接口,可以直接在任何形式的硬件上使用。
- 由于它是使用纯 C 语言开发的,不涉及硬件,因此可以在串口上运行 tcp 协议,在网络上运行 rtu 协议。
- 支持符合 Modbus 格式的自定义协议。
- 支持多个 master 和多个 slave 同时。
- 它很容易使用。您只需初始化 rtu 或 tcp 句柄,并调用相应的 API 进行打包和解包即可。
在使用Agile Modbus时我们可以查看Agile Modbus帮助文档进行使用。
在线文档:API 手册
2.移植
根据帮助手册的指示进行移植Agile_modbus。
2.1 文件移植
官方资源:
讲文件移植至工程内。在本实验中只用到了agile_modbus.c、agile_modbus.h文件。
2.2 代码移植
步骤
- 初始化RTU/TCP环境 ( agile_modbus_rtu_init / agile_modbus_tcp_init )
- 设置从地址 ( agile_modbus_set_slave )
- 等待数据接收结束
- 处理请求数据 ( agile_modbus_slave_handle )
- 发送数据
- 清除接收缓存区(可选)
- 实现 agile_modbus_slave_callback_t 类型回调函数--若无实现,则只有数据回传功能
定义
#define AGILE_MODBUS_MAX_ADU_LENGTH 260
uint8_t ctx_send_buf[AGILE_MODBUS_MAX_ADU_LENGTH];
uint8_t ctx_read_buf[AGILE_MODBUS_MAX_ADU_LENGTH];
agile_modbus_rtu_t ctx_rtu;
agile_modbus_t *ctx = &ctx_rtu._ctx;
初始化RTU和设置设备地址(只需执行一次)
/* 一、RTU 初始化 */
agile_modbus_rtu_init(&ctx_rtu, ctx_send_buf, sizeof(ctx_send_buf), ctx_read_buf, sizeof(ctx_read_buf));
/* 二、设置地址 */
agile_modbus_set_slave(ctx, 1);
循环处理数据
/* 循环执行 */
/* 三、接收字符串并通过字符串长度判断是否接收到字符串 */
if(rs485_receive_data())
{
/* rs485_rx_buf--串口接收缓存区 */
/* 四、传入参数 */
ctx->read_buf = rs485_rx_buf;
/* 五、从机数据处理 -- 将数据进行解析校验,用户通过回调函数编写自定义功能 */
int send_len = agile_modbus_slave_handle(ctx, rs485_rx_cnt, 1, agile_modbus_slave_cb, NULL, NULL);
/* 六、判断数据处理是否成功 */
if (send_len > 0)
{
/* 七、串口发送Modbus数据 -- ctx->send_buf为已经处理好的Modbus数据 */
rs485_send_data(ctx->send_buf, send_len);
}
/* 八、清除串口接收缓存区 */
rs485_receive_flush();
}
编写回调函数
/* slave handle callback */
static int agile_modbus_slave_cb(
agile_modbus_t *ctx,
struct agile_modbus_slave_info *slave_info,
const void *data)
{
int function = slave_info->sft->function;
int ret = -AGILE_MODBUS_EXCEPTION_ILLEGAL_FUNCTION;
/* 功能码 */
switch (function)
{ /* 0x03 */
case AGILE_MODBUS_FC_READ_HOLDING_REGISTERS:
break;
/* 0x06 */
case AGILE_MODBUS_FC_WRITE_SINGLE_REGISTER:
break;
/* 0x010 */
case AGILE_MODBUS_FC_WRITE_MULTIPLE_REGISTERS:
break;
}
return ret;
}
3. 代码使用
需只要在回调函数中,根据功能码对应位置编写所需功能代码即可。