一、连按、不连按
连按:手一直按按钮保持不松的状态,小灯的状态发生改变
不连按模式:手一直按按钮保持不松的状态相当于只按了一次
三个按键都处于上拉输入状态:按下GPIO口为0
下面程序中用到了static关键字,下面一起来回顾一下:
静态局部变量使用static修饰符定义,即使在声明时未赋初值,编译器也会把它初始化为0。且静态局部变量存储于进程的全局数据区,即使函数返回,它的值也会保持不变。
//static出现在类中 class Person { public: static int i; //类内声明 }; int Person::i; //类外定义 int main() { Person::i = 10; //其他地方可以改变其值 }
u8 keyScan(u8 mode) { static u8 f=1; if(mode) { f=1; } if(f&&(key0==0||key1==0||key2==0)) { delay_ms(10);//延时去抖 f=0; if(key0==0) { return 0; } else if(key1==0) { return 1; } else if(key2==0) { return 2; } } else if(key0==1&&key1==1&&key2==1) { f=1; } return -1; //返回-1表示无按键按下 } void main() { u8 key; delay_init(); //延时函数初始化 Led_init(); //led小灯初始化 Key_init(); //按键初始化 LED0=0; //刚开始使led0小灯处于亮的状态 while(1) { key=keyScan(1); switch(key) { case 0: { LED0=!LED0; //改变led小灯状态 delay_ms(1000); //延时1s break; } case 1: { LED1=!LED1; delay(1000); break; } case 2 { LED0=!LED0; LED1=!LED1; delay(1000); break; } default: { delay_ms(10); } } } }
二、按键复用
按键复用的应用在我们日常生活中非常常见,我们的智能手机的按键很少,只有开关键和音量键,但却能应用复用实现其他功能。
1、长按、短按
下面这个例子中我们来实现只用一个按键来控制两个led小灯的控制。
3s以内:控制LED0
3s以上:控制LED1
u8 key_Scan(u16 time) { u16 count=0; if(key0==0) { delay_ms(10); if(key0==0) { while(key0==0) { delay_ms(10); count++; } } if(count==0) return 0; else if(count*10<time) return 1; else return 2; } return 0; } int main(void) { u8 t=0; delay_init(); LED_Init(); KEY_Init(); LED0=0; while(1) { t=key_Scan(3000); switch(t) { case 0: { break; } case 1: { LED0=!LED0; break; } case 2: { LED1=!LED1; break; } } } }
2、在一定时间内次数复用
1s内按一次:控制LED0
1s内按两次:控制LED1
会使用中断后再写(这都过了三四个月了才想起写)
思路:按键为下降沿中断,触发后打开定时器,定时1s后判断按键次数。
main主函数:
u8 count=0; //记录1s内按下KEY0的次数 int main(void) { delay_init(); //延时函数初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2 TIM3_Int_Init(4999,7199);//10Khz的计数频率,计数到5000为500ms EXTIX_Init(); //KEY0外部中断中断初始化 LED_Init(); //初始化与LED连接的硬件接口 while(1) { } }
中断线5(KEY0)的中断服务程序:
void EXTI9_5_IRQHandler(void) { delay_ms(10); //消抖 if(KEY0==0) { count++; if(count==1) { //打开定时器 TIM_Cmd(TIM3, ENABLE); //开始计时 } } EXTI_ClearITPendingBit(EXTI_Line5); //清除LINE5上的中断标志位 }
定时器3中断服务程序:
void TIM3_IRQHandler(void) //TIM3中断 { if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源 { if(count==1) //1s内按1次KEY0,led0亮 { LED0=!LED0; } else //1s内按1次KEY0,led1亮 { LED1=!LED1; } count=0; TIM_Cmd(TIM3,DISABLE); //停止计时 TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除TIMx的中断待处理位:TIM 中断源 } }
3、两个按键共同按下
单独按下key0,控制ed0
key0和key1一起按下,控制led1
u8 key_Scan2() //一定要不支持连按 { static u8 f=1; if(f&&(KEY0==0||(KEY0==0&&KEY1==0))) { delay_ms(10); if(KEY0==0) { f=0; if(KEY0==0&&KEY1) { return 1; } else if(KEY0==0&&KEY1==0) { return 2; } else return 0; } } else if(KEY0==1) f=1; return 0; } void main(void) { u8 t=0; delay_init(); LED_Init(); KEY_Init(); LED0=0; while(1) { t=key_Scan2(); switch(t) { case 0: { break; } case 1: { LED0=!LED0; break; } case 2: { LED1=!LED1; break; } } } } }