STM32使用HAL库实现按键的单击、双击、长按
目录
- STM32使用HAL库实现按键的单击、双击、长按
-
- 前言
- 具体思路
- 工程配置
- 代码实现
- 实验效果
前言
编程开发环境:STM32CubeIDE
1 2具体思路 3---- 4 5* 初始化一个全局标记 6* 按键中断事件发生后置位标记 7* while死循环中一直检测这个标记,如果被置位那么进行消抖,然后再次检测连接KEY的IO是否处于按下状态,如是则认为本次按键有效 8* 第一次按键事件有效后,启动定时器定时300ms,在此定时期间内如果有二次按下那么就是双击,如果没有按下,等到300ms定时时间到后读取IO电平,如果处于松开状态那么本次就是单击事件,如果还是按下状态那么就再次启动700定时器,700ms过后再次读取IO电平是否处于按下状态,如是那么就是长按。 9 10* * * 11 12工程配置 13---- 14 15我是使用STM32CUBEMX配置生成的工程,配置按键: 16 17 18STM32的定时器有向上、向下计数模式,向上计数就是从0计数到N然后触发中断,向下计数模式就是倒计时到0,由于我们需要二次启动定时器来检测长按,所以再次配置为向下计数模式,分频为7199,计数3000就是定时300ms: 19 20中断配置: 21 22 23 24 25 26代码实现 27---- 28 29 30 /* 31 * key_state位说明: 32 * 33 * bit[15]:按键事件完成标志位 34 * bit[14]:按键中断触发标志位 35 * bit[13]:长按事件触发需要启动第二次定时器标志位 36 * bit[12~0]: 按键计数,=1:单击 =2:双击 =3:长按 37 */ 38 __IO uint16_t key_state = 0; 39 40 int __io_putchar(int ch) 41 { 42 43 44 HAL_UART_Transmit(&huart1, (uint8_t*) &ch, 1, 100); 45 return ch; 46 } 47 48 void TIM4_Stop(void) 49 { 50 51 52 HAL_TIM_Base_Stop_IT(&htim4); 53 } 54 55 void TIM4_Start(uint16_t timeout) 56 { 57 58 59 __HAL_TIM_SET_COUNTER(&htim4, timeout); 60 HAL_TIM_Base_Start_IT(&htim4); 61 } 62 63 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) 64 { 65 66 67 if(htim->Instance == htim4.Instance) 68 { 69 70 71 TIM4_Stop(); 72 if(key_state & 0X2000) // 如果是700ms的超时 73 { 74 75 76 // 再次检测按键如果是按下状态,那么就是长按事件,否则事件无效 77 if(HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) == GPIO_PIN_RESET) 78 { 79 80 81 key_state = 0X8003; 82 }else 83 { 84 85 86 key_state = 0X8000; 87 } 88 } 89 else // 如果是300ms的超时 90 { 91 92 93 // 300ms时间到再次检测按键状态如果仍处于按下状态,那么就启动700ms的超时, 94 // 700ms时间到后再次检测按键如果是按下状态,那么就是长按事件了。 95 if(HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) == GPIO_PIN_RESET) // 按键处于按下状态 96 { 97 98 99 key_state |= 0X2000; // 标记启动了700ms的超时定时 100 TIM4_Start(7000); // 启动700ms超时 101 } 102 else // 按键处于松开状态 103 { 104 105 106 if((key_state & 0X1FFF) == 1) // 按键按下计数=1,是单击事件 107 { 108 109 110 key_state = 0X8001; 111 }else if((key_state & 0X1FFF) >= 2) // 按键按下计数>=2,是双击事件 112 { 113 114 115 key_state = 0X8002; 116 }else // 按键按下计数为其他值,本次按键事件无效 117 { 118 119 120 key_state = 0; 121 } 122 } 123 } 124 } 125 } 126 127 void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) 128 { 129 130 131 switch(GPIO_Pin) 132 { 133 134 135 case KEY_Pin: 136 if((key_state & 0X8000) == 0) 137 { 138 139 140 key_state |= 0X4000; // 标记按键中断触发,在while死循环中进行消抖和的启动定时器 141 } 142 break; 143 default:break; 144 } 145 } 146 147 int main(void) 148 { 149 150 151 HAL_Init(); 152 SystemClock_Config(); 153 MX_GPIO_Init(); 154 MX_USART1_UART_Init(); 155 MX_TIM4_Init(); 156 __HAL_TIM_CLEAR_IT(&htim4, TIM_IT_UPDATE); // STM32的定时器初始化完毕之后如果不清理中断标记为会有直接进入中断的问题 157 158 while (1) 159 { 160 161 162 if(key_state & 0X4000) // 按键中断触发 163 { 164 165 166 key_state &= ~0x4000; // 清除事件 167 HAL_Delay(60); // 消抖延时 168 169 // 消抖完毕之后再次检测按键是否为按下状态,如是则本次按键有效,否则视为无效并清除标识。 170 if(HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) == GPIO_PIN_RESET) 171 { 172 173 174 if((key_state & 0X1FFF) == 0) // 首次按下时启动300ms超时定时器 175 { 176 177 178 TIM4_Start(3000); 179 } 180 key_state++; // 按键按下计数增加 181 } 182 } 183 184 if(key_state & 0X8000) // 按键事件发成了 185 { 186 187 188 switch(key_state) 189 { 190 191 192 case 0X8001: 193 printf("single\r\n"); 194 break; 195 case 0X8002: 196 printf("double\r\n"); 197 break; 198 case 0X8003: 199 printf("hold\r\n"); 200 break; 201 default:break; 202 } 203 key_state = 0; // 清除事件 204 } 205 } 206 } 207 208 209 210* * * 211 212实验效果 213---- 214 215按键单击、双击、长按实验效果如下: 216 217