从零写一个工控多协议通讯库(一):架构与取舍
本文首发于我的个人博客 talkplc.com同步发布于 CSDN。原文链接https://talkplc.com/2026/07/18/talkplc-architecture/上一篇把 Modbus 一帧报文逐字节拆开讲了。这一篇往上走一层与其每个项目都重写一遍 Modbus/西门子/三菱的收发不如把它做成一套能长期用、能跑嵌入式、还能给上位机绑定的库。这是这个系列的第一篇先把架构和取舍说清楚——协议实现的细节留给后面每一篇。项目代号talkplc。纯净室开发只依据公开协议规范个人时间与设备。为什么又要造一个通讯库工控现场的协议是一堆的Modbus RTU/TCP、西门子 S7、三菱 MC、欧姆龙 FINS/Hostlink、CODESYS…… 每接一个新设备、每起一个新项目都在重复写“打开串口 → 拼一帧 → 算校验 → 收一帧 → 解出寄存器”。已有的轮子里HslCommunication很成熟但主要面向 .NET。我想要的不太一样以 C 为核心能直接跑在嵌入式 Linux / 网关上不背运行时对外暴露干净的 C API方便再包一层给 C# / Python 做上位机模块解耦用哪层链哪层别一上来就拖一坨依赖。对我个人它同时是三样东西一个开源作品集、这个博客的选题引擎每实现一个协议写一篇以及一个长期想做下去的方向。一开始就定死的几条原则纯 C11 内核 干净 C API——最大可移植性绑定友好。传输与协议分离——协议层不关心底下是串口、TCP 还是内存模拟。每层单独成库、可单独链接——只想要 Modbus 帧逻辑那就只链协议模块不拖串口。没有硬件也能测——内置一个内存里的从站模拟帧逻辑不靠真设备就能验证。架构总览分层大概长这样依赖方向自上而下、绝不反向应用 / 上位机 / 绑定 (C#、Python…) │ ┌──────────▼──────────┐ │ gui Qt 监视界面 │ 可视化可选 └──────────┬──────────┘ ┌──────────▼──────────┐ │ poll 后台轮询线程 │ C11 线程对外只给“线程安全快照” └──────────┬──────────┘ ┌──────────▼──────────┐ │ driver 点位(tag)模型 │ 地址类型 → 值连续寄存器批量读 └───┬──────────────┬───┘ ┌───────▼──────┐ ┌─────▼──────────┐ │ modbus 协议 │ │ datatype 类型解码 │ └───────┬──────┘ └────────────────┘ ┌───────▼──────┐ │ serial 传输后端 │ 串口以后加 TCP └───────┬──────┘ ┌───────▼───────────────────────────┐ │ core 状态码 传输接口 收发帧回调 │ 人人依赖的地基 └───────────────────────────────────┘每层的职责模块干什么依赖core状态码、传输接口、收发帧回调trace—serial串口 I/OWindows / POSIX以后同法加 TCPcoremodbusModbus 帧的拼装 / 解析 / 校验不关心串口coredatatype寄存器 ↔ 数据类型u16/i16/u32/i32/f32/bool 字序—driver点位模型 轮询 批量读modbus, datatypepoll把驱动跑在后台线程上对外给线程安全快照drivergui工业风监视界面Qtpoll下面挑三个最关键的设计点讲讲——只讲思路代码点到为止。设计一传输层是一个“字节管道”整套库的地基是把“底层怎么收发字节”抽象成一个接口。协议层只认这个接口永远不知道自己是在串口上、TCP 上还是在一段内存里/* 一个字节管道。串口 / TCP / 内存模拟都实现它就行。 */typedefstructtp_transport{void*ctx;int(*read)(void*ctx,uint8_t*buf,size_tlen,inttimeout_ms);int(*write)(void*ctx,constuint8_t*buf,size_tlen);void(*flush)(void*ctx);void(*close)(void*ctx);}tp_transport_t;就这么几行换来两个大好处以后加Modbus TCP协议帧逻辑一行不用改只写一个新的传输后端测试时塞一个内存里的假从站进去不用真设备就能把收发全流程跑通。设计二协议层只管“一帧”Modbus RTU 的一帧结构很朴素细节见上一篇拆解┌────────┬────────┬──────────────┬────────┬────────┐ │ 从站号 │ 功能码 │ 数据 │ CRC 低 │ CRC 高 │ │ 1 B │ 1 B │ N 字节 │ 1 B │ 1 B │ └────────┴────────┴──────────────┴────────┴────────┘校验用的是 CRC-16/MODBUS公开标准算法多项式0xA001uint16_tcrc16(constuint8_t*p,size_tn){uint16_tcrc0xFFFF;while(n--){crc^*p;for(inti0;i8;i)crc(crc1)?(crc1)^0xA001:crc1;}returncrc;}小验证对 ASCII 串123456789算出来应是0x4B37——这是 CRC-16/MODBUS 的标准校验值拿它当单元测试的“已知答案”很省心。协议层还做了一件对界面很有用的事每收发一帧就通过一个回调把原始字节抛给上层。上层想怎么显示HEX / ASCII、要不要记录都随意——这就是监视界面里“收发帧”那一栏的数据来源。设计三点位模型 后台线程再往上“寄存器地址 数据类型”被抽象成点位tag。你只描述“我要读哪个地址、当成什么类型”轮询之后值就自动填好typedefstruct{charname[32];tp_area_tarea;/* 线圈 / 保持寄存器 / 输入寄存器 … */uint16_taddress;tp_datatype_ttype;/* uint16 / int16 / float32 / bool … *//* ↓ 轮询后自动填充 */doublevalue;bool valid;}tp_tag_t;这一层还顺手做了两件事批量读把同一区域里地址连续的点位合并成一次Modbus 请求而不是一个点位发一帧——少一半以上的往返并发放在 C 库里轮询跑在一个后台线程上C11threads.h那套 API界面只去读一份线程安全的快照。于是就算某个从站不应答、读超时卡住界面照样丝滑不会连“断开”都点不动。值得一提的是并发没有塞进界面框架里——它在纯 C 层。这样哪天不用这个界面、换别的前端甚至做成命令行守护进程后台采集这套照样能用。配套一个工业风监视界面光有库不够直观所以配了个 Qt 写的监视器左边选协议右边配串口、列采集点位、看实时值支持不同数据类型显示底下是收发帧监视可在 HEX / ASCII 之间切。界面只依赖最上面的poll那层通过线程安全快照拿数据——它对底下协议一无所知以后加了新协议界面几乎不用动。反过来界面本身也是可换的。它只和纯 C 的poll层打交道所以 Qt 只是“其中一种前端”桌面 / 上位机拿 Qt 写省事而同一套 C 内核也能驱动一个 LVGL 写的界面直接跑在嵌入式 HMI、触摸屏上。正因为核心是纯 C、不背运行时这条“下沉到设备端”的路才走得通——这也是当初咬定纯 C 的原因之一。接下来这个系列会一个协议一篇往下写Modbus TCP复用现成的帧逻辑换个传输后端 MBAP 头西门子S7、三菱MC、欧姆龙FINS/Hostlink……界面也不只一种桌面 / 上位机继续用 Qt嵌入式 HMI 用LVGL两者共用同一套纯 C 内核——协议、驱动、后台采集一行都不用改。每加一层都会回来对照这张架构图看看——如果新协议逼着我改了地基那多半是当初某个抽象没做对。这也是我留着这套分层、公开写出来的原因之一架构是会被新需求反复拷问的。下一篇Modbus TCP。

相关新闻

PSWinReportingV2 vs 传统日志工具:为什么它是AD事件监控的最佳选择?

PSWinReportingV2 vs 传统日志工具:为什么它是AD事件监控的最佳选择?

PSWinReportingV2 vs 传统日志工具:为什么它是AD事件监控的最佳选择? 【免费下载链接】PSWinReporting This PowerShell Module has multiple functionalities, but one of the signature features of this module is the ability to parse Security log…

2026/10/3 13:09:47 阅读更多 →
为什么你的AI音乐永远赚不到钱?——3大隐性变现断点曝光,错过本周将涨价

为什么你的AI音乐永远赚不到钱?——3大隐性变现断点曝光,错过本周将涨价

更多请点击: https://codechina.net 第一章:为什么你的AI音乐永远赚不到钱?——3大隐性变现断点曝光,错过本周将涨价 你精心训练的LoRA模型能生成媲美Billboard前10的旋律,但上架Bandcamp三个月零订单;你用…

2026/10/12 20:12:49 阅读更多 →
5个Ionic Angular Cordova Seed高级配置技巧提升开发效率

5个Ionic Angular Cordova Seed高级配置技巧提升开发效率

5个Ionic Angular Cordova Seed高级配置技巧提升开发效率 【免费下载链接】ionic-angular-cordova-seed The perfect starting point for an Ionic project 项目地址: https://gitcode.com/gh_mirrors/io/ionic-angular-cordova-seed Ionic Angular Cordova Seed是构建跨…

2026/10/3 2:30:26 阅读更多 →

最新新闻

VCU整车控制器Simulink源码深度拆解:架构、算法与工程落地

VCU整车控制器Simulink源码深度拆解:架构、算法与工程落地

做新能源三电这行,很多人对“VCU整车控制器”是既熟悉又陌生。熟悉是因为它几乎是纯电、混动、增程构型里绕不开的顶层控制器,陌生是因为真正的工程源码很难见到,网上的资料要么是论文里的原理框图,要么是教学级别的简化模型。最近…

2026/10/13 6:23:46 阅读更多 →
一张图15秒带货视频:Claude Code本地合成全链路实战

一张图15秒带货视频:Claude Code本地合成全链路实战

1. 一张随手拍凭什么能撑起一条带货视频很多人第一次听到"一张照片做15秒带货视频"的反应是:这不就是拿张图配个音乐,然后硬凑时长吗?我一开始也这么想,直到自己真正跑通整条链路,才发现这里面能玩的花样比想…

2026/10/13 6:23:46 阅读更多 →
agent-skills 实战:构建大模型智能体的技能注册、调用与编排体系

agent-skills 实战:构建大模型智能体的技能注册、调用与编排体系

最近我在折腾智能体开发时,被一个高频问题反复卡住:模型本身挺聪明,一让它干具体活儿就各种掉链子。要么不知道该调用哪个工具,要么把参数传得乱七八糟,要么只回复“我可以帮你处理”然后就没有然后了。后来我意识到&a…

2026/10/13 6:23:46 阅读更多 →
Leetcode hot100 颜色分类【中等】

Leetcode hot100 颜色分类【中等】

看懂题目后,直觉是 —— new一个一样大小的数组,遍历一遍原数组,数出来0、1、2的个数,然后按照个数直接写入新数组。但题目要求在原地弄,也就是不能通过我们这样拷贝的方式。并且进阶要求只遍历一遍。空间限制我们&…

2026/10/13 6:23:46 阅读更多 →
图像预处理实战指南:从几何变换到工程落地的全流程避坑

图像预处理实战指南:从几何变换到工程落地的全流程避坑

图像预处理这个环节,说它是整个视觉任务里最不起眼、却最容易决定成败的一步,一点都不夸张。我做过不少图像相关的项目,从分类、检测到分割,也帮人排查过不少"模型明明没问题但效果就是上不去"的案例,最后追…

2026/10/13 6:23:46 阅读更多 →
多智能体协作系统实战:架构设计与落地经验

多智能体协作系统实战:架构设计与落地经验

1. 从单兵作战到团队协同:为什么我们需要重新思考开发模式做过几年开发的人都有一个共同感受:项目越做越大,代码越写越多,但真正让人头疼的往往不是某个技术难点,而是协作本身。需求在变、接口在变、文档永远滞后于代码…

2026/10/13 6:22:46 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 14:48:49 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →