经过上次(上一篇文章)的bug,这次进行了修改,基本原理就是使用基本定时器的计数功能,根据计算赋值合适的arr(预装载值)以及psc(预装载系数),使其实现100ms计时一次,在封装两个函数,一个返回当前的时间,另一个计算上次记录的时间与这次之间的比较,废话不多说直接上代码。
time_base.h代码中笔者封装了TIM6以及TIM7,你可以选择都是用这两个计时器,也可以选择使用一个计时器。具体操作只需修改BASE_TIM6 BASE_TIM7这两个宏定义的值即可,0 禁用,1 启用
time_base.h
cpp
/**********
* @Author : 桃杬
* @describe : 实现计时功能
* @Data : 2024.06.08
***************/
#ifndef _TIM_BASE_H
#define _TIM_BASE_H
#include "stm32f10x.h"
#define BASE_TIM6 1
#define BASE_TIM7 0
void 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
cpp
#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;
#endif
void BaseTim_Init(void)
{
//定义TIM结构体
TIM_TimeBaseInitTypeDef TIM_TimBaseInitStructure;
//定义NVIC结构体
NVIC_InitTypeDef NVIC_InitStructure;
//使能时钟
#if BASE_TIM6
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6,ENABLE);
#endif
#if BASE_TIM7
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7,ENABLE);
#endif
//配置TIM
TIM_TimBaseInitStructure.TIM_Period = 7200-1; //预分频系数 psc
TIM_TimBaseInitStructure.TIM_Prescaler = 1000-1; //重装在值 arr
#if BASE_TIM6
TIM_TimeBaseInit(TIM6,&TIM_TimBaseInitStructure); //初始化计数器
#endif
#if BASE_TIM7
TIM_TimeBaseInit(TIM7,&TIM_TimBaseInitStructure); //初始化计数器
#endif
#if BASE_TIM6
TIM_ClearFlag(TIM6,TIM_FLAG_Update); //清除中断标志位
TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE); //开启计数器中断
#endif
#if BASE_TIM7
TIM_ClearFlag(TIM7,TIM_FLAG_Update); //清除中断标志位
TIM_ITConfig(TIM7,TIM_IT_Update,ENABLE); //开启计数器中断
#endif
//配置中断
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); //设置中断组为0组
#if BASE_TIM6
NVIC_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_TIM7
NVIC_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_TIM6
TIM_Cmd(TIM6,ENABLE); //使能计数器
#endif
#if BASE_TIM7
TIM_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
cpp
#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 isEnableKey1
RCC_APB2PeriphClockCmd(KEY1_GPIO_CLK,ENABLE); //key1所在的时钟
#endif
#if isEnableKey2
RCC_APB2PeriphClockCmd(KEY2_GPIO_CLK,ENABLE); //key2所在的时钟
#endif
#if isEnableKey3
RCC_APB2PeriphClockCmd(KEY3_GPIO_CLK,ENABLE); //key3所在的时钟
#endif
#if isEnableKey4
RCC_APB2PeriphClockCmd(KEY4_GPIO_CLK,ENABLE); //key4所在的时钟
#endif
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
//配置KEY
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
#if isEnableKey1
GPIO_InitStructure.GPIO_Pin = KEY1_GPIO_PIN;
GPIO_Init(KEY1_GPIO_PORT,&GPIO_InitStructure);
#endif
#if isEnableKey2
GPIO_InitStructure.GPIO_Pin = KEY2_GPIO_PIN;
GPIO_Init(KEY2_GPIO_PORT,&GPIO_InitStructure);
#endif
#if isEnableKey3
GPIO_InitStructure.GPIO_Pin = KEY3_GPIO_PIN;
GPIO_Init(KEY3_GPIO_PORT,&GPIO_InitStructure);
#endif
#if isEnableKey4
GPIO_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 isEnableKey1
if(KEY1 == RESET) //检测到按键1
{
delay_ms(20); //消抖
if(KEY1 == RESET) //再次检测按键1
{
Key1_Press = 1; //记录此时按键状态
}
}else
Key1_Press = 0;
#endif
#if isEnableKey2
if(KEY2 == RESET) //检测到按键2
{
delay_ms(20); //消抖
if(KEY2 == RESET) //再次检测按键2
Key2_Press = 1; //记录此时按键状态
}else
Key2_Press = 0;
#endif
#if isEnableKey3
if(KEY3 == RESET) //检测到按键3
{
delay_ms(20); //消抖
if(KEY3 == RESET) //再次检测按键3
Key3_Press = 1; //记录此时按键状态
}else
Key3_Press = 0;
#endif
#if isEnableKey4
if(KEY4 == SET) //检测到按键4 注意的是按键四是高电平检测到按键按下
{
delay_ms(20); //消抖
if(KEY4 == SET) //再次检测按键4
Key4_Press = 1; //记录此时按键状态
}else
Key4_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 isEnableKey1
if(Key1_Press)
return 1;
#endif
#if isEnableKey2
if(Key2_Press)
return 2;
#endif
#if isEnableKey3
if(Key3_Press)
return 3;
#endif
#if isEnableKey4
if(Key4_Press)
return 4;
#endif
return 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 isEnableKey1
case 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 isEnableKey2
case 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 isEnableKey3
case 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 isEnableKey4
case 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;
#endif
default:
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通用定时器,只是当时笔者没想那么多,使用两个定时器确实造成资源浪费😂,大家只需要再设置一个记录时间的变量,每次进入中断要记录此次进入的时间,在调用时间查函数判断按键持续了多久,很简单的就能实现同样的功能,大家有兴趣的话可以再这个代码的基础上实现逻辑层的应用即可,也就是中断函数里面的部分,不需要大家大改动。
最后,笔者在此感谢大家耐心的看完👀。