摘要:介紹一種利用組態(tài)軟件MCGS 和OPC 服務(wù)器ZOPC_SERVER 以及ZLGCAN 接口卡實(shí)現(xiàn)基于CAN-bus 總線的模擬空調(diào)溫/濕度控制系統(tǒng)的方法。
一、系統(tǒng)結(jié)構(gòu)
本系統(tǒng)是一個(gè)室內(nèi)空調(diào)溫/濕度控制系統(tǒng)的模擬系統(tǒng)數(shù)據(jù)采集及控制中心通過(guò)CAN-bus 總線定時(shí)采集各個(gè)房間的溫/濕度數(shù)據(jù),并對(duì)各個(gè)房間的溫/濕度進(jìn)行控制。系統(tǒng)的數(shù)據(jù)采集及控制中心由上位機(jī)的硬件即任一款ZLGCAN 系列接口卡和PC 構(gòu)成,軟件由組態(tài)軟件MCGS 和ZOPC_Server 組成??刂剖壹聪挛粰C(jī)由DP-668 實(shí)驗(yàn)儀和ZLGCAN 系列接口卡中的PCI-9810 接口卡模擬。
[align=center][IMG=系統(tǒng)結(jié)構(gòu)圖]/uploadpic/tech/2007/7/20070730154418131747.jpg[/IMG]
圖 1 系統(tǒng)結(jié)構(gòu)圖[/align]
二、MCGS 工程框架
本空調(diào)溫/濕度控制系統(tǒng)需要對(duì)各個(gè)控制室及風(fēng)道的溫/濕度值進(jìn)行監(jiān)控,因此工程需要有實(shí)時(shí)顯示和記錄各控制室溫/濕度值、修改房間溫/濕度SV 值、報(bào)警顯示、報(bào)警顯示瀏覽記錄等功能、工程框架如下:
用戶窗口:封面窗口、主控窗口、控制室窗口1~6、風(fēng)道平面圖、狀態(tài)條、修改控制室1~6 SV值、修改SV 值消息窗口、風(fēng)道電加熱段消息窗口、修改風(fēng)道溫度表1~2 SV 值、修改風(fēng)道濕度表1~2 SV 值、風(fēng)道內(nèi)三級(jí)加熱報(bào)警窗口。
[align=center][IMG=用戶窗口]/uploadpic/tech/2007/7/2007073015595627257E.jpg[/IMG]
圖 2 用戶窗口[/align]
運(yùn)行策略:?jiǎn)?dòng)策略、退出策略、循環(huán)策略、卡車運(yùn)動(dòng)策略、控制柜燈閃爍策略、顯示控制室1~6策略、顯示時(shí)間策略、主控窗口中提示塊顯示策略。
主菜單:用戶登錄、封面窗口、打開(kāi)主控窗口、打開(kāi)各控制室、風(fēng)道平面圖、修改SV 值、歷史記錄、通信錯(cuò)誤記錄、溫/濕度異常記錄、退出系統(tǒng)
子菜單:第一~六控制室、修改一~六號(hào)房間、SV 值修改風(fēng)道溫度、表1~2 SV 值、修改風(fēng)道濕度表1~2 SV 值
[align=center][IMG=系統(tǒng)菜單]/uploadpic/tech/2007/7/2007073016061396309W.jpg[/IMG]
圖 3 系統(tǒng)菜單[/align]
三、主要數(shù)據(jù)對(duì)象
建立好一個(gè)空調(diào)溫/濕度控制系統(tǒng)的MCGS 工程后,實(shí)現(xiàn)上位機(jī)的主要任務(wù)就是建立組態(tài)工程與OPC設(shè)備的連接,實(shí)現(xiàn)上位機(jī)的主要任務(wù)就是建立組態(tài)工程與OPC設(shè)備的連接,并對(duì)采集到的數(shù)據(jù)進(jìn)行處理和顯示。在這個(gè)工程的實(shí)時(shí)數(shù)據(jù)庫(kù)中,要進(jìn)行顯示、操作的數(shù)據(jù)對(duì)象如表1 所示。由于風(fēng)道的數(shù)據(jù)對(duì)象較多,為了統(tǒng)一管理,將風(fēng)道當(dāng)作兩個(gè)房間節(jié)點(diǎn)來(lái)處理。這樣,每個(gè)房間都只有1 個(gè)溫度值對(duì)象、1 個(gè)濕度之對(duì)象、1 個(gè)溫度SV 值對(duì)象和1 個(gè)濕度SV 值對(duì)象。
[align=center]表 1 系統(tǒng)主要數(shù)據(jù)對(duì)象
[IMG=系統(tǒng)主要數(shù)據(jù)對(duì)象]/uploadpic/tech/2007/7/20070730161302396331R.jpg[/IMG][/align]
為了使系統(tǒng)具備記錄數(shù)據(jù)及瀏覽歷史數(shù)據(jù)、錯(cuò)誤數(shù)據(jù)和異常數(shù)據(jù)的能力,在實(shí)時(shí)數(shù)據(jù)庫(kù)中建立了save、ErrorSave 和exception 三個(gè)數(shù)據(jù)對(duì)象組。其中ErrorSave 和exception 的組對(duì)象成員有:RoomID1 、ErrorTemp、ErrorHum 、ErrorTempSV 和ErrorHumSV ,save 的組成員對(duì)象如表1 所示。在運(yùn)行過(guò)程中,系統(tǒng)會(huì)定時(shí)保存save 組對(duì)象到數(shù)據(jù)庫(kù)。當(dāng)通信產(chǎn)生錯(cuò)誤和房間溫/濕度異常時(shí),系統(tǒng)會(huì)將ErrorSave 和exception 保存到數(shù)據(jù)庫(kù)。
在此系統(tǒng)中的OPC 設(shè)備使用的是ZOPC_Server 服務(wù)器。ZOPC_Server 是一個(gè)OPC 服務(wù)器軟件本軟件,支持操作全系列的ZLGCAN 系列接口卡,只要在一臺(tái)PC 機(jī)上插上ZLGCAN 系列接口卡中的任何一種或幾種,再運(yùn)行本服務(wù)器軟件,就可以使用任何一種支持OPC 協(xié)議的客戶端軟件(比如組態(tài)軟件:組態(tài)王KingView、昆侖通態(tài)MCGS 和Intouch 等)來(lái)連接到此服務(wù)器通過(guò)此服務(wù)器,來(lái)跟CAN-bus 網(wǎng)絡(luò)進(jìn)行數(shù)據(jù)的傳輸。
本設(shè)計(jì)中,ZOPC_Server 在數(shù)值存儲(chǔ)模式下和字符串存儲(chǔ)模式下提供的數(shù)據(jù)項(xiàng)都不能直接連接到實(shí)時(shí)數(shù)據(jù)庫(kù)中的數(shù)據(jù)對(duì)象,因此必須編寫(xiě)腳本程序?qū)?shù)據(jù)進(jìn)行處理。關(guān)于數(shù)據(jù)項(xiàng)存儲(chǔ)模式,這里選用被推薦的字符串存儲(chǔ)模式;但是,使用數(shù)值存儲(chǔ)模式會(huì)更容易實(shí)現(xiàn)此系統(tǒng)。
在實(shí)時(shí)數(shù)據(jù)庫(kù)添加字符型數(shù)據(jù)對(duì)象In_CANData 和Out_CANData,字符數(shù)為30,將In_CANData 和Out_CANData 分別連接到OPC 設(shè)備的輸入通道和輸出通道,In_CANData 的讀寫(xiě)屬性為只讀,Out_CANData的讀寫(xiě)屬性為只寫(xiě)。由于這兩個(gè)數(shù)據(jù)對(duì)象是字符型的,不便于進(jìn)行數(shù)據(jù)處理,所以應(yīng)該先將它們轉(zhuǎn)換為數(shù)值型對(duì)象。在MCGS 腳本程序中,用戶不能定義子程序、子函數(shù)和變量,而數(shù)據(jù)對(duì)象可以看作是腳本程序中的全局變量,在所有的程序段共用。這給編寫(xiě)較復(fù)雜的腳本程序帶來(lái)不便。要進(jìn)行類似子程序和子函數(shù)的操作,只能用先將要處理的數(shù)據(jù)放入全局變量,然后調(diào)用策略行中的腳本進(jìn)行處理,最后將返回的數(shù)據(jù)放入全局變量的方法進(jìn)行處理。在實(shí)時(shí)數(shù)據(jù)庫(kù)加添以下數(shù)值型對(duì)象作為中間變量:

然后,在運(yùn)行策略中新建一個(gè)名為StringToObject 的用戶策略,新增一策略行并添加以下腳本程序,用于將In_CANData 轉(zhuǎn)換到數(shù)值型對(duì)象:
In_Flag = !Hex2I(!mid(In_CANData, 1, 2))
In_Extern = !Hex2I(!mid(In_CANData, 3, 1))
In_Remote = !Hex2I(!mid(In_CANData, 4, 1))
In_ID = !Hex2I(!mid(In_CANData, 5, 8))
In_DataLen = !Hex2I(!mid(In_CANData, 13 , 2))
In_Data0 = !Hex2I(!mid(In_CANData, 15, 2))
In_Data1 = !Hex2I(!mid(In_CANData, 17, 2))
In_Data2 = !Hex2I(!mid(In_CANData, 19, 2))
In_Data3 = !Hex2I(!mid(In_CANData, 21, 2))
In_Data4 = !Hex2I(!mid(In_CANData, 23, 2))
In_Data5 = !Hex2I(!mid(In_CANData, 25, 2))
In_Data6 = !Hex2I(!mid(In_CANData, 27, 2))
In_Data7 = !Hex2I(!mid(In_CANData, 29, 2))
同樣,在運(yùn)行策略中新建一個(gè)名為ObjectToString 的用戶策略,新增一策略行并添加下面的腳本程序,用于將數(shù)值型對(duì)象轉(zhuǎn)換到Out_CANData 。在下面的程序中,Out_SendID 進(jìn)行自加是因?yàn)閆OPC_Server 要判斷寫(xiě)入的Out_SendID 和上一次寫(xiě)入的Out_SendID 是否相同,如果不同才將報(bào)文發(fā)出。
‘ 轉(zhuǎn)換 Out_SendID 到字符型
if Out_SendID <= 255 then
Out_SendID = Out_SendID + 1
else
Out_SendID = 0
endif
Out_CANData1 = !I2Hex(Out_SendID)
if !Len(Out_CANData1) <> 2 then Out_CANData1 = "0" + Out_CANData1
Out_CANData2 = Out_CANData1
‘ 轉(zhuǎn)換 Out_Extern 和 Out_Remote 到字符型
Out_CANData1 = !I2Hex(Out_Extern) + !I2Hex(Out_Remote)
Out_CANData2 = Out_CANData2 + Out_CANData1
‘ 轉(zhuǎn)換 Out_ID 到字符型
Out_CANData1 = !I2Hex(Out_ID)
Lenght = !Len(Out_CANData1)
while Lenght < 8
Out_CANData1 = "0" + Out_CANData1
Lenght = !Len(Out_CANData1)
endwhile
Out_CANData2 = Out_CANData2 + Out_CANData1
‘ 轉(zhuǎn)換 Out_DataLen 到字符型
Out_CANData1 = !I2Hex(Out_DataLen)
if !Len(Out_CANData1) <> 2 then Out_CANData1 = "0" + Out_CANData1
Out_CANData2 = Out_CANData2 + Out_CANData1
‘ 轉(zhuǎn)換 Out_Data0 7 到字符型
Out_CANData1 = !I2Hex(Out_Data0)
if !Len(Out_CANData1) <> 2 then Out_CANData1 = "0" + Out_CANData1
Out_CANData2 = Out_CANData2 + Out_CANData1
Out_CANData1 = !I2Hex(Out_Data1)
if !Len(Out_CANData1) <> 2 then Out_CANData1 = "0" + Out_CANData1
Out_CANData2 = Out_CANData2 + Out_CANData1
Out_CANData1 = !I2Hex(Out_Data2)
if !Len(Out_CANData1) <> 2 then Out_CANData1 = "0" + Out_CANData1
Out_CANData2 = Out_CANData2 + Out_CANData1
Out_CANData1 = !I2Hex(Out_Data3)
if !Len(Out_CANData1) <> 2 then Out_CANData1 = "0" + Out_CANData1
Out_CANData2 = Out_CANData2 + Out_CANData1
Out_CANData1 = !I2Hex(Out_Data4)
if !Len(Out_CANData1) <> 2 then Out_CANData1 = "0" + Out_CANData1
Out_CANData2 = Out_CANData2 + Out_CANData1
Out_CANData1 = !I2Hex(Out_Data5)
if !Len(Out_CANData1) <> 2 then Out_CANData1 = "0" + Out_CANData1
Out_CANData2 = Out_CANData2 + Out_CANData1
Out_CANData1 = !I2Hex(Out_Data6)
if !Len(Out_CANData1) <> 2 then Out_CANData1 = "0" + Out_CANData1
Out_CANData2 = Out_CANData2 + Out_CANData1
Out_CANData1 = !I2Hex(Out_Data7)
if !Len(Out_CANData1) <> 2 then Out_CANData1 = "0" + Out_CANData1
Out_CANData2 = Out_CANData2 + Out_CANData1
這樣,以后要將In_CANData 的數(shù)據(jù)提取到In_*變量中,只需在腳本中按!setstgy(StringToObject)就可以了。而要將Out_*數(shù)據(jù)合并到Out_CANData, 可先調(diào)用!setstgy(ObjectToString),然后再把Out_CANData2的值賦給Out_CANData。
四、協(xié)議及報(bào)文格式
因?yàn)镸CGS 不便于編寫(xiě)復(fù)雜的腳本程序,所以傳輸協(xié)議的設(shè)計(jì)以簡(jiǎn)單為原則。本系統(tǒng)使用HiLon 協(xié)議A 。HiLon 協(xié)議A 是一個(gè)通用的協(xié)議,基于非對(duì)稱型主從式網(wǎng)絡(luò)結(jié)構(gòu),支持廣播和點(diǎn)對(duì)點(diǎn)傳送命令數(shù)據(jù),命令數(shù)據(jù)包可長(zhǎng)達(dá)256 字節(jié),非常適合用作本系統(tǒng)的通信協(xié)議HiLon 協(xié)議以CAN2.0A 幀結(jié)構(gòu)為基礎(chǔ)。下圖是幀報(bào)文格式,一個(gè)CAN2.0A 標(biāo)準(zhǔn)幀由11 位ID 、1 位RTR 、4 位DLC 、數(shù)據(jù)區(qū)(最多8 個(gè)字節(jié))組成。
[align=center][IMG=HiLon A 報(bào)文格式]/uploadpic/tech/2007/7/2007073017043663226O.jpg[/IMG]
圖 4 HiLon A 報(bào)文格式[/align]
DIR :方向位。方向位決定一半的優(yōu)先級(jí)而剩余的優(yōu)先級(jí),由節(jié)點(diǎn)地址決定低地址優(yōu)先級(jí)高。當(dāng)方向位為“1” 時(shí),地址域是源節(jié)點(diǎn)地址(從節(jié)點(diǎn)到主節(jié)點(diǎn)),優(yōu)先級(jí)由地址決定;當(dāng)方向位為“0” 時(shí),地址域是目標(biāo)節(jié)點(diǎn)地址(主節(jié)點(diǎn)到從節(jié)點(diǎn)),優(yōu)先級(jí)由地址決定。從節(jié)點(diǎn)也可使用地址濾波技術(shù)從而減少需處理的網(wǎng)絡(luò)信息量,因而能有效節(jié)省CAN 節(jié)點(diǎn)控制器資源,提高控制器效率。
Address :目標(biāo)地址,表示節(jié)點(diǎn)地址,范圍只能設(shè)定為0~125
TYPE :幀類型。見(jiàn)下表中的幀類型說(shuō)明。
[align=center]表 2 HiLon 幀類型
[IMG=HiLon 幀類型]/uploadpic/tech/2007/7/200707301712087027014.jpg[/IMG]

[/align]
DLC: 每幀字節(jié)數(shù)(1~8)
Index :索引字節(jié)。對(duì)于單幀數(shù)據(jù),該字節(jié)表示傳輸數(shù)據(jù)的第一個(gè)字節(jié);對(duì)于多幀數(shù)據(jù),此字節(jié)表示索引字節(jié),即此幀數(shù)據(jù)在數(shù)據(jù)包中的位置。
Data :數(shù)據(jù)
在本系統(tǒng)中,數(shù)據(jù)中心要對(duì)各個(gè)房間的溫/濕度進(jìn)行監(jiān)控并修各個(gè)房間的溫/濕度SV 值,因此給各個(gè)控制室分配唯一的標(biāo)志符;在下位機(jī)向上位機(jī)發(fā)送的數(shù)據(jù)報(bào)文中攜帶的數(shù)據(jù)是房間的溫/濕度值;上位機(jī)向下位機(jī)發(fā)送的命令報(bào)文攜帶命令號(hào)及控制室的溫/濕度SV 值。本系統(tǒng)的傳輸數(shù)據(jù)量較小,且MCGS 的采樣周期本系統(tǒng)取5ms 相對(duì)下位機(jī)來(lái)說(shuō)較長(zhǎng),因此,本系統(tǒng)選擇使用單幀(點(diǎn)對(duì)點(diǎn))類型幀。利用HiLon報(bào)文的特點(diǎn),將7 位Address 分配給房間ID,每一個(gè)房間ID 對(duì)應(yīng)一個(gè)Address ,地址0 保留。當(dāng)數(shù)據(jù)方向是從節(jié)點(diǎn)到主節(jié)點(diǎn)時(shí),8 字節(jié)數(shù)據(jù)的前4 字節(jié)用于傳遞房間溫度,后4 字節(jié)用于傳遞房間濕度,當(dāng)數(shù)據(jù)方向是主節(jié)點(diǎn)到從節(jié)點(diǎn)時(shí),8字節(jié)數(shù)據(jù)的前4 字節(jié)作為命令I(lǐng)D,后4 字節(jié)用于傳遞命令參數(shù)(房間溫/濕度SV值)。報(bào)文幀的格式如圖1 所示。
[align=center][IMG=報(bào)文幀格式]/uploadpic/tech/2007/7/2007073017221423544B.jpg[/IMG]
圖 5 報(bào)文幀格式[/align]
對(duì)主節(jié)點(diǎn)到從節(jié)點(diǎn)的命令I(lǐng)D 的定義如下:
[align=center]表 3 控制命令類型及其參數(shù)
[IMG=控制命令類型及其參數(shù)]/uploadpic/tech/2007/7/2007073017273712141B.jpg[/IMG]

[/align]
本系統(tǒng)要監(jiān)控的數(shù)據(jù)是各房間的溫度和濕度及它們的SV 值。要將這些數(shù)據(jù)在總線上傳輸,必須將它們裝入報(bào)文幀。為了使傳輸?shù)臄?shù)據(jù)只占用較小的空間而達(dá)到較高的精確度,在報(bào)文中每一種數(shù)值都分配了4 字節(jié)的空間,數(shù)據(jù)按IEEE-754 標(biāo)準(zhǔn)的float 數(shù)據(jù)類型的格式存儲(chǔ)。這樣,在下位機(jī)進(jìn)行編程就比較方便。但是,上位機(jī)的處理程序是用類似VB 腳本的語(yǔ)言寫(xiě)的,數(shù)據(jù)對(duì)象的類型只有數(shù)值型、開(kāi)關(guān)型和字符型三種,不能直接使用接收到的數(shù)據(jù)。因此,要對(duì)接收到的數(shù)據(jù)進(jìn)行轉(zhuǎn)換。
按IEEE-754 標(biāo)準(zhǔn),一個(gè)浮點(diǎn)數(shù)用兩個(gè)部分表示:尾數(shù)和2 的冪。例如:

尾數(shù)代表浮點(diǎn)上的數(shù)據(jù)二進(jìn)制數(shù)。
二的冪代表指數(shù)。指數(shù)的保存形式是一個(gè)0 到255 的8 位值。指數(shù)的實(shí)際值是保存值0 到255 減去127,一個(gè)范圍在127 到-128 之間的值。
尾數(shù)是一個(gè)24 位值(代表大約7 個(gè)十進(jìn)制數(shù)),最高位(MSB) 通常是1, 因此,不保存。一個(gè)符號(hào)位表示浮點(diǎn)數(shù)是正或負(fù)。在尾數(shù)的左邊有一個(gè)省略的二進(jìn)制點(diǎn)和1。 這個(gè)數(shù)在浮點(diǎn)數(shù)的保存中經(jīng)常省略。
浮點(diǎn)數(shù)保存的字節(jié)格式如下:
[align=center][IMG=IEEE-754 標(biāo)準(zhǔn) float 存儲(chǔ)格式]/uploadpic/tech/2007/7/20070731104600663014.jpg[/IMG]
圖 6 IEEE-754 標(biāo)準(zhǔn) float 存儲(chǔ)格式[/align]
這里:
S 代表符號(hào)位,1 是負(fù),0 是正。
E 冪,偏移127。
M 24 位的尾數(shù)(保存在23 位中)。
零是一個(gè)特定值,表示冪是0, 尾數(shù)是0。
在運(yùn)行策略中新建一個(gè)名為SplitFloat 的用戶策略,新增一策略行并添加以下腳本程序,用于將數(shù)值型對(duì)象float 轉(zhuǎn)換到4 字節(jié)存儲(chǔ)單元Byte0 Byte3:
‘ 計(jì)算浮點(diǎn)數(shù)的冪(二進(jìn)制數(shù)小數(shù)點(diǎn)的位置)
exponent = 0
float1 = !abs(float)
while float1<>0
float1 = !BitRShift(float1, 1)
exponent = exponent + 1
endwhile
exponent = exponent - 1
‘ 計(jì)算浮點(diǎn)數(shù)的底數(shù)
mantissa = !abs(float) * (!BitLShift(2, 23 - (exponent + 1))) - 8388608
exponent = exponent + 127
Byte0 = !BitRShift(exponent, 1)
if room1tempsv < 0 then
Byte0 = !BitOr(Byte0, 128)
endif
Byte1 = !BitAnd(!BitOr(!BitRShift(mantissa, 16), !BitLShift(exponent, 7)), 255)
Byte2 = !BitAnd(!BitRShift(mantissa, 8), 255)
Byte3 = !BitAnd(mantissa, 255)
在運(yùn)行策略中新建一個(gè)名為UniteFloat 的用戶策略,新增一策略行并添加以下腳本程序,用于將4 字節(jié)存儲(chǔ)單元Byte0 Byte3 轉(zhuǎn)換到數(shù)值型對(duì)象float:
mantissa = (!BitAnd(Byte0, 128) + !BitAnd(Byte1, 127)) * 65536 + _
(Byte2 * 256) + Byte3 + 8388608
exponent = !BitOr(!BitLShift(Byte0, 1), !BitRShift(Byte1, 7)) - 127
float = mantissa / (!BitLShift(2, 23 - (exponent + 1)))
五、實(shí)現(xiàn)
系統(tǒng)的控制中心采用定時(shí)查詢的方法,每2 秒鐘對(duì)各個(gè)房間的溫度值和濕度值進(jìn)行一次查詢。查詢時(shí),組態(tài)軟件先向?qū)崟r(shí)數(shù)據(jù)庫(kù)中的數(shù)據(jù)對(duì)象Out_CANData 寫(xiě)入查詢房間溫/濕度命令的報(bào)文。命令報(bào)文的房間ID 對(duì)應(yīng)要查詢的房間號(hào),命令I(lǐng)D 為0x00000000,無(wú)命令參數(shù)。然后經(jīng)過(guò)ZOPC_Server 將報(bào)文發(fā)到CAN總線上。在發(fā)送查詢命令后控制中心將等待一段時(shí)間(這一段時(shí)間要大于MCGS 的最小采集周期),然后再?gòu)膶?shí)時(shí)數(shù)據(jù)庫(kù)中的數(shù)據(jù)對(duì)象In_CANData 讀取數(shù)據(jù)并進(jìn)行處理和顯示。
如果控制中心要修改房間的SV 值,首先發(fā)出查詢房間溫/濕度SV 值的命令,在收到房間溫/濕度SV值后,在“修改控制室SV 值”窗口中顯示SV 值(或在“修改風(fēng)道溫度/濕度表SV 值”窗口中顯示),然后發(fā)出帶有參數(shù)的修改房間溫度SV 值命令報(bào)文,參數(shù)的內(nèi)容就是要修改的SV 值。
下位機(jī)的驗(yàn)收碼設(shè)置成ID10 為0,ID9~I(xiàn)D3 為房間ID,后3 位屏蔽。當(dāng)總線上有發(fā)給該房間的報(bào)文時(shí),并根據(jù)命令進(jìn)行相應(yīng)的操作。如果收到的是查詢命令,下位機(jī)立即將房間的溫/濕度數(shù)據(jù)發(fā)送到CAN 總線上。數(shù)據(jù)報(bào)文的ID 也是該房間的ID,以表示報(bào)文中的數(shù)據(jù)是該控制室的。如果是修改房間溫/濕度SV 值命令,下位機(jī)就從命令參數(shù)取出SV 值并替換舊的SV 值。
上位機(jī)控制流程編寫(xiě)的具體步驟:
1. 在運(yùn)行策略中新建一個(gè)名為“GetRoomTHV ”的用戶策略,并添加3 個(gè)腳本程序,1 個(gè)退出策略行,如圖:
[align=center][IMG=GetRoomTHV 策略]/uploadpic/tech/2007/7/2007073111012831562I.jpg[/IMG]
圖 7 GetRoomTHV 策略[/align]
其中,“查詢房間溫/濕度值”腳本如下:
‘ 發(fā)送控制室溫/濕度查詢命令
Out_Extern = 0
Out_Remote = 0
Out_ID = !BitLShift(RoomID, 3) + 0 ‘ 控制室ID + 單幀(點(diǎn)對(duì)點(diǎn))
Out_DataLen = 8
Out_Data0 = 0
Out_Data1 = 0
Out_Data2 = 0
Out_Data3 = 0
Out_Data4 = 0
Out_Data5 = 0
Out_Data6 = 0
Out_Data7 = 0
!setstgy(ObjectToString)
‘ 發(fā)出命令
Out_CANData = Out_CANData2
‘ 等待命令發(fā)出
!TimerReset(1, 0)
!TimerRun(1)
!TimerWaitFor(1, Delay)
!TimerStop(1)
‘ 接收控制室溫/濕度
!setstgy(StringToObject)
roomtemp = roomhum = 0
if (In_Extern <> 0) or (In_Remote <> 0) _
or ((!BitAnd(In_ID, 1024)<>1024) _
and (!BitAnd(In_ID, 7)<>0)) then
In_ID = 0
exit
endif
“計(jì)算控制室的溫度”的執(zhí)行條件是!BitAnd(!BitRShift(In_ID, 3), 127) = RoomID 表達(dá)式的值為非0,腳本程序如下:
Byte0 = In_Data0
Byte1 = In_Data1
Byte2 = In_Data2
Byte3 = In_Data3
!setstgy(UniteFloat)
roomtemp = float
“計(jì)算控制室的濕度”的執(zhí)行條件是!BitAnd(!BitRShift(In_ID, 3), 127) = RoomID 表達(dá)式的值為非0,腳本程序如下:
Byte0 = In_Data4
Byte1 = In_Data5
Byte2 = In_Data6
Byte3 = In_Data7
!setstgy(UniteFloat)
roomhum = float
2. 在運(yùn)行策略中新建名為“查詢各控制室溫/濕度”的循環(huán)策略,循環(huán)時(shí)間為2000ms。 添加如下圖所示的策略行。
[align=center][IMG=查詢各控制室溫/濕度策略]/uploadpic/tech/2007/7/2007073111083487072R.jpg[/IMG]
圖 8 查詢各控制室溫/濕度策略[/align]
“初始化”的腳本程序如下:
RoomID = 1
“查詢1 號(hào)控制室溫/濕度”的腳本程序如下:
RoomID1 = RoomID
RoomID = RoomID + 1
if (roomtemp = 0) or (roomhum = 0) then
room1st = 1
ErrorTemp = roomtemp
ErrorHum = roomhum
!SaveData(ErrorSave) ‘ 記錄通信錯(cuò)誤
exit
endif
room1temp = roomtemp
room1hum = roomhum
if room1temp > room1tempsv then
room1st = 1
ErrorTemp = room1temp
ErrorHum = room1hum
!SaveData(exception) ‘ 記錄溫度異常
exit
else
room1st = 0
endif
其它策略行腳本程序與上類似。
所有的“策略調(diào)用”均調(diào)用GetRoomTHV 策略。
3. 在運(yùn)行策略中新建一個(gè)名為“GetRoomSV” 的用戶策略,其他步驟同1。
[align=center][IMG=GetRoomSV 策略]/uploadpic/tech/2007/7/20070731111436892566.jpg[/IMG]
圖 9 GetRoomSV 策略[/align]
“查詢房間溫/濕度SV 值”腳本如下:
‘ 發(fā)送控制室溫/濕度SV 查詢命令
Out_Extern = 0
Out_Remote = 0
Out_ID = !BitLShift(RoomID, 3) + 0 ‘ 控制室ID + 單幀(點(diǎn)對(duì)點(diǎn))
Out_DataLen = 8
Out_Data0 = 0
Out_Data1 = 0
Out_Data2 = 0
Out_Data3 = 1
Out_Data4 = 0
Out_Data5 = 0
Out_Data6 = 0
Out_Data7 = 0
!setstgy(ObjectToString)
‘ 發(fā)出命令
Out_CANData = Out_CANData2
‘ 等待命令發(fā)出
!TimerReset(1, 0)
!TimerRun(1)
!TimerWaitFor(1, Delay)
!TimerStop(1)
‘ 接收控制室溫/濕度
!setstgy(StringToObject)
if (In_Extern <> 0) or (In_Remote <> 0) _
or ((!BitAnd(In_ID, 1024)<>1024) _
and (!BitAnd(In_ID, 7)<>0)) then
In_ID = 0
exit
endif
roomtemp = roomhum = 0
“計(jì)算控制室的溫度SV” 的執(zhí)行條件是!BitAnd(!BitRShift(In_ID, 3), 127) = RoomID 表達(dá)式的值為非0, 腳本程序如下:
Byte0 = In_Data0
Byte1 = In_Data1
Byte2 = In_Data2
Byte3 = In_Data3
!setstgy(UniteFloat)
roomtempsv = float
“計(jì)算控制室的濕度SV” 的執(zhí)行條件是!BitAnd(!BitRShift(In_ID, 3), 127) = RoomID 表達(dá)式的值為非0, 腳本程序如下:
Byte0 = In_Data4
Byte1 = In_Data5
Byte2 = In_Data6
Byte3 = In_Data7
!setstgy(UniteFloat)
roomhumsv = float
4. 在運(yùn)行策略中新建名為“查詢房間1SV 值”的用戶策略,添加如下圖所示的3 個(gè)策略行。
[align=center][IMG=查詢房間1SV 值策略]/uploadpic/tech/2007/7/2007073111194331320L.jpg[/IMG]
圖 10 查詢房間1SV 值策略[/align]
“before” 策略行腳本程序如下:
!EnableStgy(查詢各控制室溫/濕度策略, 0)
RoomID = 1
“策略調(diào)用”調(diào)用GetRoomSV 策略。
“after” 策略行腳本程序如下:
room1tempsv = roomtempsv
!EnableStgy(查詢各控制室溫/濕度策略, 1)
5. 重復(fù)步驟4。 添加“查詢房間2~6 SV 值”和“查詢風(fēng)道溫/濕度表1~2 sv 值”策略,并由菜單“修改1~6 號(hào)房間SV 值”調(diào)用對(duì)應(yīng)的策略。
6. 雙擊主控窗口中名為“修改一號(hào)房間SV 值”的菜單項(xiàng),在菜單屬性設(shè)置對(duì)話框的“菜單操作”頁(yè)中添加執(zhí)行運(yùn)行策略塊“查詢房間1 SV 值”。
7. 重復(fù)步驟6, 添加其它房間的運(yùn)行策略。
8. 在運(yùn)行策略中建立一個(gè)名為“SetRoomTSV” 的用戶策略,添加以下腳本程序:
float = roomtempsv
!setstgy(SplitFloat)
‘ 發(fā)送控制室溫/濕度SV 設(shè)置命令
Out_Extern = 0
Out_Remote = 0
Out_ID = !BitLShift(RoomID, 3) + 0 ‘ 控制室ID + 單幀(點(diǎn)對(duì)點(diǎn))
Out_DataLen = 8
Out_Data0 = 0
Out_Data1 = 0
Out_Data2 = 0
Out_Data3 = 2
Out_Data4 = Byte0
Out_Data5 = Byte1
Out_Data6 = Byte2
Out_Data7 = Byte3
!setstgy(ObjectToString)
‘ 發(fā)出命令
Out_CANData = Out_CANData2
‘ 等待命令發(fā)出
!TimerReset(1, 0)
!TimerRun(1)
!TimerWaitFor(1, Delay)
!TimerStop(1)
9. 在運(yùn)行策略中建立一個(gè)名為“調(diào)整房間1SV 值”的用戶策略,并添加以下程序:
!EnableStgy(查詢各控制室溫/濕度策略, 0)
RoomID = 1
roomtempsv = room1tempsv
float = roomtempsv
!setstgy(SetRoomTSV)
!EnableStgy(查詢各控制室溫/濕度策略, 1)
10. 重復(fù)步驟9, 添加其它5 個(gè)控制室及風(fēng)道的腳本程序。
11. 給“修改控制室1SV 值”窗口的“確認(rèn)”按鈕添加如下腳本:
if room1tempsv1<-10 or room1tempsv1>100 then
!setwindow(修改SV 值消息窗口,1)
else
room1tempsv=room1tempsv1
!setwindow(修改控制室1SV 值,3)
room1tempsv1=0
!setstgy(調(diào)整房間1SV 值)
endif
12. 重復(fù)步驟11, 添加其它窗口的腳本。
六 模擬控制室
本系統(tǒng)可用DP-668 實(shí)驗(yàn)儀模擬產(chǎn)生控制室數(shù)據(jù)。DP-668 實(shí)驗(yàn)儀具有模擬控制室溫/濕度變化、自修改溫/濕度SV 值以及報(bào)警等功能。其模擬溫/濕度變化算法如下:
extern unsigned char code RoomID = 1; /* 房間 ID */
extern float RoomTemp = 0; /* 房間溫度 */
extern float RoomHumi = 0; /* 房間濕度 */
...
float code RoomTempTab[] = {
19.0, 19.2, 19.4, 19.6, 19.8,
20.0, 20.2, 20.4, 20.6, 20.8,
21.0, 21.2, 21.4, 21.6, 21.8,
21.8, 21.6, 21.4, 21.2, 21.0,
20.8, 20.6, 20.4, 20.2, 20.0,
19.8, 19.6, 19.4, 19.2, 19.0
};
float code RoomHumiTab[] = {
55.0, 55.5, 56.0, 56.5,
57.0, 57.5, 58.0, 58.5,
59.0, 59.5, 60.0, 60.5,
61.0, 61.5, 62.0, 62.5,
63.0, 63.5, 64.0, 64.5
};
void main(void)
{
unsigned int idata i, j;
...
while (1)
{
/* 模擬溫/濕度變化 */
RoomTemp = RoomTempTab[j % (sizeof (RoomTempTab)/sizeof(RoomTempTab[0]))];
RoomHumi = RoomHumiTab[j++ % (sizeof (RoomHumiTab)/sizeof(RoomHumiTab[0]))];
...
}
}
本系統(tǒng)也可用任一款ZLGCAN 接口卡和PC 組成的系統(tǒng)來(lái)模擬產(chǎn)生控制室數(shù)據(jù),基于ZLGCAN 通用函數(shù)接口編程,同樣具有模擬控制室溫/濕度變化、自修改溫/濕度SV 值以及報(bào)警等功能。其模擬溫/濕度變化算法(VC 示范)如下:
float m_dwTemp[8];// 房間1 6 及風(fēng)道1 2 的溫度
float m_dwHumi[8];// 房間1 6 及風(fēng)道1 2 的濕度
...
static double i;
i += 0.1;
m_dwTemp[0] = (float)sin(i + 0.0) + 20;
m_dwTemp[1] = (float)sin(i + 0.1) + 20;
m_dwTemp[2] = (float)sin(i + 0.2) + 20;
m_dwTemp[3] = (float)sin(i + 0.3) + 20;
m_dwTemp[4] = (float)sin(i + 0.4) + 20;
m_dwTemp[5] = (float)sin(i + 0.5) + 20;
m_dwTemp[6] = (float)sin(i + 0.6) + 20;
m_dwTemp[7] = (float)sin(i + 0.7) + 20;
m_dwHumi[0] = (float)cos(i + 0.0) + 60;
m_dwHumi[1] = (float)cos(i + 0.1) + 60;
m_dwHumi[2] = (float)cos(i + 0.2) + 60;
m_dwHumi[3] = (float)cos(i + 0.3) + 60;
m_dwHumi[4] = (float)cos(i + 0.4) + 60;
m_dwHumi[5] = (float)cos(i + 0.5) + 60;
m_dwHumi[6] = (float)cos(i + 0.6) + 60;
m_dwHumi[7] = (float)cos(i + 0.7) + 60;
...