用队列实现的按键扫描程序

/*key.c*/
/*说明:一个结构体用于表明按键的相关信息(如:状态(按下还是松开),按下计数器,按下后持续多长时间才算长按)
好处就是:可以实现多个按键状态转换,判断是长按还是短按,消抖*/
#include <stdio.h>
#include "sys.h"
#define KEY0 PBin(0)
#define KEY1 PBin(1)
#define KEY2 PBin(2)
#define KEY3 PBin(3)
#define KEY0 PBin(4)
/*按键数量*/
#define KEY_NUM 5 
#define key_value_size 10
#define Down  1
#define LDown 2
#define Up    3

u8 key_check(u8 n){if(PBin(n)==0) return 1;else return 0;}

typedef struct  /*按键队列结构体*/
{
    u8 kmessage[key_value_size]; /*存放按键键值*/
    u8  front;  /*头*/
    u8  rear;  /*尾*/
}key_queue_struct ;
typedef struct   /*按键结构体,管理按键*/
{
    u8 (*key_chek_func)(u8 n); /*按键检测函数*/
    u16 key_cont;  /*按键计数*/
    u16 key_lcont; /*长按计数*/
    u8  key_delay; /*消抖时长*/
    u8  key_ltime; /*设定长按时间(也就是多久后才算长按)*/
    u8  key_state; /*按键状态,0表示未按下,1表示按下*/
}key_struct;
key_struct  karry[KEY_NUM];
key_queue_struct kqueue;
void key_int(void)
{
    u8 i;
    for(i=0;i<KEY_NUM;i++)
    {
        karry[i].key_chek_func=key_check(i);
        karry[i].key_cont=0;
        karry[i].key_lcont=0;
        karry[i].key_delay=5;   /*50毫秒消抖*/
        karry[i].key_ltime=100;   /*如果延时是10ms,则10*100就是1s认为是长按*/
        karry[i].key_state=0;  
    }
  /**********按键队列初始化***********/
    kqueue.front=kqueue.rear=0;
    for(i=0;i<key_value_size;i++)
    {
        kqueue.kmessage[i]=0;
    }

}
void key_valueput(u8 value)  /*键值入队列*/
{
                                 /*检查队列是否已经满了*/
    kqueue.kmessage[kqueue.rear]=value;
    if(++kqueue.rear>=key_value_size)
    {
        kqueue.rear=0;   /*实现循环队列*/
    }


}
u8 key_valueget() /*键值出队列,得到键值*/
{
    u8 value;                               
    value=kqueue.kmessage[kqueue.front];
    if(++kqueue.front>=key_value_size)
    {
        kqueue.front=0;   /*实现循环队列*/
    }
}
void Keyn_scan(u8 n)
{
    key_struct *keystruct;
    keystruct=&karry[n];
    if(keystruct->key_chek_func) /*检测到按键按下*/
    {
        if(keystruct->key_cont<keystruct->key_delay)
        {
            keystruct->key_cont=keystruct->key_delay; /*直接加到50ms原因是0到50ms用于松开检测*/
        }
        else if(keystruct->key_cont<2*keystruct->key_delay)/*从50加到100消抖50ms*/
        {
            keystruct->key_cont++;
        }
        else
        {
            if(keystruct->key_state==0)    /*上一刻状态为0,没有按下*/
            {
                keystruct->key_state=1;   /*状态转换,按下*/
                key_valueput(n*3+Down);                       /*发送按下消息*/
            }
            if(keystruct->key_ltime>0) /*支持长按*/
            {
                if(++keystruct->key_lcont>=keystruct->key_ltime)/*时间值大于规定长按时间,满足长按条件*/
                {
                    key_valueput(n*3+LDown);   /*发送长按键值*/
                }
            }
        }

    }
    else  /*没有检测到按键按下*/
    {
        if(keystruct->key_state)/*上一个状态为按下,说明此刻可能是松开*/
        {

            if(keystruct->key_cont>keystruct->key_delay)
            {
                keystruct->key_cont=keystruct->key_delay;/*从50ms开始递减*/
            }
            else if(keystruct->key_cont>0)
            {
                keystruct->key_cont--;
            }
            else
            {
                keystruct->key_state=0;  /*切换到松开状态*/
                keystruct->key_cont=0;
                keystruct->key_lcont=0;  /*全部清零*/
                key_valueput(n*3+Up);   /*发送弹起消息*/
            }

        }
    }
}
void Key_Scan()
{
    u8 n;
    for(n=0;n<KEY_NUM;n++)
    {
        Keyn_scan(n); /*扫描n个按键*/
    }
}

猜你喜欢

转载自blog.csdn.net/shenlong1356/article/details/80411695