📄 keyprocess.c
字号:
// Copyright (c)2005 - 2006 by Laser Electronics, All Rights Reserved.
/*----------------------------------------------------------------------------+
| File Name: KeyProcess.c, v1.0.1 |
| Author: 安徽雷森电子有限公司合肥研发中心 |
| Date: 2005年08月01日 |
+-----------------------------------------------------------------------------+
| Description: 联网型智能楼宇对讲系统 -- 管理中心机按键处理驱动程序 |
| 器件选择 -- STC89C58RD+, PQFP-44 |
| 时钟频率 -- 24.000 MHz |
+-----------------------------------------------------------------------------+
/*----------------------------------------------------------------------------+
| Include files |
+----------------------------------------------------------------------------*/
#include "Main.h"
#include "LCD.h"
#include "UART.h"
#include "Timer.h"
#include "KeyProcess.h"
/*----------------------------------------------------------------------------+
| Type Definition & Macro |
+----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------+
| Global Variables |
+----------------------------------------------------------------------------*/
BYTE LastKeyTimer; // 上一次按键到这一次按键之间的时间间隔,以10ms为单位
BYTE LastKey; // 上一次的按键
// 手柄状态指示变量
bit bKey_Hand_1;
bit bKey_Hand_2;
// 压簧呼叫按键状态指示变量
bit PKey_Hand_1;
bit PKey_Hand_2;
// 压簧开锁按键状态指示变量
bit PKey_Unlock_1;
bit PKey_Unlock_2;
//bit AddTempCardByCardEnd; //读卡完毕
/*----------------------------------------------------------------------------+
| Internal Variables |
+----------------------------------------------------------------------------*/
// 按键缓冲区,共16个按键,需要16位来保存一次扫描的结果
UINT KeyBuf_1; // 保存最后一次没有变化时的按键值
UINT KeyBuf_2; // 保存最后一次检查的按键值
// 万能密码,第一个字节为长度,后面为需要输入的密码,一共7位"2117127", 为雷森电子淮北技术部的电话号码
code BYTE pwd[] = {7, 2, 1, 1, 7, 1, 2, 7};
// 定义16位中各个位对应的按键编号, 按照分别将各行拉低,读取4列上的电平的方法来排列
// 查询 # 0 * 开锁 9 8 7 呼叫 6 5 4 监视 3 2 1
code BYTE KeyNum[16] = {16, 12, 0, 11, 15, 9, 8, 7, 14, 6, 5, 4, 13, 3, 2, 1};
// 定义设置系统时间界面时按键顺序与显示顺序之间的对应关系,第一个字节没有意义
code BYTE SetupTimeDispOrder[] = {0, 3, 4, 6, 7, 9, 10, 12, 13, 15, 16};
// 定义增加射频卡时输入该卡所在的房间号时数字的显示顺序,第一个字节没有意义
code BYTE SetupAddTempCardDoorDispOrder[] = {0, 7, 8, 11, 12};
// 定义输入需要监视的单元号码的时候数字的显示顺序,第一个字节没有意义
code BYTE ViewBeforeDispOrder[] = {0, 7, 8, 11, 12};
// 定义输入需要呼叫的房间号码的时候数字的显示顺序,第一个字节没有意义
code BYTE CallBeforeDispOrder[] = {0, 7, 8, 11, 12, 13, 14};
/*----------------------------------------------------------------------------+
| System Initialization Routines |
+----------------------------------------------------------------------------*/
// 初始化按键相关
void InitKey(void)
{
LastKey = 0xFF;
LastKeyTimer = 0xFF; // 0xFF表示离上次按键的时间已经很久了
// 键盘矩阵状态初始化
KeyBuf_1 = 0xFFFF;
KeyBuf_2 = 0xFFFF;
// 手柄状态初始化为手柄压下的状态,所以如果复位的时候手柄是提起的,单片机也可以检测到手柄的状态
bKey_Hand_1 = 0;
bKey_Hand_2 = 0;
// 手柄附近呼叫按键状态初始化
PKey_Hand_1 = 1;
PKey_Hand_2 = 1;
// 手柄附近开锁按键状态初始化
PKey_Unlock_1 = 1;
PKey_Unlock_2 = 1;
KEY_ROW1 = 1;
KEY_ROW2 = 1;
KEY_ROW3 = 1;
KEY_ROW4 = 1;
}
/*----------------------------------------------------------------------------+
| General Subroutines |
+----------------------------------------------------------------------------*/
// 按键扫描例程,取得按键值
void KeyRoutine(PMSG pMsg)
{
BYTE i;
UINT j;
UINT temp;
temp = pMsg->Param;
// 下面判断按键是否有按键按下
if (KeyBuf_1 != KeyBuf_2) // 只有当前面两次的按键状态不一样时,这一次才有可能判断有按键按下
{
for (i=0, j=0x0001; i<16; i++, j<<=1) // 分别判断16个按键的状态
{
if ((KeyBuf_1 & j) != (KeyBuf_2 & j)) // 当前这一位不相同
{
if ((KeyBuf_2 & j) == (temp & j)) // 最后一次的状态和当前状态相同,则表示有按键状态变化
{
// 判断当前状态发生变化的是哪一个按键
if ((temp & j) == 0x0000) // 按键按下
{
PostMessage(MSG_KEY_DOWN, KeyNum[i]);
}
}
}
}
KeyBuf_1 = KeyBuf_2; // 保存最后一次没有变化时的按键值
}
KeyBuf_2 = temp;
if (temp == 0xFFFF) //设置按键灯光和音响
{
GREEN_LED = P_OFF;
}
else
{
GREEN_LED = P_ON;
}
}
// 按键响应函数
void KeyPressHandler(PMSG pMsg)
{
BYTE nKey;
nKey = (pMsg->Param)&0xFF;
if ((nKey >= 0) && (nKey <= 9)) // 数字0~9
{
BeepTimer = 10; // 每按一个按键,蜂鸣器响100ms
NumberKeyPress(nKey);
}
else if (nKey == Key_Cancel) // "取消"
{
BeepTimer = 10; // 每按一个按键,蜂鸣器响100ms
CancelKeyPress();
}
else if (nKey == Key_Setup) // "设置"
{
BeepTimer = 10; // 每按一个按键,蜂鸣器响100ms
EnterKeyPress();
}
else if (nKey == Key_View) // "监视"
{
BeepTimer = 10; // 每按一个按键,蜂鸣器响100ms
ViewKeyPress();
}
else if (nKey == Key_Call) // "呼叫"
{
BeepTimer = 10; // 每按一个按键,蜂鸣器响100ms
CallKeyPress();
}
else if (nKey == Key_Unlock) // "开锁"
{
BeepTimer = 10; // 每按一个按键,蜂鸣器响100ms
UnlockKeyPress();
}
else if (nKey == Key_Find) // "查询"
{
BeepTimer = 10; // 每按一个按键,蜂鸣器响100ms
FindKeyPress();
}
else if (nKey == Key_PCall) // 按下压簧呼叫键
{
BeepTimer = 10; // 每按一个按键,蜂鸣器响100ms
CallKeyPress();
}
else if (nKey == Key_HandUp) // 摘机
{
bHandleUp = TRUE;
if (SystemStatus.Status == Status_Idle) // 空闲状态摘机表示要呼叫分机,相当于按下呼叫键
{
CallKeyPress();
}
else if (SystemStatus.Status == Status_CallBefore)
{
if (KeyBuffer[0] == 6) // 如果已经输入了6位房间号,则提起手柄表示呼叫,否则没有任何反映
{
CallKeyPress();
}
}
else if ((SystemStatus.Status == Status_bCallingIn_M) // 正在被门口机或分机呼叫,摘机表示开始通话
|| (SystemStatus.Status == Status_bCallingIn_F))
{
// 摘机之后,关闭振铃信号,切换到通话的通道
ChangeToTalkChannel();
// 发送摘机命令,等待对方返回
TxFrame.Frame.Addr[0] = ConnectingAddr[0];
TxFrame.Frame.Addr[1] = ConnectingAddr[1];
TxFrame.Frame.Addr[2] = ConnectingAddr[2];
TxFrame.Frame.Addr[3] = ConnectingAddr[3];
TxFrame.Frame.nLength = 0x01;
TxFrame.Frame.aData[0] = Command_HandUp;
TxFrameLength = 6;
RS485SendWaitTimer = MAX_RS485_WAIT_TIMES * 3;
RS485SendTxFrame();
}
}
else if (nKey == Key_HandDown) // 挂机
{
bHandleUp = FALSE;
if ((SystemStatus.Status == Status_Calling) // 如果正在通话的时候挂机,则表示结束通话
|| (SystemStatus.Status == Status_Talking)
|| (SystemStatus.Status == Status_bCallingIn_F)//Status_bCallingIn_F减少无动作
|| (SystemStatus.Status == Status_bCallingIn_M)
|| (SystemStatus.Status == Status_CallSendingRequest) )
{
RS485SendCancelCommand();
ClosePower();
SystemStatus.Status = Status_Idle;
InitDispBuffer(TRUE);
UpdateDisp(FALSE);
}
else if (SystemStatus.Status == Status_CallBefore)// 呼叫分机之前的输入房间号的状态
{
KeyBuffer[0] = 0;
SystemStatus.PreStatus = Status_Idle;
SystemStatus.Status = Status_Idle;
InitDispBuffer(TRUE);
UpdateDisp(FALSE);
}
}
LastKey = nKey; // 保存上一次的按键值
LastKeyTimer = 0x00;
}
// 数字键按下
void NumberKeyPress(BYTE nKey)
{
BYTE i;
switch (SystemStatus.Status)
{
case Status_Idle:
{
// 如果是在显示开机时间的时候按下数字键, 则先将下面一行的显示清空
if ((KeyBuffer[0] == 0x00) && (SystemStatus.Status == Status_Idle))
{
memcpy(&DispBuffer[1][1], " ", DISP_BUF_LENGTH);
}
// 将按键的值放到缓冲区中
if (KeyBuffer[0] < KEY_BUF_LENGTH)
{
KeyBuffer[++KeyBuffer[0]] = nKey;
}
else // 缓冲区满,全体左移
{
// 如果按键缓冲区溢出,则将前面的按键挤出去
for (i=1; i<KEY_BUF_LENGTH; i++)
{
KeyBuffer[i] = KeyBuffer[i+1];
}
KeyBuffer[KEY_BUF_LENGTH] = nKey;
}
// 更新显示缓冲
for (i=1; i<DISP_BUF_LENGTH; i++)
{
DispBuffer[1][i] = DispBuffer[1][i+1];
}
DispBuffer[1][DISP_BUF_LENGTH] = nKey+0x30;
DispBuffer[1][0] = 0x01;
UpdateDisp(FALSE);
break;
}
case Status_ViewBefore: // 如果当前按下了监视按键,则数字的最大长度为4,超过4则挤出去
{
// 将按键的值放到缓冲区中
if (KeyBuffer[0] < 4)
{
KeyBuffer[++KeyBuffer[0]] = nKey;
// 更新显示缓冲
for (i=1; i<=KeyBuffer[0]; i++)
{
DispBuffer[1][ViewBeforeDispOrder[i]] = KeyBuffer[i] | 0x30;
}
DispBuffer[1][0] = 0x01;
UpdateDisp(FALSE);
}
break;
}
case Status_CallBefore: // 呼叫门口机之前的输入房间号的状态
{
if (KeyBuffer[0] < 6)
{
KeyBuffer[++KeyBuffer[0]] = nKey;
// 更新显示缓冲
for (i=1; i<=KeyBuffer[0]; i++) // 将按键的值显示在屏幕上
{
DispBuffer[1][CallBeforeDispOrder[i]] = KeyBuffer[i] | 0x30;
}
DispBuffer[1][0] = 0x01;
UpdateDisp(FALSE);
}
break;
}
case Status_SetupMenu: // 如果是在设置的主菜单界面,则用数字键来代替方向键
{
// 2: Up, 4: Left, 6: Right, 8: Down
switch (nKey)
{
case Key_Two: // 按向上的箭头
{
if (SystemStatus.wParam == 0x01) // 如果选中的是第一行菜单,按向上的箭头则将菜单整体上移一行
{
// 找到该第一行菜单项的上面一个菜单
for (i=1; i<(sizeof(SetupMenu)/sizeof(t_Menu)); i++)
{
if (SetupMenu[i].NextMenu == SystemStatus.lParam)
{
SystemStatus.lParam = i;
break;
}
}
}
else if (SystemStatus.wParam == 0x02) // 如果当前选中的是屏幕上的第二行菜单,则只要将选中移动到第一行即可
{
SystemStatus.wParam = 0x01;
}
else // 意外情况,回到第一项
{
SystemStatus.lParam = 0x00;
SystemStatus.wParam = 0x01;
}
InitDispBuffer(TRUE);
UpdateDisp(TRUE);
break;
}
case Key_Eight: // 按向下的箭头
{
if (SystemStatus.wParam == 0x01)
{
SystemStatus.wParam = 0x02;
}
else if (SystemStatus.wParam == 0x02)
{
SystemStatus.lParam = SetupMenu[SystemStatus.lParam].NextMenu;
}
else
{
i = SetupMenu[SystemStatus.lParam].Parent;
SystemStatus.lParam = SetupMenu[i].Child;
SystemStatus.wParam = 0x01;
}
InitDispBuffer(TRUE);
UpdateDisp(TRUE);
break;
}
case Key_Four: // 向左的箭头
{
// 其功能相当于取消退出到初始状态
CancelKeyPress();
break;
}
case Key_Six: // 向右的箭头
{
// 其功能相当于确定进入该菜单
EnterKeyPress();
break;
}
case Key_One: // Home,回到菜单的最顶端
{
// 找到这一级菜单的第一行菜单: 先找到其父菜单,然后找到其父菜单的第一个子菜单
i = SetupMenu[SystemStatus.lParam].Parent;
SystemStatus.lParam = SetupMenu[i].Child;
SystemStatus.wParam = 0x01;
InitDispBuffer(TRUE);
UpdateDisp(TRUE);
break;
}
case Key_Seven: // End,回到菜单的最底端
{
// 先找到这一级菜单的第一行菜单
i = SetupMenu[SystemStatus.lParam].Parent;
SystemStatus.lParam = SetupMenu[i].Child;
// 然后找到这一级最底下一行菜单
for (i=1; i<(sizeof(SetupMenu)/sizeof(t_Menu)); i++)
{
if (SetupMenu[i].NextMenu == SystemStatus.lParam)
{
SystemStatus.lParam = i;
break;
}
}
// 最后找到最底下一行菜单的上一行菜单,作为屏幕的第一行显示
for (i=1; i<(sizeof(SetupMenu)/sizeof(t_Menu)); i++)
{
if (SetupMenu[i].NextMenu == SystemStatus.lParam)
{
SystemStatus.lParam = i;
SystemStatus.wParam = 0x02;
break;
}
}
InitDispBuffer(TRUE);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -