⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 keyprocess.c

📁 程序概述: 这是个具体产品程序
💻 C
📖 第 1 页 / 共 5 页
字号:
// 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 + -