📄 main.c
字号:
// Copyright (c)2005 - 2006 by Laser Electronics, All Rights Reserved.
/*----------------------------------------------------------------------------+
| File Name: Main.c, v1.0.1 |
| Author: |
| Date: |
+-----------------------------------------------------------------------------+
| Description: 联网型智能楼宇对讲系统 -- 管理中心机主程序文件 |
| 器件选择 -- STC89C58RD+, PQFP-44 |
| 时钟频率 -- 24.000 MHz |
+-----------------------------------------------------------------------------+
| Release Notes: |
| | |
+----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------+
| Include files |
+----------------------------------------------------------------------------*/
#include "Main.h"
#include "LCD.h"
#include "UART.h"
#include "Timer.h"
#include "KeyProcess.h"
#include "RouteTable.h"
/*----------------------------------------------------------------------------+
| Type Definition & Macro |
+----------------------------------------------------------------------------*/
// I2C存储器的配置:使用24C512,64K字节空间, 0x0000 ~ 0xFFFF, 这里只用到16K字节
/*----------------------------------------------------------------------------+
| 0x0000(2字节): 系统标志
| 0x0002(1字节): 双击间隔时间
| 0x0003(1字节): 管理机轮检门口机的时间间隔
| 0x0004(2字节): 小区的路由信息I2C起始地址
| 0x0006(2字节): 小区的路由信息长度
| 0x0008(2字节): 射频卡信息起始地址
| 0x000A(2字节): 射频卡信息长度
| 0x000C(2字节): 报警信息起始地址
| 0x000E(2字节): 报警信息长度
| 0x0010(2字节): 报警记录第一条记录的地址
| 0x0012(2字节): 报警记录最后一条记录的地址
| 0x0020 - 0x002F (16字节): 系统密码+密码长度
| 0x0030 - 0x003F (16字节): 管理机LOGO,在管理机空闲模式下LCD屏的第一行显示的字符
| 0x0400 - 0x07FF (1K字节):
| 0x0800 - 0x0FFF (2K字节): 存放小区的路由信息,每个单元占用8个字节,所以可以存放256个单元的路由信息
| 0x1000 - 0x1FFF (4K字节): 存放卡号,每张卡号占用16个字节,所以可以存放256张卡号
| 0x2000 - 0x3FFF (8K字节): 存放报警记录,每条报警记录占用16个字节,所以可以存放512条报警记录
+----------------------------------------------------------------------------*/
#define DEFAULT_ROUTE_INFO_START_ADDR 0x0800 // 从0x0800地址处开始
#define DEFAULT_ROUTE_INFO_LENGTH 0x0800 // 用2K字节来存放小区路由信息,每个单元需要8字节,可以存放256个单元的路由信息
#define DEFAULT_RFCARDTAB_START_ADDR 0x1000 // 从0x1000地址处开始
#define DEFAULT_RFCARDTAB_LENGTH 0x1000 // 用4K字节来存放临时射频卡号,每张卡需16字节,可以存放256张临时卡
#define DEFAULT_ALARM_RECORD_START_ADDR 0x2000 // 从0x2000地址处开始
#define DEFAULT_ALARM_RECORD_LENGTH 0x2000 // 用8K字节来存放分机报警记录,每条记录需16字节,可以存放512条报警记录
/*----------------------------------------------------------------------------+
| Extern Variables |
+----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------+
| Global Variables |
+----------------------------------------------------------------------------*/
bit bHandleUp; // 指示手柄是否提起,TRUE为提起状态,FALSE为压下状态
bit LineIdle; // 当前线路上是否有数据,如果没有才可以发数据
bit TxOK; // 当前字节是否已经发送完成
data t_SystemStatus SystemStatus; // 当前选择的命令,是监视、查询还是呼叫等等
data UINT RS485SendWaitTimer; // RS485总线超时重发计数器,当这个数减计数到MAX_RS485_WAIT_TIMES的倍数的时候重发,减到0的时候表示放弃这一次发送
data UINT MessageShowTimer; // 消息显示的时间长短计数器,当这个数减到0的时候清除显示的消息并回到之前的状态
data UINT BeepTimer; // 蜂鸣器发声定时器
idata BYTE WDT_Counter; // 看门狗狗粮
idata UINT LineIdleWaitTime; // 等待485总线空闲需要等待的时间, 根据地址而各不相同
idata UINT RingTimeCounter; // 振铃信号持续时间,超过这个时间就会停止振铃
idata UINT AlarmTimeCounter; // 报警持续时间,超过这个时间就会停止报警
idata UINT ViewTimeCounter; // 监视定时器,当这个计数器减计数到0的时候向门口机发送取消监视请求的命令
xdata BYTE ConnectingAddr[4]; // 管理机正在监视的门口机地址
xdata BYTE KeyBuffer[KEY_BUF_LENGTH+1]; // 按键缓冲
xdata BYTE CardBuffer[Card_BUF_LENGTH+1]; // 卡号缓冲
xdata t_RouteInfo RouteInfo; // 路由信息缓冲区
idata BYTE DoubleKeyPressTimer; // 设定双击按键的时间间隔,以10ms为单位
idata BYTE CheckDoorIntervalTimer; // 设定管理机轮检门口机的时间间隔
idata UINT RouteInfoStartAddr; // 用于存放各个用户的路由信息的表格在I2C存储器中的起始地址
idata UINT RouteInfoLength; // 用于存放各个用户的路由信息的表格的长度
idata UINT RFCardTabStartAddr; // 用于存放各个单元所有卡号对应的I2C地址的表格的头地址,即表格的地址
idata UINT RFCardTabLength; // 用于存放各个单元所有卡号对应的I2C地址的表格的长度的地址
idata UINT AlarmRecordStartAddr; // 存放的报警记录的首地址
idata UINT AlarmRecordLength; // 存放的报警记录的长度
xdata BYTE SystemPassword[MAX_SYSTEM_PASSWORD_LENGTH+1]; // 存放系统管理员密码,第一个字节为密码长度
xdata t_AlarmRecord AlarmRecord; // 报警记录缓冲区
idata t_AlarmRecord *pAlarmRecord; // 指向报警记录的指针
xdata t_RFCardUser RFCardUser; // 定义记录刷卡用户的结构体,包括卡号,用户名
idata t_RFCardUser *p_RFCardUser;
xdata BYTE I2CBuffer[I2C_PAGE_SIZE] _at_ 0x0000; // 读写I2C存储器的内存缓冲
xdata BYTE CheckDoorIntervalArray[MAX_DOOR_NUM] _at_ I2C_PAGE_SIZE;// 管理机轮检各个门口机所用到的数据缓存,每一个门口机对应一个字节
data UINT DoorNumber; // 在I2C存储器中设置的单元的数量,根据这个数量管理机决定需要对多少个门口机进行轮检
code UINT SystemPasswordAddress = 0x20; // 用于存放系统管理员密码的I2C地址,长度为16个字节,用一页来存放
code BYTE NullString[NULL_STRING_LENGTH] = {0x00}; // 常量空字符串
code BYTE Logo[DISP_BUF_LENGTH] = " 雷森电子 ";
/*----------------------------------------------------------------------------+
| Internal Variables |
+----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------+
| Type Definition & Macro |
+----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------+
| System Initialization Routines |
+----------------------------------------------------------------------------*/
//
// 初始化定时器0, 定时1.1ms作为检测线路是否冲突的时间界限
void InitTimer0(void)
{
// initial timer0 interrupt
TMOD &= 0xF0; // zero low nibble
TMOD |= 0x01; // 设置 Timer 0 为16位计数器工作方式
// Init Timer0 counter
TH0 = LineIdleWaitTime >> 8;
TL0 = LineIdleWaitTime & 0xFF;
TF0 = 0; // clear timer 0 overflow flag
ET0 = 1; // enable timer 0 interrupt
}
//
// 初始化定时器2, Auto Reload方式定时10ms作为系统心跳信号
void InitTimer2(void)
{
// initial timer2
// T2CON __ ___
// TF2 EXF2 RCLK TCLK EXEN2 TR2 C/T2 CP/RL2
// 0 0 0 0 0 0 0 0
// T2CON = 0x00; // Mode 0, 16Bit Auto-Reload Mode
TR2 = 0; // Clear Interrupt Flag
EXF2 = 0; // reset flag
TCLK = 0; RCLK = 0; // disable baud rate generator
EXEN2 = 0; // ignore events on T2EX
C_T2 = 0; // timer mode
CP_RL2 = 0; // reload mode
T2MOD &= 0xFC; // T2OE(Timer 2 Output Enable bit)=0; DCEN(up/down counter)=0;
// initial timer2 reload value (1.1ms) @ fosc=24MHz
RCAP2H = TIMER2_H; // 自动装载寄存器, 高8位
RCAP2L = TIMER2_L; // 自动装载寄存器, 低8位
// Init timer2 counter
TH2 = TIMER2_H;
TL2 = TIMER2_L;
ET2 = ENABLE; // enable timer2 interrupt
TR2 = ENABLE; // timer2 run
}
// 初始化
void CopyDefaultSettings(void)
{
EA = DISABLE; // 关闭总中断
AUXR = 0x01; // 禁止ALE信号输出,提升系统的EMI性能,STC单片机专用
// 修改中断优先级,让Timer2中断有最高优先级,其次是INT0
IP = 0x00;
XICON = 0x00; ////////////////////////////////////////////////////
PT2 = 0;
PT2H = 1; // 设置Timer2具有优先级2
IT2 = 1; //INT2边沿触发
PX2H = 1;
PX2 = 1; // 设置INT2具最高优先级
EX2 = 1;
P_VIDEO = P_OFF; // 电源关闭
P_AUDIO = P_OFF; // 电源关闭
BeepTimer = 0;
ViewTimeCounter = 0x0000; // 监视定时器,当这个计数器减计数到0的时候向门口机发送取消监视请求的命令
MessageShowTimer = 0x0000;
RS485SendWaitTimer = 0x0000; // RS485总线超时重发计数器,当这个数减计数到MAX_RS485_WAIT_TIMES的倍数的时候重发,减到0的时候表示放弃这一次发送
KeyBuffer[0] = 0x00;
LineIdleWaitTime = 0xF6A0; // (65536-1200*2), 如果有地址,则在后面减去与地址相关的数
InitTimer0();
InitTimer2();
InitMessagePool();
}
/*----------------------------------------------------------------------------+
| Main Routine |
+----------------------------------------------------------------------------*/
void main(void)
{
bit bTemp;
UINT i;
BYTE temp;
MSG msg;
GREEN_LED = P_OFF; // 绿色LED亮
RED_LED = P_ON; // 红色LED灭
CopyDefaultSettings(); // 初始化系统变量
RESET_WDT;
Delayms(20);
RESET_WDT;
Delayms(20);
RESET_WDT;
Delayms(20);
RESET_WDT;
Delayms(20);
RESET_WDT;
InitLCD();
Delayms(1); // LCD初始化之后要等待1ms才能正常显示
RESET_WDT;
SystemStatus.PreStatus = Status_Idle;
SystemStatus.Status = Status_Init;
InitDispBuffer(TRUE);
UpdateDisp(TRUE);
InitKey();
InitUART(); // 初始化串口和模拟串口
RESET_WDT;
// i = 0x55AA;
// I2CWriteString(0x00, 0x0000, (BYTE *)(&i), 2); // 先写高字节,然后写低字节,说明高字节放在低地址处,低字节放在高地址处
// 扫描按键并判断'*'键的状态,如果是按下的状态,则进入设置模式
KEY_ROW1 = 0; // 扫描第1行(1 2 3 监视)
i <<= 4;
i |= (P0 & 0x0F); // 得到第1行按键的电平 "1, 2, 3, 13"
KEY_ROW1 = 1;
KEY_ROW2 = 0; // 扫描第2行(4 5 6 呼叫)
i <<= 4;
i |= (P0 & 0x0F); // 得到第2行按键的电平 "4, 5, 6, 14"
KEY_ROW2 = 1;
KEY_ROW3 = 0; // 扫描第3行(7 8 9 开锁)
i <<= 4;
i |= (P0 & 0x0F); // 得到第3行按键的电平 "7, 8, 9, 15"
KEY_ROW3 = 1;
KEY_ROW4 = 0; // 扫描第4行(* 0 # 查询)
i <<= 4;
i |= (P0 & 0x0F); // 得到第4行按键的电平 "11, 0, 12, 16"
KEY_ROW4 = 1;
if (i == 0xFFF7) // 0000,0000,0000,1000,即所有按键中只有'*'键是按下的
{
memcpy(&DispBuffer[0][1], "系统正在初始化 ", DISP_BUF_LENGTH);
memcpy(&DispBuffer[1][1], "请稍候! ", DISP_BUF_LENGTH);
UpdateDisp(TRUE);
// 向I2C存储器中写入默认的配置
// 清空前面2K字节空间
for (i=0x0000; i<DEFAULT_ROUTE_INFO_START_ADDR; i+=NULL_STRING_LENGTH)
{
RESET_WDT;
I2CWriteString(0x00, i, NullString, NULL_STRING_LENGTH);
}
// 清空小区路由信息所占用的2K字节空间
for (i=DEFAULT_ROUTE_INFO_START_ADDR; i<(DEFAULT_ROUTE_INFO_START_ADDR+DEFAULT_ROUTE_INFO_LENGTH); i+=NULL_STRING_LENGTH)
{
RESET_WDT;
I2CWriteString(0x00, i, NullString, NULL_STRING_LENGTH);
}
// 清空卡号所占用的4K字节空间
for (i=DEFAULT_RFCARDTAB_START_ADDR; i<(DEFAULT_RFCARDTAB_START_ADDR+DEFAULT_RFCARDTAB_LENGTH); i+=NULL_STRING_LENGTH)
{
RESET_WDT;
I2CWriteString(0x00, i, NullString, NULL_STRING_LENGTH);
}
// 清空报警记录所占用的8K字节空间
for (i=DEFAULT_ALARM_RECORD_START_ADDR; i<(DEFAULT_ALARM_RECORD_START_ADDR+DEFAULT_ALARM_RECORD_LENGTH); i+=NULL_STRING_LENGTH)
{
RESET_WDT;
I2CWriteString(0x00, i, NullString, NULL_STRING_LENGTH);
}
// 写入标志
I2CWriteString(0x00, 0x0000, "\x55\xAA", 2);
RESET_WDT;
// 初始化系统变量
RouteInfoStartAddr = DEFAULT_ROUTE_INFO_START_ADDR;
RouteInfoLength = sizeof(RouteInfoTable);//小区路由长度
RFCardTabStartAddr = DEFAULT_RFCARDTAB_START_ADDR;
RFCardTabLength = DEFAULT_RFCARDTAB_LENGTH;
AlarmRecordStartAddr = DEFAULT_ALARM_RECORD_START_ADDR;
AlarmRecordLength = DEFAULT_ALARM_RECORD_LENGTH;
DoubleKeyPressTimer = 25; // 设置按键双击间隔时间为25*10=250ms
CheckDoorIntervalTimer = 0; // 设置管理机轮检门口机的时间间隔: 60*10=600秒
I2CBuffer[0] = DoubleKeyPressTimer;
I2CWriteString(0x00, 0x0002, I2CBuffer, 1); // 按键双击间隔时间
RESET_WDT;
I2CBuffer[0] = CheckDoorIntervalTimer;
I2CWriteString(0x00, 0x0003, I2CBuffer, 1); // 管理机轮检门口机时间间隔
RESET_WDT;
I2CBuffer[0] = RouteInfoStartAddr>>8;
I2CBuffer[1] = RouteInfoStartAddr&0xFF;
I2CWriteString(0x00, 0x0004, I2CBuffer, 2); // 小区的路由信息I2C起始地址
RESET_WDT;
I2CBuffer[0] = RouteInfoLength>>8;
I2CBuffer[1] = RouteInfoLength&0xFF;
I2CWriteString(0x00, 0x0006, I2CBuffer, 2); // 小区的路由信息长度
RESET_WDT;
I2CBuffer[0] = RFCardTabStartAddr>>8;
I2CBuffer[1] = RFCardTabStartAddr&0xFF;
I2CWriteString(0x00, 0x0008, I2CBuffer, 2); // 射频卡信息起始地址
RESET_WDT;
I2CBuffer[0] = RFCardTabLength>>8;
I2CBuffer[1] = RFCardTabLength&0xFF;
I2CWriteString(0x00, 0x000A, I2CBuffer, 2); // 射频卡信息长度
RESET_WDT;
I2CBuffer[0] = AlarmRecordStartAddr>>8;
I2CBuffer[1] = AlarmRecordStartAddr&0xFF;
I2CWriteString(0x00, 0x000C, I2CBuffer, 2); // 报警信息起始地址
RESET_WDT;
I2CBuffer[0] = AlarmRecordLength>>8;
I2CBuffer[1] = AlarmRecordLength&0xFF;
I2CWriteString(0x00, 0x000E, I2CBuffer, 2); // 报警信息长度
RESET_WDT;
// 初始化管理机LOGO
I2CWriteString(0x00, 0x0030, Logo, 16); // 管理机LOGO
RESET_WDT;
memcpy(MainLogo, Logo, DISP_BUF_LENGTH);
// 初始化报警记录存储空间
AlarmRecord.Index = 0x00; // 报警记录的长度
AlarmRecord.PreRecord = AlarmRecordStartAddr; // 报警记录最后一条记录的地址
AlarmRecord.NextRecord = AlarmRecordStartAddr; // 报警记录第一条记录的地址
I2CWriteString(0x00, AlarmRecordStartAddr, (BYTE *)(&AlarmRecord), sizeof(t_AlarmRecord));
RESET_WDT;
// 写入小区的路由信息
for (i=0; i<sizeof(RouteInfoTable); )
{
if ((sizeof(RouteInfoTable) - i) > I2C_PAGE_SIZE) // 一页写不完这些数据,需要转到下一页
temp = I2C_PAGE_SIZE;
else
temp = (sizeof(RouteInfoTable) - i);
I2CWriteString(0x00, RouteInfoStartAddr+i, (BYTE *)(RouteInfoTable)+i, temp);//
RESET_WDT;
i += temp;
}
}
else
{
bTemp = FALSE;
if (I2CReadString(0x00, 0x0000, I2CBuffer, 64)) // 第一次读16各字节,包括一些系统变量的值
{
if ((I2CBuffer[0] == 0x55) && (I2CBuffer[1] == 0xAA))
{
// 初始化系统变量
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -