STM32F103实现双击、长按、短按后续

经过上次(上一篇文章)的bug,这次进行了修改,基本原理就是使用基本定时器的计数功能,根据计算赋值合适的arr(预装载值)以及psc(预装载系数),使其实现100ms计时一次,在封装两个函数,一个返回当前的时间,另一个计算上次记录的时间与这次之间的比较,废话不多说直接上代码。

time_base.h代码中笔者封装了TIM6以及TIM7,你可以选择都是用这两个计时器,也可以选择使用一个计时器。具体操作只需修改BASE_TIM6 BASE_TIM7这两个宏定义的值即可,0 禁用,1 启用

time_base.h

/*********** @Author : 桃杬* @describe : 实现计时功能* @Data : 2024.06.08
***************/#ifndef _TIM_BASE_H
#define _TIM_BASE_H#include "stm32f10x.h"#define BASE_TIM6 1
#define BASE_TIM7 0void BaseTim_Init(void);#if BASE_TIM6
uint32_t GetTime6(void);
uint32_t GetTime6Difference(uint32_t new_time,uint32_t last_time);
#endif#if BASE_TIM7
uint32_t GetTime7(void);
uint32_t GetTime7Difference(uint32_t new_time,uint32_t last_time);
#endif#endif

需要注意的是笔者这里只用了TIM6定时器,有需要的大家自行打开。

time_base.c

#include "tim_base.h"/***** 
* 计数时间计数器
* CK_INT:内部时钟,psc:分频系数
* 计算公式 Time(100ms) = (arr+1)/[(CK_INT/(psc+1))/1000]
* 此处设置100ms一跳,即CK_INT标准库设置的为72MHZ,psc设置7199,arr设置999
* 根据公式带入数值 Time(ms) = 1000/72000000HZ/7200/1000 = 100ms
*****/
#if BASE_TIM6
uint32_t Time6_Count = 0;
#endif#if BASE_TIM7
uint32_t Time7_Count = 0;
#endifvoid BaseTim_Init(void)
{//定义TIM结构体TIM_TimeBaseInitTypeDef TIM_TimBaseInitStructure;//定义NVIC结构体NVIC_InitTypeDef NVIC_InitStructure;//使能时钟
#if BASE_TIM6RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6,ENABLE);
#endif#if BASE_TIM7RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7,ENABLE);
#endif//配置TIMTIM_TimBaseInitStructure.TIM_Period = 7200-1;  //预分频系数 pscTIM_TimBaseInitStructure.TIM_Prescaler = 1000-1; //重装在值 arr#if BASE_TIM6TIM_TimeBaseInit(TIM6,&TIM_TimBaseInitStructure); //初始化计数器
#endif#if BASE_TIM7TIM_TimeBaseInit(TIM7,&TIM_TimBaseInitStructure); //初始化计数器
#endif#if BASE_TIM6TIM_ClearFlag(TIM6,TIM_FLAG_Update); //清除中断标志位TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE); //开启计数器中断
#endif#if BASE_TIM7TIM_ClearFlag(TIM7,TIM_FLAG_Update); //清除中断标志位TIM_ITConfig(TIM7,TIM_IT_Update,ENABLE); //开启计数器中断
#endif//配置中断NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); //设置中断组为0组
#if BASE_TIM6NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn; //中断源NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断源NVIC_Init(&NVIC_InitStructure);
#endif#if BASE_TIM7NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn; //中断源NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //子优先级NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断源NVIC_Init(&NVIC_InitStructure);
#endif#if BASE_TIM6TIM_Cmd(TIM6,ENABLE);  //使能计数器
#endif#if BASE_TIM7TIM_Cmd(TIM7,ENABLE);  //使能计数器
#endif
}#if BASE_TIM6
/***
* @func : GetTime6(void)
* @describe : 返回当前时间 设置的是100ms一跳,即100ms为一个单位
* @param : void
* @ret : 返回当前时间 
* @note :可以将时间转换为s,只需在接收时对 Time6_Count/10 操作即可
***/
uint32_t GetTime6(void)
{return Time6_Count;
}/***
* @func : GetTime6Difference(uint32_t new_time,uint32_t last_time)
* @param : new_time : 当前时间, last_time : 上次时间
* @describe : 返回时间差值 设置的是100ms一跳,即100ms为一个单位
* @ret : 返回时间的差值
* @note :可以将时间差值转换为s,只需在接收时对 Time6_Count/10 操作即可
***/
uint32_t GetTime6Difference(uint32_t new_time,uint32_t last_time)
{return (new_time > last_time) ? (new_time - last_time) : (0xFFFFFFFF - last_time + new_time);
}#endif#if BASE_TIM7
/***
* @func : GetTime7(void)
* @describe : 返回当前时间 设置的是100ms一跳,即100ms为一个单位
* @param : void
* @ret : 返回当前时间 
* @note :可以将时间转换为s,只需在接收时对 Time6_Count/10 操作即可
***/
uint32_t GetTime7(void)
{return Time7_Count;
}/***
* @func : GetTime7Difference(uint32_t new_time,uint32_t last_time)
* @param : new_time : 当前时间, last_time : 上次时间
* @describe : 返回时间差值 设置的是100ms一跳,即100ms为一个单位
* @ret : 返回时间的差值
* @note :可以将时间差值转换为s,只需在接收时对 Time6_Count/10 操作即可
***/
uint32_t GetTime7Difference(uint32_t new_time,uint32_t last_time)
{return (new_time > last_time) ? (new_time - last_time) : (0xFFFFFFFF - last_time + new_time);
}#endif#if BASE_TIM6
void TIM6_IRQHandler()
{if(TIM_GetITStatus(TIM6,TIM_IT_Update) == SET) //检测到中断{Time6_Count++;}TIM_ClearFlag(TIM6,TIM_FLAG_Update); //清除定时器溢出中断
}
#endif#if BASE_TIM7
void TIM7_IRQHandler()
{if(ITM6->SR & TIM_SR_UIF) //检测到中断{Time7_Count++;}TIM7->SR = ~TIM_SR_UIF;
}
#endif

key.c

#include "key.h"
#include "delay.h"
#include "time2.h"
#include "s_fputc.h"
#include "tim_base.h"/*** 最终返回状态值 长按 短按 ***/
uint16_t Key_Value = 0x0000;/*** 记录上次最终返回状态值 ***/
uint16_t Old_Key_Value = 0x0000;//初次进入中断标志位
uint8_t Key_IT_Flag = 0;//初级进入双击标志位
uint8_t DoubleClickFlag = 0;//记录上次按键的时间
uint32_t old_time;/***按键按下宏定义***/
#if isEnableKey1
static uint8_t Key1_Press = 0;
#endif#if isEnableKey2
static uint8_t Key2_Press = 0;
#endif#if isEnableKey3
static uint8_t Key3_Press = 0;
#endif#if isEnableKey4
static uint8_t Key4_Press = 0;
#endif/*****
* @func : Key_Init(void)
* @describe : 初始化按键 外部中断 以及嵌套向量中断控制器
* @param : void
* @return : void
* @note : 移植时除了控制优先级和子优先级在此处需改外其他不需要修改这里
*****/
void Key_Init(void)
{//定义GPIO结构体GPIO_InitTypeDef GPIO_InitStructure;//定义外部中断EXTI机构体EXTI_InitTypeDef EXTI_InitStructure;//定义嵌套向量中断控制器NVIC结构体NVIC_InitTypeDef NVIC_InitStructure;//使能时钟#if isEnableKey1RCC_APB2PeriphClockCmd(KEY1_GPIO_CLK,ENABLE); //key1所在的时钟#endif#if isEnableKey2RCC_APB2PeriphClockCmd(KEY2_GPIO_CLK,ENABLE); //key2所在的时钟#endif#if isEnableKey3RCC_APB2PeriphClockCmd(KEY3_GPIO_CLK,ENABLE); //key3所在的时钟#endif#if isEnableKey4RCC_APB2PeriphClockCmd(KEY4_GPIO_CLK,ENABLE); //key4所在的时钟#endifRCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//配置KEYGPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;#if isEnableKey1GPIO_InitStructure.GPIO_Pin = KEY1_GPIO_PIN;GPIO_Init(KEY1_GPIO_PORT,&GPIO_InitStructure);#endif#if isEnableKey2GPIO_InitStructure.GPIO_Pin = KEY2_GPIO_PIN;GPIO_Init(KEY2_GPIO_PORT,&GPIO_InitStructure);#endif#if isEnableKey3GPIO_InitStructure.GPIO_Pin = KEY3_GPIO_PIN;GPIO_Init(KEY3_GPIO_PORT,&GPIO_InitStructure);#endif#if isEnableKey4GPIO_InitStructure.GPIO_Pin = KEY4_GPIO_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;GPIO_Init(KEY4_GPIO_PORT,&GPIO_InitStructure);#endif#if isEnableKey1//配置KEY1外部中断及嵌套向量中断控制器GPIO_EXTILineConfig(KEY1_GPIO_EXTI_PORT_SOURCE,KEY1_GPIO_EXTI_PIN_SOURCE); //选择EXTI的信号源EXTI_InitStructure.EXTI_Line = KEY1_EXTI_LINE; //选择EXTI事件线EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //EXTI中断模式EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; //双边沿中断EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能中断EXTI_Init(&EXTI_InitStructure);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置优先级分组NVIC_InitStructure.NVIC_IRQChannel = KEY1_IRQN; //中断源NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //抢占优先级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //子优先级NVIC_Init(&NVIC_InitStructure);#endif#if isEnableKey2//配置KEY2外部中断及嵌套向量中断控制器GPIO_EXTILineConfig(KEY2_GPIO_EXTI_PORT_SOURCE,KEY2_GPIO_EXTI_PIN_SOURCE); //选择EXTI的信号源EXTI_InitStructure.EXTI_Line = KEY2_EXTI_LINE; //选择EXTI事件线EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //EXTI中断模式EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; //双边沿中断EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能中断EXTI_Init(&EXTI_InitStructure);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置优先级分组NVIC_InitStructure.NVIC_IRQChannel = KEY2_IRQN; //中断源NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //抢占优先级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //子优先级NVIC_Init(&NVIC_InitStructure);#endif#if isEnableKey3//配置KEY3外部中断及嵌套向量中断控制器GPIO_EXTILineConfig(KEY3_GPIO_EXTI_PORT_SOURCE,KEY3_GPIO_EXTI_PIN_SOURCE); //选择EXTI的信号源EXTI_InitStructure.EXTI_Line = KEY3_EXTI_LINE; //选择EXTI事件线EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //EXTI中断模式EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; //双边沿中断EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能中断EXTI_Init(&EXTI_InitStructure);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置优先级分组NVIC_InitStructure.NVIC_IRQChannel = KEY3_IRQN; //中断源NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //抢占优先级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //子优先级NVIC_Init(&NVIC_InitStructure);#endif#if isEnableKey4//配置KEY4外部中断及嵌套向量中断控制器GPIO_EXTILineConfig(KEY4_GPIO_EXTI_PORT_SOURCE,KEY4_GPIO_EXTI_PIN_SOURCE); //选择EXTI的信号源EXTI_InitStructure.EXTI_Line = KEY4_EXTI_LINE; //选择EXTI事件线EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //EXTI中断模式EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; //双边沿中断EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能中断EXTI_Init(&EXTI_InitStructure);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置优先级分组NVIC_InitStructure.NVIC_IRQChannel =KEY4_IRQN; //中断源NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //抢占优先级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //子优先级NVIC_Init(&NVIC_InitStructure);#endif
}/*****
* @func : Key_Scan(void)
* @describe : 检测按键状态
* @param : void
* @return : void
* @note : 1 按下按键 0 松开按键
*****/
void Key_Scan(void)
{#if isEnableKey1if(KEY1 == RESET) //检测到按键1{delay_ms(20); //消抖if(KEY1 == RESET) //再次检测按键1{Key1_Press = 1; //记录此时按键状态}}elseKey1_Press = 0;#endif#if isEnableKey2if(KEY2 == RESET) //检测到按键2{delay_ms(20); //消抖if(KEY2 == RESET) //再次检测按键2Key2_Press = 1; //记录此时按键状态}elseKey2_Press = 0;#endif#if isEnableKey3if(KEY3 == RESET) //检测到按键3{delay_ms(20); //消抖if(KEY3 == RESET) //再次检测按键3Key3_Press = 1; //记录此时按键状态}elseKey3_Press = 0;#endif#if isEnableKey4if(KEY4 == SET) //检测到按键4  注意的是按键四是高电平检测到按键按下{delay_ms(20); //消抖if(KEY4 == SET) //再次检测按键4Key4_Press = 1; //记录此时按键状态}elseKey4_Press = 0;#endif
}/*****
* @func : GetKeyContinuousPressNum(void)
* @describe : 支持按键连续按下
* @param : void
* @return : 按键值
*       @para : 1 按键1; 2 按键2; 3 按键3; 4 按键4
* @note : 无
*****/
uint8_t GetKeyContinuousPressNum(void)
{Key_Scan();#if isEnableKey1if(Key1_Press)return 1;#endif#if isEnableKey2if(Key2_Press)return 2;#endif#if isEnableKey3if(Key3_Press)return 3;#endif#if isEnableKey4if(Key4_Press)return 4;#endifreturn 0;
}/*****
* @func : GetKeyNum(void)
* @describe : 返回按键值
* @param : void
* @return : 按键值
*       @ret : 11 按键1短按; 12 按键1长按; 13 按键1双击
*       @ret : 21 按键2短按; 22 按键2长按; 23 按键2双击
*       @ret : 31 按键3短按; 32 按键3长按; 33 按键3双击
*       @ret : 41 按键4短按; 42 按键4长按; 43 按键4双击
* @note : 返回值如 xx 形式
*         其十位代表按键几 个位则代表长短双击, 1 短按 2 长按 3 双击
*****/
uint8_t GetKeyNum(void)
{//最终返回值static uint8_t keyNum = 0;Key_Scan();if(!Key_IT_Flag){switch(Key_Value){#if isEnableKey1case 0x0001:keyNum = 11;  //按键1短按Old_Key_Value = Key_Value;Key_Value = 0x0000;break;case 0x0002:keyNum = 12;  //按键1长按Old_Key_Value = Key_Value;Key_Value = 0x0000;break;case 0x0004:keyNum = 14;  //按键1双击Old_Key_Value = 0x0000;Key_Value = 0x0000;break;#endif#if isEnableKey2case 0x0010:keyNum = 21;  //按键2短按Old_Key_Value = Key_Value;Key_Value = 0x0000;break;case 0x0020:keyNum = 22;  //按键2长按Old_Key_Value = Key_Value;Key_Value = 0x0000;break;case 0x0040:keyNum = 24;  //按键2双击Old_Key_Value = 0x0000;Key_Value = 0x0000;break;#endif#if isEnableKey3case 0x0100:keyNum = 31;  //按键3短按Old_Key_Value = Key_Value;Key_Value = 0x0000;break;case 0x0200:keyNum = 32;  //按键3长按Old_Key_Value = Key_Value;Key_Value = 0x0000;break;case 0x0400:keyNum = 34;  //按键3双击Old_Key_Value = 0x0000;Key_Value = 0x0000;break;#endif#if isEnableKey4case 0x1000:keyNum = 41;  //按键4短按Old_Key_Value = Key_Value;Key_Value = 0x0000;break;case 0x2000:keyNum = 42;  //按键4长按Old_Key_Value = Key_Value;Key_Value = 0x0000;break;case 0x4000:keyNum = 44;  //按键4双击Old_Key_Value = 0x0000;Key_Value = 0x0000;break;#endifdefault:keyNum = 0;Key_Value = 0x0000;break;}}return keyNum;
}#if isEnableKey1
/*****
* @func : EXTI1_IRQHandler()
* @describe : 中断函数
* @param : void
* @return : void
* @note : 中断需要的处理的操作在此处执行
*****/
void EXTI1_IRQHandler()
{static uint8_t Key1State = 0; //静态按键1状态 0 松开 1按下if((EXTI_GetITStatus(KEY1_EXTI_LINE) != RESET) && (Key1_Press && Key1State))  //发生中断并且检测到松开按键{Key1State = 0; //松开标志Key_IT_Flag = 0; //退出中断标志位TIM_Cmd(TIM2,DISABLE); //关闭时钟if((Time_Count > 0 && Time_Count <= 20) && !DoubleClickFlag) //短按时间判断{old_time = GetTime6(); //记录此次获取的时间DoubleClickFlag = 1; //改变标志位Old_Key_Value = KEY1_DoubleClick_Value; //记录上次返回的状态值
//            printf("old_time = %d\n",old_time); //测试时打开}else if((Time_Count > 0 && Time_Count <= 20) && DoubleClickFlag){if((GetTime6Difference(GetTime6(),old_time) <= 5) && (Old_Key_Value == KEY1_DoubleClick_Value)) //两次按键之间差值不超过500ms,视为双击{DoubleClickFlag = 0; //重置初次进入标志位Key_Value = KEY1_DoubleClick_Value; //返回双击状态值
//                printf("time_difference = %d\n",GetTime6Difference(GetTime6(),old_time)); //测试时打开}else {
//                printf("updata time_difference = %d\n",GetTime6Difference(GetTime6(),old_time)); //测试时打开old_time = GetTime6(); //更新时间Old_Key_Value = KEY1_DoubleClick_Value; //记录上次返回的状态值
//                printf("update old_time = %d\n",old_time); //测试时打开}}else if(Time_Count > 20 && Time_Count <= 40)  //短按时间判断Key_Value = KEY1_ShortPress_Value;  //短按时间返回状态值else if(Time_Count > 40)  //长按时间判断Key_Value = KEY1_LongPress_Value;  //长按时间返回状态值//        printf("Time_Count : %d\n",Time_Count); //测试时使用EXTI_ClearITPendingBit(KEY1_EXTI_LINE); //清除中断标志位} else if((EXTI_GetITStatus(KEY1_EXTI_LINE) != RESET) &&(!Key_IT_Flag && !Key1State)) //发生中断并且按下按键{Key1State = 1; //按下标志位Key_IT_Flag = 1; //已进入中断标志位Time_Count = 0; //每次按下从0开始计时TIM_Cmd(TIM2,ENABLE); //开启时钟EXTI_ClearITPendingBit(KEY1_EXTI_LINE); //清除中断标志位}
}#endif#if isEnableKey2
/*****
* @func : EXTI9_5_IRQHandler()
* @describe : 中断函数
* @param : void
* @return : void
* @note : 中断需要的处理的操作在此处执行
*****/
void EXTI9_5_IRQHandler()
{static uint8_t Key2State = 0; //静态按键1状态 0 松开 1按下if((EXTI_GetITStatus(KEY2_EXTI_LINE) != RESET) && (Key2_Press && Key2State))  //发生中断并且检测到松开按键{Key2State = 0; //松开标志Key_IT_Flag = 0; //退出中断标志位TIM_Cmd(TIM2,DISABLE); //关闭时钟if((Time_Count > 0 && Time_Count <= 20) && !DoubleClickFlag) //短按时间判断{old_time = GetTime6(); //记录此次获取的时间DoubleClickFlag = 1; //改变标志位Old_Key_Value = KEY2_DoubleClick_Value; //记录上次返回的状态值
//            printf("old_time = %d\n",old_time); //测试时打开}else if((Time_Count > 0 && Time_Count <= 20) && DoubleClickFlag){if((GetTime6Difference(GetTime6(),old_time) <= 5) && (Old_Key_Value == KEY2_DoubleClick_Value)) //两次按键之间差值不超过500ms,视为双击{DoubleClickFlag = 0; //重置初次进入标志位Key_Value = KEY2_DoubleClick_Value; //返回双击状态值
//                printf("time_difference = %d\n",GetTime6Difference(GetTime6(),old_time)); //测试时打开}else {
//                printf("updata time_difference = %d\n",GetTime6Difference(GetTime6(),old_time)); //测试时打开old_time = GetTime6(); //更新时间Old_Key_Value = KEY2_DoubleClick_Value; //记录上次返回的状态值
//                printf("update old_time = %d\n",old_time); //测试时打开}}else if(Time_Count > 20 && Time_Count <= 40)  //短按时间判断Key_Value = KEY2_ShortPress_Value;  //短按时间返回状态值else if(Time_Count > 40)  //长按时间判断Key_Value = KEY2_LongPress_Value;  //长按时间返回状态值//        printf("Time_Count : %d\n",Time_Count); //测试时使用EXTI_ClearITPendingBit(KEY2_EXTI_LINE); //清除中断标志位} else if((EXTI_GetITStatus(KEY2_EXTI_LINE) != RESET) &&(!Key_IT_Flag && !Key2State)) //发生中断并且按下按键{Key2State = 1; //按下标志位Key_IT_Flag = 1; //已进入中断标志位Time_Count = 0; //每次按下从0开始计时TIM_Cmd(TIM2,ENABLE); //开启时钟EXTI_ClearITPendingBit(KEY2_EXTI_LINE); //清除中断标志位}
}#endif#if isEnableKey3
/*****
* @func : EXTI4_IRQHandler()
* @describe : 中断函数
* @param : void
* @return : void
* @note : 中断需要的处理的操作在此处执行
*****/
void EXTI4_IRQHandler()
{static uint8_t Key3State = 0; //静态按键1状态 0 松开 1按下if((EXTI_GetITStatus(KEY3_EXTI_LINE) != RESET) && (Key3_Press && Key3State))  //发生中断并且检测到松开按键{Key3State = 0; //松开标志Key_IT_Flag = 0; //退出中断标志位TIM_Cmd(TIM2,DISABLE); //关闭时钟if((Time_Count > 0 && Time_Count <= 20) && !DoubleClickFlag) //短按时间判断{old_time = GetTime6(); //记录此次获取的时间DoubleClickFlag = 1; //改变标志位Old_Key_Value = KEY3_DoubleClick_Value; //记录上次返回的状态值
//            printf("old_time = %d\n",old_time); //测试时打开}else if((Time_Count > 0 && Time_Count <= 20) && DoubleClickFlag){if((GetTime6Difference(GetTime6(),old_time) <= 5) && (Old_Key_Value == KEY3_DoubleClick_Value)) //两次按键之间差值不超过500ms,视为双击{DoubleClickFlag = 0; //重置初次进入标志位Key_Value = KEY3_DoubleClick_Value; //返回双击状态值
//                printf("time_difference = %d\n",GetTime6Difference(GetTime6(),old_time)); //测试时打开}else {
//                printf("updata time_difference = %d\n",GetTime6Difference(GetTime6(),old_time)); //测试时打开old_time = GetTime6(); //更新时间Old_Key_Value = KEY3_DoubleClick_Value; //记录上次返回的状态值
//                printf("update old_time = %d\n",old_time); //测试时打开}}else if(Time_Count > 20 && Time_Count <= 40)  //短按时间判断Key_Value = KEY3_ShortPress_Value;  //短按时间返回状态值else if(Time_Count > 40)  //长按时间判断Key_Value = KEY3_LongPress_Value;  //长按时间返回状态值//        printf("Time_Count : %d\n",Time_Count); //测试时使用
//        EXTI_ClearITPendingBit(KEY3_EXTI_LINE); //清除中断标志位} else if((EXTI_GetITStatus(KEY3_EXTI_LINE) != RESET) &&(!Key_IT_Flag && !Key3State)) //发生中断并且按下按键{Key3State = 1; //按下标志位Key_IT_Flag = 1; //已进入中断标志位Time_Count = 0; //每次按下从0开始计时TIM_Cmd(TIM2,ENABLE); //开启时钟EXTI_ClearITPendingBit(KEY3_EXTI_LINE); //清除中断标志位}
}#endif#if isEnableKey4
/*****
* @func : EXTI0_IRQHandler()
* @describe : 中断函数
* @param : void
* @return : void
* @note : 中断需要的处理的操作在此处执行
*****/
void EXTI0_IRQHandler()
{static uint8_t Key4State = 0; //静态按键1状态 0 松开 1按下if((EXTI_GetITStatus(KEY4_EXTI_LINE) != RESET) && (Key4_Press && Key4State))  //发生中断并且检测到松开按键{Key4State = 0; //松开标志Key_IT_Flag = 0; //退出中断标志位TIM_Cmd(TIM2,DISABLE); //关闭时钟if((Time_Count > 0 && Time_Count <= 20) && !DoubleClickFlag) //短按时间判断{old_time = GetTime6(); //记录此次获取的时间DoubleClickFlag = 1; //改变标志位Old_Key_Value = KEY4_DoubleClick_Value; //记录上次返回的状态值
//            printf("old_time = %d\n",old_time); //测试时打开}else if((Time_Count > 0 && Time_Count <= 20) && DoubleClickFlag){if((GetTime6Difference(GetTime6(),old_time) <= 5) && (Old_Key_Value == KEY4_DoubleClick_Value)) //两次按键之间差值不超过500ms,视为双击{DoubleClickFlag = 0; //重置初次进入标志位Key_Value = KEY4_DoubleClick_Value; //返回双击状态值
//                printf("time_difference = %d\n",GetTime6Difference(GetTime6(),old_time)); //测试时打开}else {
//                printf("updata time_difference = %d\n",GetTime6Difference(GetTime6(),old_time)); //测试时打开old_time = GetTime6(); //更新时间Old_Key_Value = KEY4_DoubleClick_Value; //记录上次返回的状态值
//                printf("update old_time = %d\n",old_time); //测试时打开}}else if(Time_Count > 20 && Time_Count <= 40)  //短按时间判断Key_Value = KEY4_ShortPress_Value;  //短按时间返回状态值else if(Time_Count > 40)  //长按时间判断Key_Value = KEY4_LongPress_Value;  //长按时间返回状态值//        printf("Time_Count : %d\n",Time_Count); //测试时使用EXTI_ClearITPendingBit(KEY4_EXTI_LINE); //清除中断标志位} else if((EXTI_GetITStatus(KEY4_EXTI_LINE) != RESET) &&(!Key_IT_Flag && !Key4State)) //发生中断并且按下按键{Key4State = 1; //按下标志位Key_IT_Flag = 1; //已进入中断标志位Time_Count = 0; //每次按下从0开始计时TIM_Cmd(TIM2,ENABLE); //开启时钟EXTI_ClearITPendingBit(KEY4_EXTI_LINE); //清除中断标志位}
}#endif

其余的代码跟上一篇文章一样,在这里笔者就不发了。

其实仅仅使用基本定时器或者Systick滴答定时器就能实现长按、短按、以及双击操作,并不需要开启TIM2通用定时器,只是当时笔者没想那么多,使用两个定时器确实造成资源浪费😂,大家只需要再设置一个记录时间的变量,每次进入中断要记录此次进入的时间,在调用时间查函数判断按键持续了多久,很简单的就能实现同样的功能,大家有兴趣的话可以再这个代码的基础上实现逻辑层的应用即可,也就是中断函数里面的部分,不需要大家大改动。

最后,笔者在此感谢大家耐心的看完👀。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/24486.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

校园生活服务平台的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;用户管理&#xff0c;跑腿管理&#xff0c;文娱活动管理&#xff0c;活动申请管理&#xff0c;备忘录管理 前台账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff…

正确挑选百兆超薄款工业级网络/脉冲变压器(网络隔离滤波器)

Hqst华强盛&#xff08;石门盈盛电子&#xff09;导读&#xff1a;工业级百兆超薄款网络变压器的生产要特殊的超薄磁芯配正确线径的铜线&#xff0c;使用符合相应防潮标准的凝固胶水。 一 ̖ 首先来看下商业级的超薄款的百兆网络变压器&#xff1a; 商业级&#xff08;消费级&…

麒麟操作系统运维工程师(KYCP)课程,实现职业突破

在IT行业中&#xff0c;掌握先进的技能和知识是实现职业突破的关键。如果你希望在麒麟操作系统上成为一名卓越的运维工程师&#xff0c;那么麒麟操作系统运维工程师&#xff08;KYCP&#xff09;课程将是你的理想全面提升学员在麒麟操作系统环境下的运维能力。课程内容涵盖安全…

mac读不出来ntfs mac硬盘读不出来盘

新买的Mac电脑由于需要导入旧电脑的数据&#xff0c;因此通常会读取备份硬盘&#xff0c;通过硬盘进行导入。不过由于各种原因&#xff0c;有些mac用户反馈无法正常读取或写入NTFS移动硬盘&#xff0c;下面就通过本篇教程&#xff0c;简单讲述当mac读不出来ntfs&#xff0c;mac…

开关电源中电感设计

开关电源设计中电感 只有充分理解电感在DC/DC电路中发挥的作用,才能更优的设计DC/DC电路。本文还包括对同步DC/DC及异步DC/DC概念的解释。 在开关电源的设计中电感的设计为工程师带来的许多的挑战。工程师不仅要选择电感值,还要考虑电感可承受的电流,绕线电阻,机械尺寸等…

监控易监测对象及指标之:全面监控华为FusionInsight实例

在大数据时代&#xff0c;华为FusionInsight作为一款高性能的大数据处理平台&#xff0c;承载着企业关键业务数据的处理和分析任务。为了确保FusionInsight实例的稳定运行&#xff0c;对其进行全面监控显得尤为重要。本文基于监控易工具&#xff0c;对华为FusionInsight实例的监…

产气荚膜梭菌定植与婴儿食物过敏之间的关联

谷禾健康 牛奶蛋白过敏&#xff08;CMPA&#xff09;是婴儿最常见的食物过敏类型之一。粪便病原菌培养显示产气荚膜梭菌阳性率超过30%&#xff0c;明显高于其他细菌。因此推测产气荚膜梭菌定植可能是婴儿牛奶蛋白过敏的发病因素之一。 一项真实世界的研究&#xff0c;杨敏团队从…

Linux操作系统:MongoDB在虚拟机环境下的安装及部署

上传 MongoDB 安装包 将从官网下载好的 MongoDB 上传到要安装的服务器目录中&#xff0c;建议目录为&#xff1a;/usr/local/ 解压 MongoDB 安装包 cd /usr/local/ tar -zxvf mongodb-linux-x86_64-4.0.0.tgz mv mongodb-linux-x86_64-4.0.0 mongodb 创建 MongoDB 必要目录 …

高通CSIPHY combo mode介绍

目录 使用MIPI Switch 使用高通平台CSIPHY的Combo Mode YYYY使用Combo Mode电路图如下: 如何设置combo PHY mode CSIInfo configuration when camera works in normal mode 平台SoC一般都有多个CSIPHY以满足当前手机相机设计多摄的情况,但是一款SoC CSIPHY的个数也是一定…

【python】错误SyntaxError: invalid syntax的解决方法总结

解决Python报错&#xff1a;【Python】错误SyntaxError: invalid syntax的解决方法总结 SyntaxError是Python编程中常见的错误之一&#xff0c;它表明代码中有语法错误。这种错误可能由多种原因引起&#xff0c;包括但不限于拼写错误、错误的缩进、缺少括号等。本文将介绍几种常…

Python 机器学习 基础 之 【常用机器学习库】 scikit-learn 机器学习库

Python 机器学习 基础 之 【常用机器学习库】 scikit-learn 机器学习库 目录 Python 机器学习 基础 之 【常用机器学习库】 scikit-learn 机器学习库 一、简单介绍 二、scikit-learn 基础 1、安装 scikit-learn 2、导入 scikit-learn 3、数据准备 4、数据分割 5、训练模…

使用Gitblit软件开启git服务器

文章目录 使用Gitblit软件开启git服务器&#xff0c;供局域网其他电脑当做git仓库服务1. java依赖环境安装2. Mac系统操作2.1 下载Gitblit、配置参数2.2 启动服务2.3 终止服务&#xff1a;停止脚本即可 3. window系统操作3.1 下载Gitblit、配置参数3.2 启动服务3.3 终止服务&am…

Einstein Summation 爱因斯坦求和 torch.einsum

Einstein Summation 爱因斯坦求和 torch.einsum flyfish 理解爱因斯坦求和的基本概念和语法&#xff0c;这对初学者来说可能有一定难度。对于不熟悉该表示法的用户来说&#xff0c;可能不如直接的矩阵乘法表达式易于理解。 整个思路是 向量的点积 -》矩阵乘法-》einsum 向…

揭秘抖音矩阵号低成本高效运作批量账号的秘诀!

在当今互联网时代,抖音矩阵号搭建已经成为了许多企业和个人追求高效率媒介管理的重要方式,但是高效、低成本地运作这些账号却是一个相当具有挑战性的任务。 在这篇文章中,我将从抖音矩阵账号准备,如何低成本制作视频以及在进行内容制作时,如何高效运作批量账号等大家比较…

翻译软件就用DT浏览器

翻译软件就用DT浏览器

GUI GUIDER、LVGL、LCD驱动关系

理解GUI Guider、LVGL和LCD驱动之间的关系对于开发嵌入式图形用户界面&#xff08;GUI&#xff09;非常重要。以下是它们之间关系的详细说明&#xff1a; 1. LVGL&#xff08;Light and Versatile Graphics Library&#xff09; 简介&#xff1a;LVGL 是一个轻量级、灵活的嵌…

LeetCode 7- 整数反转

给你一个 32 位的有符号整数 x &#xff0c;返回将 x 中的数字部分反转后的结果。 如果反转后整数超过 32 位的有符号整数的范围 [-231, 231 - 1] &#xff0c;就返回 0。 假设环境不允许存储 64 位整数&#xff08;有符号或无符号&#xff09;。 示例 1&#xff1a; 输入&…

最长递增子序列 - LeetCode 热题 87

大家好&#xff01;我是曾续缘&#x1f496; 今天是《LeetCode 热题 100》系列 发车第 87 天 动态规划第 7 题 ❤️点赞 &#x1f44d; 收藏 ⭐再看&#xff0c;养成习惯 最长递增子序列 给你一个整数数组 nums &#xff0c;找到其中最长严格递增子序列的长度。 子序列 是由数组…

diffusers 使用脚本导入自定义数据集

在训练扩散模型时&#xff0c;如果附加额外的条件图片数据&#xff0c;则需要我们准备相应的数据集。此时我们可以使用官网提供的脚本模板来控制导入我们需要的数据。 您可以参考官方的教程来实现具体的功能需求&#xff0c;为了更加简洁&#xff0c;我将简单描述一下整个流程…

CentOS 7基础操作13_Linux下添加、修改、删除用户账号

1、添加、修改、删除用户账号 1&#xff09;useradd命令——添加用户账号。 useradd [选项] 用户名 最简单的用法是&#xff0c;不添加任何选项&#xff0e;只使用用户名作为useradd命令的参数&#xff0c;按系统默认配置建立指定的用户账号。在CentOS系统中&#xff0…