|
易移植到相似结构的冗余系统中。
该软件模板以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 <windows.h>
#include <stdlib.h>
#include <conio.h>
#include <stdio.h>
#include <string.h>
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));//发送数据
}
}
|