New Key Scanner

Source: Internet
Author: User

Suppose you understand {
Tagshow (Event)
} "> C language, because of pure C language description, and the processor {
Tagshow (Event)
} "> Platform irrelevant, you can in MCS-51 ,{
Tagshow (Event)
} "> AVR, PIC, or even {
Tagshow (Event)
} "> Test this on the ARM platform {
Tagshow (Event)
} "> Program performance. Of course, I have multiple {
Tagshow (Event)
} "> The project has been used, and the effect is very good. Well, the engineering staff's habits should be left empty when talking nonsense. Let's get started.

Core {
Tagshow (Event)
} "> Algorithm:
Unsigned char Trg;
Unsigned char cont;
Void keyread (void)
{
Unsigned char readdata = Pinb ^ 0xff; // 1
Trg = readdata & (readdata ^ cont); // 2
Cont = readdata; // 3
}

Finished. Is there an incredible feeling? Of course, I did not want to understand what I would have done before. I will be amazed at the subtlety of this algorithm when I want to understand it !!
The program explanation is as follows:
Trg (triger) indicates a trigger, and cont (CONTINUE) indicates a continuous press.
1: Read the port data of portb, fetch the reverse port data, and send it to the readdata temporary variable to save it.
2: algorithm 1, used to calculate the trigger variable. A single position and operation, an exception or operation, I want to learn C language should understand? Trg is a global variable, which can be directly referenced by other programs.
3: algorithm 2 is used to calculate continuous variables.

I can see that there is a feeling of "knowing, not knowing why? The code is very simple, but how does it achieve our goal? Well, let's see Qingtian through the cloud.
Our most commonly used button connection method is as follows: the AVR has the internal pull-up function, but to illustrate the problem, I specifically use the external pull-up resistance. When the key is not pressed, the read port data is 1. If the key is pressed, the read port is 0. Next, let's take a look at the specific situation of this algorithm.

(1) When no buttons are available
The port is 0xff, And the read port of readdata is reversed. Obviously, it is 0x00.
Trg = readdata & (readdata ^ cont); (in the initial state, cont is also 0) very simple mathematical computation. Because readdata is 0, it is "phase" with any number ", the result is also 0.
Cont = readdata; saving cont is actually equal to readdata, 0;
The result is:
Readdata = 0;
Trg = 0;
Cont = 0;

(2) The first pb0 Press
The port data is 0xfe, And the read port of readdata is reversed. Obviously, it is 0x01.
Trg = readdata & (readdata ^ cont); because this is the first press, the cont is the last value and should be 0. Then the sub-value of this formula is not difficult to calculate, that is, Trg = 0x01 & (0x01 ^ 0x00) = 0x01
Cont = readdata = 0x01;
The result is:
Readdata = 0x01;
Trg = 0x01; Trg will only set the value of the corresponding bit to 1 at this time, and 0 at other times
Cont = 0x01;

(3) pb0 press loose (long button)
The port data is 0xfe, the read port of readdata is 0x01.
Trg = readdata & (readdata ^ cont); because this is a continuous press, the cont is the last value and should be 0x01. Then this formula is changed to Trg = 0x01 & (0x01 ^ 0x01) = 0x00
Cont = readdata = 0x01;
The result is:
Readdata = 0x01;
Trg = 0x00;
Cont = 0x01;
Because the buttons are pressed for a long time, the MCU will continuously execute this {
Tagshow (Event)
} "> Function, what will happen next time?
Readdata = 0x01; this will not change because the buttons are not released
Trg = readdata & (readdata ^ cont) = 0x01 & (0x01 ^ 0x01) = 0. As long as the buttons are not released, the Trg value is always 0 !!!
Cont = 0x01; as long as the button is not released, this value will always be 0x01 !!

(4) Release of buttons
The port data is 0xff, the read port of readdata is 0x00.
Trg = readdata & (readdata ^ cont) = 0x00 & (0x00 ^ 0x01) = 0x00
Cont = readdata = 0x00;
The result is:
Readdata = 0x00;
Trg = 0x00;
Cont = 0x00;

Obviously, this is returned to the initial state, that is, the status without pressing the button.
To sum up, do you want to understand? The answer is as follows:
Trg indicates the trigger, that is, the jump. As long as a key is pressed (the level changes from 1 to 0), the Trg will be set to one on the corresponding key bit, if we use pb0, the value of Trg is 0x01. Similarly, if we press pb7, the value of Trg should be 0x80. This is easy to understand, in the most critical aspect, the Trg value appears only once each press and is immediately cleared without manual intervention. Therefore, the key-Pressing function handler will not be executed repeatedly, saving a lot of conditional judgment. This is the essence !! Cont indicates a long button. If pb0 is not placed, the cont value is 0x01. Correspondingly, pb7 is not placed, therefore, the cont value should be 0x80, which is also easy to understand.
If you still don't understand it, you can calculate the two expressions by yourself. With this support, the button processing becomes very nice. See {
Tagshow (Event)
} "> Application:

Application 1: One-time trigger button Processing
Assume that pb0 is the buzzer button, click it, And the buzzer beep will sound. This is simple, but how did you do it before? Which of the following is more convenient?
# Define key_beep 0x01
Void keyproc (void)
{
If (Trg & key_beep) // If you press key_beep
{
Beep (); // executes the buzzer processing function.
}
}

How is it? Harmonious enough? What is the essence of Trg? The essence is that it only appears once. Therefore, if you press the button, the Trg & key_beep will only appear once, so it is very convenient to handle it, and the buzzer will not be left blank, Hoho ~~~ Or you will think that this process is simple and there is no problem. Let's continue.

Application 2: handling long buttons
Some requirements are often met in the project. For example, if a key is pressed for a short time to execute function a, if the button is pressed for 2 seconds, function B is executed, or if the button is not put for 3 seconds, what are the functions of the count connection. I don't know how you did it before? I admit that I used to be very depressed. But let's take a look at how we can handle it here. Maybe you will be surprised. The original program can be so simple. Here is a simple example to illustrate {
Tagshow (Event)
} "> Principle: pb0 is the mode button. If you press the short button, the switch mode is switched. If you press the short button, PB1 is added. If you press the long button, the join mode is added. (played {
Tagshow (Event)
} "> Workbooks? That's right !)

# Define key_mode 0x01 // mode key
# Define key_plus 0x02 // Add
Void keyproc (void)
{
If (Trg & key_mode) // If you press key_mode, it is useless to press this button,
{// It won't be executed for the second time. It must be released first and then pressed
Mode ++; // Add 1 to the mode register. Of course, this is just a demonstration. You can execute
// Any code executed
}
If (cont & key_plus) // if the "add" button is pressed
{
Cnt_plus ++; // timing
If (cnt_plus> 100) // 20 ms * 100 = 2 S if the time reaches
{
Func (); // the program you need to execute
}
}
}

I don't know how you feel? I think it is quite simple to complete the task. Of course, the code is used for demonstration.

Application 3: mixed use of touch and switch buttons
The trigger button is estimated to be used most often, especially {
Tagshow (Event)
} "> Single chip microcomputer. Switch type is also very common, such as the home lights, those pressed will not be released, unless off. These two buttons do not work very well, but have you ever thought about it {
Tagshow (Event)
} "> What are the two buttons in the system? I think of my previous processing and separated two very similar processing programs. Now it seems really stupid, but there is no way, structure determines the program. But now, we can use the method described above to solve it easily. How does it work? You may also think that for the touch switch, follow the above method to deal with one press and long press, for the switch type, we only need to deal with the cont is OK, why? It's easy to think of it as a long button, so that we can find something in common and block all the details. The program will not be given. It is completely the content of Application 2. Here we mention it to describe the principle ~~

All right, the easy-to-use button processing is finished. Some may ask, why don't we talk about the problem of delayed jitter? Haha. Sure enough, you cannot be lazy. Next, let's talk about this problem. By the way, it is very simple to talk about how I use the time slice method and how it can shake. The method for dejitters with latency is very traditional, that is, the first time the system judges that there are buttons, the delay is a certain period of time (generally 20 ms) and then reads the port. If the data read twice is the same, it indicates that the button is a real button, rather than a jitter, then enter the button processing program.
Of course, don't tell me that delay (20) goes through an endless loop. If that's the case, I sincerely {
Tagshow (Event)
} "> We recommend that you put down all your things first, and take a good look at the operating system's time-sharing working principle. You can probably understand the idea without looking at the principle in detail, otherwise, you will never escape from the cainiao circle. Of course, I am also a cainiao. I mean, the real microcontroller {
Tagshow (Event)
} "> Getting started with learning to handle multiple tasks, which is also the biggest difference between school programs and company programs. Of course, this article does not specifically talk about this, so it is not ugly.

My main program architecture is as follows:
Volatile unsigned char intrcnt;
Void interrupthandle () // interrupt the Service Program
{
Intrcnt ++; // interrupt once in 1 ms, variable
}
Void main (void)
{
Sysinit ();
While (1) // execute a large loop every 20 ms
{
Keyread (); // Scan each subroutine
Keyproc ();
Func1 ();
Funt2 ();
...
...
While (1)
{
If (intrcnt> 20) // wait until 20 ms
{
Intrcnt = "0 ";
Break; // returns the Main Loop
}
}
}
}

It seems to be far away. Back to our problem just now, that is, how to perform the key shake operation. We put the program of the read button in the main loop. That is to say, every 20 ms, we will execute the keyread () function to obtain the new Trg and cont values. Well, the following is my deshake part, which is very simple. The basic architecture is as follows. I like it myself and have been using it all the time. Of course, in combination with this, each subprogram must be executed for a short period of time and cannot be an endless loop. It is generally implemented using a finite state machine. For details, refer to other {
Tagshow (Event)
} "> Information.
After understanding the basic principles, I think it's hard for everyone to think about how to use them {
Tagshow (Event)
} "> Engineers. For example, how do I determine how to release a button? Very simple. If the Trg and cont values are both 0, they must have been released. In this {
Tagshow (Event)
} "> Added a button release detection function. The procedure is as follows:

Volatile unsigned char Trg;
Volatile unsigned char cont;
Volatile unsigned char release;
// Add new features!
Void keyread (void)
{
Unsigned char readdata = Pinb ^ 0xff; // 1 read key value
Trg = readdata & (readdata ^ cont); // 2 get the trigger value of Press
Release = (readdata ^ Trg ^ cont); // 3 get the release trigger value
Cont = readdata; // 4 get all unreleased key values
}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.