
產(chǎn)品名稱: | CDT規(guī)約轉(zhuǎn)Modbus協(xié)議 |
---|---|
規(guī) 格: | |
產(chǎn)品備注: | |
產(chǎn)品類別: | CDT電流屏協(xié)議轉(zhuǎn)Modbus方案 |
點(diǎn)擊量: | 843 |
1、概述
CDT協(xié)議通常用于電廠、電池系統(tǒng)直流屏數(shù)據(jù)監(jiān)控,我公司的AiMaster、AiMaker系列可編程產(chǎn)品內(nèi)置了CDT協(xié)議處理算法。通過Lua函數(shù)調(diào)用CDT協(xié)議庫(kù)接口函數(shù),這樣可以根據(jù)不同的設(shè)備,設(shè)計(jì)出不同的協(xié)議轉(zhuǎn)換產(chǎn)品。
CDT協(xié)議庫(kù)當(dāng)前可支持:A幀,B幀,C幀,D1幀,暫時(shí)不支持遙控命令。
在取得CDT數(shù)據(jù)后,就可以放入Modbus虛擬機(jī)的Modbus寄存器,提供給多個(gè)上位機(jī)同時(shí)讀取。無需編寫任何Modbus通訊代碼。如果使用AiMaker600物聯(lián)網(wǎng)PLC,還可以根據(jù)取得的數(shù)據(jù)做出控制動(dòng)作。
AiMaster、AiMaker產(chǎn)品也對(duì)取得CDT數(shù)據(jù),使用算法做進(jìn)一步運(yùn)算處理,也可以傳輸至云端,提供給APP讀取。
2、以艾默生E10的CDT協(xié)議轉(zhuǎn)Modbus為例子進(jìn)行說明
注意!各個(gè)廠家的產(chǎn)品所支持的功能碼都不相同,數(shù)據(jù)定義也不相同。
本CDT例程支持CDT協(xié)議所有功能碼,但是直流屏通常僅支持有限的功能碼數(shù)量,在使用前,請(qǐng)聯(lián)系直流屏廠家獲取所能支持的功能碼信息,然后填入下列代碼中。
本例子可以通過功能碼,完整獲取到CDT所有數(shù)據(jù)值,但是具體數(shù)據(jù)定義,請(qǐng)參考廠家說明書。
本例子的功能碼定義如下:
A幀重要遙測(cè)幀定義
B幀次要遙測(cè)幀定義
C幀一般遙測(cè)幀定義
D1幀遙信幀定義
下面例子通過串口3讀取CDT數(shù)據(jù),并且轉(zhuǎn)換數(shù)據(jù)至相應(yīng)的Modbus寄存器。
轉(zhuǎn)換的同時(shí)在2口原樣輸出CDT數(shù)據(jù),所以3口可以連接現(xiàn)有的CDT監(jiān)控設(shè)備,這樣可以在不影響現(xiàn)有的CDT監(jiān)控設(shè)備工作的同時(shí),實(shí)現(xiàn)再轉(zhuǎn)換出一路數(shù)據(jù)至Modbus。
print("CDT協(xié)議轉(zhuǎn)Modbus")
--遙信Modbus寄存器起始地址,默認(rèn)為0
local cfgristaddr=0
--A幀重要遙測(cè)Modbus寄存器起始地址,默認(rèn)為0
local cfgrmstaddrA=0
--B幀次要遙測(cè)Modbus寄存器起始地址,默認(rèn)為200
local cfgrmstaddrB=200
--C幀一般遙測(cè)Modbus寄存器起始地址,默認(rèn)為400
local cfgrmstaddrC=400
--等待CDT數(shù)據(jù)超時(shí),默認(rèn)為10秒,如果超過10秒未能收到CDT數(shù)據(jù)首個(gè)字節(jié),
--則認(rèn)為下位機(jī)通訊故障。
local frtreadtmo=2000
--CDT數(shù)據(jù)幀字符間隔,按照協(xié)議規(guī)定是4ms,此處設(shè)置為50ms,用于兼容慢速設(shè)備。
local sectmo=50
--通訊狀態(tài)指示寄存器
local commstateaddr=1000
--modbus下位機(jī)地址碼
local mbslaveid=1
local res=0
--cdt數(shù)組,用于存儲(chǔ)原始CDT數(shù)據(jù)
local cdtdata={0}
--存儲(chǔ)遙信數(shù)據(jù)
local cdtridata={0}
--待獲取的遙信功能碼列表,對(duì)于E10為0xF0,0xF1,0xF4,0xF7,0xF8
local cdtrifid={0xF0,0xF1,0xF4,0xF7,0xF8}
--存儲(chǔ)遙測(cè)數(shù)據(jù)
local cdtrmdata={0}
--待獲取的A幀,重要遙測(cè)功能碼列表,對(duì)于E10為0x06,0x07
local cdtrmfidA={0x06,0x07}
--待獲取的B幀,次要遙測(cè)功能碼列表,對(duì)于E10為0x01~0x04
local cdtrmfidB={0x01,0x02,0x03,0x04}
--存儲(chǔ)待獲取的C幀,一般遙測(cè)功能碼,對(duì)于E10為0x0A,0x0B
--程序從數(shù)組第一個(gè)元素循環(huán)至第二個(gè)元素指定的值,循環(huán)讀取一般遙測(cè)數(shù)據(jù)
--如果需要更多的C幀數(shù)據(jù),例如轉(zhuǎn)換12個(gè)電池組數(shù)據(jù),改成cdtrmcntC={0x01,0x18}即可
local cdtrmcntC={0x0A,0x0B}
local cdtrmfid={}
--設(shè)置通訊狀態(tài)為無通訊
lib_vmb.setvaluefc1(commstateaddr,mbslaveid,1);
while(true) do
--readcdt函數(shù)等待接收CDT數(shù)據(jù),如果收到數(shù)據(jù),此函數(shù)將對(duì)CDT數(shù)據(jù)進(jìn)行校驗(yàn),
--如果校驗(yàn)成功,將輸出完整的CDT數(shù)據(jù)幀。否則返回錯(cuò)誤。
--參數(shù)1:串口號(hào),為0起,0為第一個(gè)串口,以此類推。
--參數(shù)2:CDT輸出數(shù)據(jù)
--參數(shù)3:接收第一個(gè)字節(jié)超時(shí),如果達(dá)到此超時(shí)未能收到串口數(shù)據(jù),此函數(shù)將返回錯(cuò)誤。
--參數(shù)4:數(shù)據(jù)字節(jié)超時(shí),收到第一個(gè)字節(jié)后,使用此超時(shí)接收剩余數(shù)據(jù),在達(dá)到超時(shí)
--而未能收到數(shù)據(jù)時(shí),此函數(shù)判定所有數(shù)據(jù)已經(jīng)收齊,函數(shù)將返回收到的字節(jié)數(shù)據(jù)
--并輸出完整CDT數(shù)據(jù)幀。
--返回:返回小于等0為錯(cuò)誤。其他值為收到的字節(jié)數(shù)量
--清空緩存
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)
--接收到正確數(shù)據(jù)
lib_vmb.setvaluefc1(commstateaddr,mbslaveid,0);
break;
else
--指示通訊錯(cuò)誤
lib_vmb.setvaluefc1(commstateaddr,mbslaveid,1);
-- print(string.format("\r\n接收錯(cuò)誤:%d",res));
end
end
--判斷是否為遙信數(shù)據(jù)
if (cdtdata[7]==0x71) and (cdtdata[8]==0xF4) then
--遙信數(shù)據(jù)的Modbus起始地址
ristaddr=cfgristaddr
print(string.format("\r\n遙信數(shù)據(jù)Modbus地址:%d",ristaddr));
--循環(huán)獲取指定ID的遙信數(shù)據(jù)
for i=1,table.getn(cdtrifid) do
--getrivalue函數(shù),讀取原始CDT數(shù)據(jù)中指定功能碼的遙信數(shù)據(jù)
--參數(shù)1:遙信功能碼
--參數(shù)2:經(jīng)過檢測(cè)過的CDT遙測(cè)數(shù)據(jù)
--參數(shù)3;是否校驗(yàn)數(shù)據(jù)塊crc,0-校驗(yàn),1不校驗(yàn)
--參數(shù)4;CDT數(shù)據(jù)塊數(shù)量
--參數(shù)5:輸出的遙信數(shù)據(jù)字節(jié),固定為4個(gè)字節(jié)
--返回1:返回大于等于0為正常,小于0為錯(cuò)誤。
res=lib_cdt.getrivalue(cdtrifid[i],cdtdata,1,cdtdata[9],cdtridata)
-- debug.printarray(cdtridata);
if (res>0) then
--設(shè)置進(jìn)modbus虛擬機(jī),此函數(shù)在common lib頁(yè)中定義
setridatatomb(ristaddr,mbslaveid,cdtridata,res)
end
--遞增Modbus寄存器地址
ristaddr=ristaddr+32
end
end
rmstaddr=-1
if ((cdtdata[7]==0x71) and (cdtdata[8]==0x61)) then
--A幀重要遙測(cè)數(shù)據(jù)
rmstaddr=cfgrmstaddrA
cdtrmfid=cdtrmfidA
print(string.format("\r\n遙測(cè)A幀,Modbus寄存器地址:%d",rmstaddr));
setrmdatatomb(rmstaddr,mbslaveid,cdtdata,cdtdata[9],cdtrmfid)
elseif ((cdtdata[7]==0x71) and (cdtdata[8]==0xC2)) then
--B幀次要遙測(cè)數(shù)據(jù)
rmstaddr=cfgrmstaddrB
cdtrmfid=cdtrmfidB
print(string.format("\r\n遙測(cè)B幀,Modbus寄存器地址:%d",rmstaddr));
setrmdatatomb(rmstaddr,mbslaveid,cdtdata,cdtdata[9],cdtrmfid)
elseif ((cdtdata[7]==0x71) and (cdtdata[8]==0xB3)) then
--C幀一般遙測(cè)狀態(tài)
rmstaddr=cfgrmstaddrC
cdtrmfid=cdtrmcntC
print(string.format("\r\n遙測(cè)C幀,Modbus寄存器地址:%d",rmstaddr));
setrmdatatomb_cnt(rmstaddr,mbslaveid,cdtdata,cdtdata[9],cdtrmfid)
end
--第二口為CDT原始數(shù)據(jù)輸出口
lib_uart.uart_tx(1,cdtdata,0);
end
--將遙信數(shù)據(jù)設(shè)置進(jìn)Modbus虛擬機(jī)
local function setridatatomb(ristaddr,mbslaveid,cdtridata,datacnt)
--設(shè)置所有數(shù)據(jù)進(jìn)Modbus虛擬機(jī)
for i=1,datacnt do
--循環(huán)1至res,
for i2=1,8 do
--循環(huán)處理8個(gè)bit,使用Modbus功能碼01,使用CDT上報(bào)的站號(hào)。
lib_vmb.setvaluefc1(ristaddr+((i2-1)+(i-1)*8),
mbslaveid,lib_bit.bit_is_set(cdtridata[i],i2-1));
end
end
end
--將遙測(cè)數(shù)據(jù)設(shè)置進(jìn)虛擬機(jī)
local function setrmdatatomb(rmstaddr,mbslaveid,cdtdata,datacnt,cdtrmfid)
local res,rmres1,rmres2,sdata1,sdata2
for i=1,table.getn(cdtrmfid) do
--遙測(cè)數(shù)據(jù)
--參數(shù)1:遙測(cè)功能碼
--參數(shù)2:經(jīng)過檢測(cè)過的CDT遙測(cè)數(shù)據(jù)
--參數(shù)3;是否校驗(yàn)數(shù)據(jù)塊crc,0-校驗(yàn),1不校驗(yàn)
--參數(shù)4;CDT數(shù)據(jù)塊數(shù)量
--返回1:遙測(cè)數(shù)據(jù)1狀態(tài),返回小于等于0的值為錯(cuò)誤,其他值為正確
--返回2:遙測(cè)數(shù)據(jù)2狀態(tài),返回小于等于0的值為錯(cuò)誤,其他值為正確
--返回3:遙測(cè)數(shù)據(jù)1
--返回4:遙測(cè)數(shù)據(jù)2
res,rmres1,rmres2,sdata1,sdata2=lib_cdt.getrmvalue(cdtrmfid[i],cdtdata,1,datacnt)
if (res>=0) then
--將遙測(cè)值設(shè)置進(jìn)Modbus虛擬機(jī)
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
--將遙測(cè)數(shù)據(jù)設(shè)置進(jìn)虛擬機(jī)
local function setrmdatatomb_cnt(rmstaddr,mbslaveid,cdtdata,datacnt,cdtrmfidcnt)
local res,rmres1,rmres2,sdata1,sdata2
--循環(huán)讀取遙測(cè)數(shù)據(jù)功能碼
for i=cdtrmfidcnt[1],cdtrmfidcnt[2] do
--遙測(cè)數(shù)據(jù)
--參數(shù)1:遙測(cè)功能碼
--參數(shù)2:經(jīng)過檢測(cè)過的CDT遙測(cè)數(shù)據(jù)
--參數(shù)3;是否校驗(yàn)數(shù)據(jù)塊crc,0-校驗(yàn),1不校驗(yàn)
--參數(shù)4;CDT數(shù)據(jù)塊數(shù)量
--返回1:遙測(cè)數(shù)據(jù)1狀態(tài),返回小于等于0的值為錯(cuò)誤,其他值為正確
--返回2:遙測(cè)數(shù)據(jù)2狀態(tài),返回小于等于0的值為錯(cuò)誤,其他值為正確
--返回3:遙測(cè)數(shù)據(jù)1
--返回4:遙測(cè)數(shù)據(jù)2
res,rmres1,rmres2,sdata1,sdata2=lib_cdt.getrmvalue(i,cdtdata,1,datacnt)
if (res>=0) then
--將遙測(cè)值設(shè)置進(jìn)Modbus虛擬機(jī)
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