嵌入式按键驱动:支持短按、长按、双击(中断方式)

2019-07-12 23:08发布

概述: 1:本篇利用按键中断输入方式,当按键触发,中断处理函数置按键扫描标志位为1,开始按键键值扫描,完成后,主程序根据键值(短按、长按、双击),完成相应的动作; 2:当K1按键短按:LED1闪烁;当K1按键长按,LED2闪烁;当K1按键双击,LED3闪烁;
3:优点:相比于轮询扫描按键键值的方式,按键响应速度更快,节约CPU资源; 4:参考资料:stm32中文参考手册(EXIT的有关说明)、Cortex-M3权威指南(NVIC的有关说明) 5:开发板:STM32f103ZERT 奋斗开发板V5 开发环境:KEIL MDK5 6:工程下载: stm32外部中断配置 1: 设置中断分组 设置中断优先级之前,一定要设置中断分组,本代码中有sysclk中断和按键外部中断,设置中断中断分组为2,2位主优先级和2位次优先级,需设置内部sysclk中断的优先级高于按键中断的优先级,内部中断使用NVIC_SetPriority()函数设置,具体函数参考core_cm3.h文件,外部中断优先级在NVIC_Init()函数中设置; 2:完成外部中断线路映射 使用GPIO_EXTILineConfig()函数完成中断线路的映射; 3:NVIC寄存器初始化 完成对应中断的使能和优先级设定,使用NVIC_Init()库函数完成初始化。注意:一定要给NVIC_InitStructure结构体的成员赋值,因为NVIC_InitTypeDef结构体是在函数内部定义的,并且没有赋初值,如果不设置的话,结构体中的成员使用编译器默认的初值,有可能会出现错误,因为中断优先级很重要,如果按键中断的优先级高于sysclk中断,按键处理函数中的按键防抖会死循环,具体见下面程序; 4:EXIT寄存器初始化 使能响应的外部中断,并且设置中断的触发方式,使用EXTI_Init()函数完成初始化; 5:程序进行了2次防抖,一次是在按键中断处理函数中,一次是在主程序按键扫描中;
  1. #include "stm32f10x.h"  
  2. #include "Key_Board.h"  
  3. #include "Rcc_Driver.h"  
  4. #include "Led_Driver.h"  
  5. #include "Sysclk_Driver.h"  
  6.   
  7. volatile unsigned int led_flash_timing = 0;  
  8. volatile unsigned int get_keyvalue_timing = 0;  
  9. bool led1_flag = 0;  
  10. bool led2_flag = 0;  
  11. bool led3_flag = 0;  
  12.   
  13. unsigned char i = 0;  
  14.   
  15. int main()  
  16. {  
  17.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);     //设置中断优先级分组  
  18.     RCC_PeriphClock_Config();                           //外设时钟初始化  
  19.     SysTick_Init(INT_1MS,SysTick_CLKSource_HCLK_Div8);  //sysclk定时器初始化  
  20.     Key_Init();                                         //K1按键初始化  
  21.     Led_Init();                                         //LED初始化  
  22.       
  23.     while(1)  
  24.     {  
  25.         if((get_keyvalue_flag == 1) && (get_keyvalue_timing > 20)) //间隔20ms扫面一次,进行按键防抖  
  26.         {  
  27.             get_keyvalue_timing = 0;  
  28.             Get_Key_Value();  
  29.             Key_Func();  
  30.         }  
  31.               
  32.         if(led_flash_timing > 150)  
  33.         {  
  34.             led_flash_timing = 0;  
  35.             if(led3_flash_flag == 1)   //LED3闪烁  
  36.             {  
  37.                 led3_flag = !led3_flag;  
  38.                 if(led3_flag==1)  
  39.                 {  
  40.                     LED3_ON;  
  41.                 }  
  42.                 else  
  43.                 {  
  44.                     LED3_OFF;  
  45.                 }  
  46.             }  
  47.             else  
  48.                 LED3_OFF;  
  49.               
  50.             if(led2_flash_flag == 1)    //LED2闪烁  
  51.             {  
  52.                 led2_flag = !led2_flag;  
  53.                 if(led2_flag==1)  
  54.                 {  
  55.                     LED2_ON;  
  56.                 }  
  57.                 else  
  58.                 {  
  59.                     LED2_OFF;  
  60.                 }  
  61.             }  
  62.             else  
  63.                 LED2_OFF;  
  64.               
  65.             if(led1_flash_flag==1) //LED1闪烁  
  66.             {  
  67.                 led1_flag = !led1_flag;  
  68.                 if(led1_flag==1)  
  69.                 {  
  70.                     LED1_ON;  
  71.                 }  
  72.                 else  
  73.                 {  
  74.                     LED1_OFF;  
  75.                 }  
  76.             }  
  77.             else  
  78.                 LED1_OFF;  
  79.         }  
  80.     }  
  81. }  

Key_Board.c [cpp] view plain copy  在CODE上查看代码片派生到我的代码片
  1. #include "Key_Board.h"  
  2.   
  3. volatile unsigned int delay_timing = 0;  
  4.   
  5. /*记录按键按下时间 时间小于1.5S,按键为短按;时间大于1.5S,按键为长按*/  
  6. volatile unsigned int key1_timing = 0;  
  7.   
  8. /*记录两次短按之间的时间间隔*/  
  9. volatile unsigned int key1_doublepress_timing = 0;  
  10.   
  11. /*定义按键键值结构体*/  
  12. Key_Value k1_value;  
  13.   
  14. /*K1按键短按标志位*/  
  15. bool k1_shortpress_happen = 0;  
  16.   
  17. ///*K1按键长按标志位*/  
  18. //bool k1_longpress_happen = 0;  
  19.   
  20. /*K1按键双击标志位*/  
  21. bool k1_doublepress_happen = 0;  
  22.   
  23. /*led1闪烁时间标志位,主函数检测到此标志位为1时,led1开始闪烁,否则,结束闪烁*/  
  24. bool led1_flash_flag = 0;  
  25.   
  26. /*3个led全部闪烁标志位,主函数检测到此标志为1时,三个led灯开始同时闪烁,否则结束闪烁*/  
  27. bool led2_flash_flag = 0;  
  28.   
  29. /*流水灯事件标志位*/  
  30. bool led3_flash_flag = 0;  
  31.   
  32. /*获取键值标志*/  
  33. volatile bool get_keyvalue_flag = 0;  
  34.   
  35. /*按键初始化 
  36. *k1=GPIOC5 设置GPIOC5为上拉输入 
  37. */  
  38. void Key_Init(void)  
  39. {  
  40.     EXTI_InitTypeDef   EXTI_InitStructure;  
  41.     NVIC_InitTypeDef   NVIC_InitStructure;  
  42.       
  43.     /*按键对应GPIO口初始化*/  
  44.     GPIO_InitTypeDef GPIO_InitStruct;  
  45.     GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;  
  46.     GPIO_InitStruct.GPIO_Pin  = GPIO_Pin_5;