[MCU Notes] State machine efficient key scanning, recognition and detection method

Publisher:清新风华Latest update time:2019-02-18 Source: eefocusKeywords:MCU Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

Buttons are one of the simplest and cheapest ways of human-computer interaction. To achieve effective scanning and processing of one or more buttons, here is my modified code:


The implemented code mainly consists of four parts:


Part 1: Button initialization


void Key_Configuration(void)

{

return;

}

Different configuration methods are required here according to the IC used. I use the 51 core. During the initialization process, the I/O port is quasi-bidirectionally pulled up by default, and the button is valid at a low level, so there is no processing and it jumps out directly.


Part 2: Key level reading


//Only read the initial key level status and further process it in the state machine

static u8 Key_Read(void)

{

    if(!READ_KEY1)  

return KEY1_PRES;

    if(!READ_KEY2)  

return KEY2_PRES;       

    if(!READ_KEY3)  

return KEY3_PRES;

    if(!READ_KEY4)  

return KEY4_PRES;

    if(!READ_KEY5)  

return KEY5_PRES;


return KEY_NONE;

}

According to the specific environment and function, only one valid level is read each time and there is a priority. From the code, we can see that the order of priority is: KEY1>KEY2>KEY3>KEY4>KEY5. Of course, the number of keys to be used depends on the needs of the project. In theory, any number of independent keys is supported.


Part 3: Key judgment part of the state machine


//state machine

static u8 Key_Scan(void)

{

static u8 state = 0; //Button initialization state

static u8 KEY_LAST=0,KEY_NOW=0; //Record the status of two levels

u8 KEY_VALUE=0;

 

KEY_NOW = Key_Read(); //Read key value

   

switch(state)

{

case 0:

{

if(KEY_NOW != KEY_LAST) state = 1; //A key is pressed

}break;

case 1: 

{

if(KEY_NOW == KEY_LAST) state = 2; //The key is valid after the fight ends

else state = 0; // considered as accidental touch

}break; 

case 2: //After the fight

{

if(KEY_NOW == KEY_LAST) //Still pressed 

{

  state = 3;

}

else//Release, short press

{

state = 0; 


KEY_VALUE = KEY_LAST|KEY_SHORT; //Return key value short press

}

}break;


case 3: //Judge long press or short press

{

if(KEY_NOW == KEY_LAST) 

{

    static u8 cnt = 0;

if(cnt++ > 120) //1200ms

{

cnt = 0; 

state = 4;

KEY_VALUE = KEY_LAST|KEY_LONG; //Return key value long press

}   

}

else

{

state = 0;

KEY_VALUE = KEY_LAST|KEY_SHORT; //Return key value short press

}

}break;

case 4://Long press and release detection

{

if(KEY_NOW != KEY_LAST) 

state = 0;

}break;

}//switch


KEY_LAST = KEY_NOW; //更新

return KEY_VALUE;

}

This part is also the core code of the whole process. First, three static variables are defined: the key state, the currently read key value KEY_NOW, the last key value KEY_LAST, and the returned valid key value KEY_VALUE. Next, we will study them step by step:


The initial value of state is 0, and the switch and case are entered. The time interval for each case judgment is determined by the fourth part. Here I choose 10ms


Judge 0, as long as the key value recorded last time and the key value read this time do not equal, enter 1. There is another function here, that is, the release detection of short press. This is also the reason why there is no else. Please see state 4 for specific implementation.


Judge 1, the last key value is equal to this key value. Note that KEY_LAST has been updated after case 0, which means that the key value read this time after 10ms is still equal to the last key value. Here we consider it to be a valid press, not caused by accidental touch or interference. In this case, go to 2. Otherwise, return to 0.


Judgment 2, here comes from 1, that is, the key value at this time is valid, here we still judge the last updated KEY_LAST and the new key value read this time, if you don't want to wait, it proves that the hand has been released (single key case). In this way, it is recognized as a short press, the state returns to 0 and returns the key value of the short press, which is 0. If the key has not been released, there is a tendency to long press, enter 3.


Judgment 3 is also very simple. It determines whether the key value has been released. The count starts every time it comes in. It enters once every 10ms, so it is counted as 120 times here, which means it takes 1200ms to meet the conditions and assign the returned key value as a long press. At the same time, it enters 4. Otherwise, it is recognized as a short press and re-enters 0.


Judgment 4, the role of the code here is mainly as a long press release detection, the reason is very simple, the key is not released, then the historical key value and the current key value must be equal and not 0, and after the key is released, the read key value must be 0, which jumps out of state 4.


Part 4: Entity functions and called functions


static void KEY1_ShortHander(void)

{

 

}

static void KEY1_LongHander(void)

{

 

}

static void KEY2_ShortHander(void)

{

 

}

static void KEY2_LongHander(void)

{

 

}

static void KEY3_ShortHander(void)

{

 

}

static void KEY3_LongHander(void)

{

 

}

static void KEY4_ShortHander(void)

{

 

}

static void KEY4_LongHander(void)

{

 

}

static void KEY5_ShortHander(void)

{

 

}

static void KEY5_LongHander(void)

{

 

}

 

 

void Key_Hander(void) //Key handling function

{

u8 KEY_NUM=0;

static u32 LAST=0;

if(Systick_ms-LAST<10) return;

LAST = Systick_ms;


KEY_NUM = Key_Scan(); //Key scan value

if(KEY_NUM == KEY_NONE) return;


//A button is pressed

if(KEY_NUM & KEY_SHORT) //short press

{    

if(KEY_NUM & KEY1_PRES)//KEY1_PRES

{

KEY1_ShortHander();

}

else if(KEY_NUM & KEY2_PRES)//KEY2_PRES

{

KEY2_ShortHander();

}

else if(KEY_NUM & KEY3_PRES)//KEY3_PRES

{

KEY3_ShortHander();

}

else if(KEY_NUM & KEY4_PRES)//KEY4_PRES

{

KEY4_ShortHander();

}

else if(KEY_NUM & KEY5_PRES)//KEY5_PRES

{

KEY5_ShortHander();

}

}

else if(KEY_NUM & KEY_LONG) //长按 

{

if(KEY_NUM & KEY1_PRES)//KEY1_PRES

{

KEY1_LongHander();

}

else if(KEY_NUM & KEY2_PRES)//KEY2_PRES

{

KEY2_LongHander();

}

else if(KEY_NUM & KEY3_PRES)//KEY3_PRES

{

KEY3_LongHander();

}

else if(KEY_NUM & KEY4_PRES)//KEY4_PRES

{

KEY4_LongHander();

}

else if(KEY_NUM & KEY5_PRES)//KEY5_PRES

{

KEY5_LongHander();

}

}

}

This part of the code is relatively clear. Through the analysis of the previous three parts, the results of the key values ​​are obtained by calling the previous three parts here, and then the results are judged to perform corresponding functions and functional processing. The function body is given directly here, and the user can directly add the corresponding code in the function body. However, a more effective way should be to replace the execution function with a marker variable, so that the program execution will be more organized and will not occupy the time slice incorrectly.


Finally, attach the header file:


#ifndef __FY_KEY_H

#define __FY_KEY_H

 

#include "fy_includes.h"

 

#define READ_KEY1 P30

#define READ_KEY2 P14

#define READ_KEY3 P13

#define READ_KEY4 P10

//#define READ_KEY5 P17

 

#define KEY1_PRES 0x01

#define KEY2_PRES 0x02

#define KEY3_PRES 0x04

#define KEY4_PRES 0x08

#define KEY5_PRES 0x10

 

#define KEY_SHORT  0x40

#define KEY_LONG   0x80

#define KEY_NONE      0

 

#define HOT_KEY_PRES KEY1_PRES

#define PWR_KEY_PRES KEY2_PRES

#define H2_KEY_PRES KEY3_PRES

#define MP3_KEY_PRES KEY4_PRES

 

void Key_Configuration(void);

void Key_Hander(void);

 

#endif

 

/*********************************************END OF FILE**********************************************/


Keywords:MCU Reference address:[MCU Notes] State machine efficient key scanning, recognition and detection method

Previous article:[MCU Notes] Single button to achieve single click, double click, long press
Next article:[MCU Notes] Power supply design integrating USB charging, USB power supply and battery power supply

Recommended ReadingLatest update time:2024-11-15 18:56

How to generate random numbers using a single chip microcomputer
There are many random numbers in the application of single-chip microcomputers. Of course, there are many ways to generate random numbers. One of them is to use the single-chip microcomputer timer to take out the unknown timer THX and TLX values, and then calculate to get a random value within a specified range. This
[Microcontroller]
How to generate random numbers using a single chip microcomputer
Blue Bridge Cup STC15 MCU Review - Use of Digital Tube
Preface Let's review the use of digital tubes Mainly divided into static display and dynamic display Static display When we only need to display one bit on the digital tube, we can directly achieve it through the static display of the digital tube, that is, turn on the corresponding bit selector, and then directly i
[Microcontroller]
Blue Bridge Cup STC15 MCU Review - Use of Digital Tube
An example of using the microcontroller plus 1 instruction
The purpose of the addition instruction   INC A  INC Rn  INC direct  INC @Ri  INC DPTR  is very simple, that is, to add 1 to the value in the subsequent target. Example: (A) = 12H, (R0) = 33H, (21H) = 32H, (34H) = 22H, DPTR = 1234H. Execute the following instructions:  INC A (A) = 13H  INC R2 (R0) = 34H  INC
[Microcontroller]
Tracking and obstacle avoidance remote control car based on STC15 single chip microcomputer
The schematic diagram and PCB diagram of the tracking and obstacle avoidance remote control car based on STC15 drawn by Altium Designer are as follows: The microcontroller source program is as follows: #include "all.h" extern unsigned char code INRECO ,TL ,TriLU ,TriLD ,TRU ,TRD ,FR ,TriRU ,TriRD ,ST ,TR ,BR ,Back ;
[Microcontroller]
Tracking and obstacle avoidance remote control car based on STC15 single chip microcomputer
Pin description and off-chip bus structure of MCS-51 single-chip microcomputer
1. Chip pin description The MCS-51 microcontrollers manufactured with the HMOS process all use a 40-pin direct-insertion package (DIP). The 80C51/80C31 chips manufactured with the CHMOS process use a square package process in addition to the DIP package, and the pin arrangement is shown in the figure. The square packa
[Microcontroller]
111 instructions of the microcontroller
Data transfer instructions: 1 MOV A,Rn register content is sent to the accumulator 2 MOV A,direct The data in the direct address unit is sent to the accumulator 3 MOV A,@Ri The data in the indirect RAM is sent to the accumulator 4 MOV A,#data The immediate value is sent to the accumulator 5 MOV Rn,A The accumulato
[Microcontroller]
What are the planning principles of microcontroller data memory RAM?
The planning principles of data memory RAM are: (1) Plan the application according to the type of data used and place frequently used data with a fixed memory footprint at high addresses. (2) Since the capacity of the on-chip RAM is relatively small, it should be used in an overlapping manner as much as possible.
[Microcontroller]
AT89C series microcontroller encryption and decryption principle
The simple decryption of a microcontroller is to erase the encryption lock bit in the microcontroller. Due to the unreasonable design of the erase operation timing of the AT89C series microcontroller, it is possible to erase the encryption lock bit before erasing the on-chip program. The timing of the erase operation o
[Microcontroller]
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号