蓝桥杯单片机---独立按键单击、长按、双击检测

一、文章概述

  1. 本文章将介绍基于蓝桥杯单片机实现独立按键的单击、长按、双击状态检测。主要思路为主函数不断扫描按键状态,若有按键按下,记录从按键按下到按键松开所需时间,如果时间超过1s即为长按。如果时间小于500ms则开启双击检测,启动双击间隔时间计时,如果经过230ms还没有按键按下则为单击,如果在230ms内检测到按键按下返回双击状态。
  2. 代码实现功能:蓝桥杯开发板跳帽接到独立按键时可支持键盘第一列四个独立按键的单击、长按、双击状态检测(采用switch语句实现多按键同时检测)。

二、代码解析

  • separate_key.c

#include "separate_key.h"

sbit S7=P3^0;  //按键引脚定义
sbit S6=P3^1;
//================按键KEY7变量定义===================//
volatile bit KeyTimerState=0;  //控制定时器是否开始计时按键按下时间
volatile bit KeyDoubleTimerState=0; //控制定时器是否开始计时双击间隔时间
volatile u16 PressTime=0;      //按键按下时间
volatile u16 PressDoubleTime=0;  //双击间隔时间
volatile bit PressState=1;   //判断是否为误触
volatile bit KeyDoubleCount=0;  //双击标志位,可防止双击检测过程循环执行时重复执行判断按键初次按下是否误触和第一次按下是否长按
//================按键KEY6变量定义===================//
volatile bit KeyTimerState1=0;  //控制定时器是否开始计时按键按下时间
volatile bit KeyDoubleTimerState1=0; //控制定时器是否开始计时双击间隔时间
volatile u16 PressTime1=0;      //按键按下时间
volatile u16 PressDoubleTime1=0;  //双击间隔时间
volatile bit PressState1=1;   //判断是否为误触
volatile bit KeyDoubleCount1=0;  //双击标志位

extern void SmgDisplay(void);

void Delay2ms(void)	//@12.000MHz
{
	unsigned char data i, j;

	i = 24;
	j = 85;
	do
	{
		while (--j);
	} while (--i);
}

void Timer0Init(void)		//2毫秒@12.000MHz
{
	AUXR |= 0x80;		//定时器时钟1T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0x40;		//设置定时初始值
	TH0 = 0xA2;		//设置定时初始值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
    
    ET0=1;
    EA=1;
}

void Timer0(void)  interrupt 1 //定时器0中断服务函数中实现按键按下时间、双击间隔时间和数码管显示
{
    if(KeyTimerState==1)
        PressTime++;
    else 
        PressTime=0;
    
    if(KeyDoubleTimerState==1)
        PressDoubleTime++;
    else 
        PressDoubleTime=0;
    
    if(KeyTimerState1==1)
        PressTime1++;
    else 
        PressTime1=0;
    
    if(KeyDoubleTimerState1==1)
        PressDoubleTime1++;
    else 
        PressDoubleTime1=0;
    
    SmgDisplay();
}

u8 KeyScan(u8 key) //switch函数内部(KEY7和KEY6)即(case0和case1)的代码实现逻辑相同,以此类推将case后代码复制一次即可增加对一个按键的检测 
{
    switch(key)
    {
        case 0:if((S7==0)&&(KeyTimerState==0)&&(KeyDoubleCount==0))
        {
            Delay2ms();   //消抖
            if(S7==0)
            {
                KeyTimerState=1;    //开始计算按下时长
                PressState=0;       //按键按下标志
            }
            else
                KeyTimerState=0;
            
        }
        if((PressState==0)&&(S7==1)&&(KeyDoubleCount==0))    //判断按键松开时间
        {
            if(PressTime<250)   //500ms内松开为短按
            {
                KeyDoubleCount=1;  //进入双击检测
                PressState=1; 
                KeyTimerState=0;
                KeyDoubleTimerState=1;  //双击标志位置1,开始进入双击检测
            }
            if(PressTime>500)  //超过500ms为长按
            {
                KeyTimerState=0;
                PressState=1;
                return KEY7_LONG;
            }
        }
        if((KeyDoubleCount==1)&&(PressDoubleTime<115)&&(S7==0))  //如果双击间隔时间小于 
230ms时有按键按下为双击                                                                       
        {                                                        
                Delay2ms();
                if(S7==0)
                {
                    KeyDoubleCount=0;
                    KeyDoubleTimerState=0;
                    while(S7==0);
                    return KEY7_DOUBLE;
                }
            
        }
        if(PressDoubleTime>115) //双击间隔时间超过230ms仍无按键按下为单击
        {
            KeyDoubleCount=0;
            KeyDoubleTimerState=0;
            return KEY7_SHORT;
        }
        break;
    
    
    case 1:if((S6==0)&&(KeyTimerState1==0)&&(KeyDoubleCount1==0))
        {
            Delay2ms();   //消抖
            if(S6==0)
            {
                KeyTimerState1=1;    //开始计算按下时长
                PressState1=0;
            }
            else
                KeyTimerState1=0;
            
        }
        if((PressState1==0)&&(S6==1)&&(KeyDoubleCount1==0))    //判断按键松开时间
        {
            if(PressTime1<250)   //500ms内松开为短按
            {
                KeyDoubleCount1=1;  //进入双击检测
                PressState1=1; 
                KeyTimerState1=0;
                KeyDoubleTimerState1=1;
            }
            if(PressTime1>500)
            {
                KeyTimerState1=0;
                PressState1=1;
                return KEY6_LONG;
            }
        }
        if((KeyDoubleCount1==1)&&(PressDoubleTime1<115)&&(S6==0))
        {
                Delay2ms();
                if(S6==0)
                {
                    KeyDoubleCount1=0;
                    KeyDoubleTimerState1=0;
                    while(S6==0);
                    return KEY6_DOUBLE;
                }
            
        }
        if(PressDoubleTime1>115)
        {
            KeyDoubleCount1=0;
            KeyDoubleTimerState1=0;
            return KEY6_SHORT;
        }
        break;
    }
    return KEY_NO;
}






  • separate.h

#ifndef separate_key_H
#define separate_key_H

#include "stc15.h"
#include "intrins.h"

typedef unsigned char u8;
typedef unsigned int u16;

enum KeyNum  //按键键值
{
    KEY7=0,
    KEY6,
    KEY5,
    KEY4
};

enum KeyState  //按键状态
{
    KEY7_SHORT=0,
    KEY7_LONG,
    KEY7_DOUBLE,
    KEY6_SHORT,
    KEY6_LONG,
    KEY6_DOUBLE,
    KEY_NO
};

void Timer0Init(void);
u8 KeyScan(u8 key);

#endif

  • main.c

#include "stc15.h"
#include "intrins.h"
#include "separate_key.h"

#define HC138(x) P2=(P2&0x1F)|(x<<5)

u8 code smg_dm[]={0xc0, 0xf9, 0xa4, 0xb0, 
             0x99, 0x92, 0x82,0xf8, 
             0x80, 0x90,0xff};
u8 smg_num[]={10,10,10,10,10,10,10,10};
u8 com=0;

u8 KEY7_STATE=KEY_NO;
u8 KEY6_STATE=KEY_NO;

void SmgDisplay(void);

void Init(u8 i)
{
    P2&=0x1F;
    switch(i)
    {
        case 4:P0=0xFF;HC138(i);P2&=0x1F;P0=0x00;break;
        case 5:HC138(i);break;
        case 6:HC138(i);break;
        case 7:P2&=0x1F;P0=0xFF;HC138(i);break;
    }
    P2&=0x1F;
}

void main(void)
{
    Init(4);
    Init(5);
    Init(6);
    Init(7);
    Timer0Init();
    while(1)
    {
        KEY7_STATE=KeyScan(KEY7);  //读取按键状态
        KEY6_STATE=KeyScan(KEY6);
//采用数码管第零位显示数值来演示按键状态
        if(KEY7_STATE==KEY7_SHORT)
        {
            smg_num[0]=0;
        }
        if(KEY7_STATE==KEY7_LONG)
        {
            smg_num[0]=1;
        }
        if(KEY7_STATE==KEY7_DOUBLE)
        {
            smg_num[0]=2;
        }
        if(KEY6_STATE==KEY6_SHORT)
        {
            smg_num[0]=3;
        }
        if(KEY6_STATE==KEY6_LONG)
        {
            smg_num[0]=4;
        }
        if(KEY6_STATE==KEY6_DOUBLE)
        {
            smg_num[0]=5;
        }
    }
}

void SmgDisplay(void)
{
    P0=0xFF;
    HC138(6);
    P0=(1<<com);
    HC138(7);
    P0=0xFF;
    P0=smg_dm[smg_num[com]];
    (com==7)?(com=0):(com++);
}

三:总结

       上面所提供的代码可以实现对独立按键的单击、长按以及双击状态的检测,但其实时性和准确度仍有待提升,最后希望大家能从中有所收获,如有更好写法欢迎大家交流讨论,让我们共同学习进步!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值