多协议网关设计架构与实现,支持 RS485/232、CAN、M-Bus、MQTT、TCP 等工业协议接入(附代码示例)

news2024/9/26 3:26:26

一、项目概述

1.1 背景

随着物联网技术的快速发展,越来越多的设备需要接入网络进行数据交互。然而,不同设备往往采用不同的通信协议,例如工业现场常用的Modbus、CAN、电力载波等,以及物联网领域常用的MQTT、TCP/IP等,这给设备的互联互通带来了巨大的挑战。

多协议网关作为连接不同协议设备的桥梁,能够将不同协议的数据进行转换和转发,实现不同设备之间的数据互通,解决物联网碎片化问题,具有重要的应用价值。

1.2 目标

本项目旨在设计并实现一款多协议网关,支持以下功能:

  • 数据采集:
    • 支持RS485、RS232接口的Modbus协议(RTU和TCP)。
    • 支持CAN总线协议。
    • 支持M-Bus总线协议。
    • 支持DL/T645协议。
    • 支持IEC104协议。
    • 支持电力载波协议(待补充具体协议)。
  • 数据上传:
    • 支持UDP、TCP协议。
    • 支持WiFi、以太网等网络接入方式。
    • 支持MQTT协议接入物联网平台。
1.3 应用场景
  • 工业自动化:采集和控制不同厂家的PLC、传感器等设备数据。
  • 智能楼宇:采集和控制楼宇自控系统中的各种设备数据。
  • 智能家居:采集和控制智能家居设备数据。
  • 环境监测:采集各种环境传感器数据,上传至云平台进行分析。

二、系统设计

2.1 硬件架构

本项目采用模块化设计,硬件架构如下图所示:

  • 主控模块: 负责整个系统的控制和数据处理,采用高性能MCU作为主控芯片,配备RAM和Flash用于程序运行和数据存储。
  • 通信模块: 负责与外部网络进行通信,支持WiFi、以太网等多种网络接入方式,可选配4G/5G模块。
  • 接口模块: 负责与各种设备进行通信,支持RS485、RS232、CAN、M-Bus等多种接口,并可根据需求扩展其他接口,如数字量输入输出、模拟量输入输出等。
2.2 软件架构

本项目软件架构采用分层设计,如下图所示:

  • 硬件抽象层(HAL): 对硬件进行抽象,提供统一的接口给上层调用,屏蔽硬件差异。
  • 驱动层: 实现各种硬件模块的驱动程序,例如WiFi驱动、Ethernet驱动、RS485驱动、RS232驱动、CAN驱动等。
  • 应用层: 实现协议转换、数据处理、业务逻辑等功能。
2.3 协议转换

多协议网关的核心功能是协议转换,本项目采用“协议库”的方式实现,如下图所示:

  • 协议库: 包含各种协议的解析和封装函数,例如Modbus协议库、CAN协议库、MQTT协议库等。
  • 协议转换: 根据配置信息,调用相应的协议库函数,将一种协议的数据转换成另一种协议的数据。

三、代码实现

3.1 协议库设计

本项目采用C语言实现,每个协议库包含以下几个部分:

  • 数据结构定义: 定义协议相关的数据结构,例如报文格式、数据类型等。
  • 函数接口: 提供协议解析、数据封装、校验等函数接口。
  • 示例代码: 提供使用示例代码,方便用户快速上手。

示例代码:Modbus RTU协议库

// modbus_rtu.h
#ifndef MODBUS_RTU_H
#define MODBUS_RTU_H

#include <stdint.h>

// Modbus功能码定义
#define MODBUS_FC_READ_COILS               0x01
#define MODBUS_FC_READ_DISCRETE_INPUTS      0x02
#define MODBUS_FC_READ_HOLDING_REGISTERS   0x03
#define MODBUS_FC_READ_INPUT_REGISTERS    0x04
#define MODBUS_FC_WRITE_SINGLE_COIL        0x05
#define MODBUS_FC_WRITE_SINGLE_REGISTER     0x06
#define MODBUS_FC_WRITE_MULTIPLE_COILS     0x0F
#define MODBUS_FC_WRITE_MULTIPLE_REGISTERS  0x10

// Modbus异常码定义
#define MODBUS_EXCEPTION_ILLEGAL_FUNCTION           0x01
#define MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS      0x02
#define MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE         0x03
#define MODBUS_EXCEPTION_SLAVE_DEVICE_FAILURE     0x04

// Modbus RTU报文结构体
typedef struct {
    uint8_t  slave_addr;      // 从机地址
    uint8_t  function_code;   // 功能码
    uint8_t  *data;           // 数据
    uint16_t data_len;       // 数据长度
    uint16_t crc;            // CRC校验码
} modbus_rtu_t;

// Modbus RTU协议库函数接口
uint16_t modbus_rtu_calculate_crc(uint8_t *data, uint16_t len);
int modbus_rtu_pack(modbus_rtu_t *rtu, uint8_t *buffer, uint16_t buffer_size);
int modbus_rtu_unpack(modbus_rtu_t *rtu, uint8_t *buffer, uint16_t buffer_len);
int modbus_rtu_check_crc(modbus_rtu_t *rtu);
int modbus_rtu_send(uint8_t slave_addr, uint8_t function_code, uint8_t *data, uint16_t data_len);
int modbus_rtu_receive(modbus_rtu_t *rtu);

#endif

// modbus_rtu.c
#include "modbus_rtu.h"

// 计算CRC校验码
uint16_t modbus_rtu_calculate_crc(uint8_t *data, uint16_t len) {
    uint16_t crc = 0xFFFF;
    uint16_t pos, i;
    for (pos = 0; pos < len; pos++) {
        crc ^= (uint16_t)data[pos];
        for (i = 0; i < 8; i++) {
            if (crc & 0x0001) {
                crc >>= 1;
                crc ^= 0xA001;
            } else {
                crc >>= 1;
            }
        }
    }
    return crc;
}

// 打包Modbus RTU报文
int modbus_rtu_pack(modbus_rtu_t *rtu, uint8_t *buffer, uint16_t buffer_size) {
    uint16_t len = 0;
    if (buffer_size < rtu->data_len + 5) {
        return -1;
    }
    buffer[len++] = rtu->slave_addr;
    buffer[len++] = rtu->function_code;
    memcpy(buffer + len, rtu->data, rtu->data_len);
    len += rtu->data_len;
    rtu->crc = modbus_rtu_calculate_crc(buffer, len);
    buffer[len++] = (rtu->crc >> 8) & 0xFF;
    buffer[len++] = rtu->crc & 0xFF;
    return len;
}

// 解包Modbus RTU报文
int modbus_rtu_unpack(modbus_rtu_t *rtu, uint8_t *buffer, uint16_t buffer_len) {
    if (buffer_len < 5) {
        return -1;
    }
    rtu->slave_addr = buffer[0];
    rtu->function_code = buffer[1];
    rtu->data_len = buffer_len - 5;
    rtu->data = buffer + 2;
    rtu->crc = (buffer[buffer_len - 2] << 8) | buffer[buffer_len - 1];
    return 0;
}

// 校验CRC
int modbus_rtu_check_crc(modbus_rtu_t *rtu) {
    uint16_t crc;
    crc = modbus_rtu_calculate_crc(rtu->data, rtu->data_len + 2);
    return (crc == rtu->crc);
}

// 发送Modbus RTU报文
int modbus_rtu_send(uint8_t slave_addr, uint8_t function_code, uint8_t *data, uint16_t data_len) {
    modbus_rtu_t rtu;
    uint8_t buffer[256];
    int len;
    rtu.slave_addr = slave_addr;
    rtu.function_code = function_code;
    rtu.data = data;
    rtu.data_len = data_len;
    len = modbus_rtu_pack(&rtu, buffer, sizeof(buffer));
    if (len < 0) {
        return -1;
    }
    // TODO: 通过串口发送数据
    // uart_send(buffer, len);
    return 0;
}

// 接收Modbus RTU报文
int modbus_rtu_receive(modbus_rtu_t *rtu) {
    uint8_t buffer[256];
    int len;
    // TODO: 通过串口接收数据
    // len = uart_receive(buffer, sizeof(buffer));
    if (len < 0) {
        return -1;
    }
    if (modbus_rtu_unpack(rtu, buffer, len) < 0) {
        return -1;
    }
    if (!modbus_rtu_check_crc(rtu)) {
        return -1;
    }
    return 0;
}

代码说明:

  • modbus_rtu_calculate_crc 函数: 实现CRC16校验码计算算法。
  • modbus_rtu_pack 函数: 将 modbus_rtu_t 结构体数据打包成Modbus RTU报文,包括添加从机地址、功能码、数据和CRC校验码。
  • modbus_rtu_unpack 函数: 从接收到的报文中解析出Modbus RTU数据结构,包括提取从机地址、功能码、数据和CRC校验码。
  • modbus_rtu_check_crc 函数: 校验接收到的报文的CRC校验码是否正确。
  • modbus_rtu_send 函数: 发送Modbus RTU报文,需要根据实际使用的串口进行修改,调用串口发送函数发送数据。
  • modbus_rtu_receive 函数: 接收Modbus RTU报文,需要根据实际使用的串口进行修改,调用串口接收函数接收数据。
3.2 驱动程序开发

驱动程序负责与硬件模块进行交互,例如初始化硬件、发送数据、接收数据等。

示例代码:RS485串口驱动程序

// uart.h
#ifndef UART_H
#define UART_H

#include <stdint.h>

// 初始化串口
int uart_init(uint32_t baudrate);
// 发送数据
int uart_send(uint8_t *data, uint16_t len);
// 接收数据
int uart_receive(uint8_t *data, uint16_t max_len);

#endif
// uart.c
#include "uart.h"

// TODO: 根据实际使用的MCU和串口进行修改
#define UARTx ...

// 初始化串口
int uart_init(uint32_t baudrate) {
    // 配置串口波特率、数据位、停止位、校验位
    // ...
    return 0;
}

// 发送数据
int uart_send(uint8_t *data, uint16_t len) {
    // 通过串口发送数据
    // ...
    return 0;
}

// 接收数据
int uart_receive(uint8_t *data, uint16_t max_len) {
    // 通过串口接收数据
    // ...
    return 0;
}

代码说明:

  • uart_init 函数: 初始化串口参数,包括波特率、数据位、停止位、校验位等。
  • uart_send 函数: 通过串口发送数据。
  • uart_receive 函数: 通过串口接收数据。
3.3 应用层开发

应用层负责实现协议转换、数据处理、业务逻辑等功能。

示例代码:数据采集和上传

// main.c
#include <stdio.h>
#include "modbus_rtu.h"
#include "uart.h"
#include "mqtt.h"

int main() {
    // 初始化串口
    uart_init(115200);

    // 初始化MQTT客户端
    mqtt_init();

    while (1) {
        // 从Modbus RTU设备读取数据
        modbus_rtu_t rtu;
        rtu.slave_addr = 1;
        rtu.function_code = MODBUS_FC_READ_HOLDING_REGISTERS;
        rtu.data = NULL;
        rtu.data_len = 2;
        modbus_rtu_send(rtu.slave_addr, rtu.function_code, rtu.data, rtu.data_len);
        if (modbus_rtu_receive(&rtu) == 0) {
            // 处理接收到的数据
            int16_t temperature = (rtu.data[0] << 8) | rtu.data[1];
            printf("Temperature: %d\n", temperature);

            // 通过MQTT协议上传数据
            char topic[] = "sensor/temperature";
            char message[16];
            sprintf(message, "%d", temperature);
            mqtt_publish(topic, message);
        }
    }
    return 0;
}

代码说明:

  • 程序首先初始化串口和MQTT客户端。
  • 在主循环中,程序从Modbus RTU设备读取数据,并将数据上传
  • 在主循环中,程序从Modbus RTU设备读取数据,并将接收到的数据解析出来。
  • 然后,程序将解析出来的温度值通过MQTT协议发布到主题 "sensor/temperature" 上。

四、项目总结

本项目设计并实现了一款多协议网关,能够实现不同协议设备之间的数据互通,为物联网应用提供了一种有效的解决方案。

4.1 优势
  • 模块化设计: 采用模块化设计,方便用户根据需求进行扩展。
  • 支持多种协议: 支持多种工业现场和物联网常用协议,方便用户接入不同类型的设备。
  • 易于使用: 提供了详细的文档和示例代码,方便用户快速上手。

注意:

        不懂的可以评论或者私信我,整个流程的思路我都可以提供!!!

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1914643.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

推荐一款功能强大的 GPT 学术优化开源项目GPT Academic:学术研究的智能助手

今天&#xff0c;我将向大家介绍一个强大的开源项目—GPT Academic&#xff0c;它或许正是你一直在寻找的理想工具。 已一跃成为 60.4k Star 的热门项目 GPT Academic 目前在 GitHub 上已经揽获了 60.4k 的 Star&#xff0c;这不仅反映了它的受欢迎程度&#xff0c;更证明了它…

什么是光储充一体化? 光储充一体化有什么优势?

大部分省份划定配储的比例不低于10% “光储充一体化”政策文件:国家层面政策名称 政策要点 发布时间 发布单位 结合实际建设光伏发电、储能、充换电一体化的充电基础设施。中央财政将安排奖励资金支持试点县开展试点工作&#xff0c;示范期内&#xff0c;每年均达到最高目标的试…

(pyqt5)弹窗-Token验证

前言 为了保护自己的工作成果,控制在合理的范围内使用,设计一个用于Token验证的弹窗. 代码 class TokenDialog(QDialog):def __init__(self, parentNone, login_userNone, mac_addrNone, funcNone):super(TokenDialog, self).__init__(parent)self.login_user login_userself…

2024年网络监控软件排名|10大网络监控软件是哪些

网络安全&#xff0c;小到关系到企业的生死存亡&#xff0c;大到关系到国家的生死存亡。 因此网络安全刻不容缓&#xff0c;在这里推荐网络监控软件。 2024年这10款软件火爆监控市场。 1.安企神软件&#xff1a; 7天免费试用https://work.weixin.qq.com/ca/cawcde06a33907e6…

d3dcompiler_43.dll文件是什么?如何快速有效的解决d3dcompiler_43.dll文件丢失问题

dcompiler_43.dll 是一个Windows系统中的系统文件&#xff0c;属于DirectX软件的一部分。这个dcompiler_43.dll&#xff08;动态链接库&#xff09;文件主要用于处理与3D图形编程有关的任务&#xff0c;是运行许多游戏和高级图形程序必需的组件之一。那么如果电脑丢失d3dcompil…

新手如何配置运行yolov5环境

&#x1f4da;博客主页&#xff1a;knighthood2001 ✨公众号&#xff1a;认知up吧 &#xff08;目前正在带领大家一起提升认知&#xff0c;感兴趣可以来围观一下&#xff09; &#x1f383;知识星球&#xff1a;【认知up吧|成长|副业】介绍 ❤️如遇文章付费&#xff0c;可先看…

部署Harbor仓库

本章内容&#xff1a; 安装docker-ce部署harbor仓库上传和拉取 1.安装docker 1&#xff09;拉取源码 yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo 2&#xff09;安装docker-ce yum -y install docker-ce 3&#…

Java 8革新:现代编程的全新标准与挑战

文章目录 一、方法引用二、接口默认方法三、接口静态方法四、集合遍历forEach()方法 一、方法引用 方法引用是Java 8中一种简化Lambda表达式的方式&#xff0c;通过直接引用现有方法来代替Lambda表达式。 方法引用使得代码更加简洁和易读&#xff0c;特别是在处理函数式接口时&…

数学建模国赛入门指南

文章目录 认识数学建模及国赛认识数学建模什么是数学建模&#xff1f;数学建模比赛 国赛参赛规则、评奖原则如何评省、国奖评奖规则如何才能获奖 国赛赛题分类及选题技巧国赛赛题特点赛题分类 国赛历年题型及优秀论文数学建模分工技巧数模必备软件数模资料文献数据收集资料收集…

NeRF++论文理解

今天想起这篇论文&#xff0c;于是将之前做得笔记复制过来以后方便查看

机器学习与深度学习:区别与联系(含工作站硬件推荐)

一、机器学习与深度学习区别 机器学习&#xff08;ML&#xff1a;Machine Learning&#xff09;与深度学习&#xff08;DL&#xff1a;Deep Learning&#xff09;是人工智能&#xff08;AI&#xff09;领域内两个重要但不同的技术。它们在定义、数据依赖性以及硬件依赖性等方面…

网页报错err_connection_timed_out 怎么办?教你快速修复错误代码

遇到网页错误提示“ERR_CONNECTION_TIMED_OUT”时&#xff0c;通常表示你的网络浏览器无法在规定时间内从服务器获取数据。这种错误不仅会阻碍你访问特定网站&#xff0c;而且可能会引起一些疑惑和不便。首先&#xff0c;这个问题可能是由于网络连接问题、服务器响应延迟或配置…

华为浏览器,Chrome的平替,插件无缝连接

文章目录 背景插件书签 背景 不知道各位小伙伴有没有这样的痛点&#xff0c;办公电脑、家里的电脑还有手机、平板等&#xff0c;收藏了一个网址或者在手机上浏览了某个网页&#xff0c;保存起来&#xff0c;可是一换平台或者换个电脑&#xff0c;在想要浏览之前收藏的东西&…

剪画小程序:父辈的照片模糊不清晰,怎么变清晰!

在我们的记忆深处&#xff0c;父辈和爷爷辈的影像总是伴随着一些模糊不清晰的老照片。这些照片或许没有现代摄影技术的高清与细腻&#xff0c;但它们却承载着无比厚重的岁月痕迹和情感温度。 每一张模糊的老照片&#xff0c;都是时光的切片。它们可能是父辈年轻时的纯真笑容&am…

Linux -- 认识 make/makefile

目录 前言&#xff1a; 什么是 make/makefile&#xff1f; 怎么使用 make/makefile&#xff1f; 依赖关系和依赖方法&#xff1a; 清理&#xff1a; 怎么使用 make&#xff1f; 如何编写多文件的 makefile&#xff1f; 什么是PHNOY&#xff1f; ACM时间 什么是AC…

maven项目读取文件错误

开发工具&#xff1a;idea 一个简单的maven项目&#xff0c;程序读取不到src/main/resources目录下的文件 寻找了一些原因后&#xff0c;还是没解决&#xff0c;最后灵机一动改了设置居然好了。 然后就解决了

LAZYNVIM学习使用笔记

文章目录 1. 前言VIM的模式快捷键参考 1. 前言 习惯使用vscode进行代码编辑&#xff0c;无意中刷到lazynvim&#xff0c;感觉功能强大&#xff0c;于是下载、安装&#xff0c;学习使用一下&#xff0c;本篇主要记录学习使用lazynvim的一些要点&#xff0c;防止遗忘。 持续更新…

视频版权音乐处理☞AI分离人声、音效、背景音乐的需求和进展-2024

随着互联网的普及和短视频的兴起&#xff0c;视频内容的全球各大平台分发越来越普遍。然而&#xff0c;不同国家和地区的音乐版权、不同社媒平台拥有的版权和处理政策都存在差异&#xff0c;因此同一个视频在多渠道分发的时候就会产生版权侵权风险。如何既能满足全球多渠道、多…

【大白话讲清楚:什么是 Langchain 及其核心概念】

文末有福利&#xff01; 在AI和机器学习领域&#xff0c;每天都有新技术和框架涌现。今天&#xff0c;我们来聊聊最近引起广泛关注的一个框架 —— Langchain。 https://python.langchain.com/docs/get_started/introduction 那么&#xff0c;Langchain到底是什么&#xff0c…

【教程】Hexo 部署到 Github Page 后,自定义域名失效的问题

目录 前言&问题描述解决方案细节 前言&问题描述 近期给 Github Page 上托管的静态网站映射了自定义域名&#xff08;aiproducthome.top&#xff09;&#xff0c;之后发现每次更新并部署 hexo 到 Github Page &#xff08;hexo d&#xff09;后就会出现自定义域名失效的…