(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
Previous article:Combination of independent buttons, short press and long press, even triggering by holding down
Next article:The Three Realms of Marquee
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Innolux's intelligent steer-by-wire solution makes cars smarter and safer
- 8051 MCU - Parity Check
- How to efficiently balance the sensitivity of tactile sensing interfaces
- What should I do if the servo motor shakes? What causes the servo motor to shake quickly?
- 【Brushless Motor】Analysis of three-phase BLDC motor and sharing of two popular development boards
- Midea Industrial Technology's subsidiaries Clou Electronics and Hekang New Energy jointly appeared at the Munich Battery Energy Storage Exhibition and Solar Energy Exhibition
- Guoxin Sichen | Application of ferroelectric memory PB85RS2MC in power battery management, with a capacity of 2M
- Analysis of common faults of frequency converter
- In a head-on competition with Qualcomm, what kind of cockpit products has Intel come up with?
- Dalian Rongke's all-vanadium liquid flow battery energy storage equipment industrialization project has entered the sprint stage before production
- Allegro MicroSystems Introduces Advanced Magnetic and Inductive Position Sensing Solutions at Electronica 2024
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- New real-time microcontroller system from Texas Instruments enables smarter processing in automotive and industrial applications
- Differences between different versions of TI's ZigBee protocol stack
- Studying Things to Gain Knowledge 05: Dimensions and Elementary Functions
- Review summary: Arteli AT32WB415 series Bluetooth BLE 5.0 MCU, free first-hand experience!
- Nexperia ESD Application Notes Free Download | Read ESD Tips and Answer Questions to Win Prizes
- The new version is so beautiful, I decided not to update it for the time being!
- [SAMR21 New Gameplay] 12. Driving OLED
- [NXP Rapid IoT Review] Adding USB Serial Port Simulation Function to Rapid
- Detailed explanation of five classic power supply circuits
- MSP430 MCU Development Record (8)
- Newbie help! Wireless remote control LED constant current drive circuit. Which part of the receiving circuit is the mixing circuit?