首先我们要明确吗,单击/双击/多击/长按/短按/等思路
本质思想要区别连击是在松开后处理,通过对比松开的时间间隔来做出连击的反应。
而长按是在按下后的一段时间后做出时间点的判断。
短按可以理解为按下后,如果没有松开,或者过一会松开才叫短按,这里要理清楚各个按键的时间节点。
此外我们写代码思路的流程图应该是先:
初始化-----读取按键io口的有效电平----(定时器轮巡xxxms)-----在读取按键io口的有效电平之后判断上次一次的有效值和实际有效值---(不相等)----消抖---区别连击双击的效果
接下来是代码的使用,值得我们注意的是:
(1)如果是长按键设置的计时应该采用uint_16而不是uint_8(因为我们会设置大于255的时间计时。
(2)理清楚每一个计时的变量,防止计时溢出,要及时清0
(3)本代码采用自锁标志位,防止多次触发
(4)理解if else是一个完整的判断语句
(5)分清楚局部变量/全局变量在计时的区别,如果采用全局变量,没有及时清0,会导致是那个数值数值停留在那个位置,而局部变量可以方便的清0初始化
#define _KEY_C_
#include "KEY.h"
uint8_t KEY_Real_Vaule = 0;
uint8_t KEY_Last_Vaule = 0;
uint8_t KEY_STATE = 0;//思考是不是可以用结构体
uint8_t key1_lock_flag; //按键key1自锁标志
uint8_t key2_lock_flag; //按键key2自锁标志
uint8_t key1_short_flag; //按键key1短按标志位
uint8_t key1_one_flag; //单击标志位
uint8_t key2_cnt;
uint8_t key_time;//按键的次数计数
uint8_t key_count_time;//统计按键单击到双击
uint8_t key_component_flag; //组合按键的标志位
uint8_t key_component_cnt; //组合按键的计时
//(1)
//如果按键是松开前判断,会把单击现象给重复计时出现,但如果把按键放在松开后的话,
//可以避免单击伴随双击的出现现象
//(2)
//重点! 有累计的时间的地方要清0
//(3)
//自锁标志-防止按键多次触发.
/单双连续按///
void key_scan(void) //按键松开后判断,
{
static uint16_t key1_cnt = 0;
static uint16_t key2_cnt = 0;
if(PIN_KEY1 == 1) //如果没有按键按下
{
key1_lock_flag = 0; //自锁标志
key1_cnt = 0; //消抖计时
//LED_R = 1;
//LED_G = 1;
//LED_B = 1;
if(key_time>0)
{
key_count_time++;
if(key_count_time > 10)//单击到双击的间隔时间
{
if(key_time == 1)
{
key_led_flag.state = DIS_START;
key_led_flag.mode = DIS_BLINK;
key_led_flag.blink_num = 1;//写一个单击现象
//KeyNum = 1; //单击
key_time = 0;
}
key_count_time = 0; 重点! 有累计的时间的地方要清0
key1_cnt = 0; //清除按键次数
}
}
}
else if (!key1_lock_flag) //按键按下
{
key1_cnt++; //xiaodou?
if(key1_cnt > KEY_SHAKE_TIME)
{
///单击
key1_cnt = 0;
key_count_time = 0;//清除
key_time++;//统计按键次数
key1_lock_flag = 1;//自锁标志-防止按键多次触发
//if(key_time == 1)
//{
// KeyNum = 1; //单击
// //key_time = 0;
//}
if(key_time == 2)
{
//KeyNum = 2; //双击
key_time = 0;
key_led_flag.state = DIS_START;
key_led_flag.mode = DIS_BLINK;
key_led_flag.blink_num = 2;//写一个单击现象
key1_lock_flag = 1;//自锁标志-防止按键多次触发
}
//这里的else if 可以写多个按键次数
}
}
}
短按和连按
void key_scan(void) //按键松开后判断,
{
if(PIN_KEY1 == 1) //如果没有按键按下
{
key1_lock_flag = 0; //自锁标志
key1_cnt = 0; //消抖计时
if(key1_short_flag ) //松开后判断是不是短按
{
key1_short_flag = 0;
key_led_flag.state = DIS_START;
key_led_flag.mode = DIS_BLINK;
key_led_flag.blink_num = 2;//写一个单击现象
}
}
else if (!key1_lock_flag)
//按键按下 ps !key1_lock_flag:
//这是一个条件表达式,
//其中 ! 表示逻辑非,意味着如果 key1_lock_flag 不为真(即为假),则条件成立
{
key1_cnt++; //xiaodou?
if(key1_cnt > KEY_SHAKE_TIME)
{
key1_short_flag = 1;
}
if (key1_cnt > KEY_LONG_TIME)
{
key1_cnt = 0;//计时清0
key1_short_flag = 1;// 短按要清0,避免误判
key1_lock_flag = 1; //防止按键重复触
LED_W_ON();
//key_led_flag.state = DIS_START;
//key_led_flag.mode = DIS_BLINK;
//key_led_flag.blink_num = 5;//写一个长按现象
}
}
}
void key_LED_Ctrl()
{
static uint16_t dis_time_cnt = 0; //显示时间
static uint8_t blink_cnt = 0; //闪烁次数
//显示开始 清变量 转运行状态
if ( key_led_flag.state == DIS_START )
{
dis_time_cnt = 0;
blink_cnt = 0;
key_led_flag.state = DIS_RUN;
key_led_flag.blink_before_off_flag = TRUE;
//key_led_flag.dis_color = DIS_LED_W;
if (key_led_flag.mode == DIS_BREATH )
{
if ( key_led_flag.breath_state == LOW_TO_HEIGHT )
{
Analog_PWM.DUTY = 0;
}
Analog_PWM.EN = ENABLE;
}
else Analog_PWM.EN = DISABLE;
}
else if ( key_led_flag.state == DIS_DONE )
{
key_led_flag.mode = DIS_OFF;
}
//各种模式显示
switch( key_led_flag.mode )
{
// 常亮
case DIS_ON:
if ( dis_time_cnt == 0 )
{
//LED_Select_Color(Display_Ctrl.dis_color);
LED_W_ON();
}
if ( key_led_flag.on_time > ONTIME )
{
if ( ++dis_time_cnt > Display_Ctrl.on_time )
{
key_led_flag.state = DIS_DONE; //完成
}
}
else
{
dis_time_cnt = 1;
}
break;
// 闪烁
case DIS_BLINK:
//闪烁前灭灯避免前灯亮影响
if ( key_led_flag.blink_before_off_flag == TRUE )
{
//灭灯 150ms
dis_time_cnt++;
if ( dis_time_cnt <= 20 ) //定时
{
//LED_Select_Color(DIS_LED_NONE);
//LED_W_OFF();
LED_R = 1;
}
else
{
dis_time_cnt = 0;
key_led_flag.blink_before_off_flag = FALSE; //灭灯完成
}
}
else
{
if ( key_led_flag.blink_num > 0 )
{
dis_time_cnt++;
if ( dis_time_cnt <= 25 )
{
//亮
//LED_Select_Color(Display_Ctrl.dis_color);
//LED_W_ON();
LED_R = 0;
}
else if ( dis_time_cnt <= 50 )
{
//LED_Select_Color(DIS_LED_NONE);
//LED_W_OFF();
LED_R = 1;
}
else
{
dis_time_cnt = 0;
key_led_flag.blink_num--;
}
}
else
{
key_led_flag.state = DIS_DONE; //完成
}
}
break;
//呼吸
case DIS_BREATH:
if ( key_led_flag.breathe_num != BREATHE_2_T )
{
if ( dis_time_cnt > 1 )
{
dis_time_cnt = 0;
}
else
{
dis_time_cnt++;
return;
}
}
// 渐亮
if ( key_led_flag.breath_state == LOW_TO_HEIGHT )
{
if ( Analog_PWM.DUTY < SIM_PWM_LED_CYCLE )
{
Analog_PWM.DUTY++;
}
else
{
if ( key_led_flag.breathe_num == BREATHE_1_T ) //吸烟渐亮到保持常亮
{
key_led_flag.state = DIS_STOP;
}
else
{
key_led_flag.breath_state = HEIGHT_TO_LOW;
}
}
}
// 渐灭
else
{
if ( Analog_PWM.DUTY > 0 )
{
Analog_PWM.DUTY--;
}
else
{
if( key_led_flag.breathe_num == BREATHE_1_T || key_led_flag.breathe_num == BREATHE_2_T)
{
key_led_flag.state = DIS_DONE; //完成
}
else
{
key_led_flag.breath_state = LOW_TO_HEIGHT;
}
}
}
break;
case DIS_OFF:
//Analog_PWM_Duty(0);
key_led_flag.state = DIS_DONE;
break;
}
}
//}
void key_do(void)
{
//uint8_t key_cv = 0;
//key_cv = key_scan();
// key_handle(key_cv);
key_scan();
key_LED_Ctrl();
}
#ifndef KEY_H
#define KEY_H
#include "config.h"
#include "main.h"
#ifdef _KEY_C_
#define KEY_EXT
#else
#define KEY_EXT extern
#endif
//
#define OPEN 1
#define CLOSE 0
#define PRESS 1
#define UN_PRESS 0
#define LOSSEN 1
#define UN_LOSSEN 0
typedef struct
{
uint8_t key_press :1; //按下标志位
uint8_t key_lossen :1; //松开标志
uint8_t state;
}STRUCT_key;
KEY_EXT STRUCT_key key_flag;
//显示状态 state
#define DIS_STOP 0 // 显示停止
#define DIS_START 1 // 显示开始
#define DIS_RUN 2 // 显示中
#define DIS_DONE 3 // 显示完成
//显示状态 state
#define DIS_OFF 5 //灭
#define DIS_ON 1 //亮
#define DIS_BLINK 2 //闪烁
#define DIS_BREATH 3 //呼吸
//按键捆绑
#define PIN_KEY1 PA5
#define PIN_KEY2 PB2
//switch----key
#define KEY_NONE 0
#define KEY_ONE 1
#define KEY_LONG 2
#define KEY_SHORT 3
//按键时间限制
#define KEY_ONE_TIME 10 //10*10MS=100MS
#define KEY_TWO_TIME 100 //
#define KEY_SHORT_TIME 100 //
#define KEY_LONG_TIME 1000 //600* 10MS =6S
#define KEY_SHAKE_TIME 2 //2*10= 20ms
#define KEY_TIMES 10
#define KEY_SHAKEs_TIME // 3*10=30ms //处理消除超过的消抖时间
#define KEY_Continuous_TIME 300//200*10 =1S
#define KEY_lianai_time 200 //100*10=1s
//LED
#define LED_R PA7
#define LED_G PA2
#define LED_B PB0
#define LED_R_ON {LED_R = 0;LED_G = 1; LED_B = 1;}
#define LED_R_OFF {LED_R = 1;LED_G = 1; LED_B = 1;}
//按键状态--led
#define key_none 0
#define key_one 1
#define key_two 2
#define key_short 3
#define key_long 4
#define key_close 5
typedef struct
{
uint8_t Power_On_Init :1; //上电初始化标志位
uint8_t blink_before_off_flag :1; //闪烁前灭灯标志位
uint8_t breath_state :1; //呼吸状态 0:从灭到亮
uint8_t mode; //显示模式
uint8_t state; //显示状态
uint8_t dis_color; //显示颜色
//常亮参数
uint16_t on_time; //常亮时间
//闪烁参数
uint8_t blink_num; //闪烁次数
uint8_t blink_time; //闪烁时间 = blink_time=
//呼吸参数
uint8_t breathe_time; //每隔breathe_time * 5ms(LED执行一次时间)改变占空比
uint8_t breathe_num; //呼吸次数
uint8_t breathe_duty;
}STRUCT_key_LED;
KEY_EXT STRUCT_key_LED key_led_flag;
//效果
#define blink 0
#define breath 1
//声明函数处
//uint8_t key_scan(void);
void key_handle(uint8_t KeyNum);
void key_do(void);
void key_LED_Ctrl();
void key_scan(void); //按键松开后判断,
#endif