Single and double click with separate buttons like a mouse

Publisher:心语乐章Latest update time:2022-05-23 Source: eefocus Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

(1) Non-blocking driver for buttons and buzzers

There are two levels of debouncing: the first one judges the electrical level status twice and adds a "fixed delay time" in between. The disadvantage is that the "fixed time" relies on experience, the software's anti-interference ability is also much weaker, and the "password level" is not high enough. The second one is "zero-clearing filtering".


#include "reg52.h"

#define KEY_VOICE_TIME 50 //The length of the sound after the key is triggered

#define KEY_FILTER_TIME 25 //Key filter "stable time" 25ms

sbit beep=P2^3;

sbit KEY_INPUT1=P3^4;

sbit KEY_INPUT2=P3^5; //Key recognition input port

volatile unsigned char vGu8BeepTimerFlag=0;

volatile unsigned int vGu16BeepTimerCnt=0;

volatile unsigned char vGu8KeySec=0;//Key trigger number

void SystemInitial()

{

    TMOD=0x01;

    TH0=0xfc;

    TL0=0x66;

    EA=1;

    ET0=1;

    TR0=1;

}

void Delay(unsigned long u32DelayTime)

{

    for(;u32DelayTime>0;u32DelayTime--);

}

void PeripheralInitial()

{


}

void BeepOpen()

{

    beep=0;

}

void BeepClose()

{

    beep=1;

}

void VoiceScan() //Non-blocking driver for the buzzer. The driver function of the "driver layer" is placed in the timing interrupt function to scan once every 1ms to ensure the consistency of the sound length.

{

    static unsigned char Su8Lock=0;

    if(1==vGu8BeepTimerFlag && vGu16BeepTimerCnt>0)

    {

        if(0==Su8Lock)

        {

            Su8Lock=1; //After triggering the sound, it will lock itself to avoid BeepOpen() being scanned repeatedly and affecting the execution efficiency. When the sound is emitted, only execute the BeepOpen() function once.

            BeepOpen(); //The buzzer sounds, encapsulated into a function for code portability

        }

        else //Use the else structure to make the sound first and then start the timing after the next interruption

        {

            vGu16BeepTimerCnt--;

            if(0==vGu16BeepTimerCnt)

            {

                Su8Lock=0; //Unlock in time after turning off the sound to prepare for the next trigger

                BeepClose();

            }

        }

    }

}

void KeyScan()//Non-blocking, "zero-clearing filtering"

{

    static unsigned char Su8KeyLock1; //Self-lock of key 1

    static unsigned int Su16KeyCnt1; //Timer for key 1

    static unsigned char Su8KeyLock2; //Self-lock of key 2

    static unsigned int Su16KeyCnt2; //Timer for key 2


    if(0!=KEY_INPUT1)//The IO port is at a high level, and no key is pressed. The "de-jitter delay counter" is always cleared. If there is external interference or jitter, the instantaneous clutter interference can be removed.

    {

        Su8KeyLock1=0; //Key unlock

        Su16KeyCnt1=0; //"Debounce delay counter", an important statement for key debounce. Once a high level is reached during the debounce process, it will be immediately reset to 0 until it stabilizes.

    }

    else if(0 == Su8KeyLock1) // indicates that the key is pressed, the else design is very clever, equivalent to KEY_INPUT1==0

    {

        Su16KeyCnt1++; //The accumulation process is filtering. If the IO port is disturbed and triggers a high level during the accumulation process, Su16KeyCnt1 will be set to 0 immediately to remove the instantaneous clutter.

        if(Su16KeyCnt1>=KEY_FILTER_TIME)//Filter "stable time"

        {

            Su8KeyLock1=1; //Key self-locking flag, once the key flag position 1 is triggered, it prevents the key from being continuously triggered when the key is pressed and not released

            vGu8KeySec=1; //Trigger key 1

        }

    }


    if(0!=KEY_INPUT2)

    {

        Su8KeyLock2=0;

        Su16KeyCnt2=0;

    }

    else if(0 == Su8KeyLock2)

    {

        Su16KeyCnt2++;

        if(Su16KeyCnt2>=KEY_FILTER_TIME)

        {

            Su8KeyLock2=1;

            vGu8KeySec=2; //Trigger key 2

        }

    }

}

void KeyTask()

{

    if(0==vGu8KeySec)

    {

        return; //No. 0 is not triggered by a key, so exit the current function. Because when there are dozens of keys, it can avoid the main function entering the switch multiple times every time it enters the KeyTask function, which may be more efficient

    }

    switch(vGu8KeySec)

    {

        case 1:

            vGu8BeepTimerFlag=0;

            vGu16BeepTimerCnt=KEY_VOICE_TIME; //The "application layer" only needs to assign a value to emit a fixed-length sound

            vGu8BeepTimerFlag=1;

            vGu8KeySec=0; //After responding to the key service program, the key number is cleared to avoid continuous triggering

            break;

        case 2:

            vGu8BeepTimerFlag=0;

            vGu16BeepTimerCnt=KEY_VOICE_TIME;

            vGu8BeepTimerFlag=1;

            vGu8KeySec=0;

            break;

    }

}

void main()

{

    SystemInitial();

    Delay(10000);

    PeripheralInitial();

    while(1)

    {

        KeyTask();

    }

}

void T0_time() interrupt 1

{

    VoiceScan();

    KeyScan(); //Because KeyScan is a special function placed in the interrupt function, it involves filtering of the IO port input signal. Filtering involves the timeliness and uniformity of time. Placing it in the interrupt can better ensure the consistency of time.

    TH0=0xfc; //Such as buzzer driver, dynamic digital tube driver, key scan driver

    TL0=0x66;

}


(2) Single and double click of independent buttons


#include "reg52.h"

#define KEY_VOICE_TIME 50 //The length of the sound after the key is triggered

#define KEY_FILTER_TIME 25 //Key filter "stable time" 25ms

#define KEY_INTERVAL_TIME 400 //The maximum effective time between two consecutive clicks

sbit beep=P2^3; //buzzer

sbit P1_4=P1^4;//LED

sbit KEY_INPUT1=P3^4; //Key recognition input port

volatile unsigned char vGu8BeepTimerFlag=0;

volatile unsigned int vGu16BeepTimerCnt=0;

unsigned char Gu8LedStatus=0; //LED status, 0 means off, 1 means on

volatile unsigned char vGu8SingleKeySec=0; //Trigger sequence number of single-click button

volatile unsigned char vGu8DoubleKeySec=0; //Double click button trigger number

void SystemInitial()

{

    TMOD=0x01;

    TH0=0xfc;

    TL0=0x66;

    EA=1;

    ET0=1;

    TR0=1;

}

void Delay(unsigned long u32DelayTime)

{

    for(;u32DelayTime>0;u32DelayTime--);

}

void LedOpen()

{

    P1_4=0;

}

void LedClose()

{

    P1_4=1;

}

void PeripheralInitial()

{//The LED initialization is not placed in SystemInitial because the LED display content does not have high requirements for the power-on moment. If it is to control the relay, it should be placed in SystemInitial

    if(0 == Gu8LedStatus)

    {

        LedClose();

    }

    else

    {

        LedOpen();

    }

}

void BeepOpen()

{

    beep=0;

}

void BeepClose()

{

    beep=1;

}

void VoiceScan() //Non-blocking driver for the buzzer. The driver function of the "driver layer" is placed in the timing interrupt function to scan once every 1ms to ensure the consistency of the sound length.

{

    static unsigned char Su8Lock=0;

    if(1==vGu8BeepTimerFlag && vGu16BeepTimerCnt>0)

    {

        if(0==Su8Lock)

        {

            Su8Lock=1; //After triggering the sound, it will lock itself to avoid BeepOpen() being scanned repeatedly and affecting the execution efficiency. When the sound is emitted, only execute the BeepOpen() function once.

            BeepOpen(); //The buzzer sounds, encapsulated into a function for code portability

        }

        else //Use the else structure to make the sound first and then start the timing after the next interruption

        {

            vGu16BeepTimerCnt--;

            if(0==vGu16BeepTimerCnt)

            {

                Su8Lock=0; //Unlock in time after turning off the sound to prepare for the next trigger

                BeepClose();

            }

        }

    }

}

void KeyScan()//Non-blocking, "zero-clearing filtering"

{

    static unsigned char Su8KeyLock1; //Self-lock of key 1

    static unsigned int Su16KeyCnt1; //Timer for key 1

    static unsigned char Su8KeyTouchCnt1; //key press count record

    static unsigned int Su16KeyIntervalCnt1; //Key time interval counter


    if(0!=KEY_INPUT1)//The IO port is at a high level, and no key is pressed. The "de-jitter delay counter" is always cleared. If there is external interference or jitter, the instantaneous clutter interference can be removed.

    {

        Su8KeyLock1=0; //Key unlock

        Su16KeyCnt1=0; //"Debounce delay counter", an important statement for key debounce. Once a high level is reached during the debounce process, it will be immediately reset to 0 until it stabilizes.

        if(Su8KeyTouchCnt1>=1) //Start the interval time counter after the key is triggered once

        {

            Su16KeyIntervalCnt1++;

            if(Su16KeyIntervalCnt1>=KEY_INTERVAL_TIME)

            {

                Su16KeyIntervalCnt1=0;

                Su8KeyTouchCnt1=0; //When the interval time is reached, the number of times the key is pressed will be cleared

            }

        }

    }

    else if(0 == Su8KeyLock1) // indicates that the key is pressed, the else design is very clever, equivalent to KEY_INPUT1==0

    {

        Su16KeyCnt1++; //The accumulation process is filtering. If the IO port is disturbed and triggers a high level during the accumulation process, Su16KeyCnt1 will be set to 0 immediately to remove the instantaneous clutter.

        if(Su16KeyCnt1>=KEY_FILTER_TIME)//Filter "stable time"

        {

            Su8KeyLock1=1; //Key self-locking flag, once the key flag position 1 is triggered, it prevents the key from being continuously triggered when the key is pressed and not released

            Su16KeyIntervalCnt1=0; //The effective interval time will be cleared after pressing the key once

            Su8KeyTouchCnt1++; //Record the number of times pressed

            if(1==Su8KeyTouchCnt1)

            {

                vGu8SingleKeySec=1;//Click to trigger

            }

            else if(Su8KeyTouchCnt1>=2)

            {

                Su8KeyTouchCnt1=0; //Reset the number of presses

                vGu8SingleKeySec=1;//Click task

                vGu8DoubleKeySec=1; //Double click trigger

            }

        }

    }

}

void SingleKeyTask()

{

    if(0==vGu8SingleKeySec)

    {

        return; //No. 0 is not triggered by a key, so exit the current function. Because when there are dozens of keys, it can avoid the main function entering the switch multiple times every time it enters the KeyTask function, which may be more efficient

[1] [2]
Reference address:Single and double click with separate buttons like a mouse

Previous article:Combination of independent buttons, short press and long press, even triggering by holding down
Next article:The Three Realms of Marquee

Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号