×
单片机 > 单片机程序设计 > 详情

非常完备的按键操作系统,单击、双击、N击,长按。可移植

发布时间:2021-04-25 发布时间:
|

#define BaseTime 10        //时间基准10 ms ,如果设计的时基是5ms 则前面的10就用该变成5

#define number_init          0xfffffffd  // 初始化相关的utime(unsigned long)变量(如果是unsigned int 就应该是0xfffd),采用这个值的好处是,即使发生时钟计数器溢出,也不影响其他的程序


typedef unsigned long utime;  //这个类型是为了方便移植专门给时间相关变量使用

typedef unsigned long ulong;

typedef unsigned int uint;

typedef unsigned char uchar;


enum ButtonModel{noneClick=0,singalClick,doubleClick,repeatClick,longPress}; //doubleClick目前未定义完整动作 pressDownHold,按下保持

enum ButtonStaus{nonePress=1,pressDown,pressUp,pressDownHold};        /



struct button

{

    uchar outPutEn:1; //发送数据使能

    uchar lastButton:1; //按键上次变动后的状态 默认 1

    uchar init_leavel:1; //设置默认按键电平

        uchar longPressFlag:1;            //长按释放标志 默认0,一旦开始长按则置1

        uchar Gpio_level :3;

        uchar applyUseOpenMaxPwm:1;         //在关机状态下,若本按键按下启动了系统,则需要申请全局变量标明,禁止其他按键关闭被本按键打开的系统(自己打开自己负责关闭)


        uchar ticks;            //按键按下次数

    enum ButtonStaus lastButtonStaus;   //按键上个循环的状态

    enum ButtonStaus thisButtonStaus;   //按键本循环的状态

    enum ButtonModel lastButtonModel; //按键上个循环所处的模式

    enum ButtonModel thisButtonModel; //按键本循环应该所处的模式


    uint changeModelTime;  //10ms基准              //长按时间定义

    uint pressLongTime;    //10ms基准              //多击时间定义


    utime lastPressDownMoment;     //上次按键按下所处的时刻

    utime thisPressDownMoment; //本次按键按下所处的时刻

    uint tempTime;           //缓存按键两次按下之间的时长


    utime buttonConfir;     //按键防抖时长



    utime getTimer; //获取时钟精准时刻,用于设定按键扫描周期

    utime acquisitionMoment; //获取时钟精准时刻,用于记录相同按键状态持续时长


    uchar  (*read_gpio)(void); //获取按键状态方法

};

/*================================

outPutEn 是为后面接收按键是单击、多击长按函数准备的参数。比如按键扫描程序10ms运行一次,输出的是单击,如果没有outPutEn这个参数,后面的接收程序会在10ms内一直都接收的是单击指令,这样就会一直执行单击需要进行的操作,本来单击一次档位变化1,结果现在档位变化了n


applyUseOpenMaxPwm 是为多按键且按键操作有优先权做准备,,有优先权的操作不会被其他按键操作打断





===============================*/

struct button button1,button2,button3;


void Scan_key(struct button *Key,utime timer ,uint enOutTime ,uint noiseProofTime)

{

         enOutTime/=BaseTime;

     noiseProofTime/=BaseTime;

     if(number_init==Key->getTimer) //如果是第一次运行,则更新时间

     {

         Key->getTimer=timer;

     }


     else

     {

         if(timer-Key->getTimer>=enOutTime) //如果时间足够“定义的循环时间” ,则更新时间并允许运行

         {

            Key->getTimer=timer;

            Key->Gpio_level=Key->read_gpio();

            if(Key->Gpio_level>1);

                        else

            {

                         if(Key->lastButton^Key->Gpio_level)//按键有电平变化模块处理开始----------------------------------------------------------------------------//

             {

                                 if(number_init==Key->buttonConfir)

                                        Key->buttonConfir=timer;


                 if(timer-Key->buttonConfir>=noiseProofTime)//按键防抖,必须再确认状态

                 {

                     Key->lastButton=Key->Gpio_level;

                                         Key->acquisitionMoment=number_init;

                     Key->buttonConfir=number_init; //二次确认标志重置




                     if(Key->init_leavel^Key->Gpio_level)//本次按键状态改变后与定义的电平不一致模块处理开始

                     {

                         switch(Key->lastButtonStaus)

                         {

                         case nonePress: //上个循环是定义的初始电平

                         case pressUp:

                            {

                                if(number_init==Key->lastPressDownMoment)//是第一次记录按键按下时刻

                                {

                                    Key->thisPressDownMoment=Key->lastPressDownMoment=timer;

                                }

                                else //不第一次记录

                                {

                                    Key->thisPressDownMoment=timer;

                                    Key->tempTime+=Key->thisPressDownMoment-Key->lastPressDownMoment; //获取两次按键按下之间的时间间隔

                                    Key->lastPressDownMoment=Key->thisPressDownMoment;  //更新

                                }



                                Key->ticks++;



//不在此处增加pressLongTime判断的原因是,buftime0记录的是两次按键按下之间的时长,在两次按下之间必有弹起,一旦弹起,pressLongTime 就置零


                                switch(Key->ticks)

                                {

                                case 1:

                                    {

                                        if(Key->tempTime>=Key->changeModelTime)//ticks未初始化。

                                        {

                                            Key->ticks=0;

                                            Key->tempTime=0;


                                        }

                                                                                Key->thisButtonModel=singalClick;



『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
STM32单片机的复用端口初始化的步骤及方法