逻辑是通过定时器溢出周期进行判断按下次数
比如设置定时器溢出周期为500MS,每次溢出都会判断按键按下次数,如果下个周期前没有触发按下,则结束键值判断.并确定触发键值.清空按下次数标志.测试比一个定时器周期按下按键次数判断写法要稳定...
记录STM32实现多功能按键_stm32一个按键实现多种功能-CSDN博客
直接上代码,这里使用的是M4内核芯片,如果需要使用M3则修改初始化代码
按键外部中断代码
#include "exti.h"
#include "key.h"
#include "systick.h"
#include "TIM6.h"#include "io_bit.h" //位带操作 正点原子的是SYS.H
#define KEY1 PAin(0) extern u8 multi_flag; //外部声明//PA0---KEY1
void Exti_Init(void)//函数定义
{EXTI_InitTypeDef EXTI_KEY_Init={0};NVIC_InitTypeDef NVIC_KEY_Init={0};//1.配置SYSCFG系统配置寄存器时钟使能RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);//2.打开GPIOABC外设时钟使能 RCC->AHB1ENRRCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);//KEY1GPIO_InitTypeDef GPIO_KEY_Init={0};GPIO_KEY_Init.GPIO_Mode=GPIO_Mode_IN;GPIO_KEY_Init.GPIO_Pin=GPIO_Pin_0;GPIO_KEY_Init.GPIO_PuPd=GPIO_PuPd_DOWN;GPIO_Init(GPIOA, &GPIO_KEY_Init);//3.映射对应的中断线到IO上SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0);//4.配置EXTI中断初始化EXTI_KEY_Init.EXTI_Line=EXTI_Line0;//中断线EXTI_KEY_Init.EXTI_LineCmd=ENABLE;EXTI_KEY_Init.EXTI_Mode=EXTI_Mode_Interrupt;//中断模式EXTI_KEY_Init.EXTI_Trigger=EXTI_Trigger_Rising;//上升沿触发EXTI_Init(&EXTI_KEY_Init);//5.配置NVIC中断控制器初始化NVIC_KEY_Init.NVIC_IRQChannel=EXTI0_IRQn;NVIC_KEY_Init.NVIC_IRQChannelCmd=ENABLE;NVIC_KEY_Init.NVIC_IRQChannelPreemptionPriority=2;NVIC_KEY_Init.NVIC_IRQChannelSubPriority=2;NVIC_Init(&NVIC_KEY_Init);
}
//6.配置中断服务函数
u8 multi_flag;//记录按下的次数 需要外部声明
void EXTI0_IRQHandler(void)
{int i=20;delay(1500);if(EXTI_GetITStatus(EXTI_Line0)){ TIM_Cmd(TIM6, ENABLE);printf("KEY1外部中断触发,打开定时器\r\n");multi_flag++;//记录按下次数TIM_SetCounter(TIM6,0);//更新计数}//7.清除中断标志 EXTI_ClearITPendingBit(EXTI_Line0);
}
定时器配置:
#include "TIM6.h"
#include "exti.h"void Tim6_Init(uint32_t prc,uint32_t arr)
{//定义结构体变量TIM_TimeBaseInitTypeDef TIM_Time6_Init={};NVIC_InitTypeDef NVIC_Time6_Init={};//对定时器TIM6时钟使能 RCC_APB1ENRRCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM6,ENABLE);//给成员赋值TIM_Time6_Init.TIM_ClockDivision=TIM_CKD_DIV1;//不分频TIM_Time6_Init.TIM_CounterMode=TIM_CounterMode_Up;//TIM6只有向上计数TIM_Time6_Init.TIM_Period=arr;//重装载TIM_Time6_Init.TIM_Prescaler=prc-1;//xxx+1 预分频//定时器TIM_Init()初始化函数调用TIM_TimeBaseInit(TIM6, &TIM_Time6_Init);//使能定时器TIM_Cmd(TIM6, DISABLE);//打开定时器中断TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE);//清除定时器中断标志位TIM_ClearITPendingBit( TIM6,TIM_IT_Update);//NVIC优先级配置 NVIC_Time6_Init.NVIC_IRQChannel=TIM6_DAC_IRQn;//中断源NVIC_Time6_Init.NVIC_IRQChannelCmd=ENABLE;//使能中断NVIC_Time6_Init.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级NVIC_Time6_Init.NVIC_IRQChannelSubPriority=2;//响应优先级 NVIC_Init(&NVIC_Time6_Init);
}
//编写中断服务函数(1s时间进一次中断)
void TIM6_DAC_IRQHandler(void)
{if(TIM_GetITStatus(TIM6,TIM_IT_Update)){TIM_Cmd(TIM6, DISABLE);printf("TIM6定时时间到!\r\n");if(KEY1==0&&multi_flag==1)//松手并且标志位为1---单击 KEY1 位带操作{printf("触发单击!\r\n");}else if(KEY1==0&&multi_flag==2)// KEY1 位带操作{printf("触发双击!\r\n");}else if(KEY1==0&&multi_flag==3){printf("触发三击!\r\n");}else if(KEY1==0&&multi_flag>3){printf("此功能不存在\r\n");}else if(KEY1==1&&multi_flag==1){printf("长按\r\n");}multi_flag=0;//清空标志}//清除中断标志位TIM_ClearITPendingBit( TIM6,TIM_IT_Update);
}