网关开发从入门到落地(06)MQTT 最简 C 代码实战:Modbus 采集数据一键上云

3 阅读4分钟

开篇

上一节我们用 C 代码完成 Modbus 从设备采集电压、电流数据,数据存在内存变量里还停留在本地。网关最终目的是把现场数据发到云端平台,工业项目主流方案全部依靠 MQTT。很多新手卡在 MQTT 复杂封装、连接断线、JSON 组包,本节抛开重型第三方 SDK,用轻量化思路,给出嵌入式网关通用最简代码:MQTT 连接 + JSON 拼装 + 发布上报 + 断线重连逻辑,配合前面 Modbus 代码直接拼成完整小型网关工程。

一、MQTT 在网关里的工作逻辑

  1. 网关上电:TCP 连接 MQTT 服务器 → 发送连接报文登录
  2. 循环周期:Modbus 轮询仪表拿到数据 → 组装 JSON 字符串
  3. 调用 MQTT 发布接口,把 JSON 报文上传云端
  4. 心跳保活 + 断线自动重连,保障 7×24h 无人值守上传

云端收到 JSON,即可在平台展示电压、电流、做超限告警。

工业场景固定格式 JSON 示例:{"addr":1,"voltage":300.0,"current":10.1}

二、前置说明

示例基于嵌入式 Linux 网关环境,采用通用 Socket 做 TCP 通信,不用大型 paho 完整库,方便 OpenWrt/Buildroot 固件移植;实际量产可选用裁剪版 paho-mqtt。

1. 定义全局参数(网关配置项)

c

运行

// MQTT服务器配置,替换成自己的公有云/私有平台地址
#define MQTT_HOST     "xxx.aliyunmq.com"
#define MQTT_PORT     1883
#define DEV_CLIENT_ID "gate_001"
#define PUB_TOPIC     "/device/gate01/data"

// 数据缓存
char json_buf[256];
int  mqtt_sock = -1;

2. 基础工具:拼装上报 JSON

承接上一章 Modbus 解析出来的电压、电流数值,一键生成上报报文

c

运行

// 拼接上报用JSON
void Build_JsonData(unsigned short dev_addr, float volt, float curr)
{
    sprintf(json_buf, "{"addr":%d,"voltage":%.1f,"current":%.1f}", dev_addr, volt, curr);
}

调用后json_buf自动生成标准 JSON 字符串,就是云端能识别的数据格式。

三、最简 MQTT 发布函数(精简版)

c

运行

// 发布数据到指定topic
int MQTT_PublishData(const char *topic, const char *payload)
{
    if(mqtt_sock < 0)
    {
        // 连接异常直接返回,上层触发重连
        return -1;
    }
    // 省略标准MQTT报文封装,量产项目替换标准MQTT封装接口
    // 核心:TCP发送JSON字符串到MQTT服务端
    send(mqtt_sock, payload, strlen(payload), 0);
    return 0;
}

四、结合 Modbus,完整网关主采集任务

和第 5 篇 Modbus 代码无缝对接,整套程序闭环

c

运行

// 完整网关业务主循环
void Gateway_MainTask(void)
{
    unsigned char cmd[8];
    unsigned char resp[32];
    unsigned short data[2];
    int cmd_len, resp_len, ret;
    float voltage, current;

    // 1.Modbus组包读取1号设备寄存器
    Modbus_Read_03(1, 0x0000, 2, cmd, &cmd_len);
    UART_Send(cmd, cmd_len);
    resp_len = UART_Recv(resp, sizeof(resp), 100);

    // 2.解析寄存器数据
    ret = Modbus_Parse_03(resp, resp_len, data);
    if(ret == 0)
    {
        voltage = data[0] * 0.1f;
        current = data[1] * 0.1f;

        // 3.组装JSON
        Build_JsonData(1, voltage, current);

        // 4.MQTT上报云端
        MQTT_PublishData(PUB_TOPIC, json_buf);
    }

    // 现场485轮询间隔,避免总线拥堵
    usleep(100000);
}

五、量产必加:断线自动重连设计(工业网关核心)

消费级产品断连无所谓,工业网关必须自愈,是区分玩具固件和量产固件的关键点:

c

运行

// 定时检测链路,断开则重连MQTT
void MQTT_CheckLink(void)
{
    if(mqtt_sock < 0)
    {
        // 关闭旧套接字、重新TCP连接+MQTT登录
        CloseSocket(mqtt_sock);
        mqtt_sock = ConnectMqttServer(MQTT_HOST, MQTT_PORT, DEV_CLIENT_ID);
    }
}

主循环里每一轮调用MQTT_CheckLink();,断网恢复后自动重连、恢复上报。

六、新手落地 3 大高频踩坑点

  1. JSON 格式写错:引号、逗号缺失,云端解析失败;尽量用 sprintf 固定模板,不要手动拼接字符串。
  2. MQTT 心跳忘记配置:长时间无数据下发,云端断开 TCP,设备离线不上报;量产务必开启 30s~60s 心跳包。
  3. 上报频率过快:仪表采集 + 上云间隔低于 50ms,串口总线 + 网络双双拥堵,常规采集周期 1~5s 最合适。

七、整套链路总结(从硬件到云端全流程)

485仪表 → Modbus RTU串口采集 → C代码解析换算 → JSON打包 → MQTT → 物联网云端到此,一个最简商用工业网关的软件逻辑全部落地,前面六篇串起一整套落地项目。

下篇预告

下一篇《网关本地缓存与断点续传设计》:断网时数据存入 Flash,恢复联网自动补发,解决现场断网丢数据的项目验收痛点,也是市面廉价网关缺失、老工程师接单加分项。

结尾

从协议报文→C 代码采集→MQTT 上云,六篇走完网关完整开发主线。市面上大量外包项目需求就是这套功能,依托十几年落地经验,既能做项目开发接单,也能整理源码方案售卖被动收入。