- 一、前言
- [二、移植前提:H5 作为 RS485-USB 转接核心](#二、移植前提:H5 作为 RS485-USB 转接核心)
- [三、libmodbus 移植:复用 H5 成熟代码](#三、libmodbus 移植:复用 H5 成熟代码)
- [四、F030 从机任务实现:寄存器联动 LED](#四、F030 从机任务实现:寄存器联动 LED)
- [五、功能验证:PC Modbus 软件控制 LED](#五、功能验证:PC Modbus 软件控制 LED)
- 六、总结
- 七、结尾
一、前言
上一篇笔记完成了 STM32F030 串口硬件层的收发测试(通过串口指令直接控制 LED 亮灭),本次在此基础上移植 libmodbus 协议栈,核心目标是让 F030 传感器开发板作为 Modbus 从机,支持 PC 端 Modbus 专用软件通过改写寄存器值的方式,实现对 LED 的远程控制。因 F030 开发板无直接对接 PC 的 USB 接口,仍保留 STM32H5 开发板作为 RS485-USB 转接设备,保障 PC 与 F030 之间的 Modbus 通信链路畅通。
二、移植前提:H5 作为 RS485-USB 转接核心
为实现 PC 与 F030 的 Modbus 通信,STM32H5 开发板需继续承担 "RS485-USB 转接" 角色:无需修改 H5 端已实现的双向数据转发代码,仅需保持其 USB 与 RS485 的透传功能,即可完成 PC 指令到 F030 RS485 串口的传输。
三、libmodbus 移植:复用 H5 成熟代码
F030 端的 libmodbus 移植无需从零开发,直接复用 STM32H5 开发板中已调试完成的 libmodbus 文件夹,将其完整复制到 F030 工程目录并配置编译路径(如添加头文件路径、源文件到工程等操作,因属于基础工程配置,不再赘述)。本次重点讲解 F030 端 Modbus 从机任务的具体实现代码。
代码原作者韦东山
四、F030 从机任务实现:寄存器联动 LED
在 F030 的默认 FreeRTOS 任务中实现 Modbus 从机核心逻辑,沿用成熟的从机框架并新增寄存器与 LED 的联动控制,代码及关键注释如下:
c
void StartDefaultTask(void *argument)
{
/* USER CODE BEGIN StartDefaultTask */
/* Infinite loop */
uint8_t *query; // Modbus请求报文缓冲区
modbus_t *ctx; // Modbus RTU上下文
int rc; // 函数返回值,判断操作是否成功
modbus_mapping_t *mb_mapping; // Modbus寄存器映射结构体
// 创建串口1的Modbus RTU上下文:波特率115200、无校验、8数据位、1停止位
ctx = modbus_new_st_rtu("uart1", 115200, 'N', 8, 1);
modbus_set_slave(ctx, 1); // 设置从机地址为1
// 分配请求报文缓冲区(使用FreeRTOS内存接口)
query = pvPortMalloc(MODBUS_RTU_MAX_ADU_LENGTH);
// 初始化寄存器映射:四类寄存器起始地址0,数量各10
mb_mapping = modbus_mapping_new_start_address(0,
10, // 线圈寄存器数量
0,
10, // 离散输入寄存器数量
0,
10, // 输入寄存器数量
0,
10); // 保持寄存器数量
// 初始化线圈寄存器为0(LED初始熄灭)
memset(mb_mapping->tab_bits, 0, mb_mapping->nb_bits);
// 初始化保持寄存器为0x55(测试用初始值)
memset(mb_mapping->tab_registers, 0x55, mb_mapping->nb_registers*2);
// 建立Modbus RTU连接
rc = modbus_connect(ctx);
if (rc == -1) {
//fprintf(stderr, "Unable to connect %s\n", modbus_strerror(errno));
modbus_free(ctx);
vTaskDelete(NULL);; // 连接失败则删除任务
}
// 无限循环接收并响应PC端Modbus请求
for (;;) {
do {
// 接收PC端请求报文,过滤无效请求(返回0的查询)
rc = modbus_receive(ctx, query);
/* Filtered queries return 0 */
} while (rc == 0);
/* The connection is not closed on errors which require on reply such as
bad CRC in RTU. */
// 非CRC错误则继续循环,不退出
if (rc == -1 && errno != EMBBADCRC) {
/* Quit */
continue;
}
// 解析请求并回复PC端
rc = modbus_reply(ctx, query, rc, mb_mapping);
if (rc == -1) {
//break;
}
// 线圈寄存器0控制PB11 LED1:1点亮(低电平)、0熄灭(高电平)
if (mb_mapping->tab_bits[0])
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_RESET); //LED1点亮
else
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_SET); //LED1熄灭
// 线圈寄存器1控制PB12 LED2:1点亮、0熄灭
if (mb_mapping->tab_bits[1])
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET); //LED2点亮
else
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET); //LED2熄灭
// 线圈寄存器2控制PB13 LED3:1点亮、0熄灭
if (mb_mapping->tab_bits[2])
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_RESET); //LED3点亮
else
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_SET); //LED3熄灭
}
// 释放资源(实际循环不会执行到此处,仅作资源释放示范)
modbus_mapping_free(mb_mapping);
vPortFree(query);
modbus_close(ctx);
modbus_free(ctx);
vTaskDelete(NULL);
/* USER CODE END StartDefaultTask */
}
代码核心逻辑:在标准 Modbus 从机请求接收、响应流程基础上,新增线圈寄存器与 LED 引脚的联动判断 ------ 当 PC 端改写线圈寄存器(0/1/2 号)的值时,立即触发对应 LED 的亮灭状态切换。
五、功能验证:PC Modbus 软件控制 LED
烧录代码后,通过 PC 端 Modbus 软件向 F030 从机下发寄存器改写指令,可实现精准的 LED 控制:
- 改写 0 号线圈寄存器值为 On:F030 第一个 LED(PB11)点亮;
- 改写 1 号线圈寄存器值为 On:第二个 LED(PB12)点亮;
- 改写 2 号线圈寄存器值为 On:第三个 LED(PB13)点亮;
- 寄存器值为 Off 时,对应 LED 熄灭。
0 号寄存器控制第一个 LED 点亮的测试效果如下:

六、总结
- F030 移植 libmodbus 复用 H5 成熟代码,大幅降低移植成本与调试难度;
- 从机任务新增线圈寄存器与 LED 的联动逻辑,实现 PC 端寄存器改写控制硬件;
- H5 作为 RS485-USB 转接设备,保障了 PC 与 F030 的 Modbus 通信链路。
七、结尾
本次完成了 STM32F030 的 libmodbus 移植与从机功能实现,成功通过 PC 端 Modbus 软件改写寄存器值控制 LED 亮灭,打通了低成本 Modbus 传感器的 "协议层 - 硬件层" 控制链路。这套移植方案无需从零开发协议栈,复用成熟代码的思路可直接落地至各类工业传感器开发场景。感谢各位的阅读,持续关注本系列笔记,一起完成低成本 Modbus 传感器的量产级开发!