第一个: 功能:按键去抖; 描述:按钮按下时RES1返回1,如果持续按下的时间超过delay_key_on,则置按键状态status_res1为1,不超过则保持status_res1原值; 同样,按钮释放时RES1返回0,如果持续释放的时间超过delay_key_off,则置按键状态status_res1为0,不超过则保持status_res1原值; step_res1:当前处理状态,按下/释放; add_res1:用于累计状态持续时间 ====================== switch(step_res1) //处理输入信号 { case 0: if(RES1) //如果按钮被按下 { add_res1++; if(add_res1>delay_key_on){//如果持续按下的时间足够 status_res1=1;//置当前状态为闭合 add_res1=0;//清计数器 step_res1=1;//进入第二步 } } else{ add_res1=0;//如果按钮被释放,则重新累计 } break; case 1: if(!RES1) //如果按钮被释放 { add_res1++; if(add_res1>delay_key_off){//如果持续释放的时间足够 status_res1=0;//置当前状态为释放 add_res1=0;//清计数器 step_res1=0;//回到第一步 } } else{ add_res1=0;//如果按钮仍然闭合,则重新累计 } break; default: add_res1=0;//若为其他状态,则初始化 step_res1=0; break; }
第二个: 1-头文件:KeyBoard.h #ifndef_Key_Board_h_ #define _Key_Board_h_ #define Key_Up 0x3E //上箭头 #define Key_Down 0x3D //下箭头 #define Key_Add 0x3B //加 #define Key_Sub 0x37 //减 #define Key_Enter 0x2F //回车 #define Key_Return 0x1F //返回 #define Key_LR 0x33 //左右组合键 //可以在此定义其它组合键…… #define Key_NULL 0xFF //无任何按键 //声明几个需要在外部调用的函数 extern void Key_Board_Init(void);//键盘接口初始化 extern u8 Read_Key(void); //读键函数,返回键盘缓冲区中的键值 extern void Key_In(void);//处理按键输入函数,在定时器中断里调用 extern void Key_Board_Test(void); //键盘接口测试函数(仅在调试阶段使用) #endif 2-源文件:KeyBoard.c //#include"includes.h" //公共头文件 #include"Key_Board.h" //键盘缓冲区相关常量定义 #defineKeyBuffLen 8 //定义键值环形缓冲区长度为8(缓冲区大小可自由定义,只要大于0即可) //定义一个键盘缓冲区结构体 structStruct_KeyBoardBuff { u8 buff[KeyBuffLen];//键值环形缓冲区 u8 in; //写键值指示(定时器中断写) u8 out; //读键值指示(用户读) }Key; /************************************************************************* 函数原型:void Key_Board_Init(void) 函数功能:对键盘接口进行初始化,即把键值缓冲区清零 传入参数:无 返回参数:无 全局变量:直接操作键盘缓冲区结构体 修改日期:2007-9-5 备 注:仅在上电初始化的时候被调用一次 **************************************************************************/ voidKey_Board_Init(void) { memset(&Key,0,sizeof(Key)); } /************************************************************************* 函数原型:u8 Read_Key(void) 函数功能:从键值缓冲区读取一个键值 传入参数:无 返回参数:u8型按键值,如果缓冲区为空,则返回-1 修改日期:2007-9-5 备 注:供用户程序调用;用户不用关心键盘底层硬件。 **************************************************************************/ u8Read_Key(void) { u8 Value; if(Key.out != Key.in) { Value=Key.buff[Key.out++];//"读"还没有追上"写",缓冲区有键值,读之 if(Key.out >= KeyBuffLen) //如果"读"跑到了队列尾部,则重新跳回原点 { Key.out=0; } } else { Value=Key_NULL;//"读"追上了"写",缓冲区没有键值,返回空键值 } return(Value); } //判断一个键值的键数(在本硬件里1bit对应一个按键,0表示按键按下) u8 JudgeKey(u8key) { u8 i,count=0; for(i=0;i<6;i++) { if((key & 0x01)==0) count++; key >>= 1; } return(count); } /************************************************************************* 函数原型:void Key_In(void) 函数功能:在定时器中断里每10ms调用1次,处理按键输入,并将按键值放入键值缓冲区中。 支持单键、双键组合键 传入参数:无 返回参数:无 修改日期:2007-10-12 备 注:详细功能和处理算法请参照本文件相关的流程图和文档 **************************************************************************/ enumKeyFSM_Enum //按键状态有限状态机 { _Key_Idle=0, //空闲 _Key1_down, //单键按下消抖 _Key1_press, //单键按下 _Key1_up, //单键抬起消抖 _Key2_down, //双键按下消抖 _Key2_press, //双键按下 _Key2_up, //双键抬起消抖 _Key_confirm, //按键确认成功 }; //处理扫描按键、判断按键、保存键值等。在定时器中断里(周期为10ms以上即可)调用本函数。 voidKey_In(void) { static u8 Key_Input=0; //在此添加获取键值代码(参照硬件电路图) static u8 volatile step=0;//步骤 u8 NewKey = uPSD.DATAIN_A & 0x3F;//读取按键 //获取键值代码结束 u8 num=JudgeKey(NewKey);//判断当前有几个按键按下 switch(step)//状态机 { case _Key_Idle://空闲 { switch(num) { case 1://单键 { Key_Input = NewKey;//保存键值 step = _Key1_down;//单键按下消抖 SoundLight_ms(_TypeLcdBkLED,9000);//LCD背光亮一段时间 break; } case 2://双键 { Key_Input = NewKey;//保存键值 step = _Key2_down;//双键按下消抖 SoundLight_ms(_TypeLcdBkLED,9000);//LCD背光亮一段时间 break; } default://其它 { break; } } break; } case _Key1_down://单键按下消抖 { switch(num) { case 1://单键 { if(NewKey == Key_Input)//键值不变 step = _Key1_press;//单键按下 else step = _Key_Idle;//空闲 break; } case 2://双键 { Key_Input = NewKey;//保存键值 step = _Key2_down;//双键按下消抖 break; } default://其它 { step = _Key_Idle;//空闲 break; } } break; } case _Key1_press://单键按下 { switch(num) { case 1://单键 { if(NewKey != Key_Input)//键值改变 step = _Key1_up;//单键抬起消抖 break; } case 2://双键 { Key_Input = NewKey;//保存键值 step = _Key2_down;//双键按下消抖 break; } default://其它 { step = _Key1_up;//单键抬起消抖 break; } } break; } case _Key1_up://单键抬起消抖 { switch(num) { case 1://单键 { if(NewKey == Key_Input)//键值不变 step = _Key1_press;//单键按下 else step = _Key_confirm;//按键确认成功 break; } case 2://双键 { Key_Input = NewKey;//保存键值 step = _Key2_down;//双键按下消抖 break; } default://其它 { step = _Key_confirm;//按键确认成功 break; } } break; } case _Key2_down://双键按下消抖 { if(NewKey == Key_Input)//键值不变 step = _Key2_press;//双键按下 else step = _Key_Idle;//空闲 break; } case _Key2_press://双键按下 { if(num==0)//无键 step = _Key2_up;//双键抬起消抖 break; } case _Key2_up://双键抬起消抖 { if(num==0)//无键 step = _Key_confirm;//按键确认成功 break; } default://出现异常,流程复位 { step = _Key_Idle;//空闲 break; } } if(step == _Key_confirm)//按键确认成功 { step = _Key_Idle;//空闲 // SoundLight_ms(_TypeLcdBkLED,9000);//LCD背光亮一段时间 //放入键值缓冲区中 if(Key_Input != 0)//如果键值有效,则放入缓冲区中 { // SoundLight_ms(_TypeBeep,30);//蜂鸣器发声30ms // menu_auto_return_s = 60;//60秒后菜单自动返回 Key.buff[Key.in++] = Key_Input; if(Key.in >= KeyBuffLen)//如果"写"跑到了队列尾部,则重新跳回原点 { Key.in=0; } } } //"写"只管在前面跑,不用管"读"在后面怎么追;如果"写"跑了一圈又超过了"读" //就算是自动将缓冲区清空了,这样的算法具有天生的容错性,只会丢掉前面的键值, //而不会崩溃。 } file:///C:/Users/wangchun/AppData/Local/Temp/msohtml1/01/clip_image002.jpg
这些是我摘抄的21IC论坛上,一些大虾的成果,你看看的.
|