Modbus多主机通讯网关 串口服务器

可编程串口以太网网关 全新的极简编程

物联网可编程控制器

可编程CAN-bus物联网网关

高性价比多网口串口服务器

以太网IO模块 模拟量采集、输出模块

常用代码下载

大道至简 极简物联网平台方案

联系我们

虚拟串口软件

诚邀代理

项目合作及代客研发服务

特价商品

/ 淘宝购买
产品名称: 国网DL645-2007电表规约转Modbus方案
规  格:
产品备注:
产品类别: DL645-2007协议转Modbus方案
点击量: 1655

1、概述
DL645协议是智能电表常用的通讯协议。此协议规定了非常多的数据点,但是目前的智能电表通常只支持几个常用数据点,而且所支持数据点并无统一标准。为协议处理和转换造成了比较大的难度。

我公司的AiMaster、AiMaker系列可编程产品内置了DL645-2007处理算法。通过Lua函数调用DL645库接口函数,这样可以根据不同的电表,灵活进行数据处理。

在取得DL645数据后,就可以放入Modbus虚拟机的Modbus寄存器,提供给多个上位机同时读取。无需编写任何Modbus通讯代码。如果使用AiMaker600物联网PLC,还可以根据取得的数据做出控制动作。

AiMaster、AiMaker产品也可以对取得DL645数据,使用算法做进一步运算处理,也可以传输至云端,提供给APP读取。

2、读取电能数据

此例子读取总电量数据,所有电表都支持此功能。电表是否支持规约中的其他电能数据,请咨询电表厂家。


tab1.jpg



print("读取DL645正向有功总电能数据。")
--表号
local saddr={20,19,01,01,50,02}
--标识码,此标识码为DL645-2007协议所规定的电能数据标识码
--格式为BCD码,可以直接套用协议中的标识码规定
--00010000为
local idcode={0x00,0x01,0x00,0x00}
--电表应答的原始数据
local rawdata={0}
local res=0.0

while (true) do
rawdata={0}
--readpwvalue读取电能数据函数
--参数1:串口号,为0起,0为串口1,1为串口2,以此类推
--参数2:6个数字的表号,通常在电表上可以找到表号,直接填入即可,表号为BCD数字格式。
--参数3:为数组格式的标识码,用于指出要读取的电能数据,应符合DL645-2007的定义,
--例如:00010000为读取正向有功总电能,00020000为读取反向有功总电能。
--参数4:接收到的原始数据数组,从电表收到的原始数据,如果读取错误,此数据无效。
--参数5:通讯超时,发送读取指令后,等待电表应答的超时,如果达到超时而未收到电表
--应答数据,则认为电表无应答,将返回错误。
--返回:如果返回数据为nil说明读取失败。否则返回读取到的电能数据值,为带2位小数的浮点数。
res=dl645.readpwvalue(2,saddr,idcode,rawdata,1000)

if (res==nil) then
      print(string.format("\r\n读取失败"));
else
   --res为浮点数格式的总电量数据
       print(string.format("\r\nres:%6.2f",res));
    end
debug.printarray(rawdata);
--setvaluefc3函数,将电能数据值,设置进Modbus寄存器值
--参数1:Modbus寄存器地址,2个地址保存4个字节
--参数2:下位机地址码
--参数3:数据类型2-ushort,3-long,4-float,5-int,6-short;
--参数4:此Modbus寄存器地址的数据
--相同类型的数据,应组织在各自的连续的寄存器地址,不应混和组合.
--数据类型为u_short,u_short为16bit数据,占用1个寄存器地址,寄存器读取数量为1
--设置进Modbus寄存器提供给上位机读取。
--对应的Modbus参数为,下位机地址1,寄存器地址0起,读取2个寄存器,格式为反转float
lib_vmb.setvaluefc3(0,1,4,res);
syslib.ossleep(1000);
 end

3、读取变量数据

并不是所有电表都支持此例子所读取的变量数据,请咨询电表厂家以获得更多信息。

图片.png


print("读取DL645变量数据。")
--启用发送前导字符4个0xFE
--setopt函数设置DL645库的全局参数。
--参数1:为选项编号,1-是否启用发送前导字符4个0xFE
--参数2:为选项数据,1-发送(默认),0-不发送前导字符
--dl645.setopt(1,1)
while (true) do
--表号
local saddr={20,19,01,01,50,02}

--idcode为16进制格式的4字节标识码
--字节存储顺序,按照DL645-2007协议规定的DI3、DI2、DI1、DI0顺序排列。
--idcode数组的第1个字节是DI3。以此类推。
--第1个字节0x02为读取变量数据,第2个字节0x01是读取电压
--第3个字节0x01为读取A相电压,第3个字节未用,设置为0.
--读取其他变量数据的标识码,请查阅DL645-2007协议手册。或参考"常用DL645数据转Modbus"例程
local idcode={0x02,0x01,0x01,0x00}
--rawdata用于存储电表应答的原始数据
local rawdata={0}
--res为读取到的数据。
local res=0.0

--readvaldata读取变量数据函数
--参数1:串口号,为0起,0为串口1,1为串口2,以此类推
--参数2:6个数字的表号,通常在电表上可以找到表号,直接填入即可,表号为BCD数字格式。
--参数3:为数组格式的标识码,用于指出要读取的电能数据,应符合DL645-2007,1997的定义,
--例如:02010000为读取A相电压
--参数4:接收到的原始数据数组,从电表收到的原始数据,如果读取错误,此数据无效。
--参数5:通讯超时,发送读取指令后,等待电表应答的超时,如果达到超时而未收到电表
--应答数据,则认为电表无应答,将返回错误。

--返回:如果返回数据为nil说明读取失败。
--否则返回读取到的数据,返回的数据小数位数已经根据DL645-2007协议的规定进行了处理。
res=dl645.readvaldata(2,saddr,idcode,rawdata,1000)

if (res==nil) then
     print(string.format("\r\n读取失败"));
    else
     print(string.format("\r\nA相电压:%6.2f",res));
     --A相电压数据在Modbus寄存器地址100,读取2个寄存器地址。
lib_vmb.setvaluefc3(100,1,4,res);

    end
--查看返回的原始数据
debug.printarray(rawdata);

--读取A相电流
idcode={0x02,0x02,0x01,0x00}

res=dl645.readvaldata(2,saddr,idcode,rawdata,1000)

if (res==nil) then
     print(string.format("\r\n读取失败"));
    else
      print(string.format("\r\nA相电流:%6.2f",res));
     --A相电流数据在Modbus寄存器地址102,读取2个寄存器地址。
lib_vmb.setvaluefc3(102,1,4,res);
    end
--查看返回的原始数据
debug.printarray(rawdata);

--读取电网频率
idcode={0x02,0x80,0x00,0x02}

res=dl645.readvaldata(2,saddr,idcode,rawdata,1000)

if (res==nil) then
     print(string.format("\r\n读取失败"));
    else
      print(string.format("\r\n电网频率:%6.2f",res));
     --电网频率数据在Modbus寄存器地址104,读取2个寄存器地址。
lib_vmb.setvaluefc3(104,1,4,res);
    end
--查看返回的原始数据
debug.printarray(rawdata);

--读取A相相角
idcode={0x02,0x07,0x01,0x00}

res=dl645.readvaldata(2,saddr,idcode,rawdata,1000)

if (res==nil) then
     print(string.format("\r\n读取失败"));
    else
print(string.format("\r\nA相相角:%6.2f",res));
--A相相角在Modbus寄存器地址106,读取2个寄存器地址。
lib_vmb.setvaluefc3(106,1,4,res);

  end
--查看返回的原始数据
debug.printarray(rawdata);

--读取瞬时总有功功率
idcode={0x02,0x80,0x00,0x05}

res=dl645.readvaldata(2,saddr,idcode,rawdata,1000)

if (res==nil) then
     print(string.format("\r\n读取失败"));
    else
      print(string.format("\r\n瞬时总有功功率:%6.4f",res));
--瞬时总有功功率在Modbus寄存器地址108,读取2个寄存器地址。
lib_vmb.setvaluefc3(108,1,4,res);
  end
--查看返回的原始数据
debug.printarray(rawdata);

syslib.ossleep(1000);
 
end

3、读取最大需量数据

很多电表不支持最大需量数据,请咨询电表厂家以获得相关信息。

table3.jpg


print("读取DL645最大需量数据。")
--启用发送前导字符4个0xFE
--setopt函数设置DL645库的全局参数。
--参数1:为选项编号,1-是否启用发送前导字符4个0xFE
--参数2:为选项数据,1-发送(默认),0-不发送前导字符
--dl645.setopt(1,1)
while (true) do
--表号
local saddr={20,19,01,01,50,02}

--idcode为16进制格式的4字节标识码
--字节存储顺序,按照DL645-2007协议规定的DI3、DI2、DI1、DI0顺序排列。
--请查阅DL645-2007协议手册。或参考"常用DL645数据转Modbus"例程
--0x01,0x01,0x00,0x00标识码为读取正向有功最大需量及发生日期
local idcode={0x01,0x01,0x00,0x00}
--rawdata用于存储电表应答的原始数据
local rawdata={0}

--maxqrdata为最大需量数据,为浮点数
local res=0.0
--maxqrdt为最大需量发生日期
local maxqrdt

--readmaxrqdata读取最大需数据及发生日期函数
--参数1:串口号,为0起,0为串口1,1为串口2,以此类推
--参数2:6个数字的表号,通常在电表上可以找到表号,直接填入即可,表号为BCD数字格式。
--参数3:为数组格式的标识码,用于指出要读取的电能数据,应符合DL645-2007的定义,
--例如:01010000为读取正向有功最大需量数据及发生日期
--参数4:接收到的原始数据数组,从电表收到的原始数据,如果读取错误,此数据无效。
--参数5:通讯超时,发送读取指令后,等待电表应答的超时,如果达到超时而未收到电表
--应答数据,则认为电表无应答,将返回错误。

--返回2个数据:
--数据1:最大需量数据(maxqrdata),为浮点数。
--数据2:最大需量发生日期(maxqrdt),数据为数组格式,数值按照{年,月,日,小时,分钟}存储。
maxqrdt,maxqrdata=dl645.readmaxrqdata(2,saddr,idcode,rawdata,1000)

if (maxqrdata==nil) then
     print(string.format("\r\n读取失败"));
    else
     print(string.format("\r\n正向有功最大需量值:%2.4f",maxqrdata));
     print(string.format("\r\n正向有功最大需量发生日期:%d年%d月%d日%d时%d分",maxqrdt[1],maxqrdt[2],maxqrdt[3],
                            maxqrdt[4],maxqrdt[5]));
    end
     debug.printarray(rawdata);    

--例子2 ,读取A相正向有功最大需量数据
local idcode={0x01,0x15,0x00,0x00}
maxqrdt,maxqrdata=dl645.readmaxrqdata(2,saddr,idcode,rawdata,1000)

if (maxqrdata==nil) then
     print(string.format("\r\n读取失败"));
    else
     print(string.format("\r\nA相正向有功最大需量值:%2.4f",maxqrdata));
     print(string.format("\r\nA相正向有功最大需量发生日期:%d年%d月%d日%d时%d分",maxqrdt[1],maxqrdt[2],maxqrdt[3],
                            maxqrdt[4],maxqrdt[5]));
    end
     debug.printarray(rawdata);    

syslib.ossleep(1000);
 end

版权所有:深圳市一天广联科技有限公司 邮箱:getit95@163.com 粤ICP备18087671号