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

然后,在運行策略中新建一個名為StringToObject 的用戶策略,新增一策略行并添加以下腳本程序,用于將In_CANData 轉換到數值型對象:
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 的用戶策略,新增一策略行并添加下面的腳本程序,用于將數值型對象轉換到Out_CANData 。在下面的程序中,Out_SendID 進行自加是因為ZOPC_Server 要判斷寫入的Out_SendID 和上一次寫入的Out_SendID 是否相同,如果不同才將報文發出。
‘ 轉換 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
‘ 轉換 Out_Extern 和 Out_Remote 到字符型
Out_CANData1 = !I2Hex(Out_Extern) + !I2Hex(Out_Remote)
Out_CANData2 = Out_CANData2 + Out_CANData1
‘ 轉換 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
‘ 轉換 Out_DataLen 到字符型
Out_CANData1 = !I2Hex(Out_DataLen)
if !Len(Out_CANData1) <> 2 then Out_CANData1 = "0" + Out_CANData1
Out_CANData2 = Out_CANData2 + Out_CANData1
‘ 轉換 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 的數據提取到In_*變量中,只需在腳本中按!setstgy(StringToObject)就可以了。而要將Out_*數據合并到Out_CANData, 可先調用!setstgy(ObjectToString),然后再把Out_CANData2的值賦給Out_CANData。
四、協議及報文格式
因為MCGS 不便于編寫復雜的腳本程序,所以傳輸協議的設計以簡單為原則。本系統使用HiLon 協議A 。HiLon 協議A 是一個通用的協議,基于非對稱型主從式網絡結構,支持廣播和點對點傳送命令數據,命令數據包可長達256 字節,非常適合用作本系統的通信協議HiLon 協議以CAN2.0A 幀結構為基礎。下圖是幀報文格式,一個CAN2.0A 標準幀由11 位ID 、1 位RTR 、4 位DLC 、數據區(最多8 個字節)組成。
[align=center][IMG=HiLon A 報文格式]/uploadpic/tech/2007/7/2007073017043663226O.jpg[/IMG]
圖 4 HiLon A 報文格式[/align]
DIR :方向位。方向位決定一半的優先級而剩余的優先級,由節點地址決定低地址優先級高。當方向位為“1” 時,地址域是源節點地址(從節點到主節點),優先級由地址決定;當方向位為“0” 時,地址域是目標節點地址(主節點到從節點),優先級由地址決定。從節點也可使用地址濾波技術從而減少需處理的網絡信息量,因而能有效節省CAN 節點控制器資源,提高控制器效率。
Address :目標地址,表示節點地址,范圍只能設定為0~125
TYPE :幀類型。見下表中的幀類型說明。
[align=center]表 2 HiLon 幀類型
[IMG=HiLon 幀類型]/uploadpic/tech/2007/7/200707301712087027014.jpg[/IMG]

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

[/align]
本系統要監控的數據是各房間的溫度和濕度及它們的SV 值。要將這些數據在總線上傳輸,必須將它們裝入報文幀。為了使傳輸的數據只占用較小的空間而達到較高的精確度,在報文中每一種數值都分配了4 字節的空間,數據按IEEE-754 標準的float 數據類型的格式存儲。這樣,在下位機進行編程就比較方便。但是,上位機的處理程序是用類似VB 腳本的語言寫的,數據對象的類型只有數值型、開關型和字符型三種,不能直接使用接收到的數據。因此,要對接收到的數據進行轉換。
按IEEE-754 標準,一個浮點數用兩個部分表示:尾數和2 的冪。例如:

尾數代表浮點上的數據二進制數。
二的冪代表指數。指數的保存形式是一個0 到255 的8 位值。指數的實際值是保存值0 到255 減去127,一個范圍在127 到-128 之間的值。
尾數是一個24 位值(代表大約7 個十進制數),最高位(MSB) 通常是1, 因此,不保存。一個符號位表示浮點數是正或負。在尾數的左邊有一個省略的二進制點和1。 這個數在浮點數的保存中經常省略。
浮點數保存的字節格式如下:
[align=center][IMG=IEEE-754 標準 float 存儲格式]/uploadpic/tech/2007/7/20070731104600663014.jpg[/IMG]
圖 6 IEEE-754 標準 float 存儲格式[/align]
這里:
S 代表符號位,1 是負,0 是正。
E 冪,偏移127。
M 24 位的尾數(保存在23 位中)。
零是一個特定值,表示冪是0, 尾數是0。
在運行策略中新建一個名為SplitFloat 的用戶策略,新增一策略行并添加以下腳本程序,用于將數值型對象float 轉換到4 字節存儲單元Byte0 Byte3:
‘ 計算浮點數的冪(二進制數小數點的位置)
exponent = 0
float1 = !abs(float)
while float1<>0
float1 = !BitRShift(float1, 1)
exponent = exponent + 1
endwhile
exponent = exponent - 1
‘ 計算浮點數的底數
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 字節存儲單元Byte0 Byte3 轉換到數值型對象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)))
五、實現
系統的控制中心采用定時查詢的方法,每2 秒鐘對各個房間的溫度值和濕度值進行一次查詢。查詢時,組態軟件先向實時數據庫中的數據對象Out_CANData 寫入查詢房間溫/濕度命令的報文。命令報文的房間ID 對應要查詢的房間號,命令ID 為0x00000000,無命令參數。然后經過ZOPC_Server 將報文發到CAN總線上。在發送查詢命令后控制中心將等待一段時間(這一段時間要大于MCGS 的最小采集周期),然后再從實時數據庫中的數據對象In_CANData 讀取數據并進行處理和顯示。
如果控制中心要修改房間的SV 值,首先發出查詢房間溫/濕度SV 值的命令,在收到房間溫/濕度SV值后,在“修改控制室SV 值”窗口中顯示SV 值(或在“修改風道溫度/濕度表SV 值”窗口中顯示),然后發出帶有參數的修改房間溫度SV 值命令報文,參數的內容就是要修改的SV 值。
下位機的驗收碼設置成ID10 為0,ID9~ID3 為房間ID,后3 位屏蔽。當總線上有發給該房間的報文時,并根據命令進行相應的操作。如果收到的是查詢命令,下位機立即將房間的溫/濕度數據發送到CAN 總線上。數據報文的ID 也是該房間的ID,以表示報文中的數據是該控制室的。如果是修改房間溫/濕度SV 值命令,下位機就從命令參數取出SV 值并替換舊的SV 值。
上位機控制流程編寫的具體步驟:
1. 在運行策略中新建一個名為“GetRoomTHV ”的用戶策略,并添加3 個腳本程序,1 個退出策略行,如圖:
[align=center][IMG=GetRoomTHV 策略]/uploadpic/tech/2007/7/2007073111012831562I.jpg[/IMG]
圖 7 GetRoomTHV 策略[/align]
其中,“查詢房間溫/濕度值”腳本如下:
‘ 發送控制室溫/濕度查詢命令
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)
‘ 發出命令
Out_CANData = Out_CANData2
‘ 等待命令發出
!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
“計算控制室的溫度”的執行條件是!BitAnd(!BitRShift(In_ID, 3), 127) = RoomID 表達式的值為非0,腳本程序如下:
Byte0 = In_Data0
Byte1 = In_Data1
Byte2 = In_Data2
Byte3 = In_Data3
!setstgy(UniteFloat)
roomtemp = float
“計算控制室的濕度”的執行條件是!BitAnd(!BitRShift(In_ID, 3), 127) = RoomID 表達式的值為非0,腳本程序如下:
Byte0 = In_Data4
Byte1 = In_Data5
Byte2 = In_Data6
Byte3 = In_Data7
!setstgy(UniteFloat)
roomhum = float
2. 在運行策略中新建名為“查詢各控制室溫/濕度”的循環策略,循環時間為2000ms。 添加如下圖所示的策略行。
[align=center][IMG=查詢各控制室溫/濕度策略]/uploadpic/tech/2007/7/2007073111083487072R.jpg[/IMG]
圖 8 查詢各控制室溫/濕度策略[/align]
“初始化”的腳本程序如下:
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) ‘ 記錄溫度異常
exit
else
room1st = 0
endif
其它策略行腳本程序與上類似。
所有的“策略調用”均調用GetRoomTHV 策略。
3. 在運行策略中新建一個名為“GetRoomSV” 的用戶策略,其他步驟同1。
[align=center][IMG=GetRoomSV 策略]/uploadpic/tech/2007/7/20070731111436892566.jpg[/IMG]
圖 9 GetRoomSV 策略[/align]
“查詢房間溫/濕度SV 值”腳本如下:
‘ 發送控制室溫/濕度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)
‘ 發出命令
Out_CANData = Out_CANData2
‘ 等待命令發出
!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” 的執行條件是!BitAnd(!BitRShift(In_ID, 3), 127) = RoomID 表達式的值為非0, 腳本程序如下:
Byte0 = In_Data0
Byte1 = In_Data1
Byte2 = In_Data2
Byte3 = In_Data3
!setstgy(UniteFloat)
roomtempsv = float
“計算控制室的濕度SV” 的執行條件是!BitAnd(!BitRShift(In_ID, 3), 127) = RoomID 表達式的值為非0, 腳本程序如下:
Byte0 = In_Data4
Byte1 = In_Data5
Byte2 = In_Data6
Byte3 = In_Data7
!setstgy(UniteFloat)
roomhumsv = float
4. 在運行策略中新建名為“查詢房間1SV 值”的用戶策略,添加如下圖所示的3 個策略行。
[align=center][IMG=查詢房間1SV 值策略]/uploadpic/tech/2007/7/2007073111194331320L.jpg[/IMG]
圖 10 查詢房間1SV 值策略[/align]
“before” 策略行腳本程序如下:
!EnableStgy(查詢各控制室溫/濕度策略, 0)
RoomID = 1
“策略調用”調用GetRoomSV 策略。
“after” 策略行腳本程序如下:
room1tempsv = roomtempsv
!EnableStgy(查詢各控制室溫/濕度策略, 1)
5. 重復步驟4。 添加“查詢房間2~6 SV 值”和“查詢風道溫/濕度表1~2 sv 值”策略,并由菜單“修改1~6 號房間SV 值”調用對應的策略。
6. 雙擊主控窗口中名為“修改一號房間SV 值”的菜單項,在菜單屬性設置對話框的“菜單操作”頁中添加執行運行策略塊“查詢房間1 SV 值”。
7. 重復步驟6, 添加其它房間的運行策略。
8. 在運行策略中建立一個名為“SetRoomTSV” 的用戶策略,添加以下腳本程序:
float = roomtempsv
!setstgy(SplitFloat)
‘ 發送控制室溫/濕度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 = 2
Out_Data4 = Byte0
Out_Data5 = Byte1
Out_Data6 = Byte2
Out_Data7 = Byte3
!setstgy(ObjectToString)
‘ 發出命令
Out_CANData = Out_CANData2
‘ 等待命令發出
!TimerReset(1, 0)
!TimerRun(1)
!TimerWaitFor(1, Delay)
!TimerStop(1)
9. 在運行策略中建立一個名為“調整房間1SV 值”的用戶策略,并添加以下程序:
!EnableStgy(查詢各控制室溫/濕度策略, 0)
RoomID = 1
roomtempsv = room1tempsv
float = roomtempsv
!setstgy(SetRoomTSV)
!EnableStgy(查詢各控制室溫/濕度策略, 1)
10. 重復步驟9, 添加其它5 個控制室及風道的腳本程序。
11. 給“修改控制室1SV 值”窗口的“確認”按鈕添加如下腳本:
if room1tempsv1<-10 or room1tempsv1>100 then
!setwindow(修改SV 值消息窗口,1)
else
room1tempsv=room1tempsv1
!setwindow(修改控制室1SV 值,3)
room1tempsv1=0
!setstgy(調整房間1SV 值)
endif
12. 重復步驟11, 添加其它窗口的腳本。
六 模擬控制室
本系統可用DP-668 實驗儀模擬產生控制室數據。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]))];
...
}
}
本系統也可用任一款ZLGCAN 接口卡和PC 組成的系統來模擬產生控制室數據,基于ZLGCAN 通用函數接口編程,同樣具有模擬控制室溫/濕度變化、自修改溫/濕度SV 值以及報警等功能。其模擬溫/濕度變化算法(VC 示范)如下:
float m_dwTemp[8];// 房間1 6 及風道1 2 的溫度
float m_dwHumi[8];// 房間1 6 及風道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;
...