51单片机按键双击
关键字:51单片机 按键双击
//hnrain 改 //适用于CEPARK 51开发板
/******************************************************************************************
*********************** www.cepark.com 电子园 按键高阶攻略设计大赛
名称: 2*4矩阵键盘扫描 (状态机) 功能: 按键0单击时,点亮P0口的第1357个LED,按键1双击时,点亮P0口的2468个LED,按键2三
击时,点亮P0口的所有的LED 按键按下的时间间隔小于200ms。 其他键按下时,LED状态不变 作者: alger2009 时间: 2009.12.30 星期三 版本: V1.0 其他: 该开发板的LED不是单个的LED组成,而是LED逻辑卡; 看门狗程序防止程序跑飞 *******************************************************************************************
**********************/
#include "reg52.h" #include "intrins.h" #include "key2.h"
/******宏定义
*******************************************************************************************
********/ #define No_key 255 //无键按下返回值
/****** 定义全局变量
*******************************************************************************************
*/ unsigned char keyread_flag = 0; //矩阵键盘扫描标志位 unsigned char num = 0; //定时计数器计数变量 unsigned char outdata = 0; //返回值
/******2*4矩阵键盘扫描程序
*******************************************************************************************
*** 返回值:key_return key_return = 0 单击 key_return = 1 双击 key_return = 2 三击 key_return = 其他,按键无效 *******************************************************************************************
*****************************/ unsigned char read_keyboard(void) { static unsigned char key_state = 0, key_value, key_line; // 列读取变量,行扫
描码 static unsigned char key_times = 0; //按键击打次数 static unsigned char Tcount = 0; //按键连击计时变量 unsigned char key_return = No_key, i; //按键返回值 switch (key_state) { case 0: //key you meiyou cunzai jiancha //状
态0功能: 按键扫描 连击计时 和连击超时处理 key_line = 0x10; if (key_times != 0) Tcount++; //如果不是第一次击打,计时变量加1
if (Tcount > 20) //若连击按键按下时间间隔大于200毫秒
{ key_times = 0; // 按键击打次数归0 Tcount = 0; // 计时变量归0 } for (i = 0; i < 2; i++) // 扫描键盘 { P2 = ~key_line; // 输入行扫描码 P2 = ~key_line; // 重复送一次 key_value = 0x0f & P2; // 读列电平 if (key_value == 0x0f) key_line <<= 1; // 没有按键,继续扫描 else { key_state++; // 有按键,停止扫描 break; // 跳出按键扫描 } } break; case 1: //状态1功能:确认按键 读取按键值 if (key_value == (0x0f & P2)) // 再次读列电平,若非抖动 { switch (key_line | key_value) //行扫描码和列电平,确认按键 { // 键盘编码,返回编码值 case 0x1e: //单击按键0 key_return = 1; break; case 0x1d: { if(key_times == 1 && Tcount < 20) key_return = 2; //双击按键1 else key_times++; //第一次按下,计数加1 } break; case 0x1b: { if(key_times == 2 && Tcount < 20) key_return = 3; //三击按键2 else key_times++; //第一次或第二次按下,计数加1 } break; case 0x17: key_return = 4; break; case 0x27: key_return = 5; break; case 0x2b: key_return = 6; break; case 0x2d: key_return = 7; break; case 0x2e: key_return = 8; break; } key_state++; // 转入等待按键释放状态 } else key_state--; // 两次列电平不同返回状态0,(消抖处理) break; case 2: //状态2功能:按键释放判定 P2 = 0x0f; // 行线全部输出低电平 P2 = 0x0f; // 重复送一次 if ( (P2 & 0x0f) == 0x0f) key_state = 0; // 按键释放,返回状态0 break; } return key_return; //返回值 }
/******定时器1 定时1毫秒
******************************************************************************/ void timer1(void) interrupt 3 { TH1 = (65536-1000)/256; TL1 = (65536-1000)%256; if(++num == 10) {keyread_flag = 1; //按键扫描允许标志位 num = 0; } }
/******定时器初始化
**********************************************************************************/ void timer1_initial(void) { TH1 = (65536-1000)/256; TL1 = (65536-1000)%256; //装初始值 IE = 0x88; //开总中断和定时器1中断 TMOD = 0x10; //工作方式1 TR1 = 1; //启动定时器 }
/******看门狗子程序
*********************************************************************************/ void clr_wdt(void) { WDTRST=0x1e; WDTRST=0xe1; }
/******主程序
****************************************************************************************/ main(void) { P0 = 0xff; //初始化LED端口 timer1_initial(); //定时器1初始化 while(1) { if(keyread_flag == 1) //矩阵扫描标志位允许 { keyread_flag = 0; clr_wdt(); //调用看门狗 (每2的14次方个机器周期内必须调用一
次,使看门狗复位) outdata = read_keyboard(); //读取矩阵键盘返回值 }
if(outdata == 1) P0 = 0xaa; //单击按键0 点亮第1357个LED else if(outdata == 2) P0 = 0x55; //双击按键1 点亮第2468个LED else if(outdata == 3) P0 = 0x00; //三击按键2 点亮全部LED } }