新唐 N76E003 按键 单击/双击/长按 demo程序
-
#include "N76E003.h" #include "Common.h" #include "Delay.h" #include "SFR_Macro.h" #include "Function_define.h" #define TIMER1_INIT (6663 * 2) UINT8 u8TH1_Tmp,u8TL1_Tmp; UINT8 time_10ms_ok; unsigned char key; #define IO_KEY_INPUT P10 // 按键输入口 #define IO_BEEP P30 #define N_key 0 //无键 #define S_key 1 //单键 #define D_key 2 //双键 #define L_key 3 //长键 #define key_state_0 0 #define key_state_1 1 #define key_state_2 2 #define key_state_3 3 unsigned char key_driver(void) { static unsigned char key_state = key_state_0, key_time = 0; unsigned char key_press, key_return = N_key; key_press = IO_KEY_INPUT; // 读按键I/O电平 switch (key_state) { case key_state_0: // 按键初始态 if (!key_press) key_state = key_state_1; // 键被按下,状态转换到按键消抖和确认状态 break; case key_state_1: // 按键消抖与确认态 if (!key_press) { key_time = 0; // key_state = key_state_2; // 按键仍然处于按下,消抖完成,状态转换到按下键时间的计时状态,但返回的还是无键事件 } else key_state = key_state_0; // 按键已抬起,转换到按键初始态。此处完成和实现软件消抖,其实按键的按下和释放都在此消抖的。 break; case key_state_2: if(key_press) { key_return = S_key; // 此时按键释放,说明是产生一次短操作,回送S_key key_state = key_state_0; // 转换到按键初始态 } else if (++key_time >= 100) // 继续按下,计时加10ms(10ms为本函数循环执行间隔) { key_return = L_key; // 按下时间>1000ms,此按键为长按操作,返回长键事件 key_state = key_state_3; // 转换到等待按键释放状态 } break; case key_state_3: // 等待按键释放状态,此状态只返回无按键事件 if (key_press) key_state = key_state_0; //按键已释放,转换到按键初始态 break; } return key_return; } /*============= 中间层按键处理函数,调用低层函数一次,处理双击事件的判断,返回上层正确的无键、单键、双键、长键4个按键事件。 本函数由上层循环调用,间隔10ms ===============*/ unsigned char key_read(void) { static unsigned char key_m = key_state_0, key_time_1 = 0; unsigned char key_return = N_key,key_temp; key_temp = key_driver(); switch(key_m) { case key_state_0: if (key_temp == S_key ) { key_time_1 = 0; // 第1次单击,不返回,到下个状态判断后面是否出现双击 key_m = key_state_1; } else key_return = key_temp; // 对于无键、长键,返回原事件 break; case key_state_1: if (key_temp == S_key) // 又一次单击(间隔肯定<500ms) { key_return = D_key; // 返回双击键事件,回初始状态 key_m = key_state_0; } else { // 这里500ms内肯定读到的都是无键事件,因为长键>1000ms,在1s前低层返回的都是无键 if(++key_time_1 >= 50) { key_return = S_key; // 500ms内没有再次出现单键事件,返回上一次的单键事件 key_m = key_state_0; // 返回初始状态 } } break; } return key_return; } /* 下面,根据程序分析按键事件的反映时间: 1。对于长键,按下超过1s马上响应,反映最快 2。对于双键,第2次按键释放后马上得到反映。 3。对于单键,释放后延时拖后500ms才能响应,反映最慢。这个与需要判断后面是否有双击操作有关,只能这样。实际应用中,可以调整两次单击间隔时间定义,比如为300ms,这样单击的响应回快一点,单按键操作人员需要加快按键的操作过程。如果产品是针对老年人的,这个时间不易太短,因为年纪大的人,反映和动作都比较慢。 当然,上面两段可以合在一起。我这样做的目的,是为了可以方便的扩展为N击(当然,需要做修改)。可是最底层的就是最基本的操作处理短按和长按,不用改动的。至于双击,还是N击,在中间层处理。这就是程序设计中分层结构的优点。 测试代码环境如下: */ void Timer1_ISR (void) interrupt 3 // timer1定时器10ms中断服务 { TH1 = u8TH1_Tmp; TL1 = u8TL1_Tmp; P06 = ~P06; //P0.3 toggle when interrupt time_10ms_ok = 1; } main(void) { Set_All_GPIO_Quasi_Mode; TIMER1_MODE1_ENABLE; //定时器1, 模式1, 16bit定时器, 定时器值满 0xFFFF -> 0x0000 产生中断。 clr_T1M; //T1M = 0,兼容传统 8051, TIMER1时钟 = Fsys/12 = 16M /12 //set_T1M; //T1M = 1, TIMER1时钟 = Fsys = 16M u8TH1_Tmp = (65536 - TIMER1_INIT)/256; u8TL1_Tmp = (65536 - TIMER1_INIT)%256; TH1 = u8TH1_Tmp; TL1 = u8TL1_Tmp; set_ET1; //enable Timer1 interrupt set_EA; //enable interrupts set_TR1; //Timer1 run while (1) { if (time_10ms_ok) //每10ms执行一次, { time_10ms_ok =0; key = key_read(); //《====== 10ms一次调用按键中间层函数,根据返回键值,点亮不同的LED灯,全面测试按键操作是否正常 if(key == S_key) //短按 { IO_BEEP = 0; Timer0_Delay1ms(10); IO_BEEP = 1; } else if(key == D_key) //双击 { IO_BEEP = 0; Timer0_Delay1ms(50); IO_BEEP = 1; } else if (key == L_key) //长按 { IO_BEEP = 0; Timer0_Delay1ms(150); IO_BEEP = 1; } } } }
Copyright © 2023 深圳全志在线有限公司 粤ICP备2021084185号 粤公网安备44030502007680号