基于CAN-bus 總線的模擬空調(diào)溫/濕度控制系統(tǒng)
來源:網(wǎng)絡(luò) 2012-07-15 關(guān)鍵詞:組態(tài)軟件 控制系統(tǒng) 自動化 CAN-bus 總線 摘要:介紹一種利用組態(tài)軟件MCGS 和OPC 服務(wù)器ZOPC_SERVER 以及ZLGCAN 接口卡實現(xiàn)基于CAN-bus 總線的模擬空調(diào)溫/濕度控制系統(tǒng)的方法?! ∫?、系統(tǒng)結(jié)構(gòu) 本系統(tǒng)是一個室內(nèi)空調(diào)溫/濕度控制系統(tǒng)的模擬系統(tǒng)數(shù)據(jù)采集及控制中心通過CAN-bus 總線定時采集各個房間的溫/濕度數(shù)據(jù),并對各個房間的溫/濕度進行控制。系統(tǒng)的數(shù)據(jù)采集及控制中心由上位機的硬件即任一款ZLGCAN 系列接口卡和PC 構(gòu)成,軟件由組態(tài)軟件MCGS 和ZOPC_Server 組成??刂剖壹聪挛粰C由DP-668 實驗儀和ZLGCAN 系列接口卡中的PCI-9810 接口卡模擬?! ?center>
二、MCGS 工程框架 本空調(diào)溫/濕度控制系統(tǒng)需要對各個控制室及風(fēng)道的溫/濕度值進行監(jiān)控,因此工程需要有實時顯示和記錄各控制室溫/濕度值、修改房間溫/濕度SV 值、報警顯示、報警顯示瀏覽記錄等功能、工程框架如下: 用戶窗口:封面窗口、主控窗口、控制室窗口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)三級加熱報警窗口。 運行策略:啟動策略、退出策略、循環(huán)策略、卡車運動策略、控制柜燈閃爍策略、顯示控制室1~6策略、顯示時間策略、主控窗口中提示塊顯示策略?! ≈鞑藛危河脩舻卿?、封面窗口、打開主控窗口、打開各控制室、風(fēng)道平面圖、修改SV 值、歷史記錄、通信錯誤記錄、溫/濕度異常記錄、退出系統(tǒng) 子菜單:第一~六控制室、修改一~六號房間、SV 值修改風(fēng)道溫度、表1~2 SV 值、修改風(fēng)道濕度表1~2 SV 值 三、主要數(shù)據(jù)對象 建立好一個空調(diào)溫/濕度控制系統(tǒng)的MCGS 工程后,實現(xiàn)上位機的主要任務(wù)就是建立組態(tài)工程與OPC設(shè)備的連接,實現(xiàn)上位機的主要任務(wù)就是建立組態(tài)工程與OPC設(shè)備的連接,并對采集到的數(shù)據(jù)進行處理和顯示。在這個工程的實時數(shù)據(jù)庫中,要進行顯示、操作的數(shù)據(jù)對象如表1 所示。由于風(fēng)道的數(shù)據(jù)對象較多,為了統(tǒng)一管理,將風(fēng)道當(dāng)作兩個房間節(jié)點來處理。這樣,每個房間都只有1 個溫度值對象、1 個濕度之對象、1 個溫度SV 值對象和1 個濕度SV 值對象。表 1 系統(tǒng)主要數(shù)據(jù)對象 為了使系統(tǒng)具備記錄數(shù)據(jù)及瀏覽歷史數(shù)據(jù)、錯誤數(shù)據(jù)和異常數(shù)據(jù)的能力,在實時數(shù)據(jù)庫中建立了save、ErrorSave 和exception 三個數(shù)據(jù)對象組。其中ErrorSave 和exception 的組對象成員有:RoomID1 、ErrorTemp、ErrorHum 、ErrorTempSV 和ErrorHumSV ,save 的組成員對象如表1 所示。在運行過程中,系統(tǒng)會定時保存save 組對象到數(shù)據(jù)庫。當(dāng)通信產(chǎn)生錯誤和房間溫/濕度異常時,系統(tǒng)會將ErrorSave 和exception 保存到數(shù)據(jù)庫?! ≡诖讼到y(tǒng)中的OPC 設(shè)備使用的是ZOPC_Server 服務(wù)器。ZOPC_Server 是一個OPC 服務(wù)器軟件本軟件,支持操作全系列的ZLGCAN 系列接口卡,只要在一臺PC 機上插上ZLGCAN 系列接口卡中的任何一種或幾種,再運行本服務(wù)器軟件,就可以使用任何一種支持OPC 協(xié)議的客戶端軟件(比如組態(tài)軟件:組態(tài)王KingView、昆侖通態(tài)MCGS 和Intouch 等)來連接到此服務(wù)器通過此服務(wù)器,來跟CAN-bus 網(wǎng)絡(luò)進行數(shù)據(jù)的傳輸?! ”驹O(shè)計中,ZOPC_Server 在數(shù)值存儲模式下和字符串存儲模式下提供的數(shù)據(jù)項都不能直接連接到實時數(shù)據(jù)庫中的數(shù)據(jù)對象,因此必須編寫腳本程序?qū)?shù)據(jù)進行處理。關(guān)于數(shù)據(jù)項存儲模式,這里選用被推薦的字符串存儲模式;但是,使用數(shù)值存儲模式會更容易實現(xiàn)此系統(tǒng)。 在實時數(shù)據(jù)庫添加字符型數(shù)據(jù)對象In_CANData 和Out_CANData,字符數(shù)為30,將In_CANData 和Out_CANData 分別連接到OPC 設(shè)備的輸入通道和輸出通道,In_CANData 的讀寫屬性為只讀,Out_CANData的讀寫屬性為只寫。由于這兩個數(shù)據(jù)對象是字符型的,不便于進行數(shù)據(jù)處理,所以應(yīng)該先將它們轉(zhuǎn)換為數(shù)值型對象。在MCGS 腳本程序中,用戶不能定義子程序、子函數(shù)和變量,而數(shù)據(jù)對象可以看作是腳本程序中的全局變量,在所有的程序段共用。這給編寫較復(fù)雜的腳本程序帶來不便。要進行類似子程序和子函數(shù)的操作,只能用先將要處理的數(shù)據(jù)放入全局變量,然后調(diào)用策略行中的腳本進行處理,最后將返回的數(shù)據(jù)放入全局變量的方法進行處理。在實時數(shù)據(jù)庫加添以下數(shù)值型對象作為中間變量:
然后,在運行策略中新建一個名為StringToObject 的用戶策略,新增一策略行并添加以下腳本程序,用于將In_CANData 轉(zhuǎn)換到數(shù)值型對象: 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)) 同樣,在運行策略中新建一個名為ObjectToString 的用戶策略,新增一策略行并添加下面的腳本程序,用于將數(shù)值型對象轉(zhuǎn)換到Out_CANData 。在下面的程序中,Out_SendID 進行自加是因為ZOPC_Server 要判斷寫入的Out_SendID 和上一次寫入的Out_SendID 是否相同,如果不同才將報文發(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?! ∷摹f(xié)議及報文格式 因為MCGS 不便于編寫復(fù)雜的腳本程序,所以傳輸協(xié)議的設(shè)計以簡單為原則。本系統(tǒng)使用HiLon 協(xié)議A 。HiLon 協(xié)議A 是一個通用的協(xié)議,基于非對稱型主從式網(wǎng)絡(luò)結(jié)構(gòu),支持廣播和點對點傳送命令數(shù)據(jù),命令數(shù)據(jù)包可長達(dá)256 字節(jié),非常適合用作本系統(tǒng)的通信協(xié)議HiLon 協(xié)議以CAN2.0A 幀結(jié)構(gòu)為基礎(chǔ)。下圖是幀報文格式,一個CAN2.0A 標(biāo)準(zhǔn)幀由11 位ID 、1 位RTR 、4 位DLC 、數(shù)據(jù)區(qū)(最多8 個字節(jié))組成?! IR :方向位。方向位決定一半的優(yōu)先級而剩余的優(yōu)先級,由節(jié)點地址決定低地址優(yōu)先級高。當(dāng)方向位為“1” 時,地址域是源節(jié)點地址(從節(jié)點到主節(jié)點),優(yōu)先級由地址決定;當(dāng)方向位為“0” 時,地址域是目標(biāo)節(jié)點地址(主節(jié)點到從節(jié)點),優(yōu)先級由地址決定。從節(jié)點也可使用地址濾波技術(shù)從而減少需處理的網(wǎng)絡(luò)信息量,因而能有效節(jié)省CAN 節(jié)點控制器資源,提高控制器效率?! ddress :目標(biāo)地址,表示節(jié)點地址,范圍只能設(shè)定為0~125 TYPE :幀類型。見下表中的幀類型說明?! ?center>
DLC: 每幀字節(jié)數(shù)(1~8) Index :索引字節(jié)。對于單幀數(shù)據(jù),該字節(jié)表示傳輸數(shù)據(jù)的第一個字節(jié);對于多幀數(shù)據(jù),此字節(jié)表示索引字節(jié),即此幀數(shù)據(jù)在數(shù)據(jù)包中的位置?! ata :數(shù)據(jù) 在本系統(tǒng)中,數(shù)據(jù)中心要對各個房間的溫/濕度進行監(jiān)控并修各個房間的溫/濕度SV 值,因此給各個控制室分配唯一的標(biāo)志符;在下位機向上位機發(fā)送的數(shù)據(jù)報文中攜帶的數(shù)據(jù)是房間的溫/濕度值;上位機向下位機發(fā)送的命令報文攜帶命令號及控制室的溫/濕度SV 值。本系統(tǒng)的傳輸數(shù)據(jù)量較小,且MCGS 的采樣周期本系統(tǒng)取5ms 相對下位機來說較長,因此,本系統(tǒng)選擇使用單幀(點對點)類型幀。利用HiLon報文的特點,將7 位Address 分配給房間ID,每一個房間ID 對應(yīng)一個Address ,地址0 保留。當(dāng)數(shù)據(jù)方向是從節(jié)點到主節(jié)點時,8 字節(jié)數(shù)據(jù)的前4 字節(jié)用于傳遞房間溫度,后4 字節(jié)用于傳遞房間濕度,當(dāng)數(shù)據(jù)方向是主節(jié)點到從節(jié)點時,8字節(jié)數(shù)據(jù)的前4 字節(jié)作為命令I(lǐng)D,后4 字節(jié)用于傳遞命令參數(shù)(房間溫/濕度SV值)。報文幀的格式如圖1 所示?! χ鞴?jié)點到從節(jié)點的命令I(lǐng)D 的定義如下: 表 3 控制命令類型及其參數(shù) 本系統(tǒng)要監(jiān)控的數(shù)據(jù)是各房間的溫度和濕度及它們的SV 值。要將這些數(shù)據(jù)在總線上傳輸,必須將它們裝入報文幀。為了使傳輸?shù)臄?shù)據(jù)只占用較小的空間而達(dá)到較高的精確度,在報文中每一種數(shù)值都分配了4 字節(jié)的空間,數(shù)據(jù)按IEEE-754 標(biāo)準(zhǔn)的float 數(shù)據(jù)類型的格式存儲。這樣,在下位機進行編程就比較方便。但是,上位機的處理程序是用類似VB 腳本的語言寫的,數(shù)據(jù)對象的類型只有數(shù)值型、開關(guān)型和字符型三種,不能直接使用接收到的數(shù)據(jù)。因此,要對接收到的數(shù)據(jù)進行轉(zhuǎn)換?! “碔EEE-754 標(biāo)準(zhǔn),一個浮點數(shù)用兩個部分表示:尾數(shù)和2 的冪?!《膬绱碇笖?shù)。指數(shù)的保存形式是一個0 到255 的8 位值。指數(shù)的實際值是保存值0 到255 減去127,一個范圍在127 到-128 之間的值?! ∥矓?shù)是一個24 位值(代表大約7 個十進制數(shù)),最高位(MSB) 通常是1, 因此,不保存。一個符號位表示浮點數(shù)是正或負(fù)。在尾數(shù)的左邊有一個省略的二進制點和1。 這個數(shù)在浮點數(shù)的保存中經(jīng)常省略?! 「↑c數(shù)保存的字節(jié)格式如下圖 6 IEEE-754 標(biāo)準(zhǔn) float 存儲格式: 這里: S 代表符號位,1 是負(fù),0 是正?! 冪,偏移127?! 24 位的尾數(shù)(保存在23 位中)?! ×闶且粋€特定值,表示冪是0, 尾數(shù)是0?! ≡谶\行策略中新建一個名為SplitFloat 的用戶策略,新增一策略行并添加以下腳本程序,用于將數(shù)值型對象float 轉(zhuǎn)換到4 字節(jié)存儲單元Byte0 Byte3: ‘ 計算浮點數(shù)的冪(二進制數(shù)小數(shù)點的位置) exponent = 0 float1 = !abs(float) while float1<>0 float1 = !BitRShift(float1, 1) exponent = exponent + 1 endwhile exponent = exponent - 1 ‘ 計算浮點數(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) 在運行策略中新建一個名為UniteFloat 的用戶策略,新增一策略行并添加以下腳本程序,用于將4 字節(jié)存儲單元Byte0 Byte3 轉(zhuǎn)換到數(shù)值型對象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))) 五、實現(xiàn) 系統(tǒng)的控制中心采用定時查詢的方法,每2 秒鐘對各個房間的溫度值和濕度值進行一次查詢。查詢時,組態(tài)軟件先向?qū)崟r數(shù)據(jù)庫中的數(shù)據(jù)對象Out_CANData 寫入查詢房間溫/濕度命令的報文。命令報文的房間ID 對應(yīng)要查詢的房間號,命令I(lǐng)D 為0x00000000,無命令參數(shù)。然后經(jīng)過ZOPC_Server 將報文發(fā)到CAN總線上。在發(fā)送查詢命令后控制中心將等待一段時間(這一段時間要大于MCGS 的最小采集周期),然后再從實時數(shù)據(jù)庫中的數(shù)據(jù)對象In_CANData 讀取數(shù)據(jù)并進行處理和顯示?! ∪绻刂浦行囊薷姆块g的SV 值,首先發(fā)出查詢房間溫/濕度SV 值的命令,在收到房間溫/濕度SV值后,在“修改控制室SV 值”窗口中顯示SV 值(或在“修改風(fēng)道溫度/濕度表SV 值”窗口中顯示),然后發(fā)出帶有參數(shù)的修改房間溫度SV 值命令報文,參數(shù)的內(nèi)容就是要修改的SV 值。 下位機的驗收碼設(shè)置成ID10 為0,ID9~I(xiàn)D3 為房間ID,后3 位屏蔽。當(dāng)總線上有發(fā)給該房間的報文時,并根據(jù)命令進行相應(yīng)的操作。如果收到的是查詢命令,下位機立即將房間的溫/濕度數(shù)據(jù)發(fā)送到CAN 總線上。數(shù)據(jù)報文的ID 也是該房間的ID,以表示報文中的數(shù)據(jù)是該控制室的。如果是修改房間溫/濕度SV 值命令,下位機就從命令參數(shù)取出SV 值并替換舊的SV 值。 上位機控制流程編寫的具體步驟: 1. 在運行策略中新建一個名為“GetRoomTHV ”的用戶策略,并添加3 個腳本程序,1 個退出策略行,如圖 圖 7 GetRoomTHV 策略: 其中,“查詢房間溫/濕度值”腳本如下: ‘ 發(fā)送控制室溫/濕度查詢命令 Out_Extern = 0 Out_Remote = 0 Out_ID = !BitLShift(RoomID, 3) + 0 ‘ 控制室ID + 單幀(點對點) 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 “計算控制室的溫度”的執(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 “計算控制室的濕度”的執(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. 在運行策略中新建名為“查詢各控制室溫/濕度”的循環(huán)策略,循環(huán)時間為2000ms。 添加如下圖所示的策略行,圖 8 查詢各控制室溫/濕度策略?! ?center>
圖 8 查詢各控制室溫/濕度策略 “初始化”的腳本程序如下: RoomID = 1 “查詢1 號控制室溫/濕度”的腳本程序如下: RoomID1 = RoomID RoomID = RoomID + 1 if (roomtemp = 0) or (roomhum = 0) then room1st = 1 ErrorTemp = roomtemp ErrorHum = roomhum !SaveData(ErrorSave) ‘ 記錄通信錯誤 exit endif room1temp = roomtemp room1hum = roomhum if room1temp > room1tempsv then room1st = 1 ErrorTemp = room1temp ErrorHum = room1hum !SaveData(exception) ‘ 記錄溫度異?! xit else room1st = 0 endif 其它策略行腳本程序與上類似?! ∷械摹安呗哉{(diào)用”均調(diào)用GetRoomTHV 策略。 3. 在運行策略中新建一個名為“GetRoomSV” 的用戶策略,其他步驟同1,圖 9 GetRoomSV 策略?! 安樵兎块g溫/濕度SV 值”腳本如下: ‘ 發(fā)送控制室溫/濕度SV 查詢命令 Out_Extern = 0 Out_Remote = 0 Out_ID = !BitLShift(RoomID, 3) + 0 ‘ 控制室ID + 單幀(點對點) 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 “計算控制室的溫度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 “計算控制室的濕度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. 在運行策略中新建名為“查詢房間1SV 值”的用戶策略,添加如下圖所示的3 個策略行,圖 10 查詢房間1SV 值策略。
“before” 策略行腳本程序如下: !EnableStgy(查詢各控制室溫/濕度策略, 0) RoomID = 1 “策略調(diào)用”調(diào)用GetRoomSV 策略?! 癮fter” 策略行腳本程序如下: room1tempsv = roomtempsv !EnableStgy(查詢各控制室溫/濕度策略, 1) 5. 重復(fù)步驟4。 添加“查詢房間2~6 SV 值”和“查詢風(fēng)道溫/濕度表1~2 sv 值”策略,并由菜單“修改1~6 號房間SV 值”調(diào)用對應(yīng)的策略。 6. 雙擊主控窗口中名為“修改一號房間SV 值”的菜單項,在菜單屬性設(shè)置對話框的“菜單操作”頁中添加執(zhí)行運行策略塊“查詢房間1 SV 值”?! ?. 重復(fù)步驟6, 添加其它房間的運行策略?! ?. 在運行策略中建立一個名為“SetRoomTSV” 的用戶策略,添加以下腳本程序: float = roomtempsv !setstgy(SplitFloat) ‘ 發(fā)送控制室溫/濕度SV 設(shè)置命令 Out_Extern = 0 Out_Remote = 0 Out_ID = !BitLShift(RoomID, 3) + 0 ‘ 控制室ID + 單幀(點對點) 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. 在運行策略中建立一個名為“調(diào)整房間1SV 值”的用戶策略,并添加以下程序: !EnableStgy(查詢各控制室溫/濕度策略, 0) RoomID = 1 roomtempsv = room1tempsv float = roomtempsv !setstgy(SetRoomTSV) !EnableStgy(查詢各控制室溫/濕度策略, 1) 10. 重復(fù)步驟9, 添加其它5 個控制室及風(fēng)道的腳本程序?! ?1. 給“修改控制室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 實驗儀模擬產(chǎn)生控制室數(shù)據(jù)。DP-668 實驗儀具有模擬控制室溫/濕度變化、自修改溫/濕度SV 值以及報警等功能。其模擬溫/濕度變化算法如下: 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]))]; ... ?。 。 ”鞠到y(tǒng)也可用任一款ZLGCAN 接口卡和PC 組成的系統(tǒng)來模擬產(chǎn)生控制室數(shù)據(jù),基于ZLGCAN 通用函數(shù)接口編程,同樣具有模擬控制室溫/濕度變化、自修改溫/濕度SV 值以及報警等功能。其模擬溫/濕度變化算法(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; ...
二、MCGS 工程框架 本空調(diào)溫/濕度控制系統(tǒng)需要對各個控制室及風(fēng)道的溫/濕度值進行監(jiān)控,因此工程需要有實時顯示和記錄各控制室溫/濕度值、修改房間溫/濕度SV 值、報警顯示、報警顯示瀏覽記錄等功能、工程框架如下: 用戶窗口:封面窗口、主控窗口、控制室窗口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)三級加熱報警窗口。 運行策略:啟動策略、退出策略、循環(huán)策略、卡車運動策略、控制柜燈閃爍策略、顯示控制室1~6策略、顯示時間策略、主控窗口中提示塊顯示策略?! ≈鞑藛危河脩舻卿?、封面窗口、打開主控窗口、打開各控制室、風(fēng)道平面圖、修改SV 值、歷史記錄、通信錯誤記錄、溫/濕度異常記錄、退出系統(tǒng) 子菜單:第一~六控制室、修改一~六號房間、SV 值修改風(fēng)道溫度、表1~2 SV 值、修改風(fēng)道濕度表1~2 SV 值 三、主要數(shù)據(jù)對象 建立好一個空調(diào)溫/濕度控制系統(tǒng)的MCGS 工程后,實現(xiàn)上位機的主要任務(wù)就是建立組態(tài)工程與OPC設(shè)備的連接,實現(xiàn)上位機的主要任務(wù)就是建立組態(tài)工程與OPC設(shè)備的連接,并對采集到的數(shù)據(jù)進行處理和顯示。在這個工程的實時數(shù)據(jù)庫中,要進行顯示、操作的數(shù)據(jù)對象如表1 所示。由于風(fēng)道的數(shù)據(jù)對象較多,為了統(tǒng)一管理,將風(fēng)道當(dāng)作兩個房間節(jié)點來處理。這樣,每個房間都只有1 個溫度值對象、1 個濕度之對象、1 個溫度SV 值對象和1 個濕度SV 值對象。表 1 系統(tǒng)主要數(shù)據(jù)對象 為了使系統(tǒng)具備記錄數(shù)據(jù)及瀏覽歷史數(shù)據(jù)、錯誤數(shù)據(jù)和異常數(shù)據(jù)的能力,在實時數(shù)據(jù)庫中建立了save、ErrorSave 和exception 三個數(shù)據(jù)對象組。其中ErrorSave 和exception 的組對象成員有:RoomID1 、ErrorTemp、ErrorHum 、ErrorTempSV 和ErrorHumSV ,save 的組成員對象如表1 所示。在運行過程中,系統(tǒng)會定時保存save 組對象到數(shù)據(jù)庫。當(dāng)通信產(chǎn)生錯誤和房間溫/濕度異常時,系統(tǒng)會將ErrorSave 和exception 保存到數(shù)據(jù)庫?! ≡诖讼到y(tǒng)中的OPC 設(shè)備使用的是ZOPC_Server 服務(wù)器。ZOPC_Server 是一個OPC 服務(wù)器軟件本軟件,支持操作全系列的ZLGCAN 系列接口卡,只要在一臺PC 機上插上ZLGCAN 系列接口卡中的任何一種或幾種,再運行本服務(wù)器軟件,就可以使用任何一種支持OPC 協(xié)議的客戶端軟件(比如組態(tài)軟件:組態(tài)王KingView、昆侖通態(tài)MCGS 和Intouch 等)來連接到此服務(wù)器通過此服務(wù)器,來跟CAN-bus 網(wǎng)絡(luò)進行數(shù)據(jù)的傳輸?! ”驹O(shè)計中,ZOPC_Server 在數(shù)值存儲模式下和字符串存儲模式下提供的數(shù)據(jù)項都不能直接連接到實時數(shù)據(jù)庫中的數(shù)據(jù)對象,因此必須編寫腳本程序?qū)?shù)據(jù)進行處理。關(guān)于數(shù)據(jù)項存儲模式,這里選用被推薦的字符串存儲模式;但是,使用數(shù)值存儲模式會更容易實現(xiàn)此系統(tǒng)。 在實時數(shù)據(jù)庫添加字符型數(shù)據(jù)對象In_CANData 和Out_CANData,字符數(shù)為30,將In_CANData 和Out_CANData 分別連接到OPC 設(shè)備的輸入通道和輸出通道,In_CANData 的讀寫屬性為只讀,Out_CANData的讀寫屬性為只寫。由于這兩個數(shù)據(jù)對象是字符型的,不便于進行數(shù)據(jù)處理,所以應(yīng)該先將它們轉(zhuǎn)換為數(shù)值型對象。在MCGS 腳本程序中,用戶不能定義子程序、子函數(shù)和變量,而數(shù)據(jù)對象可以看作是腳本程序中的全局變量,在所有的程序段共用。這給編寫較復(fù)雜的腳本程序帶來不便。要進行類似子程序和子函數(shù)的操作,只能用先將要處理的數(shù)據(jù)放入全局變量,然后調(diào)用策略行中的腳本進行處理,最后將返回的數(shù)據(jù)放入全局變量的方法進行處理。在實時數(shù)據(jù)庫加添以下數(shù)值型對象作為中間變量:
DLC: 每幀字節(jié)數(shù)(1~8) Index :索引字節(jié)。對于單幀數(shù)據(jù),該字節(jié)表示傳輸數(shù)據(jù)的第一個字節(jié);對于多幀數(shù)據(jù),此字節(jié)表示索引字節(jié),即此幀數(shù)據(jù)在數(shù)據(jù)包中的位置?! ata :數(shù)據(jù) 在本系統(tǒng)中,數(shù)據(jù)中心要對各個房間的溫/濕度進行監(jiān)控并修各個房間的溫/濕度SV 值,因此給各個控制室分配唯一的標(biāo)志符;在下位機向上位機發(fā)送的數(shù)據(jù)報文中攜帶的數(shù)據(jù)是房間的溫/濕度值;上位機向下位機發(fā)送的命令報文攜帶命令號及控制室的溫/濕度SV 值。本系統(tǒng)的傳輸數(shù)據(jù)量較小,且MCGS 的采樣周期本系統(tǒng)取5ms 相對下位機來說較長,因此,本系統(tǒng)選擇使用單幀(點對點)類型幀。利用HiLon報文的特點,將7 位Address 分配給房間ID,每一個房間ID 對應(yīng)一個Address ,地址0 保留。當(dāng)數(shù)據(jù)方向是從節(jié)點到主節(jié)點時,8 字節(jié)數(shù)據(jù)的前4 字節(jié)用于傳遞房間溫度,后4 字節(jié)用于傳遞房間濕度,當(dāng)數(shù)據(jù)方向是主節(jié)點到從節(jié)點時,8字節(jié)數(shù)據(jù)的前4 字節(jié)作為命令I(lǐng)D,后4 字節(jié)用于傳遞命令參數(shù)(房間溫/濕度SV值)。報文幀的格式如圖1 所示?! χ鞴?jié)點到從節(jié)點的命令I(lǐng)D 的定義如下: 表 3 控制命令類型及其參數(shù) 本系統(tǒng)要監(jiān)控的數(shù)據(jù)是各房間的溫度和濕度及它們的SV 值。要將這些數(shù)據(jù)在總線上傳輸,必須將它們裝入報文幀。為了使傳輸?shù)臄?shù)據(jù)只占用較小的空間而達(dá)到較高的精確度,在報文中每一種數(shù)值都分配了4 字節(jié)的空間,數(shù)據(jù)按IEEE-754 標(biāo)準(zhǔn)的float 數(shù)據(jù)類型的格式存儲。這樣,在下位機進行編程就比較方便。但是,上位機的處理程序是用類似VB 腳本的語言寫的,數(shù)據(jù)對象的類型只有數(shù)值型、開關(guān)型和字符型三種,不能直接使用接收到的數(shù)據(jù)。因此,要對接收到的數(shù)據(jù)進行轉(zhuǎn)換?! “碔EEE-754 標(biāo)準(zhǔn),一個浮點數(shù)用兩個部分表示:尾數(shù)和2 的冪?!《膬绱碇笖?shù)。指數(shù)的保存形式是一個0 到255 的8 位值。指數(shù)的實際值是保存值0 到255 減去127,一個范圍在127 到-128 之間的值?! ∥矓?shù)是一個24 位值(代表大約7 個十進制數(shù)),最高位(MSB) 通常是1, 因此,不保存。一個符號位表示浮點數(shù)是正或負(fù)。在尾數(shù)的左邊有一個省略的二進制點和1。 這個數(shù)在浮點數(shù)的保存中經(jīng)常省略?! 「↑c數(shù)保存的字節(jié)格式如下圖 6 IEEE-754 標(biāo)準(zhǔn) float 存儲格式: 這里: S 代表符號位,1 是負(fù),0 是正?! 冪,偏移127?! 24 位的尾數(shù)(保存在23 位中)?! ×闶且粋€特定值,表示冪是0, 尾數(shù)是0?! ≡谶\行策略中新建一個名為SplitFloat 的用戶策略,新增一策略行并添加以下腳本程序,用于將數(shù)值型對象float 轉(zhuǎn)換到4 字節(jié)存儲單元Byte0 Byte3: ‘ 計算浮點數(shù)的冪(二進制數(shù)小數(shù)點的位置) exponent = 0 float1 = !abs(float) while float1<>0 float1 = !BitRShift(float1, 1) exponent = exponent + 1 endwhile exponent = exponent - 1 ‘ 計算浮點數(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) 在運行策略中新建一個名為UniteFloat 的用戶策略,新增一策略行并添加以下腳本程序,用于將4 字節(jié)存儲單元Byte0 Byte3 轉(zhuǎn)換到數(shù)值型對象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))) 五、實現(xiàn) 系統(tǒng)的控制中心采用定時查詢的方法,每2 秒鐘對各個房間的溫度值和濕度值進行一次查詢。查詢時,組態(tài)軟件先向?qū)崟r數(shù)據(jù)庫中的數(shù)據(jù)對象Out_CANData 寫入查詢房間溫/濕度命令的報文。命令報文的房間ID 對應(yīng)要查詢的房間號,命令I(lǐng)D 為0x00000000,無命令參數(shù)。然后經(jīng)過ZOPC_Server 將報文發(fā)到CAN總線上。在發(fā)送查詢命令后控制中心將等待一段時間(這一段時間要大于MCGS 的最小采集周期),然后再從實時數(shù)據(jù)庫中的數(shù)據(jù)對象In_CANData 讀取數(shù)據(jù)并進行處理和顯示?! ∪绻刂浦行囊薷姆块g的SV 值,首先發(fā)出查詢房間溫/濕度SV 值的命令,在收到房間溫/濕度SV值后,在“修改控制室SV 值”窗口中顯示SV 值(或在“修改風(fēng)道溫度/濕度表SV 值”窗口中顯示),然后發(fā)出帶有參數(shù)的修改房間溫度SV 值命令報文,參數(shù)的內(nèi)容就是要修改的SV 值。 下位機的驗收碼設(shè)置成ID10 為0,ID9~I(xiàn)D3 為房間ID,后3 位屏蔽。當(dāng)總線上有發(fā)給該房間的報文時,并根據(jù)命令進行相應(yīng)的操作。如果收到的是查詢命令,下位機立即將房間的溫/濕度數(shù)據(jù)發(fā)送到CAN 總線上。數(shù)據(jù)報文的ID 也是該房間的ID,以表示報文中的數(shù)據(jù)是該控制室的。如果是修改房間溫/濕度SV 值命令,下位機就從命令參數(shù)取出SV 值并替換舊的SV 值。 上位機控制流程編寫的具體步驟: 1. 在運行策略中新建一個名為“GetRoomTHV ”的用戶策略,并添加3 個腳本程序,1 個退出策略行,如圖 圖 7 GetRoomTHV 策略: 其中,“查詢房間溫/濕度值”腳本如下: ‘ 發(fā)送控制室溫/濕度查詢命令 Out_Extern = 0 Out_Remote = 0 Out_ID = !BitLShift(RoomID, 3) + 0 ‘ 控制室ID + 單幀(點對點) 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 “計算控制室的溫度”的執(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 “計算控制室的濕度”的執(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. 在運行策略中新建名為“查詢各控制室溫/濕度”的循環(huán)策略,循環(huán)時間為2000ms。 添加如下圖所示的策略行,圖 8 查詢各控制室溫/濕度策略?! ?center>
圖 8 查詢各控制室溫/濕度策略 “初始化”的腳本程序如下: RoomID = 1 “查詢1 號控制室溫/濕度”的腳本程序如下: RoomID1 = RoomID RoomID = RoomID + 1 if (roomtemp = 0) or (roomhum = 0) then room1st = 1 ErrorTemp = roomtemp ErrorHum = roomhum !SaveData(ErrorSave) ‘ 記錄通信錯誤 exit endif room1temp = roomtemp room1hum = roomhum if room1temp > room1tempsv then room1st = 1 ErrorTemp = room1temp ErrorHum = room1hum !SaveData(exception) ‘ 記錄溫度異?! xit else room1st = 0 endif 其它策略行腳本程序與上類似?! ∷械摹安呗哉{(diào)用”均調(diào)用GetRoomTHV 策略。 3. 在運行策略中新建一個名為“GetRoomSV” 的用戶策略,其他步驟同1,圖 9 GetRoomSV 策略?! 安樵兎块g溫/濕度SV 值”腳本如下: ‘ 發(fā)送控制室溫/濕度SV 查詢命令 Out_Extern = 0 Out_Remote = 0 Out_ID = !BitLShift(RoomID, 3) + 0 ‘ 控制室ID + 單幀(點對點) 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 “計算控制室的溫度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 “計算控制室的濕度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. 在運行策略中新建名為“查詢房間1SV 值”的用戶策略,添加如下圖所示的3 個策略行,圖 10 查詢房間1SV 值策略。
自動對焦:總線的
我要收藏
個贊
評論排行