📄 main.c
字号:
DoubleKeyPressTimer = I2CBuffer[2];
CheckDoorIntervalTimer = I2CBuffer[3];
RouteInfoStartAddr = *(UINT *)(&I2CBuffer[4]);
RouteInfoLength = *(UINT *)(&I2CBuffer[6]);
RFCardTabStartAddr = *(UINT *)(&I2CBuffer[8]);
RFCardTabLength = *(UINT *)(&I2CBuffer[10]);
AlarmRecordStartAddr = *(UINT *)(&I2CBuffer[12]);
AlarmRecordLength = *(UINT *)(&I2CBuffer[14]);
DoorNumber = RouteInfoLength / sizeof(t_RouteInfo); // DoorNumber决定了管理机需要轮检的门口机的数量,也就决定了数组的大小
if (DoorNumber > MAX_DOOR_NUM)
{
DoorNumber = MAX_DOOR_NUM;
}
memcpy(MainLogo, &I2CBuffer[0x30], DISP_BUF_LENGTH);
bTemp = TRUE; // 初始化成功
// 开机画面延时
RESET_WDT;
Delayms(20);
RESET_WDT;
Delayms(20);
RESET_WDT;
Delayms(20);
}
}
if (bTemp == FALSE) // 如果初始化失败,即读I2C不成功或者I2C没有被初始化
{
memcpy(&DispBuffer[0][1], "严重错误: ", DISP_BUF_LENGTH);
memcpy(&DispBuffer[1][1], "系统初始化失败!", DISP_BUF_LENGTH);
UpdateDisp(TRUE);
BEEP = P_ON;
while (1) // 出现严重错误后系统将停留在初始化状态,不再继续工作
{
RESET_WDT;
PCON |= IDL_;
_nop_();
_nop_();
}
}
}
RESET_WDT;
// 初始化CheckDoorIntervalArray[]为默认值
for (i=0; i<DoorNumber; i++)
{
if (CheckDoorIntervalTimer == 0)
{
CheckDoorIntervalArray[i] = 0;
}
else
{
CheckDoorIntervalArray[i] = CheckDoorIntervalTimer;
}
}
InitRealTimer();
RESET_WDT;
SystemStatus.Status = Status_Idle;
InitDispBuffer(TRUE);
UpdateDisp(FALSE);
RED_LED = P_OFF;
ENABLE_WDT;
EA = ENABLE; // Enable global interrupt
while ( 1 )
{
RED_LED = P_ON;
WDT_Counter = 0x00; // 给狗粮
if (GetMessage(&msg))
{
switch (msg.Msg)
{
case MSG_TIMER_OVER: // 10ms系统心跳
{
if (BeepTimer > 0)
{
BEEP = P_ON;
BeepTimer --;
if (BeepTimer == 0)
{
BEEP = P_OFF;
}
}
if (SystemStatus.Status == Status_Idle) //多余(除开锁)
{
ClosePower( ); //空闲状态关闭音视频
}
if (MessageShowTimer > 0)
{
if (SystemStatus.Status == Status_ShowingMessage) // 如果当前正在显示消息
{
if ((--MessageShowTimer) == 0) // 如果显示的时间到,则退回到显示消息之前的状态
{
SystemStatus.Status = SystemStatus.PreStatus;
SystemStatus.PreStatus = Status_Idle;
InitDispBuffer(TRUE);
UpdateDisp(TRUE);
}
}
else
{
MessageShowTimer = 0;
}
}
if (RingTimeCounter > 0)
{
if ((SystemStatus.Status == Status_Calling) // 管理机正在呼叫室内分机
|| (SystemStatus.Status == Status_bCallingIn_F) // 管理机正在振铃
|| (SystemStatus.Status == Status_bCallingIn_M))
{
if ((--RingTimeCounter) == 0)
{
// 发送断开连接的命令
RS485SendCancelCommand();
// 关闭音频、视频电源
ClosePower();
SystemStatus.Status = Status_Idle;
}
}
else
{
RingTimeCounter = 0;
}
}
if (AlarmTimeCounter > 0)
{
if ((SystemStatus.Status == Status_Alarming_F) // 管理机正在报警
|| (SystemStatus.Status == Status_Alarming_M))
{
if ((--AlarmTimeCounter) == 0)
{
ClosePower();
SystemStatus.Status = Status_Idle;
}
}
else
{
AlarmTimeCounter = 0;
}
}
if (ViewTimeCounter > 0) // 监视定时器减计数
{
if (SystemStatus.Status == Status_Viewing)
{
if ((--ViewTimeCounter) == 0)
{
// 发送取消命令
RS485SendCancelCommand();
SystemStatus.Status = Status_Idle;//多余,防止返回出错
}
}
else
{
ViewTimeCounter = 0;
}
}
// 超时重发定时器减计数
if (RS485SendWaitTimer > 0) // 正在等待应答
{
if ((--RS485SendWaitTimer) == 0) // 超过重发次数,放弃发送
{
memcpy(&DispBuffer[1][1], "对方没有应答! ", DISP_BUF_LENGTH);
DispBuffer[1][0] = 0x01;
if ((SystemStatus.Status == Status_Viewing)
|| (SystemStatus.Status == Status_Talking)
|| (SystemStatus.Status == Status_Calling)
|| (SystemStatus.Status == Status_Alarming_F)
|| (SystemStatus.Status == Status_Alarming_M)
|| (SystemStatus.Status == Status_bCallingIn_F)
|| (SystemStatus.Status == Status_bCallingIn_M))
{
ClosePower();
}
MessageShowTimer = 200;
SystemStatus.PreStatus = Status_Idle;
SystemStatus.Status = Status_ShowingMessage;
UpdateDisp(FALSE);
}
else if ((RS485SendWaitTimer%MAX_RS485_WAIT_TIMES) == 0) // 超时,重发
{
RS485SendTxFrame();
}
}
if (LastKeyTimer < 0xFF)// 给两次按键之间的时间间隔计数,最大为2550ms
LastKeyTimer ++;
TickCountAdd(); // 更新时间显示
break;
}
case MSG_TIMER_TEN_SECOND: // 1秒钟定时时间到,检查整个路由表中的每一个门口机发来的数据包的时间间隔是否超过设定值
{
/*
for (i=0; i<DoorNumber; i++)
{
if (CheckDoorIntervalArray[i] > 0)
{
CheckDoorIntervalArray[i] --;
if (CheckDoorIntervalArray[i] == 0)
{
j = RouteInfoStartAddr + i * sizeof(t_RouteInfo);
I2CReadString(0x00, j, (BYTE *)(&RouteInfo), sizeof(t_RouteInfo));
// 判断当前门口机是否存在
if (RouteInfo.User != 0)
{
// 以下为保存报警记录并初始化报警显示缓冲
SystemStatus.Status = Status_Alarming_M;
InitDispBuffer(TRUE);
AlarmRecord.Addr[0] = 0x00; // 第一个字节
AlarmRecord.Addr[1] = RouteInfo.House; // 楼栋号
DispBuffer[1][7] = (RouteInfo.House >> 4) | 0x30;
DispBuffer[1][8] = (RouteInfo.House&0x0F) | 0x30;
AlarmRecord.Addr[2] = RouteInfo.Door; // 单元号
DispBuffer[1][11] = (RouteInfo.Door >> 4) | 0x30;
DispBuffer[1][12] = (RouteInfo.Door&0x0F) | 0x30;
AlarmRecord.Addr[3] = 0x00; // 第四个字节为0x00表示是从门口机报警而不是从分机报警
// 然后发出报警声音
AlarmTimeCounter = MAX_ALARM_TIMES/2; // 设定最长报警时间为分机报警时间的一半
OpenAlarmPower(); // 打开报警音频电路
UpdateDisp(FALSE);
memcpy((BYTE *)(&(AlarmRecord.Time)), (BYTE *)(&Time), sizeof(t_Time));// 保存时间
SaveAlarmRecord(&AlarmRecord); // 将报警记录AlarmRecord结构体写入到I2C存储器中
// 将I2C存储器中该单元的路由信息更新为该门口机不存在
RouteInfo.User = 0;
I2CWriteString(0x00, j, (BYTE *)(&RouteInfo), sizeof(t_RouteInfo));
// 当这次发现某一个门口机失去联系的时候,就跳出这次的检查,等下一个1秒钟再来检查其它的门口机,防止管理机不能响应其它的消息
// break;
}
}
}
}
*/
break;
}
case MSG_KEY_ROUTINE:
{
KeyRoutine(&msg);
break;
}
case MSG_KEY_DOWN:
{
KeyPressHandler(&msg);
break;
}
case MSG_TIME_DISPLAY:
{
// 更新显示
// 如果当前显示的是时间, 则更新显示, 否则不更新
if ((KeyBuffer[0] == 0x00) && (SystemStatus.Status == Status_Idle))
{
InitDispBuffer(FALSE);
UpdateDisp(FALSE);
}
break;
}
case MSG_RS485_RX_FRAME:
{
RS485RxFrameHandler(&msg);
break;
}
// case MSG_RS232_RX: // 从模拟串口接收到数据
// {
// RS232RxHandler(&msg);
// break;
// }
case MSG_RX_CARDNUMBER: // 接收到一张卡的卡号
{
KeyBuffer[0] = 0x00;
BEEP = 0;
// 转换为12位数字
for (i=1; i<=CardBuffer[0]; i++)
{
KeyBuffer[++KeyBuffer[0]] = CardBuffer[i] / 100;
CardBuffer[i] = CardBuffer[i] % 100;
KeyBuffer[++KeyBuffer[0]] = CardBuffer[i] / 10;
CardBuffer[i] = CardBuffer[i] % 10;
KeyBuffer[++KeyBuffer[0]] = CardBuffer[i];
//
}
for(i=0; i<KeyBuffer[0]; i++)
{
DispBuffer[1][DISP_BUF_LENGTH-i] = KeyBuffer[KeyBuffer[0]-i]+0x30;
}
BeepTimer = 20; // 每按一个按键,蜂鸣器响100ms
// 更新LCD显示缓冲
DispBuffer[1][0] = 0x01;
UpdateDisp(FALSE);
break;
}
default:
break;
}
}
else // 队列中没有消息
{
RED_LED = P_OFF;
// 进入休眠状态, 靠中断来激活
PCON |= IDL_;
_nop_();
_nop_();
}
}
}
/*----------------------------------------------------------------------------+
| General Subroutines |
+----------------------------------------------------------------------------*/
//
// 延时微秒
void Delayus(BYTE timer) reentrant
{
// 每微秒执行2条指令
#if (SYS_CLOCK/N_DIV) == 2000
timer -= 4;
while ( --timer ) ;
// 每微秒执行4条指令
#else
#if (SYS_CLOCK/N_DIV) == 4000
timer -= 2;
_nop_();
do {
_nop_();
_nop_();
}while (--timer);
#endif
#endif
}
//
// 延时毫秒
void Delayms(BYTE timer)
{
do {
Delayus(250);
Delayus(250);
Delayus(250);
Delayus(248);
}while (--timer);
}
//
// 从RS485串口接收到一帧数据
void RS485RxFrameHandler(PMSG msg)
{
BYTE i;
BYTE j;
// BYTE k;
bit bTemp;
UINT temp;
FRAME xdata *pRxFrame;
// t_RouteInfo *p_temp;
pRxFrame = (FRAME *)msg->Param;
RouteInfo.RouteAddr = pRxFrame->Frame.Addr[1];// 由数据帧中的路由地址找到其对应的单元地址
RouteInfo.DoorAddr = pRxFrame->Frame.Addr[2];
RouteInfo.User = pRxFrame->Frame.Addr[3];// 用用户的房号暂时存放分机地址,在查找对应的单元地址的时候同时把用户的楼层和房号更新
if (pRxFrame->Frame.Addr[3] == 0x00) // 数据帧是从门口机发来的
{
if (pRxFrame->Frame.aData[0] & Command_Ack) // 应答帧
{
pRxFrame->Frame.aData[0] &= ~Command_Ack;
// 判断数据类型
switch (pRxFrame->Frame.aData[0])
{
case Command_ViewRequest: // 门口机应答管理机发出的监视请求命令
{
if (SystemStatus.Status == Status_ViewSendingRequest) // 如果管理机正在等待门口机的返回
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -