?? 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 + -