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

2024-06-08 11:12

本文主要是介绍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通用定时器,只是当时笔者没想那么多,使用两个定时器确实造成资源浪费😂,大家只需要再设置一个记录时间的变量,每次进入中断要记录此次进入的时间,在调用时间查函数判断按键持续了多久,很简单的就能实现同样的功能,大家有兴趣的话可以再这个代码的基础上实现逻辑层的应用即可,也就是中断函数里面的部分,不需要大家大改动。

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

这篇关于STM32F103实现双击、长按、短按后续的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1042017

相关文章

windos server2022里的DFS配置的实现

《windosserver2022里的DFS配置的实现》DFS是WindowsServer操作系统提供的一种功能,用于在多台服务器上集中管理共享文件夹和文件的分布式存储解决方案,本文就来介绍一下wi... 目录什么是DFS?优势:应用场景:DFS配置步骤什么是DFS?DFS指的是分布式文件系统(Distr

NFS实现多服务器文件的共享的方法步骤

《NFS实现多服务器文件的共享的方法步骤》NFS允许网络中的计算机之间共享资源,客户端可以透明地读写远端NFS服务器上的文件,本文就来介绍一下NFS实现多服务器文件的共享的方法步骤,感兴趣的可以了解一... 目录一、简介二、部署1、准备1、服务端和客户端:安装nfs-utils2、服务端:创建共享目录3、服

C#使用yield关键字实现提升迭代性能与效率

《C#使用yield关键字实现提升迭代性能与效率》yield关键字在C#中简化了数据迭代的方式,实现了按需生成数据,自动维护迭代状态,本文主要来聊聊如何使用yield关键字实现提升迭代性能与效率,感兴... 目录前言传统迭代和yield迭代方式对比yield延迟加载按需获取数据yield break显式示迭

Python实现高效地读写大型文件

《Python实现高效地读写大型文件》Python如何读写的是大型文件,有没有什么方法来提高效率呢,这篇文章就来和大家聊聊如何在Python中高效地读写大型文件,需要的可以了解下... 目录一、逐行读取大型文件二、分块读取大型文件三、使用 mmap 模块进行内存映射文件操作(适用于大文件)四、使用 pand

python实现pdf转word和excel的示例代码

《python实现pdf转word和excel的示例代码》本文主要介绍了python实现pdf转word和excel的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价... 目录一、引言二、python编程1,PDF转Word2,PDF转Excel三、前端页面效果展示总结一

Python xmltodict实现简化XML数据处理

《Pythonxmltodict实现简化XML数据处理》Python社区为提供了xmltodict库,它专为简化XML与Python数据结构的转换而设计,本文主要来为大家介绍一下如何使用xmltod... 目录一、引言二、XMLtodict介绍设计理念适用场景三、功能参数与属性1、parse函数2、unpa

C#实现获得某个枚举的所有名称

《C#实现获得某个枚举的所有名称》这篇文章主要为大家详细介绍了C#如何实现获得某个枚举的所有名称,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以参考一下... C#中获得某个枚举的所有名称using System;using System.Collections.Generic;usi

Go语言实现将中文转化为拼音功能

《Go语言实现将中文转化为拼音功能》这篇文章主要为大家详细介绍了Go语言中如何实现将中文转化为拼音功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 有这么一个需求:新用户入职 创建一系列账号比较麻烦,打算通过接口传入姓名进行初始化。想把姓名转化成拼音。因为有些账号即需要中文也需要英

C# 读写ini文件操作实现

《C#读写ini文件操作实现》本文主要介绍了C#读写ini文件操作实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录一、INI文件结构二、读取INI文件中的数据在C#应用程序中,常将INI文件作为配置文件,用于存储应用程序的

C#实现获取电脑中的端口号和硬件信息

《C#实现获取电脑中的端口号和硬件信息》这篇文章主要为大家详细介绍了C#实现获取电脑中的端口号和硬件信息的相关方法,文中的示例代码讲解详细,有需要的小伙伴可以参考一下... 我们经常在使用一个串口软件的时候,发现软件中的端口号并不是普通的COM1,而是带有硬件信息的。那么如果我们使用C#编写软件时候,如