目录
- 一、前言
- 二、源码融合核心步骤
- [三、FreeRTOS 内存管理函数替换](#三、FreeRTOS 内存管理函数替换)
- [四、USB 串口接口适配实现](#四、USB 串口接口适配实现)
- 五、收发函数适配与移植建议
- 六、总结
- 七、结尾
一、前言
此前我们已经完成了 STM32 平台 USB 串口的基础收发功能实现,同时基于 libmodbus 改造出了适配 STM32+FreeRTOS 的空模板。为了打通完整的通信链路,实现USB 串口作为 libmodbus 底层通信后端的核心目标,需要将两套独立的源码进行融合适配。本篇笔记将重点讲解源码合并编译、内存管理替换、USB 接口适配等关键步骤,梳理移植的核心逻辑与实操要点。
二、源码融合核心步骤
实现 USB 串口作为 libmodbus 通信后端,整体分为两个阶段执行,分步推进可降低调试难度:
- 编译适配阶段 :将 libmodbus 核心文件(
modbus-st-rtu.c、modbus.c)添加至 Keil 工程,通过编译报错逐步删减冗余代码、修复语法冲突,无需实现底层硬件逻辑,仅保证工程可正常编译通过; - 功能实现阶段:基于可编译的工程模板,完善 USB 串口收发、连接管理等硬件相关函数,完成 libmodbus 上层协议与 USB 串口底层驱动的对接。
补充:源码编辑与调试推荐使用 Source Insight 4.0 打开
modbus-st-rtu.c与modbus.c,便捷完成函数查找、代码修改与结构梳理。
libmodbus 标准函数执行流程,适配 USB 串口后端时需按顺序修改对应硬件相关接口:
modbus_new_rtu→modbus_set_slave→modbus_connect→读写操作(send_msg/_modbus_receive_msg/check_confirmation)→modbus_close→modbus_free
三、FreeRTOS 内存管理函数替换
在 STM32+FreeRTOS 环境中,原生 C 库的malloc/free存在线程不安全、内存碎片、无统计能力等问题,需要将源码中所有内存分配释放函数替换为 FreeRTOS 专用接口 :malloc替换为pvPortMalloc,free替换为vPortFree。
通过对比表格明确替换依据,适配嵌入式实时操作系统的运行特性:
| 场景 | 选malloc |
选pvPortMalloc |
|---|---|---|
| FreeRTOS 多任务环境 | ❌ 绝对不推荐(线程不安全) | ✅ 唯一推荐(天生适配) |
| 裸机(无 RTOS)嵌入式程序 | ✅ 可使用(单线程无竞争) | ❌ 没必要(依赖 FreeRTOS 内核) |
| 需要监控内存使用 / 定位泄漏 | ❌ 无统计功能 | ✅ 可通过xFreeBytesRemaining监控 |
| 要求内存严格对齐(ARM 内核) | ❌ 需手动处理 | ✅ 源码强制对齐 |
| 实时性要求高(如中断 / 高优先级任务) | ❌ 耗时不可控 | ✅ 算法简单,耗时可预测 |
| 场景 | 选free |
选vPortFree |
|---|---|---|
释放pvPortMalloc分配的内存 |
❌ 绝对不推荐(内存管理混乱) | ✅ 唯一推荐(配套设计,兼容内存块标记 / 链表规则) |
| FreeRTOS 多任务环境下释放内存 | ❌ 线程不安全(无任务调度挂起) | ✅ 天生线程安全(释放时挂起调度,原子操作) |
| 释放时需要合并相邻空闲块(减少碎片) | ❌ 通用合并逻辑,不适配嵌入式小内存 | ✅ 针对性合并 FreeRTOS 空闲链表,优化碎片问题 |
依赖 FreeRTOS 内存统计(如xFreeBytesRemaining) |
❌ 不更新统计值(内存使用监控失效) | ✅ 自动更新剩余内存 / 最小剩余内存等统计值 |
| 嵌入式 ARM 内核(内存对齐要求) | ❌ 无对齐校验(可能破坏内存块结构) | ✅ 校验内存块对齐,符合 FreeRTOS 分配规则 |
补充:内存管理函数必须全局统一替换,禁止混用标准库与 FreeRTOS 内存接口,避免出现内存泄漏、程序崩溃等严重问题。
四、USB 串口接口适配实现
在定制化上下文创建函数modbus_new_st_rtu中,增加设备接口类型判断逻辑,实现 USB 串口与板载普通串口的动态切换选择,通过设备名称字符串匹配绑定对应的 libmodbus 后端结构体。
核心适配代码如下:
C
// 判断设备接口类型,绑定对应通信后端
if (!strcmp(device, "usb"))
ctx->backend = &_modbus_rtu_backend_usbserial;
else
ctx->backend = &_modbus_rtu_backend_uart;
补充:
_modbus_rtu_backend_usbserial为适配 USB 串口的自定义后端结构体,需提前定义并绑定 USB 专用的收发、连接、关闭等硬件操作函数;_modbus_rtu_backend_uart为原生板载串口后端结构体,兼容原有串口逻辑。
五、收发函数适配与移植建议 <a id="func-adapt>
完成基础框架适配后,需要对核心通信函数进行定制化修改:
- 消息发送函数 :
send_msg及底层依赖的发送接口,需要替换为 STM32 USB 串口(USB_CDC)的发送驱动函数; - 消息接收函数 :
_modbus_receive_msg底层接收接口,适配 USB 串口的中断接收 / 轮询接收逻辑; - 从机回应函数:基于 USB 串口的传输特性,调整应答时序、缓冲区配置等参数。
该部分移植工作需结合硬件驱动与工程实际需求动态调整,修改点分散且灵活性较高。核心移植思路为参考成熟源码的封装逻辑,结合自身硬件平台与业务需求完成二次适配。
补充:复杂移植场景下,可结合专业视频教学步骤逐步调试,或借助工具辅助完成代码修改与问题排查,提升移植效率。
六、总结
- 融合 USB 串口与 libmodbus 分为编译适配、功能实现两步,优先保证工程可编译再完善硬件逻辑;
- FreeRTOS 环境下必须将
malloc/free全局替换为pvPortMalloc/vPortFree,保证内存操作安全; - 通过设备名称判断实现 USB / 普通串口后端动态切换,核心通信函数需适配 USB 串口驱动;
- 移植核心是复用成熟逻辑,结合自身需求定制化修改硬件相关接口。
七、结尾
本篇完成了 libmodbus 对接 USB 串口后端的核心方案梳理,解决了源码融合、内存管理、接口适配三大关键问题,为实现 STM32+FreeRTOS 平台下的 USB-Modus 通信奠定了基础。熟练掌握这套移植逻辑,可快速适配不同类型的串行通信接口,拓展工业通信方案的适用场景。感谢各位的阅读,持续关注本系列笔记,一起深耕嵌入式 USB 与 Modbus 通信开发,解锁更多工程实战技巧!