当前位置:首页 > 工业控制 > 工业控制
[导读]工业现场大量设备还在跑Modbus RTU(RS485)或Modbus TCP,而上层平台(云、MES、SCADA)普遍走MQTT。嵌入式网关(ARM Cortex-A7/M4 + Linux/RTOS)做协议转换时,最核心的是处理好“定时轮询Modbus从站→打包JSON→发布MQTT”和“订阅MQTT主题→解析→写Modbus寄存器”两条通路。下面以STM32MP157(Cortex-A7跑Linux) + libmodbus + Eclipse Paho MQTT C库为例,讲代码实现和调试要点。

工业现场大量设备还在跑Modbus RTU(RS485)或Modbus TCP,而上层平台(云、MES、SCADA)普遍走MQTT。嵌入式网关(ARM Cortex-A7/M4 + Linux/RTOS)做协议转换时,最核心的是处理好“定时轮询Modbus从站→打包JSON→发布MQTT”和“订阅MQTT主题→解析→写Modbus寄存器”两条通路。下面以STM32MP157(Cortex-A7跑Linux) + libmodbus + Eclipse Paho MQTT C库为例,讲代码实现和调试要点。

一、整体架构与线程模型

网关开三个线程:

• Modbus轮询线程:每秒循环读取所有从站的寄存器(如温度、压力、转速),存入共享内存结构体。

• MQTT发布线程:每5秒从共享内存取最新数据,拼成JSON字符串,发布到/gw/{device_id}/telemetry。

• MQTT订阅线程:阻塞等待下行消息(如设定值),解析后调用Modbus写寄存器。

// 共享数据结构

typedef struct {

  float temperature;

  float pressure;

  uint16_t rpm;

  uint32_t timestamp;

} device_data_t;

device_data_t shared_data;

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

二、Modbus轮询实现

用libmodbus,支持RTU和TCP自动切换(通过URI)。轮询函数:

void *modbus_poll_thread(void *arg) {

  modbus_t *ctx = modbus_new_rtu("/dev/ttySTM2", 9600, 'N', 8, 1);

  modbus_set_slave(ctx, 1);

  modbus_connect(ctx);

  uint16_t regs[10];

  while (1) {

      // 读取起始地址0,长度3个寄存器(温度、压力、转速)

      if (modbus_read_registers(ctx, 0, 3, regs) == 3) {

          pthread_mutex_lock(&lock);

          shared_data.temperature = regs[0] * 0.1f;  // 假设精度0.1

          shared_data.pressure    = regs[1] * 0.01f;

          shared_data.rpm         = regs[2];

          shared_data.timestamp   = time(NULL);

          pthread_mutex_unlock(&lock);

      } else {

          fprintf(stderr, "Modbus error: %s\n", modbus_strerror(errno));

      }

      sleep(1);  // 轮询间隔1秒

  }

  modbus_free(ctx);

  return NULL;

}

三、MQTT发布与订阅

使用Paho MQTT C异步客户端。发布线程:

void *mqtt_publish_thread(void *arg) {

  MQTTClient client;

  MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;

  MQTTClient_create(&client, "tcp://broker.emqx.io:1883", "gateway_001",

                    MQTTCLIENT_PERSISTENCE_NONE, NULL);

  conn_opts.keepAliveInterval = 20;

  conn_opts.cleansession = 1;

  MQTTClient_connect(client, &conn_opts);

  char topic[64], payload[256];

  snprintf(topic, sizeof(topic), "/gw/%s/telemetry", "gw_001");

  while (1) {

      pthread_mutex_lock(&lock);

      snprintf(payload, sizeof(payload),

               "{ \"temp\":%.1f,\"press\":%.2f,\"rpm\":%u,\"ts\":%lu }",

               shared_data.temperature, shared_data.pressure,

               shared_data.rpm, shared_data.timestamp);

      pthread_mutex_unlock(&lock);

      MQTTClient_publish(client, topic, strlen(payload), payload, 0, 0, NULL);

      sleep(5);

  }

  MQTTClient_disconnect(client, 10000);

  MQTTClient_destroy(&client);

  return NULL;

}

订阅线程需要注册回调,收到/gw/gw_001/command后解析JSON并写Modbus:

int msg_arrived(void *context, char *topicName, int topicLen, MQTTClient_message *msg) {

  // 解析JSON,提取setpoint字段,调用modbus_write_register

  cJSON *root = cJSON_Parse(msg->payload);

  if (root) {

      cJSON *sp = cJSON_GetObjectItem(root, "setpoint");

      if (sp) {

          uint16_t val = (uint16_t)(sp->valuedouble * 10);

          modbus_write_register(modbus_ctx, 10, val); // 写入地址10

      }

      cJSON_Delete(root);

  }

  MQTTClient_freeMessage(&msg);

  MQTTClient_free(topicName);

  return 1;

}

四、调试要点

1. Modbus抓包:用mbpoll命令行工具或串口助手验证从站响应。如果modbus_read_registers返回-1,检查波特率、校验、从站地址。

2. MQTT调试:用Mosquitto客户端订阅/gw/#看发布内容;用mosquitto_pub发下行命令测试订阅。

3. JSON解析:推荐cJSON库,注意浮点数精度,避免字符串溢出。

4. 日志输出:在关键点加syslog或文件日志,便于定位“Modbus通了但MQTT没发”的问题。

五、三个翻车高发点

• Modbus超时设置:默认1秒,如果从站响应慢(如老PLC),需modbus_set_response_timeout(ctx, 2, 0),否则频繁超时。

• MQTT QoS:工业场景建议QoS=1(至少一次),并开启持久会话,防止断线丢消息。

• JSON键名与云端对齐:云端期望temperature,代码里写成temp,数据上去了但平台不认。提前约定好字段名。




本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除( 邮箱:macysun@21ic.com )。
换一批
延伸阅读

当机器人在室内运行时,对指令的响应相当良好,但仍需保持在遥控器的直接视线范围内。然而,当机器人清洁窗户外部时,接收指令就会变得相当困难。有时我不得不站在玻璃旁边,反复按按钮,机器人才会做出反应。

关键字: 机器人 Wi-Fi MQTT Zigbee

在产线设备中,PLC常作为主控单元负责工艺流程,FPGA作为高速算法加速/多路采集前端。两者之间通过Modbus RTU(RS485)或 Modbus TCP(以太网)互通,是成本与开发难度最平衡的协同方案。本文以西门子...

关键字: PLC FPGA Modbus

一位自动化工程师站在PLC选型的十字路口,面前摆着的不再仅仅是I/O点数、CPU速度、内存大小这些传统指标。工业物联网的浪潮下,两个陌生的字母组合——MQTT和OPC UA——正悄然成为选型表单上的“必答题”。工厂需要将...

关键字: MQTT OPC

在老旧产线改造中,常有大量RS485 Modbus RTU设备(温湿度、电表、变频器)需要接入上位机或MES,但它们不支持TCP。此时用Raspberry Pi(树莓派)运行Modbus TCP↔RTU网关程序,既能做协...

关键字: Raspberry Modbus TCP网关

在万物互联的今天,物联网已经从概念走向落地,走进了我们生活生产的方方面面:从家中的智能灯泡到工厂流水线的传感器,从田间的土壤监测设备到共享单车上的定位装置,无数联网设备每时每刻都在交换着数据。要让这些计算能力有限、网络条...

关键字: 物联网 MQTT

大多数传统的街道照明系统依赖于简单的天文定时器或光敏传感器,本质上是“盲目的”和“呆板的”。当灯光熄灭或继电器故障时,维修人员只能通过市民投诉才能得知。

关键字: MQTT JSON 光敏传感器

机器对机器(M2M)通信场景,消息队列作为系统解耦的核心组件,通过异步传输机制提升系统吞吐量与容错能力。服务质量(QoS)保障机制则是确保消息可靠传递的关键技术。本文将从协议原理、QoS等级划分、技术实现及典型应用场景四...

关键字: MQTT CoAP AMQP

在资源受限的嵌入式场景中,RTOS的引入往往带来额外的内存开销和调度复杂性。以某智能电表项目为例,其主控芯片STM32F103仅配备20KB RAM,若采用FreeRTOS,仅内核就需占用8KB内存,导致剩余资源无法满足...

关键字: W5500 MQTT

智慧城市与工业物联网,超长待机设备的需求正以每年30%的速度增长。以杭州某独居老人火灾预警系统为例,其部署的2000台NB-IoT烟感报警器需在5号电池供电下持续工作3年以上,这对通信频率与功耗的平衡提出了严苛挑战。ST...

关键字: NB-IoT MQTT
关闭