Modbus 协议实战:Modbus-RTU/TCP 采集传感器、变频器工控案例
Modbus 协议实战Modbus-RTU/TCP 采集传感器、变频器工控案例工控圈有句行话没听过 Modbus都不好意思说自己是搞自动化的。这篇从协议帧到代码实操一次性讲透。一、Modbus 协议简介Modbus 是 1979 年 Modicon 公司现施耐德电气发明的工业通信协议如今已成为工业自动化领域事实上的通信标准。几乎所有工控设备——PLC、变频器、传感器、电表——都支持 Modbus。Modbus 有三种传输模式模式传输介质特点典型场景Modbus-RTU串口RS232/RS485二进制帧CRC校验效率高现场设备通信Modbus-ASCII串口ASCII字符LRC校验可读性好调试场景Modbus-TCP以太网去掉CRC加MBAP头端口502网络化监控实际工控项目中RTU 和 TCP 用得最多ASCII 基本淘汰。二、Modbus-RTU 帧结构2.1 帧格式一个完整的 Modbus-RTU 帧结构如下| 从机地址(1B) | 功能码(1B) | 数据区(NB) | CRC校验(2B) |帧与帧之间靠时间间隔区分两个字符之间的间隔不能超过 3.5 个字符的传输时间在 9600bps 下约 3.6ms。超过这个间隔就认为是新的一帧。2.2 常用功能码功能码操作说明0x01读线圈读开关量输出状态ON/OFF0x02读离散输入读开关量输入状态只读0x03读保持寄存器读模拟量/参数最常用0x04读输入寄存器读模拟量输入只读0x05写单个线圈控制单个开关0x06写单个寄存器设定单个参数值0x0F写多个线圈批量控制开关0x10写多个寄存器批量设定参数举例读保持寄存器的请求帧和响应帧请求01 03 00 00 00 02 C4 0B | | | | |—CRC | | | |—寄存器数量(2个) | | |—起始地址(0x0000) | |—功能码(03 读保持寄存器) |—从机地址(01) 响应01 03 04 01 90 00 7A 6B 3D | | | |————|—数据(2个寄存器4字节) | | |—字节数(4) | |—功能码 |—从机地址寄存器值 0x0190 和 0x007A即十进制 400 和 122。三、Modbus-TCP 帧结构Modbus-TCP 用 MBAP 头替代了 RTU 的从机地址CRC| MBAP头(7B) | 功能码(1B) | 数据区(NB) |MBAP 头结构字段长度说明事务标识2B请求/响应匹配标识协议标识2B固定0x0000长度2B后续字节数单元标识1B从机地址对应RTU地址TCP 不需要 CRC因为 TCP 本身就保证数据完整性。默认端口502。四、libmodbus 开源库使用4.1 安装# Ubuntu/Debiansudoaptinstalllibmodbus-dev# 或从源码编译推荐版本更新gitclone https://github.com/stephane/libmodbus.gitcdlibmodbus ./autogen.sh ./configuremake-j$(nproc)sudomakeinstallsudoldconfig4.2 libmodbus 核心APImodbus_t*mb;// 上下文句柄mbmodbus_new_rtu(/dev/ttyS0,9600,N,8,1);// RTU模式mbmodbus_new_tcp(192.168.1.100,502);// TCP模式modbus_set_slave(mb,1);// 设置从机地址modbus_connect(mb);// 建立连接// 读写操作uint16_tregs[10];modbus_read_registers(mb,0,2,regs);// 读保持寄存器modbus_write_register(mb,0,500);// 写单个寄存器modbus_write_registers(mb,0,2,regs);// 写多个寄存器uint8_tbits[10];modbus_read_bits(mb,0,8,bits);// 读线圈modbus_write_bit(mb,0,TRUE);// 写单个线圈modbus_close(mb);modbus_free(mb);五、实战案例1读取温湿度传感器 Modbus 数据场景某 RS485 温湿度传感器地址01波特率96008N1。温度在保持寄存器0x0000湿度在0x0001。#includestdio.h#includemodbus.hintmain(){modbus_t*mb;uint16_tregs[2];intrc;// 初始化RTU连接mbmodbus_new_rtu(/dev/ttyS0,9600,N,8,1);if(mbNULL){fprintf(stderr,Failed to create modbus context\n);return-1;}modbus_set_slave(mb,1);if(modbus_connect(mb)-1){fprintf(stderr,Connection failed: %s\n,modbus_strerror(errno));modbus_free(mb);return-1;}// 读取地址0x0000开始的2个保持寄存器rcmodbus_read_registers(mb,0x0000,2,regs);if(rc-1){fprintf(stderr,Read failed: %s\n,modbus_strerror(errno));}else{// 假设传感器输出温度×10存于寄存器0湿度×10存于寄存器1floattempregs[0]/10.0f;floathumiregs[1]/10.0f;printf(Temperature: %.1f C\n,temp);printf(Humidity: %.1f %%\n,humi);}modbus_close(mb);modbus_free(mb);return0;}编译gcc modbus_sensor.c -o modbus_sensor -lmodbus六、实战案例2控制变频器启停与频率设定场景变频器地址02波特率96008E1。控制字寄存器地址0x2000频率设定寄存器地址0x2001。#includestdio.h#includemodbus.h#includeunistd.h#defineVFD_ADDR2#defineCTRL_REG0x2000// 控制字寄存器#defineFREQ_REG0x2001// 频率设定寄存器// 控制字定义以某品牌变频器为例#defineCMD_STOP0x0006// 停止#defineCMD_START0x0007// 正转启动#defineCMD_REVERSE0x000F// 反转启动intmain(){modbus_t*mb;intrc;mbmodbus_new_rtu(/dev/ttyS0,9600,E,8,1);if(mbNULL)return-1;modbus_set_slave(mb,VFD_ADDR);if(modbus_connect(mb)-1){modbus_free(mb);return-1;}// 设置频率25.0Hz → 寄存器值250频率×10rcmodbus_write_register(mb,FREQ_REG,250);if(rc-1){fprintf(stderr,Set frequency failed: %s\n,modbus_strerror(errno));}else{printf(Frequency set to 25.0 Hz\n);}// 启动变频器rcmodbus_write_register(mb,CTRL_REG,CMD_START);if(rc-1){fprintf(stderr,Start failed: %s\n,modbus_strerror(errno));}else{printf(VFD started\n);}// 运行10秒后停止sleep(10);modbus_write_register(mb,CTRL_REG,CMD_STOP);printf(VFD stopped\n);modbus_close(mb);modbus_free(mb);return0;}注意不同品牌变频器的控制字定义和寄存器地址不同务必查阅对应型号的 Modbus 通信手册。七、CRC 校验原理与手动计算Modbus-RTU 使用 CRC-16 校验多项式 0xA001计算步骤预置 CRC 寄存器为 0xFFFF取帧中第一个字节与 CRC 低8位异或如果最低位为1右移一位并异或 0xA001为0则直接右移重复步骤3共8次处理完一个字节对帧中每个字节重复步骤2~4最终 CRC 寄存器的值即为校验码低字节在前高字节在后C 语言实现uint16_tmodbus_crc16(uint8_t*data,intlen){uint16_tcrc0xFFFF;for(inti0;ilen;i){crc^data[i];for(intj0;j8;j){if(crc0x0001)crc(crc1)^0xA001;elsecrc1;}}returncrc;}手动验证对帧01 03 00 00 00 02计算 CRC结果应为0x0BC4发送时低字节在前... C4 0B。八、Modbus 调试工具推荐8.1 modpoll命令行工具快速测试 Modbus 设备# 读RTU设备地址1的保持寄存器0数量2modpoll-mrtu-b9600-pnone-a1-r1-c2/dev/ttyS0# 读TCP设备地址1的保持寄存器0modpoll-mtcp-a1-r1-c2192.168.1.1008.2 QModMaster图形化 Modbus 主站工具支持 RTU/TCP可以图形界面配置参数、查看数据适合现场调试。8.3 Modbus Poll / Modbus Slave经典调试组合Poll 模拟主站Slave 模拟从站方便在没有真实设备时测试程序。九、小结Modbus 协议本身非常简单——就是地址功能码数据CRC的字节流。但它的工程价值极高RTU 场景用 libmodbus 几行代码就能读传感器、控变频器TCP 场景换一个初始化函数其余 API 完全一样调试modpoll QModMaster 足以覆盖现场大部分需求掌握 Modbus等于拿到了工控通信的入场券。

相关新闻

工控硬件通信基础:串口 RS232/485、I2C、SPI 用户层读写实操

工控硬件通信基础:串口 RS232/485、I2C、SPI 用户层读写实操

工控硬件通信基础:串口 RS232/485、I2C、SPI 用户层读写实操搞工控,不会跟硬件"说话"怎么行?这篇带你从串口到 I2C 再到 SPI,把用户层读写一次性撸明白。一、工控常用硬件接口总览 工控场景下,主板和各种外设…

2026/7/24 2:02:29阅读更多 →
systemd工控服务开发:常驻程序、开机自启、异常自动重启、多服务依赖管理

systemd工控服务开发:常驻程序、开机自启、异常自动重启、多服务依赖管理

systemd工控服务开发:常驻程序、开机自启、异常自动重启、多服务依赖管理init.d那套启动脚本像手工裁缝——每个服务一个脚本,写法各不相同,出了问题得翻壳脚本找bug。systemd像流水线工厂——统一格式、统一管理、日志自带、依赖编排。工控时…

2026/7/24 2:02:29阅读更多 →
工控必备Shell脚本开发:自动挂载、日志归档、看门狗、程序守护脚本

工控必备Shell脚本开发:自动挂载、日志归档、看门狗、程序守护脚本

工控必备Shell脚本开发:自动挂载、日志归档、看门狗、程序守护脚本工控设备没有人在旁边盯着,出问题得自己修自己扛。Shell脚本就是工控系统的"瑞士军刀"——挂磁盘、管日志、喂狗、保活,一个脚本搞定一个活。一、Shell脚本在工控中…

2026/7/24 2:02:29阅读更多 →
C++文件操作完全指南:从fstream读写到实战应用

C++文件操作完全指南:从fstream读写到实战应用

1. 项目概述:为什么文件操作是C程序员的必修课 在C编程的世界里,无论你是开发一个简单的数据处理脚本,还是一个复杂的游戏引擎,有一个技能点几乎是绕不开的——那就是文件操作。想象一下,你写了一个程序,计…

2026/7/24 4:57:18阅读更多 →
RAGflow 2026架构解析与本地化部署实战

RAGflow 2026架构解析与本地化部署实战

1. RAGflow 2026核心架构解析RAGflow作为当前最先进的检索增强生成框架,其2026版在架构设计上实现了三大突破。核心采用分层处理模式,底层由知识摄取层、向量化层、检索层和生成层构成。知识摄取层支持PDF、Word、Excel等15种文件格式的自动解析&#xf…

2026/7/24 4:57:18阅读更多 →
Codex自定义代码审查规则:解决通用工具无法覆盖团队特定需求的痛点

Codex自定义代码审查规则:解决通用工具无法覆盖团队特定需求的痛点

最近在团队里做了一次小范围调研,发现一个挺有意思的现象:超过七成的开发者认为现有代码审查工具“太死板”,要么规则过于宽松漏掉关键问题,要么规则过于严格产生大量误报。更麻烦的是,当团队引入新的技术栈或架构模式…

2026/7/24 4:57:18阅读更多 →
C++线程安全队列:基于条件变量实现生产者-消费者模型

C++线程安全队列:基于条件变量实现生产者-消费者模型

1. 项目概述:为什么需要线程安全队列?在C多线程编程的世界里,数据共享是个绕不开的话题。想象一下,你有一个流水线,一边是生产者线程源源不断地制造零件,另一边是消费者线程马不停蹄地组装产品。如果零件&a…

2026/7/24 4:57:18阅读更多 →
C++实现非局部均值去噪:从原理到工程优化

C++实现非局部均值去噪:从原理到工程优化

1. 项目概述:为什么非局部均值去噪值得深究?在图像处理领域,噪声是永恒的敌人。无论是手机拍摄的夜景照片,还是医学影像、卫星遥感图,噪声都会掩盖细节,影响后续的分析与识别。传统的去噪方法,比…

2026/7/24 4:57:18阅读更多 →
Cursor AI在测试开发中的应用:从自动化脚本到智能测试伙伴

Cursor AI在测试开发中的应用:从自动化脚本到智能测试伙伴

如果你是一名测试开发工程师,最近可能已经感受到了行业的变化:传统的功能测试、自动化脚本编写正在被AI重新定义。而在这场变革中,Cursor作为一款AI编程助手,正在成为技术团队的新标配。但Cursor的真正价值远不止于代码补全。当马…

2026/7/24 4:55:18阅读更多 →
Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/24 0:58:53阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/24 0:58:53阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/24 0:58:53阅读更多 →
我的编程之路:第一篇博客

我的编程之路:第一篇博客

大家好,我是一名编程初学者,同时这也是我编程学习之路上的第一篇博客。在这里,我想要向大家介绍我的一些想法和规划。a.自我介绍我是一个刚刚接触编程的新手,目前在学习c语言,我对编程世界充满了强烈的好奇。当然&…

2026/7/24 0:00:06阅读更多 →
【LeetCode 54】螺旋矩阵

【LeetCode 54】螺旋矩阵

问题描述: 解法: 1、模拟(参考自【LeetCode 54】螺旋矩阵-CSDN博客) int *spiralOrder(int **matrix, int matrixSize, int *matrixColSize, int *returnSize) {static const int dirs[4][2] {{0, 1}, {1, 0}, {0, -1}, {-1, …

2026/7/24 0:00:06阅读更多 →
2026 WAIC:模型隐身、智能体疯野,厂商竞赛聚焦办公场景与商业闭环

2026 WAIC:模型隐身、智能体疯野,厂商竞赛聚焦办公场景与商业闭环

知春路不相信模型领先今年WAIC大会,昔日AI六小龙来了五家,分别是Kimi、阶跃星辰、Minimax、百川智能、零一万物。连放弃基模的百川和零一万物都来了,唯一缺席的竟是近几个月来风光无限的智谱。(DeepSeek一直不参加)WAI…

2026/7/24 0:00:06阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/23 22:58:43阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/23 18:58:18阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/23 18:58:18阅读更多 →