测试环境
开发板: nk-980iot v1.0 的开发板
rt-thread 版本:4.1.1
ide:keil + env
nuc980 serialx 驱动
之前,笔者介绍 serialx 的时候,曾详细的讲解过 struct rt_uart_ops 接口中的每一个函数的功能。完全按照每一个函数功能定义去做,后面的事情就是水到渠成的。
花了小半天的时间从 drv_uart.c 改成 drv_uartx.c 。
然后使用 serialx 中提供的 测试程序 serialx_test.c 简单测试了一下,收发回环没发现严重问题(没有数据丢失,没有数据错误)。
启用控制台和 finsh 。改成“中断收发读写”模式,试了几个命令,打印结果完整。
可以说,验证了这次写的驱动还是很不错的,是成功的。
启用 libmodbus
env 环境里启用 libmodbus,使能 “enable libmodbus rtu mode” rtu 模式并使能 “enable rtu example” rtu 样例程序。
使用命令 pkgs --update 下载 libmodbus 源码。
libmodbus 的源码文件数量比 freemodbus 少很多了。看起来清晰很多。
第一次试编译
生成项目后先尝试编译一次,出现了很多错误。
首先,第一类错误是:
error: #20: identifier ebadf is undefined
error: #20: identifier econnreset is undefined
...
这几个宏定义在 “errno.h” 头文件,这个文件呢,在某个版本移动过路径,没记错的话也是从 4.0.3 之后开始的。现在的用法是 #include
modbus-rtu.c 修改 #include -> #include
modbus.c 修改 #include -> #include
然后,第二种错误是:
error: #20: identifier fd_set is undefined
warning: #223-d: function fd_zero declared implicitly
warning: #223-d: function fd_set declared implicitly
这几个定义在 “sys/select.h” ,可以 #include ,也可以 #include ,因为后者文件也只有一行内容就是 #include 。
modbus.c 添加 #include
至此,应该是把所有版本升级引起的兼容错误修正了。
第一次运行测试程序
开始跑测试程序之前,去掉 rs485 的所有相关代码。添加 libmodbus 的 debug modbus_set_debug(ctx, true);。这可以让我们看到很多的有用信息。
和上次的 freemodbus 样例程序不一样的是,这次是读保持寄存器,并不是写寄存器。
测试开始以后,笔者在控制台终端里看到如下信息,
[01][03][00][00][00][0a][c5][cd]
waiting for a confirmation...
msh >error unknown error: select
[ 0][read num = -1]
而,在 slave 端的调试信息是:
qt.modbus.lowlevel: (rtu server) received adu: 01030000000ac5cd
qt.modbus: (rtu server) request pdu: 0x030000000a
qt.modbus: (rtu server) response pdu: 0x031400110022003300440055006600770088009900aa
qt.modbus.lowlevel: (rtu server) response adu: 01031400110022003300440055006600770088009900aa4584
分析两端的调试信息, slave 端既接收到了请求 adu,也正常回复了响应 adu。但是 libmodbus 的 master 端并没有收到任何响应!
问题定位过程
首先确定串口接收中断没触发,也就是给开发板发的数据并没有接收中断;
调出串口外设寄存器发现,中断使能寄存器的值变成 0 了!串口中断使能寄存器被某个力量情况复位了!
再次回到串口驱动测试程序,笔者很确定是使用的中断接收模式,并且可以有接收中断。
问题好像很明显,libmodbus 在打开串口外设的过程中,某些操作清理了串口外设寄存器。
经过详细比对,libmodbus 打开串口设备后使用 termios 配置串口设备的波特率数据位等。而笔者上次在测试 posix 接口时使用的默认配置,并没有修改波特率。为了验证并跟踪问题位置,笔者在 “serialx_posix.c” 里添加 termios 配置函数。
经过一步步代码调试跟踪,得到函数调用链 tcsetattr -> ioctl -> fcntl -> dfs_file_ioctl -> serial_fops_ioctl -> rt_device_control -> rt_serial_control -> nu_uart_configure ,最后这个函数有一句 nu_sys_ip_reset(((nu_uart_t)serial)->rstidx); ,这句会复位中断寄存器的值。
第二次运行测试程序
注释掉这句代码后,再跑 libmodbus 样例程序,
[01][03][00][00][00][0a][c5][cd]
waiting for a confirmation...
[ 11][read num = 10]
终于看到想要的信息了。
问题复盘
使用过 rt-thread 串口驱动框架的人都知道,rt_device_find rt_device_control rt_device_open 是读写串口设备前的三步曲,这三个步骤顺序的不能乱的。rt_device_control和rt_device_open执行先后的问题
也就是说,配置串口波特率数据位等必须在打开设备之前!
我们再看 libmodbus 的做法,先 open ,然后调用 tcsetattr … -> rt_device_control。
那么,笔者删掉的那句代码是错误的吗?好像也不能这么说,它是“有用的”,可能它是出现在了不该出现的地方。
结束语
使用 libmodbus 的代价是很高的,从前边提到过的函数调用过程,就够人头疼的
但是,libmodbus 更适合系统,它只用了一个线程就能跑起来。freemodbus 用了三个(意味着更多的线程栈耗用)。
这次测试,我们发现了两处升级引入的版本兼容错误,以及 open configure 顺序引起的外设工作异常的问题。
星纵物联入选【2023年先进制造业倍增计划企业名单】!
Microchip推出新型加密单片机CEC1712 可躲开反恶意程序软件
马斯克表示星链太空卫星互联网延迟约为20毫秒 观看高清视频和玩在线游戏不卡顿
嵌入式技术在生活中是如何应用的
国家新一代人工智能的重要发展方向是决策智能
基于serialX串口驱动移植libmodbus的步骤
AMD RX Vega怒怼GTX 1080 Ti!发布三款全曝光:水冷375W
Intel最新CPU和主板不能装Win7?解决办法来了
车载以太网—TSN篇
全球半导体十大买家 中企占四家华为跃升第三
ffmpeg支持的音视频格式有哪些
日立家用中央空调NewAir新风系统 一键保护室内空气环境
基于PyTorch的深度学习入门教程之训练一个神经网络分类器
通俗易懂的IPv6知识介绍
让义肢能够不断学习 才能真正让残疾人的世界变得更加美好
亿光去年获利稳定成长 今年重点产品将包括MiniLED及UV系列新品等
红外成像跟踪系统的EMC探讨
输电线路弧垂变化的原因及弧垂在线监测装置的工作原理
Redis集群缓存方案,缓存常见问题盘点
小米手机在墨西哥为何被限制使用双卡?