串口通信在雙機冗余系統中應用
胡強
摘要:本文扼要分析了當今帶專用檢測轉換電路的雙機冗余系統存在的可靠性問題,提出了利用雙機的串行口代替專用檢測轉換電路,通過串行通信相互檢測主備機工作狀態,由軟件完成備機切換成主機的新型設計思想,為計算機在工業實時監控系統應用中的可靠性開辟新思路。
關鍵詞:雙機 冗余 軟件 切換
1、引言
冗余技術是計算機系統可靠性設計中常用的一種技術,是提高計算機系統可靠性的最有效方法,同時也是鑒別各類計算機控制系統好壞的標志之一。故世界各地廠商推出的新產品都或多或少帶有冗余技術。如美國的Honeywell、德國的西門子和日本的三武等,它們都有一個共同的特點,就是自己設計了專用檢測轉換電路來實現主備切換。本文提出一種新的構思,取消專用檢測轉換電路,采用一種高效、實用的軟件冗余技術來完成雙機切換。
2、冗余系統介紹
雙機冗余包括CPU、擴展電路、電源和外設雙備份的全系統冗余,不但可簡化設計方案,還可大大地提高應用系統的可靠性。這種冗余系統具有如圖1所示的典型硬件結構。
在圖1所示的系統中,U1和U2單元的軟硬件結構完全相同。如有必要,在設計各單元時,通過采用自診斷技術,軟件陷井或Watch dog等系統自行恢復措施可使單元可靠性達到最大限度的提高。系統正常運行時,U1和U2中的一個單元處于正常工作狀態(把該單元稱為主機),完成應用功能,而另一個單元(備機)處于等待備用狀態。當檢測轉換電路檢測到主機不能正常工作時,自動啟動備機進入正常運行狀態,完成應用功能。此時,可對故障單元進行脫線維護,在排除其故障后,可使其聯機進入等待備用狀態。顯然,這種冗余系統已大大提高了應用系統的可靠性,并基本保證了應用系統的不間斷運行。但仔細分析,就會發現它存在以下不足之處:
① 系統存在可靠性瓶頸,當檢測轉換電路自身出現故障時,不能監視主備機狀態,也無法完成主備機自動切換功能;
② 對于某些冗余系統,當備機需要實時保留主機之間的數據備份時,檢測轉換電路無法完成主備機之間的數據通信功能;
③ 由于需要設計檢測轉換電路,系統設計和實現復雜,引入了附加的不可靠因素。
3、改進設計方案
針對圖1所示的雙機冗余系統結構和缺點,筆者實現了一個簡單高效、具有更高可靠性和主備機數據通信功能的改進設計方案。其基本設計思想是:不改變上述冗余系統的基本結構,但完全去掉專用的檢測轉換電路,利用主備機雙方的串行口和軟件相結合的方法,實現檢測轉換電路的功能和主備機之間的數據通信功能。在此改進的設計方案中,主備單元的硬件和軟件結構完全相同,各單元的主備工作狀態由上電順序決定,先上電的一方自動進入主機工作狀態,后上電者則進入備機狀態。主機在其工作過程中除實現應用功能外,定期向備機發送反映其工作正常的狀態數據,當需要備份的數據發生變化時,主機及時向備機發送已更新的數據。此外,主機也定期接收來自備機的狀態數據,當發生接收超時時,主機認為備機已經發生故障,并通過本單元的顯示裝置向用戶給出通知信號,以便及時對備機進行脫線維護。備機在其工作過程中不完成應用功能,但定期接收來自主機的狀態數據,當發生接收超時,備機認為主機以經發生故障,自動切換進入主機工作狀態,并通過本單元顯示裝置通知用戶,以便對原主機單元進行脫線維護。此外,備機還自動接收來自主機的備份數據并進行存儲備份。
4、軟件模板
下面的軟件模板給出了筆者已實現的雙機冗余系統的軟件框架,和應用系統實現密切相關的部分用自然語言簡單描述,其余部分為Visual C++源代碼,因此,這一軟件模板很容易移植到相似結構的冗余系統中。
該軟件模板以Visual C++進行程序設計,常量OK,REQ,ACK和NACK分別表示主備機工作狀態正常,備份數據發送請求,肯定應答和否定應答信息的字符常量,MAIN,STANDBY分別是表示工作單元為主機或備機的常量標志。全局變量timeout用于設定以毫秒為單位的超時間隔,而Update,CpuStatus和Failure分別是表示備份數據是否更新,主備機狀態和主備機是否發生故障的標志位變量。
定時器0產生每隔1ms的定時中斷(采用QueryPerformanceCounter((LARGE_INTEGER *)&endtime )計數方式),每次中斷將全局變量timeout的值減1,減到0時即關閉定時器0。所有需要軟件超時機制或延時功能的程序模塊都可在設定timeout的值后開啟定時器0,并通過判斷該變量的值是否為0而實現定時功能。
定時器1產生每隔55ms的定時中斷(采用SetTime(55)函數)。每次中斷,主備單元的中斷服務程序都向對方單元發送表示自身工作狀態正常的OK字符,同時也接收對方單元發送的OK字符,若連續三次都未能成功接收,則本單元認為對方單元出了故障,并將表示對方單元工作狀態的全局變量Failure置為常量Yes,否則,置為No;若為備機,還將表示主備身份的標志變量CpuStatus的值置為Main,從而為備機程序切換和給出原主機故障提示設置判斷標志。若備機在中斷服務程序中接收到字符REQ,則置表示備份數據是否更新的標志變量Update為Yes,并立即退出中斷服務程序,以便主程序及時接收備份數據幀。
主函數在完成應用系統的公共初使化,主備單元的定時器1在后臺產生定時中斷并通過串行通信進行相互檢測,由于規定兩個單元的上電時間間隔大于500ms,因此,利用中斷服務程序的檢測結果必能自動確定初使的主備身份。主函數延時500ms后,即根據當前的主備身份自動進入主(備)機的前臺監控例程,主機的前臺監控例程除完成應用功能外,當應用功能改變了需要備份的數據時,則調用send_frame函數關閉定時器1的中斷并發送備份數據幀。當備機的前臺監控例程判斷出需要接收備份數據時,調用receive_frame函數關閉定時器1的中斷并接收備份數據幀。當備機的前臺監控例程監視到主機故障時,備機的前臺監控循環自動切換進入主機的前臺監控循環。主函數中的監控切換代碼較難理解,應結合并發執行的定時器1的中斷服務程序一起分析。
函數send_char和receive_char通過串行口直接發送和接收單個字符。函數send_frame和receive_frame分別發送和接收備份數據幀。VC++中用通訊控件開發串行通信程序,通訊控件的工作原理類似與中斷方式,當有通訊事件發生時(如發送數據、接收數據等),就會觸發OnComm事件,在該事件的處理函數中調用GetCommEvent()函數,通過返回值即可確定是那類事件,再作出相應的處理。通信成功時返回1,否則返回0。Delay為以毫秒數為調用參數的延時函數。
限于篇幅,本文僅給出完成檢測切換功能的主函數和定時器1的中斷服務函數,以及相關數據的代碼,其它函數僅給出函數原型。代碼如下:
#include "stdafx.h"
#include "Try.h"
#include "TryDoc.h"
#include "TryView.h"
#include
#include
#include
#include
#include
int timeout;
bool Update,Failure;
char CpuStatus[12],
void delay(unsigned int time);
void CTryDlg::Send_char(unsigned char ch)
{
if(!m_Comm.GetPortOpen())
{
m_Comm.SetPortOpen(TRUE);//打開串口
m_Comm.SetOutput(COleVariant(ch));//發送數據
}
}
void CTryDlg::receive_char(unsigned char * ch)
{
VARIANT m_input1;
if(m_Comm.GetInBufferCount())
{
m_input1=m_Comm.GetInput();//讀取緩沖區內的數據
ch=m_input1.bstrVal;//將VARIANT型變量轉換為CString型變量
return 1;
}
else return 0;
}
mian()
{和應用系統相關的公共初使化程序段;
Updata=false;Failure=true;
Delay(500);/* 等待與對方建立通信連接,通信由定時器1的中斷例程完成 */
If(Failure)/* 在定時器1的中斷例程判斷出初使主備狀態后 */
{CpuStatus=MAIN;和應用系統實現相關的主機初使化程序斷;
while(1)/* 主機單元的前臺例行監控循環 */
{和應用系統實現相關的主機應用功能例程;
if(應用例程修改了需要備份的數據) Update;
if((Update)&&(!Failure)&&send_frame()) Update=false;
if(Failure){給出備機故障通知信號;Update=true;}
}}
else
{CpuStatus=STANDBY;和應用系統實現相關的備機初使化程序段;
while(1)/* 備機單元的前臺例行監控循環*/
{if(CpuStatus= =STANDBY)
while(CpuStatus= =STANDBY)/* 在備機狀態中循環 */
{和應用系統實現相關的備機例程;
if((!Failure)&&(Update)&&receive_frame()) Update=false;
}
else
{Update=true;/* 以便在未來的備機聯機后再次發送備份數據 */
while(1)/* 切換到主機的前臺監控循環中 */
{和應用系統實現相關的主機應用功能例程;
if(應用例程修改了需要備份的數據) Update;
if((Update)&&(!Failure)&&send_frame()) Update=false;
if(Failure){給出備機故障通知信號;Update=YES;}
}}}}}
void CTryDlg::OnTimer(UINT nIDEvent) /* 定時器1的55ms中斷服務程序 */
{int count=0;
if(receive_char(&ch)= =NULL)
{count++;
if(count= =3)/* 三次接收字符不成功*/
{count=0; Failure=true;/* 對方單元故障,如果本方為備機,準備切換 */
if(CpuStatus= =STANDBY) CpuStatus= MAIN;
}}
else
{count=0;Failure=false;
if((ch= =REQ)&&(CpuStatus= =STANDBY))/* 如果備機接收到主機的備份數據幀 */
{Update=true;return;} /* 發送請求字符,立即返回,接收此備份數據幀 */
}
send_char(OK);/* 發送本單元工作正常的狀態數據字符 */
應用系統和55ms定時相關的例程;
}
5、結束語
以上改進的冗余系統設計具有結構簡單,可靠性高,易于實現等顯著特點。不足之處是通信協議太簡單,因此,系統僅適用于通信質量比較可靠的應用場合,通過引入滑動窗口流協議或其它更為完善的通信協議,可大大提高通信可靠性,從而使系統具有更廣泛的適應性。
參 考 文 獻
[1] 俞金壽何衍慶.集散控制系統原理及應用.北京:化學工業出版社.1995.
[2] 史惠康.實用編程技術.中國水利電力出版社.1997.8.