基于定时器/ST8/单击/双击/多击/长按/短按/等快速移植和思路

         首先我们要明确吗,单击/双击/多击/长按/短按/等思路

        本质思想要区别连击是在松开后处理,通过对比松开的时间间隔来做出连击的反应。

        而长按是在按下后的一段时间后做出时间点的判断。

        短按可以理解为按下后,如果没有松开,或者过一会松开才叫短按,这里要理清楚各个按键的时间节点。 

此外我们写代码思路的流程图应该是先:

        初始化-----读取按键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

  • 7
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值