工业网关设计:Modbus转MQTT协议转换实践
工业现场的现实
工厂车间里,70%以上的设备用的是Modbus协议。PLC、变频器、温控仪、电表、网关——全是Modbus RTU(RS485)或Modbus TCP。
但云平台只认MQTT和HTTP。
你在云端搭建了漂亮的物联网平台,数据看板、告警规则、设备管理全准备好了。然后到了工厂现场发现:设备根本接不上。
中间缺一个东西:协议转换网关。把Modbus数据读出来,转成MQTT消息发到云端。
这就是工业互联网落地的第一道坎。
协议转换网关架构
[PLC/传感器] --Modbus RTU(RS485)--> [网关] --MQTT--> [云平台] | [本地存储+断点续传]网关的核心功能:
- Modbus轮询:按配置定时读取设备寄存器
- 数据格式转换:Modbus寄存器值 → JSON
- MQTT上报:转成JSON通过4G/WiFi发到云端
- 断点续传:网络断了先存本地,恢复后补传
- 边缘计算:简单规则引擎(温度>80度直接报警,不等云端)
硬件方案
我们虎王科技在工业项目中用的网关方案:
| 方案 | 主控 | 通信 | 成本 | 适用场景 |
|---|---|---|---|---|
| 方案A | ESP32 | WiFi+4G模组 | ~80元 | 小型设备,<20个测点 |
| 方案B | STM32F4 | 4G模组 | ~120元 | 工业级,-40~85度 |
| 方案C | Linux工控机 | 以太网+4G | ~500元 | 复杂场景,多协议 |
方案B是最常用的。STM32F407 + EC25 4G模组 + RS485芯片,工业级温度范围,稳定可靠。
Modbus RTU读取实践
寄存器配置表
假设我们有一个温湿度控制器,Modbus寄存器表如下:
| 地址 | 功能码 | 数据类型 | 描述 |
|---|---|---|---|
| 0x0000 | 03 | uint16 | 当前温度(x10) |
| 0x0001 | 03 | uint16 | 当前湿度(x10) |
| 0x0002 | 03 | uint16 | 设定温度 |
| 0x0003 | 03 | uint16 | 运行状态(bit0=运行, bit1=告警) |
| 0x0010 | 06 | uint16 | 设定温度(可写) |
STM32读取Modbus的核心代码
// modbus_rtu.c - Modbus RTU主站实现#defineMODBUS_ADDR0x01// 从站地址#defineMODBUS_FC_READ0x03// 功能码:读保持寄存器#defineMODBUS_REG_TEMP0x0000// 温度寄存器地址#defineMODBUS_REG_HUMI0x0001// 湿度寄存器地址// 构建Modbus请求帧intbuild_read_request(uint8_t*buf,uint8_tslave,uint16_treg,uint16_tcount){buf[0]=slave;// 从站地址buf[1]=MODBUS_FC_READ;// 功能码buf[2]=(reg>>8)&0xFF;// 寄存器地址高字节buf[3]=reg&0xFF;// 寄存器地址低字节buf[4]=(count>>8)&0xFF;// 读取数量高字节buf[5]=count&0xFF;// 读取数量低字节// CRC16校验uint16_tcrc=crc16(buf,6);buf[6]=crc&0xFF;// CRC低字节buf[7]=(crc>>8)&0xFF;// CRC高字节return8;// 请求帧长度}// 解析Modbus响应帧intparse_read_response(uint8_t*buf,intlen,uint16_t*values,intmax_count){if(len<5)return-1;if(buf[0]!=MODBUS_ADDR)return-1;if(buf[1]!=MODBUS_FC_READ)return-1;uint8_tbyte_count=buf[2];intreg_count=byte_count/2;if(reg_count>max_count)return-1;// CRC校验uint16_tcrc_calc=crc16(buf,len-2);uint16_tcrc_recv=buf[len-2]|(buf[len-1]<<8);if(crc_calc!=crc_recv)return-2;for(inti=0;i<reg_count;i++){values[i]=(buf[3+i*2]<<8)|buf[4+i*2];}returnreg_count;}CRC16实现
Modbus RTU的CRC16是标准CRC-16/MODBUS算法:
uint16_tcrc16(uint8_t*data,intlen){uint16_tcrc=0xFFFF;for(inti=0;i<len;i++){crc^=data[i];for(intj=0;j<8;j++){if(crc&0x0001)crc=(crc>>1)^0xA001;elsecrc>>=1;}}returncrc;}数据转换:Modbus到MQTT
读到的寄存器原始值需要转成有意义的JSON:
// 读取温湿度uint16_tregs[2];intret=modbus_read(MODBUS_ADDR,0x0000,2,regs);if(ret>0){floattemp=regs[0]/10.0f;// 温度:除以10floathumi=regs[1]/10.0f;// 湿度:除以10// 构建JSONcharjson[256];snprintf(json,sizeof(json),"{\"device_id\":\"GW001\",\"temp\":%.1f,\"humi\":%.1f,\"ts\":%ld}",temp,humi,time(NULL));// 通过4G模组MQTT发布mqtt_publish("devices/GW001/telemetry",json);}最终云平台收到的消息:
{"device_id":"GW001","temp":25.3,"humi":68.5,"ts":1723113600}Modbus通信的几个坑
坑1:RS485总线冲突
多个从站设备挂在同一条RS485总线上,如果两个设备同时发送数据,总线会冲突。
解决:Modbus是主从协议,从站只在被问的时候才回答。确保你的代码不会并发查询多个从站。轮询一个,等回答或超时,再问下一个。
坑2:寄存器地址偏移
有些设备的Modbus地址从0开始,有些从1开始。文档上写"地址40001",实际读取时要用0x0000。
建议:拿到设备文档后,先用手持Modbus调试器读几个地址验证。不要直接写代码,否则调试时分不清是代码bug还是地址错误。
坑3:4G模组MQTT断连
4G网络在工厂车间信号不稳定,MQTT连接偶尔断。如果不处理,数据就丢了。
解决:本地SPI Flash缓存。网络断了把数据存Flash,网络恢复后按时间戳补传。
#defineMAX_CACHE100typedefstruct{uint32_ttimestamp;floattemp;floathumi;}cache_entry_t;cache_entry_tcache[MAX_CACHE];intcache_count=0;// 断网时缓存voidcache_data(floattemp,floathumi){if(cache_count<MAX_CACHE){cache[cache_count].timestamp=time(NULL);cache[cache_count].temp=temp;cache[cache_count].humi=humi;cache_count++;}// 满了就覆盖最旧的}// 恢复后补传voidflush_cache(){for(inti=0;i<cache_count;i++){charjson[256];snprintf(json,sizeof(json),"{\"device_id\":\"GW001\",\"temp\":%.1f,\"humi\":%.1f,\"ts\":%ld}",cache[i].temp,cache[i].humi,cache[i].timestamp);mqtt_publish("devices/GW001/telemetry",json);}cache_count=0;}批量配置方案
工厂里50台网关,一台台手动配置不现实。我们的方案:
- 配置文件通过MQTT下发:云平台发配置消息,网关收到后更新本地配置
- 设备模板:预置常见设备的Modbus寄存器表模板,选模板即可
- 自动发现:网关上电后扫描RS485总线上的设备地址,自动识别设备类型
配置消息格式:
{"config_id":"factory_A_line1","devices":[{"type":"temp_controller","slave_addr":1,"baudrate":9600,"registers":[{"addr":0,"type":"uint16","scale":0.1,"name":"temperature"},{"addr":1,"type":"uint16","scale":0.1,"name":"humidity"}],"interval":5}]}实际项目数据
虎王科技在某个工厂的温湿度监控项目:
- 网关数量:12台
- 每台网关连接设备:8台(共96台温控器)
- Modbus轮询间隔:5秒
- MQTT上报频率:30秒(聚合5次轮询的数据一次上报)
- 月平均数据完整率:99.2%
- 4G月流量:每台网关约50MB
总结
工业物联网落地的核心环节就是协议转换。Modbus到MQTT看似简单,但实际部署中RS485总线、4G网络稳定性、寄存器地址映射等细节问题很多。
关键经验:Modbus轮询要可靠,4G断网要补传,批量配置要自动化。这三件事做对了,工业网关方案就能落地。
沧州虎王科技,专注物联网软硬件开发、通信设备、嵌入式系统与设备管理平台。
