数据网关程序架构说明
——新增设备集采时,程序改动流程
程序架构
序号 | 文件 | 说明 |
---|---|---|
1 | json分组下的1个c、h文件 | 每种类型的设备定义在1个c文件中,根据和云平台的通信协议,定义了json的key数组、设备ID,用一个 srvc_t 类型的结构体映射了该类型设备的参数。如:基础款多功能仪表,定义在了《energy_multimeter.c》文件,对于该类型的设备,本分组只需改动这个文件即可 |
2 | collect.c | 定义 modbus 指令,针对具体的设备,根据设备的数据手册、通讯协议寄存器表,定义几条modbus指令,读取完所需要的数据;第2步,修改modbus轮询各设备的指令结构体 md_poll md_cmd_poll[]={设备类型代号(实际没用),设备通信地址, 读该设备需要的指令条数,指令指针,读到的数据存放位置指针}。 |
3 | time.h | 配置 网关上传 数据的周期,多长时间上传1其次,改宏定义值即可 |
4 | main、data_pkt | 配置网关要上传的设备类型 |
5 | W5500_confg.h | 配置 W5500本机IP,MAC、默认网关 |
以基础款多功能表为例进行说明
1. 定义设备类型的 json 格式的 key
修改文件《energy_multimeter.c》
key_t key7[]=
{
"device_id",
"device_type",
"device_status",
"phase_voltage_a",
"phase_voltage_b",
"phase_voltage_c",
"phase_current_a",
"phase_current_b",
"phase_current_c",
"active_power_a",
"active_power_b",
"active_power_c",
"active_power_total",
"reactive_power_a",
"reactive_power_b",
"reactive_power_c",
"reactive_power_total",
"power_factor_a",
"power_factor_b",
"power_factor_c",
"power_factor_total",
"active_energy_total",
"reactive_energy_total",
"time_energy_total",
"switch_value_1",
"switch_value_2",
"line_voltage_ab",
"line_voltage_bc",
"line_voltage_ac",
"apparent_power_a",
"apparent_power_b",
"apparent_power_c",
"apparent_power_total",
"frequency",
};
这个数组定义了本设备类型对应的 json 格式的 key。要与云平台通信协议格式一致,也就是数据库中每个字段对应的文本内容。
2. 初始化本设备类型的 点表
#ifdef __ZY_
node_table_t zy_talbe[]=
{//中原电气仪表
// byte n adr
0, 0, 0,
0, 0, 0, //数据存储在 coilReg中
0, 0x11, 0, //数据存储在 holdReg中
2, 0x00, 12,
2, 0x00, 13,
2, 0x00, 14,
2, 0x09, 15,
2, 0x09, 16,
2, 0x09, 17,
2, 0x01, 0,
2, 0x01, 1,
2, 0x01, 2,
2, 0x01, 3,
2, 0x01, 4,
2, 0x01, 5,
2, 0x01, 6,
2, 0x01, 7,
2, 0x00, 19,
2, 0x00, 20,
2, 0x00, 21,
2, 0x00, 22,
4, 0x01, 35,
4, 0x01, 43,
0, 0xAA, 0,
0, 0xAA, 0,
0, 0xAA, 0,
2, 0x00, 23,
2, 0x00, 24,
2, 0x00, 25,
2, 0x01, 8,
2, 0x01, 9,
2, 0x01, 10,
2, 0x01, 11,
2, 0x00, 27,
};
#endif
点表的数据类型定义是 结构体,指明了设备寄存器数据特性,即数据存储在本网关的寄存器地址,数据和真实值的比例关系,数据所占的字节长度。原型如下:
typedef struct
{
u8 byte; //变量所占字节数;当为开关量时(.n=0xff),表示本寄存器中的位地址
u8 n; //通道处理,10的n次方;n<=4,否则特殊处理
u16 adr; //寄存器地址
}node_table_t;
对于已经有的型号,对应点表已经建立好了,就不需要改动。新的未定义的点表定义方式是:
- 建立Excel表格,表头有如下几个字段:key、byte(所占字节数)、n(10的次方数)、网关寄存器地址、设备寄存器地址、数据类型
- 对照设备的寄存器表,在上述表格中填写对应key 的数据的寄存器地址、及所占字节长度
- 根据设备数据说明,转化数据到真实数据,再由平台数据上传的数据比例确定 n 的值,即 上传到数据库的数据值与读到的设备数据值关系如下 数据库值 = 1 0 n × 读到的数据 数据库值 = 10^{n} ×读到的数据 数据库值=10n×读到的数据
- 编辑网关寄存器地址。从0开始,按照平台协议的 key 顺序 每个 key 对应1个寄存器地址对应2个字节长读,顺次递增,当数据长度是4字节时,寄存器地址增长步长为2
如上操作完成后,将点表需要的3个字段的值,按照c语言的语法格式,初始化 node_table_t zy_talbe[] 即可。
特别说明
点表中 n 的说明:
-
低3位 表示10的幂次;bit3表示幂次的正负,1表示负幂次。如n=0x09,表示10的-1次幂,等于1,即读到的设备数据不用做处理,等于上传的数据
-
n=0xAA 、A5、CC表示没有此项数据,上传到平台的数据固定或为空值
-
n=0xBB表示数据虚拟和其他设备共用,一般用不到,可忽略这种情况
-
0xff,代码型开关量,设备的开关量数据存储在 保持寄存器区,用03功能码读取整个16位寄存器,读回来的数据,保存在网关的 线圈寄存器区(一般少用,可忽略)
-
0x11,开关量数据,用01、02功能码读取,保存在网关的 线圈寄存器区
3. 初始化 map7[] 数组的其中1个元素:点表指针
map_t map7[]=
{//仪表类
#ifdef __LIKON_
{.table = likon_talbe},
#endif
#ifdef __BRL_
{.table = brl_talbe},
#endif
#ifdef __ZY_
{.table = zy_talbe},{.table = zy_talbe},{.table = zy_talbe},{.table = zy_talbe},{.table = zy_talbe},//5
{.table = zy_talbe},{.table = zy_talbe},{.table = zy_talbe},{.table = zy_talbe},{.table = zy_talbe},//10
{.table = zy_talbe},{.table = zy_talbe},{.table = zy_talbe},{.table = zy_talbe},{.table = zy_talbe},//15
{.table = zy_talbe},{.table = zy_talbe},{.table = zy_talbe},{.table = zy_talbe},{.table = zy_talbe},//20
{.table = zy_talbe},{.table = zy_talbe},{.table = zy_talbe},{.table = zy_talbe},{.table = zy_talbe},//25
{.table = zy_talbe},{.table = zy_talbe},{.table = zy_talbe},{.table = zy_talbe},{.table = zy_talbe},//30
{.table = zy_talbe},{.table = zy_talbe},{.table = zy_talbe},{.table = zy_talbe},{.table = zy_talbe},//35
{.table = zy_talbe},{.table = zy_talbe},{.table = zy_talbe},{.table = zy_talbe},{.table = zy_talbe},//40
{.table = zy_talbe},{.table = zy_talbe},{.table = zy_talbe},//43
#endif
};
map7的数据类型是结构体,定义如下
typedef struct
{
reg_t reg; // 读取到的设备的原始数据
node_table_t *table; //点表指针
prprty_t val[VAL_NUM]; //json 格式的val 值(经过了通道处理)
// char ID[10];
// struct
// {
// u16 holdReg[VAL_NUM];
// u16 coilReg[VAL_NUM];
// }; //从机返回的数据寄存器
}map_t;
有多少个设备ID就初始化多少个map元素,每个元素的点表,对应初始化为设备的点表指针。
4. 初始化 设备ID
char *ID7[] = {
"072302280710",
"072302280730",
"072302280731",
"072302280732",
"072302280733",
"072302280734",
"072302280735",
"072302280736",
"072302280737",
"072302280740",
"072302280741",
"072302280742",
"072302280743",
"072302280744",
"072302280745",
"072302280746",
"072302280747",
"072302280810",
"072302280830",
"072302280831",
"072302280832",
"072302280833",
"072302280834",
"072302280835",
"072302280836",
"072302280837",
"072302280840",
"072302280841",
"072302280842",
"072302280843",
"072302280844",
"072302280845",
"072302280846",
"072302280847",
"072302280910",
"072302280930",
"072302280931",
"072302280932",
"072302280933",
"072302280934",
"072302280935",
"072302280936",
"072302280937",
};
char *ID7[] = {
"072302280710",
"072302280730",
"072302280731",
"072302280732",
"072302280733",
"072302280734",
"072302280735",
"072302280736",
"072302280737",
"072302280740",
"072302280741",
"072302280742",
"072302280743",
"072302280744",
"072302280745",
"072302280746",
"072302280747",
"072302280810",
"072302280830",
"072302280831",
"072302280832",
"072302280833",
"072302280834",
"072302280835",
"072302280836",
"072302280837",
"072302280840",
"072302280841",
"072302280842",
"072302280843",
"072302280844",
"072302280845",
"072302280846",
"072302280847",
"072302280910",
"072302280930",
"072302280931",
"072302280932",
"072302280933",
"072302280934",
"072302280935",
"072302280936",
"072302280937",
};
至此,json分组下文件修改完毕。
5.修改《collect.c》,定义modbus指令
md_cmd_t md_cmd_zy[]=
{//中原电气仪表
0x03, 0x01, 0x2D, 0x00, 0x2D, //从301地址开始读取45个寄存器
};
可以有多条指令,按照如上格式,一条一条追加在后面即可。指令数据原型为:
//Modbus 轮询从机指令
typedef struct
{
u8 func; //功能码
u8 adrH; //起始地址高字节
u8 adrL; //起始地址低字节
u8 numH; //读取的寄存器(开关量)数量
u8 numL; // 读取的寄存器(开关量)数量低字节
}md_cmd_t;
6.初始化网关轮询485总线下的设备的 指令结构体
//modbus 轮询指令-end----------------------------------------------------------
md_poll md_cmd_poll[]=
{
0x07, 42, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[0].reg,
0x07, 32, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[1].reg,
0x07, 33, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[2].reg,
0x07, 34, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[3].reg,
0x07, 35, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[4].reg,
0x07, 36, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[5].reg,
0x07, 39, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[6].reg,
0x07, 40, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[7].reg,
0x07, 41, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[8].reg,
0x07, 22, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[9].reg,
0x07, 23, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[10].reg,
0x07, 26, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[11].reg,
0x07, 27, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[12].reg,
0x07, 28, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[13].reg,
0x07, 29, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[14].reg,
0x07, 30, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[15].reg,
0x07, 31, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[16].reg,
0x07, 1, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[17].reg,
0x07, 2, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[18].reg,
0x07, 3, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[19].reg,
0x07, 6, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[20].reg,
0x07, 7, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[21].reg,
0x07, 8, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[22].reg,
0x07, 9, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[23].reg,
0x07, 10, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[24].reg,
0x07, 11, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[25].reg,
0x07, 12, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[26].reg,
0x07, 13, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[27].reg,
0x07, 14, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[28].reg,
0x07, 15, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[29].reg,
0x07, 16, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[30].reg,
0x07, 19, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[31].reg,
0x07, 20, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[32].reg,
0x07, 21, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[33].reg,
0x07, 53, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[34].reg,
0x07, 43, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[35].reg,
0x07, 44, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[36].reg,
0x07, 45, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[37].reg,
0x07, 46, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[38].reg,
0x07, 47, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[39].reg,
0x07, 48, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[40].reg,
0x07, 50, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[41].reg,
0x07, 51, sizeof(md_cmd_zy)/sizeof(md_cmd_t), md_cmd_zy,&map7[42].reg,
};
数据原型:
typedef struct
{
u8 devType;
u8 adr; //modbus 从机地址
u8 num; //每种设备类型的指令条数 =sizeof(.cmd)/sizeof(md_cmd_t)
md_cmd_t *cmd; //每种类型对应的几条Modbus指令
reg_t *reg; //从机,返回的数据存储寄存器
}md_poll; //可根据设备类型,处理相应的返回数据
注意:前文定义的 ID 和这里的 从机地址、返回的数据存储寄存器,需要对应,否则设备数据会对应错误
7.初始化大类设备结构体数组
定义了本网关,要采集的设备类型,及对应设备类型的 ID指针,可以有多种不同类型的设备,逐条追加即可
//注册所接的终端设备---用户初始化自定义---------------------
psrvc_t service[] = {
&multimeter, ID7,
// &double_power, ID8,
};
//----------------------------------------------------------
以太网方式的程序,本结构体初始化 在文件《data_pkt.c》中;
4G程序,本结构体初始化在《main.c》中。
8.定义数据上传的频次
修改 time.h 文件 宏定义
以太网方式
#define Ts(a) (a * 1000) //a 秒
#define Tms(a) (a) //a 毫秒
#define T_net Tms(400) //上传周期
4G方式
#define Tmin(a) (a * 60 *1000) //a 分钟
#define T_4G Tmin(1) //4G上传周期
至此,数据采集相关的修改已完成
以太网配网
配置服务器 IP、端口(对应本司服务器固定,不用配置),文件《W5500_confg.h》
#define MAX_CONTENT_LENGTH 16000 //16k字节内,发送的报文长度 14600
#define SERVER_IP 114,115,221,203 //服务器域名/IP
#define SERVER_PORT 6003 //服务器端口号
#define URL "/hardware/t2?" //url
/*定义MAC地址,如果多块W5500网络适配板在同一现场工作,请使用不同的MAC地址*/
#define MAC_DEF 192,168,1,88
配置本数据网关的IP等参数
#define MAC_W5500 {0x00,0x08,0xdc,0x11,0x11,0x21}
/*定义默认IP信息*/
#define LOCAL_IP {192,168,0,51} /*定义W5500默认IP地址*/
#define SUBNET {255,255,255,0} /*定义W5500默认子网掩码*/
#define GATEWAY {192,168,0,1} /*定义W5500默认网关*/
#define DNS_SERVER {114,114,114,114} /*定义W5500默认DNS*/
#define LOCAL_PORT (5000) //本地端口