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

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

物联网可编程控制器

可编程CAN-bus物联网网关

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

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

常用代码下载

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

联系我们

虚拟串口软件

诚邀代理

项目合作及代客研发服务

特价商品

/ 淘宝购买
产品名称: CDT规约转Modbus协议
规  格:
产品备注:
产品类别: CDT电流屏协议转Modbus方案
点击量: 562


1、概述
CDT协议通常用于电厂、电池系统直流屏数据监控,我公司的AiMaster、AiMaker系列可编程产品内置了CDT协议处理算法。通过Lua函数调用CDT协议库接口函数,这样可以根据不同的设备,设计出不同的协议转换产品。

CDT协议库当前可支持:A帧,B帧,C帧,D1帧,暂时不支持遥控命令。

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

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

2、以艾默生E10的CDT协议转Modbus为例子进行说明

注意!各个厂家的产品所支持的功能码都不相同,数据定义也不相同。

本CDT例程支持CDT协议所有功能码,但是直流屏通常仅支持有限的功能码数量,在使用前,请联系直流屏厂家获取所能支持的功能码信息,然后填入下列代码中。

本例子可以通过功能码,完整获取到CDT所有数据值,但是具体数据定义,请参考厂家说明书。


本例子的功能码定义如下:


A帧重要遥测帧定义


cdtfid.jpg


B帧次要遥测帧定义

cdtfid_b.jpg



C帧一般遥测帧定义

cdtfid_c.jpg



D1帧遥信帧定义

cdtfid_d1.jpg



下面例子通过串口3读取CDT数据,并且转换数据至相应的Modbus寄存器。


转换的同时在2口原样输出CDT数据,所以3口可以连接现有的CDT监控设备,这样可以在不影响现有的CDT监控设备工作的同时,实现再转换出一路数据至Modbus。


print("CDT协议转Modbus")

--遥信Modbus寄存器起始地址,默认为0
local cfgristaddr=0
--A帧重要遥测Modbus寄存器起始地址,默认为0
local cfgrmstaddrA=0
--B帧次要遥测Modbus寄存器起始地址,默认为200
local cfgrmstaddrB=200
--C帧一般遥测Modbus寄存器起始地址,默认为400
local cfgrmstaddrC=400

--等待CDT数据超时,默认为10秒,如果超过10秒未能收到CDT数据首个字节,
--则认为下位机通讯故障。
local frtreadtmo=2000
--CDT数据帧字符间隔,按照协议规定是4ms,此处设置为50ms,用于兼容慢速设备。
local sectmo=50
--通讯状态指示寄存器
local commstateaddr=1000
--modbus下位机地址码
local mbslaveid=1
local res=0
--cdt数组,用于存储原始CDT数据
local cdtdata={0}
--存储遥信数据
local cdtridata={0}
--待获取的遥信功能码列表,对于E10为0xF0,0xF1,0xF4,0xF7,0xF8
local cdtrifid={0xF0,0xF1,0xF4,0xF7,0xF8}

--存储遥测数据
local cdtrmdata={0}
--待获取的A帧,重要遥测功能码列表,对于E10为0x06,0x07
local cdtrmfidA={0x06,0x07}
--待获取的B帧,次要遥测功能码列表,对于E10为0x01~0x04
local cdtrmfidB={0x01,0x02,0x03,0x04}

--存储待获取的C帧,一般遥测功能码,对于E10为0x0A,0x0B
--程序从数组第一个元素循环至第二个元素指定的值,循环读取一般遥测数据
--如果需要更多的C帧数据,例如转换12个电池组数据,改成cdtrmcntC={0x01,0x18}即可
local cdtrmcntC={0x0A,0x0B}
local cdtrmfid={}

--设置通讯状态为无通讯
lib_vmb.setvaluefc1(commstateaddr,mbslaveid,1);

while(true) do
          --readcdt函数等待接收CDT数据,如果收到数据,此函数将对CDT数据进行校验,
          --如果校验成功,将输出完整的CDT数据帧。否则返回错误。
          --参数1:串口号,为0起,0为第一个串口,以此类推。
          --参数2:CDT输出数据
          --参数3:接收第一个字节超时,如果达到此超时未能收到串口数据,此函数将返回错误。
          --参数4:数据字节超时,收到第一个字节后,使用此超时接收剩余数据,在达到超时
          --而未能收到数据时,此函数判定所有数据已经收齐,函数将返回收到的字节数据
          --并输出完整CDT数据帧。  
          --返回:返回小于等0为错误。其他值为收到的字节数量
           --清空缓存
           cdtdata={0}
           --清空缓存
           cdtridata={0}
           cdtrmdata={0}
           
           while(true) do
           res=lib_cdt.readcdt(2,cdtdata,frtreadtmo,sectmo)
           if (res>0) then
                  --指示通讯正常
                 print(string.format("\r\n接收正确:%d",res));
                 debug.printarray(cdtdata)
                 --接收到正确数据
                 lib_vmb.setvaluefc1(commstateaddr,mbslaveid,0);
                 break;
               else
                  --指示通讯错误
                  lib_vmb.setvaluefc1(commstateaddr,mbslaveid,1);
        --          print(string.format("\r\n接收错误:%d",res));
               end
            end
                          --判断是否为遥信数据
                          if (cdtdata[7]==0x71) and (cdtdata[8]==0xF4) then
                                 --遥信数据的Modbus起始地址
                                ristaddr=cfgristaddr
                                print(string.format("\r\n遥信数据Modbus地址:%d",ristaddr));
                                --循环获取指定ID的遥信数据
                                for i=1,table.getn(cdtrifid) do
                                        --getrivalue函数,读取原始CDT数据中指定功能码的遥信数据
                                    --参数1:遥信功能码
                                    --参数2:经过检测过的CDT遥测数据
                                    --参数3;是否校验数据块crc,0-校验,1不校验
                                    --参数4;CDT数据块数量
                                    --参数5:输出的遥信数据字节,固定为4个字节
                                        --返回1:返回大于等于0为正常,小于0为错误。
                                         res=lib_cdt.getrivalue(cdtrifid[i],cdtdata,1,cdtdata[9],cdtridata)
--                                         debug.printarray(cdtridata);
                                         if (res>0) then
                                              --设置进modbus虚拟机,此函数在common lib页中定义
                                               setridatatomb(ristaddr,mbslaveid,cdtridata,res)
                                           end
                                           --递增Modbus寄存器地址
                                           ristaddr=ristaddr+32
                                 end
                            end
        
                            rmstaddr=-1
                            if ((cdtdata[7]==0x71) and (cdtdata[8]==0x61)) then
                                 --A帧重要遥测数据
                                  rmstaddr=cfgrmstaddrA
                                  cdtrmfid=cdtrmfidA
                                  print(string.format("\r\n遥测A帧,Modbus寄存器地址:%d",rmstaddr));                                  
                                  setrmdatatomb(rmstaddr,mbslaveid,cdtdata,cdtdata[9],cdtrmfid)
                                elseif ((cdtdata[7]==0x71) and (cdtdata[8]==0xC2)) then
                                 --B帧次要遥测数据                    
                                  rmstaddr=cfgrmstaddrB
                                  cdtrmfid=cdtrmfidB
                                  print(string.format("\r\n遥测B帧,Modbus寄存器地址:%d",rmstaddr));                                  
                                  setrmdatatomb(rmstaddr,mbslaveid,cdtdata,cdtdata[9],cdtrmfid)                                                                    
                                elseif ((cdtdata[7]==0x71) and (cdtdata[8]==0xB3)) then
                                --C帧一般遥测状态
                                  rmstaddr=cfgrmstaddrC
                                  cdtrmfid=cdtrmcntC   
                                  print(string.format("\r\n遥测C帧,Modbus寄存器地址:%d",rmstaddr));
                                  setrmdatatomb_cnt(rmstaddr,mbslaveid,cdtdata,cdtdata[9],cdtrmfid)                                                                 
                              end
                           
                            --第二口为CDT原始数据输出口
                            lib_uart.uart_tx(1,cdtdata,0);                            
                            
end



--将遥信数据设置进Modbus虚拟机
local function setridatatomb(ristaddr,mbslaveid,cdtridata,datacnt)
        --设置所有数据进Modbus虚拟机
        for i=1,datacnt do
                --循环1至res,
                for i2=1,8 do
                  --循环处理8个bit,使用Modbus功能码01,使用CDT上报的站号。
                  lib_vmb.setvaluefc1(ristaddr+((i2-1)+(i-1)*8),
                                mbslaveid,lib_bit.bit_is_set(cdtridata[i],i2-1));
                end
        end
end

--将遥测数据设置进虚拟机
local function setrmdatatomb(rmstaddr,mbslaveid,cdtdata,datacnt,cdtrmfid)
local res,rmres1,rmres2,sdata1,sdata2
        for i=1,table.getn(cdtrmfid) do
                --遥测数据
                --参数1:遥测功能码
            --参数2:经过检测过的CDT遥测数据
            --参数3;是否校验数据块crc,0-校验,1不校验
            --参数4;CDT数据块数量
            --返回1:遥测数据1状态,返回小于等于0的值为错误,其他值为正确
                --返回2:遥测数据2状态,返回小于等于0的值为错误,其他值为正确    
                --返回3:遥测数据1    
                --返回4:遥测数据2
                 res,rmres1,rmres2,sdata1,sdata2=lib_cdt.getrmvalue(cdtrmfid[i],cdtdata,1,datacnt)
                
                 if (res>=0) then
                          --将遥测值设置进Modbus虚拟机
                           if (rmres1<0) then
                                 sdata1=0x8000
                              end
                           lib_vmb.setvaluefc3(rmstaddr,mbslaveid,6,sdata1)

                           if (rmres2<0) then
                                sdata2=0x8000
                             end
                           
                           lib_vmb.setvaluefc3(rmstaddr+1,mbslaveid,6,sdata2)
                  end
                rmstaddr=rmstaddr+2
          end
end

--将遥测数据设置进虚拟机
local function setrmdatatomb_cnt(rmstaddr,mbslaveid,cdtdata,datacnt,cdtrmfidcnt)
local res,rmres1,rmres2,sdata1,sdata2
        --循环读取遥测数据功能码
        for i=cdtrmfidcnt[1],cdtrmfidcnt[2] do
                --遥测数据
                --参数1:遥测功能码
            --参数2:经过检测过的CDT遥测数据
            --参数3;是否校验数据块crc,0-校验,1不校验
            --参数4;CDT数据块数量
            --返回1:遥测数据1状态,返回小于等于0的值为错误,其他值为正确
                --返回2:遥测数据2状态,返回小于等于0的值为错误,其他值为正确    
                --返回3:遥测数据1    
                --返回4:遥测数据2
                 res,rmres1,rmres2,sdata1,sdata2=lib_cdt.getrmvalue(i,cdtdata,1,datacnt)
                 if (res>=0) then
                          --将遥测值设置进Modbus虚拟机
                           if (rmres1<0) then
                                   sdata1=0x8000
                               end
                           lib_vmb.setvaluefc3(rmstaddr,mbslaveid,6,sdata1)
                           
                           if (rmres2<0) then
                                   sdata2=0x8000                           
                            end
                           lib_vmb.setvaluefc3(rmstaddr+1,mbslaveid,6,sdata2)                              
                  end
                rmstaddr=rmstaddr+2
          end
end

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