本文为实现modbus协议转换提供技术上的总体思路,具体实现需根据实际情况来确定。

需求说明

FSU对南向设备进行数据采集、控制,进行协议转换,对上层平台提供modbus协议来读写南向设备,屏蔽底层南向设备的交互细节,实现上层平台与底层南向设备协议间的解耦。

  1. 协议生成:

    平台层使用的是一份由GatewayServer自动化生成的modbus协议文档
  2. 协议配置:

    GatewayServer支持web配置modbus协议
  3. 协议实现:

    modbus要同时支持tcp和rtu

需求拆分

协议生成

数据定义

    uint32_t regAddr;   //寄存器地址
    uint16_t regNum;    //单个meter包含的寄存器数量
    int regSize;        //寄存器总个数(这一轮里面,-1时表示无效)
    CData deviceID;     //设备id
    bool meterBit = false;  //meter是否是一个bit对应一个量(如果是的话,regNum和regSize都必须为1)
    int meterBitSize;   //meterBit为true时才有效(有效时指定有效的bit位个数)
    CData type;         //解析的数据类型
    double factor;      //当前的数值需要乘以多少
    CData access;       //读写权限
    bool def = false;   //是否有默认值(默认值为false)
    double defVal;      //如果有,默认值为多少
    bool range = false; //数据是否有数据范围(默认为false)
    double rangeMin;    //如果有范围,此范围的最小值
    double rangeMax;    //如果有范围,此范围的最大值

    //下面这两个只有主meter才会有此字段
    bool distance = false;  //是否有距离间隔
    int distanceVal;    //如果有,每组meterList之间间隔的寄存器值是多少
    int step = 1000;    //量id之间的变化基数(默认为1000)
    int highLowPos = -1;    //解析方式是否按高16位和低16位解析(小于0表示不按照高低位解析,0表示低16位,1表示高16位)

协议格式

<?xml version="1.0" encoding="UTF-8" ?>
<version>1.00</version>
<devices>
	<!-- 系统状态r -->
	<device deviceId="5000001" name="系统状态">
		<meter regAddr="0" regNum="1" regSize="1" meterID="312005001" meterBit="false" meterBitSize="0" type="u16" factor="1" access="r" default="true" defaultVal="1" range="false" rangeMin="0.1" rangeMax="10.0" distance="false" distanceVal="0"/>
		<meterList>
			<meter regAddr="1" regNum="1" regSize="1" meterID="312006001" meterBit="false" meterBitSize="0" type="u16" factor="1" access="r" default="false" defaultVal="0" range="false" rangeMin="0.1" rangeMax="10.0" step="1"/>
		</meterList>
	</device>
</devices>


协议配置

页面原型(草稿)

在配置管理增加Modbus配置入口。

进入配置页面,根据实际需要增加对应的前端功能。


协议实现

GatewayServer解析xml配置文件,将xml配置文件包含的量存放到缓存中,采取定时获取meter值和订阅meter值变更时间的方式更新数据,并将值同步到Modbus的寄存器。

根据web页面是否开启tcp、rtu服务,来启动tcp、rtu子模块。

  • 无标签

5 评论

  1. XiongYong 发表:

    看完协议实现的是使用Modbus RTU over TCP和 Modbus TCP来进行平台接入,需要平台与网关之间配置的同步(平台要解析,网关要生成Modbus 寄存器的点位,要保证平台与网关之间的一致性),如下图所示

    Modbus RTU over TCP/Modbus TCP 的数据端一般是从机,即网关是从机,平台 是主机,在实现上可能需要 网关发起连接,再由平台来请求,除连接外其他 按照 标准的 Modbus 实现即可;

    Modbus 的设备地址、寄存器与网关上设备和量的映射关系设置;

    实现的协议是在 TCP 连接上,TCP 是明文传输,需要考虑是否 基于 TLS 的连接进行传输。

  2. xie 发表:

    项目计划说明
    模块划分功能明细预估时间当前进度说明是否逾期,若逾期请说明原因
    主机、从机功能支持

    1、modbus tcp主机功能
    2、modbus tcp从机功能
    3、modbus rtu主机功能

    4、modbus rtu从机功能

    2025/03/11

    1、已完成,已自测

    2、已完成,未自测

    3、已完成,已自测

    4、已完成,已自测



    网关控制下发

    1、网关配置modbus协议及主从机

    2、网关配置寄存器信息

    3、数据存储

    2025/03/21

    1、已完成,已自测

    2、已完成,已自测

    3、已完成,已自测



    数据解析及同步更新

    1、解析本地xml配置项

    2、解析网关下发的配置,将其缓存到某个数据结构中

    3、根据解析的配置,将网关上的数据同步更新到modbus寄存器中

    2025/03/28

    1、已完成,已自测

    2、已完成,已自测

    3、已完成,未自测

    web的功能可能需要姚工帮忙开发
    平台控制下发

    1、定义与平台交互的接口及字段

    2、将网关配置项与平台同步

    2025/04/11

    1、已自测,无需额外开发

    2、已自测,无需额外开发

    平台的功能可能需要平台那边帮忙开发
    模块功能整合

    1、模块功能整合

    2025/04/141、已完成

    项目优化及总结

    1、项目评审、优化、测试及bug验证

    2、线上环境验证及bug修改

    2025/05/09
    项目验证可能需要李工或陈工帮忙验证


  3. xie 发表:

    web网关下发json,控制协议类型相关的字段如下:

    "isOnModbusRtuSer":1,    //是否开启rtuServer(0不开启,1开启)
    "isOnModbusRtuCli":1,    //是否开启rtuClient(0不开启,1开启)
    "isOnModbusTcpSer":0,    //是否开启tcpServer(0不开启,1开启)
    "isOnModbusTcpCli":0,    //是否开启tcpClient(0不开启,1开启)

    "rtuServer": {

    "device": "串口设备名称",

    "baud": 9600,

    "parity": "N",    //"N":无奇偶校验, "O":奇校验,"E":偶校验

    "dataBit": 8,

    "stopBit": 1 

    },

    "rtuClient": {

    "device": "串口设备名称2"

    "baud": 9600,

    "parity": "N",    //"N":无奇偶校验, "O":奇校验,"E":偶校验

    "dataBit": 8,

    "stopBit": 1 

    },

    "tcpServer":{

    "ip": "0.0.0.0",   //ip和端口

    "port": 502

    },

    "tcpClient":{

    "ip": "192.168.1.100",   //ip和端口

    "port": 502

    }

    web网关下发json,获取、配置相关的字段如下:

    [
        {

             "devName": "Device2",
             "deviceId": "0",
            "configs": [
                {
                    "meterId": "0",

                    "regAddr": 1000,
                    "regNum": 10,
                    "regSize": -1,
                    "type": "uint16",
                    "factor": 1.0,
                    "access": "r",    //这个字段只有"r"和"rw"两种可选值
                    "def": false,
                    "defVal": 0.0,
                    "range": false,
                    "rangeMin": 0.0,
                    "rangeMax": 0.0,
                    "step": 1000,
                    "highLowPos": -1
                }

            ]
        }
    ]


    数据定义修改如下:

        uint16_t regAddr;   //寄存器地址
        uint16_t regNum;    //单个meter包含的寄存器数量
        int regSize = -1;   //寄存器总个数(这一轮里面,-1时表示无效)
        CData deviceId = "0";     //设备id
        CData meterId = "0";       //meterId(读的meterId)
        std::string type;   //解析的数据类型
        double factor;      //当前的数值需要乘以多少
        std::string access; //读写权限
        bool def = false;   //是否有默认值(默认值为false)
        double defVal;      //如果有,默认值为多少
        bool range = false; //数据是否有数据范围(默认为false)
        double rangeMin;    //如果有范围,此范围的最小值
        double rangeMax;    //如果有范围,此范围的最大值   

        int step = 1000;    //量id之间的变化基数(默认为1000)
        int highLowPos = -1;    //解析方式是否按高16位和低16位解析(小于0表示不按照高低位解析,0表示低16位,1表示高16位)



    数据类型:type的字段值有:str(字符串)、s16(int16_t)、u16(uint16_t)、hl(high 8 bit or low 8 bit)、bit(bit位)

  4. xie 发表:

    与web交互的四个接口验证如下:


    1、Get请求协议选择的数据:

    URL:http://192.168.1.113/jscmd/getModbusChoose

    回复Body:

    {
        "jsonrpc": "2.0",
        "method": "null",
        "id": "null",
        "result": {
            "isOnModbusRtuSer": 0,
            "isOnModbusRtuCli": 0,
            "isOnModbusTcpSer": 1,
            "isOnModbusTcpCli": 1,
            "tcpServer": {
                "ip": "192.168.1.100",
                "port": 502
            },
            "tcpClient": {
                "ip": "",
                "port": 0
            }
        }
    }


    2、Post设置协议选择的数据:

    URL:http://192.168.1.113/jscmd/setModbusChoose

    请求Body:

    {
        "jsonrpc":"2.0",
        "method":"webrpc",
        "id":1,
        "params": {
            "isOnModbusRtuSer": 0,
            "isOnModbusRtuCli": 0,
            "isOnModbusTcpSer": 1,
            "isOnModbusTcpCli": 1,
            "tcpServer": {
                "ip": "192.168.1.100",
                "port": 502
            },
            "tcpClient": {
                "ip": "",
                "port": 0
            }
        }
    }

    回复Body:

    {
        "jsonrpc": "2.0",
        "method": "null",
        "id": "null",
        "result": "true"
    }


    3、Get获取配置信息:

    URL:http://192.168.1.113/jscmd/getDeviceList

    回复Body:

    {
        "jsonrpc": "2.0",
        "method": "null",
        "id": "null",
        "result": [
            {
                "devName": "系统状态",
                "deviceId": "5000001",
                "configs": [
                    {
                        "meterId": "312006001",
                        "regAddr": 1,
                        "regNum": 1,
                        "regSize": 1,
                        "type": "u16",
                        "factor": 1,
                        "access": "r",
                        "def": 0,
                        "defVal": 0,
                        "range": 0,
                        "rangeMin": 0.1,
                        "rangeMax": 10,
                        "step": 1000,
                        "highLowPos": 0
                    },
                    {
                        "meterId": "312002001",
                        "regAddr": 2,
                        "regNum": 1,
                        "regSize": 1,
                        "type": "u16",
                        "factor": 1,
                        "access": "r",
                        "def": 0,
                        "defVal": 0,
                        "range": 0,
                        "rangeMin": 0.1,
                        "rangeMax": 10,
                        "step": 1000,
                        "highLowPos": 0
                    }
                ]
            }
        ]
    }


    4、Post修改配置信息:

    URL:http://192.168.1.113/jscmd/updateDeviceList

    请求Body:

    {
        "jsonrpc": "2.0",
        "method": "null",
        "id": "null",
        "params": [
            {
                "devName": "系统状态",
                "deviceId": "5000001",
                "configs": [
                    {
                        "meterId": "312006002",
                        "regAddr": 1,
                        "regNum": 1,
                        "regSize": 1,
                        "type": "u16",
                        "factor": 1,
                        "access": "r",
                        "def": 0,
                        "defVal": 0,
                        "range": 0,
                        "rangeMin": 0.1,
                        "rangeMax": 10,
                        "step": 1000,
                        "highLowPos": 0
                    },
                    {
                        "meterId": "312002001",
                        "regAddr": 2,
                        "regNum": 1,
                        "regSize": 1,
                        "type": "u16",
                        "factor": 1,
                        "access": "r",
                        "def": 0,
                        "defVal": 0,
                        "range": 0,
                        "rangeMin": 0.1,
                        "rangeMax": 10,
                        "step": 1000,
                        "highLowPos": 0
                    }
                ]
            }
        ]
    }

    回复Body:

    {
        "jsonrpc": "2.0",
        "method": "null",
        "id": "null",
        "result": "true"
    }

  5. xie 发表:

    {
        "jsonrpc":"2.0",
        "method":"webrpc",
        "id":1,
        "params": {
            "isOnModbusRtuSer": 0,
            "isOnModbusRtuCli": 0,
            "isOnModbusTcpSer": 1,
            "isOnModbusTcpCli": 1,
            "tcpServer": {
                "ip": "192.168.1.100",
                "port": 502
            },
            "tcpClient": {
                "ip": "",
                "port": 0
            }
        }
    }

    将ip字段修改为“nic”,表示网卡(不使用ip了)

    1. 你还没有登录。你所做的任何更改会将作者标记为匿名用户。 如果你已经拥有帐户,请登录