第五次汇报学习笔记:把“串口字节流”提升为“协议级可视化”。核心点:请求快速构建、响应按字节标尺展示、CRC 校验、异常响应提示、寄存器表格化解析。
串口调试助手做到后期,常见诉求会变成: “我不想每次手打 01 03 00 00 00 02 C4 0B,能不能让我只填从站、功能码、起始地址、数量,然后自动生成并解析?”
这就是做协议工具的起点。以 Modbus RTU 为例,我总结了四个最有价值的能力:
-
请求构建(参数 → 帧)
-
组帧接收
-
CRC/异常处理(告诉用户哪里错了)
-
语义化解析(把寄存器值填进表格)
1. 为什么要单独做一个 Dialog?
如果把 Modbus 功能全塞进主界面,UI 会越来越拥挤,而且协议工具往往需要一套独立交互(预设指令、解析表、响应视图)。
所以我更倾向于做一个 ModbusToolDialog:
-
请求区:从站、功能码、地址、数量/数值;
-
预览帧:直接展示最终请求帧;
-
预设表:一键填充常用命令;
-
响应区:HEX + 字节标尺;
-
解析区:寄存器表格(addr/value 十进制 + 十六进制)。
这样主界面仍然专注“通用串口”,协议窗口专注“Modbus”。
2. 组帧:readyRead 的多次触发不是“多帧”,可能是一帧被拆了
Modbus RTU 在串口上也是字节流,readyRead 可能分多次到达。 调试工具要做的事情是:把多次 readAll 拼成一帧。
一个常用工程策略是“空闲时间判帧结束”:
-
每次收到数据就 append 到缓冲区;
-
启动一个 singleShot 定时器(例如 50ms);
-
若在 50ms 内又收到数据:重置定时器;
-
50ms 到期:认为一帧结束,拿缓冲区做解析,然后清空。
这种方法不需要精确计算帧长度,对调试工具很友好。
3. CRC 与异常响应:把“看不懂的失败”变成“可解释的提示”
对调试体验来说,最关键的是:失败时给出清晰原因,而不是“解析失败”。
-
CRC 不通过:提示 CRC 错误;
-
响应为异常帧:提示异常码含义;
-
其他解析问题:提示 error 字符串。
当你在窗口里看到“CRC 错误”或“异常响应:Illegal Data Address”,排查效率会比对 HEX 强太多。
4. 响应视图:HEX + 字节标尺(ruler)
看 Modbus 响应时,最烦的是数偏移: “这个 02 是字节数还是数据的一部分?”
所以我喜欢做一个 toHexRuler():把每行按固定字节数(如 16)排版,并在上方/左侧加偏移标尺,帮助快速定位字段。
5. 语义化解析:把 0x03 / 0x06 做成表格
对常用功能码:
-
0x03读保持寄存器:响应会带寄存器数组; -
0x06写单个寄存器:响应回显 addr/value;
解析后不要只在文本框里输出一串数字,而是填到 QTableWidget:
-
地址列:十进制 + 0xXXXX
-
值列:十进制 + 0xXXXX
表格化有两个好处:
-
人眼更容易扫;
-
后续可扩展(比如加“有符号/浮点解析”列)。
6. DPI 与窗口尺寸:工具类窗口也要“像样”
很多时候需求会指定一个固定外框像素尺寸(包含标题栏),但 Qt 的 resize/setFixedSize 是按 DPI 无关像素作用于 client area。
一种折中做法是:在 showEvent 后根据 DPI 缩放和边框厚度,再做一次换算校准。这样在 Windows 125%/150% 缩放下,窗口视觉尺寸更接近预期。
7. 小结
做 Modbus RTU 工具让我把“串口层”与“协议层”分开思考:
-
串口层负责:收发、组帧、计数、保存;
-
协议层负责:构建、CRC、异常、语义化解析;
-
UI 层负责:让用户用最少输入得到最大信息量。







