#include "main.h"
#include "tim.h"
void Key_ExitEvent()
{
static bool flag=true;
if(flag)
{
HAL_GPIO_WritePin(LED0_GPIO_Port,LED0_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin,GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(LED0_GPIO_Port,LED0_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin,GPIO_PIN_SET);
}
flag=!flag;
HAL_TIM_Base_Stop_IT(&htim2);
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin==KEY1_Pin)
{
if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==0)
{
//去除定时器 2(TIM2)的更新中断标志位(UIF) 的宏函数
//防止定时器中断上电误触发
__HAL_TIM_CLEAR_FLAG(&htim2, TIM_SR_UIF);
htim2.Instance->CNT=0;
HAL_TIM_Base_Start_IT(&htim2);
}
else
{
HAL_TIM_Base_Stop_IT(&htim2);
}
}
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM2)
{
//进入定时器中断后再次对按键IO口高低电平进行判断,如果此时按键依然按下说明是长按9
if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==0)
{
Key_ExitEvent();
}
HAL_TIM_Base_Stop_IT(&htim2);
}
}
该程序实现 "按键持续按下 3 秒后执行 LED 状态翻转" 的核心执行过程如下,可分为 4 个关键阶段:
1. 按键按下(触发外部中断)
- 当按键
KEY1被按下(假设低电平有效,即HAL_GPIO_ReadPin返回0)时,触发HAL_GPIO_EXTI_Callback中断回调函数。 - 函数内首先清除定时器
TIM2的更新中断标志位(UIF),防止上电时误触发。 - 清零
TIM2的计数器(CNT),确保从 0 开始计时,然后启动TIM2的定时中断(HAL_TIM_Base_Start_IT),开始 3 秒计时。
2. 定时器计时期间(3 秒内)
TIM2以 3 秒为周期运行,计数器从 0 开始累加。- 若在 3 秒内松开按键(
HAL_GPIO_ReadPin返回1),则再次触发HAL_GPIO_EXTI_Callback,执行else分支:立即停止TIM2定时中断(HAL_TIM_Base_Stop_IT),计时终止,后续无操作。 - 若 3 秒内持续按下按键,
TIM2会继续计时直到 3 秒结束。
3. 定时器 3 秒溢出(触发定时中断)
- 当
TIM2计时满 3 秒,触发HAL_TIM_PeriodElapsedCallback定时中断回调函数。 - 函数内首先判断定时器实例为
TIM2,然后再次检查按键状态 :- 若按键仍处于按下状态(
HAL_GPIO_ReadPin返回0,即持续按下 3 秒),则调用Key_ExitEvent执行操作。 - 若按键已松开(
HAL_GPIO_ReadPin返回1),则不执行任何操作。
- 若按键仍处于按下状态(
- 无论是否执行操作,最终都会停止
TIM2定时中断(HAL_TIM_Base_Stop_IT)。
4. 执行 LED 状态翻转(Key_ExitEvent函数)
- 该函数通过静态变量
flag记录 LED 当前状态,初始为true。 - 当
flag为true时,熄灭 LED(GPIO_PIN_RESET);为false时,点亮 LED(GPIO_PIN_SET)。 - 执行后翻转
flag状态(flag=!flag),并再次停止TIM2(双重保障,防止定时器未正确停止)。
核心逻辑总结
程序通过 "外部中断启动定时 + 定时中断时二次检查按键状态" 的机制,确保只有当按键持续按下满 3 秒时,才会执行 LED 状态翻转;若中途松开按键,会提前终止计时,不执行任何操作,最终实现 "长按 3 秒触发操作" 的功能。