Understanding and implementing independent key controls for LEDs on microcontrollers
What are independent keys?
Tactile switches: These function as electronic switches that close when pressed and open when released. The mechanism involves internal metal springs that flex to make or break connections.
Note: GND is the negative terminal. When a key is pressed, it connects to ground, resulting in 0V (low level) being registered by the microcontroller. When released, the key returns to high level (5V).
Key K1 corresponds to P3_1 and K2 corresponds to P3_0.
As shown in the diagram:
// P3 is the register controlled by the independent keys
if(P3_1==0) // When K1 is pressed
if(P3_1==1) // When K1 is released
The above represents the fundamental principles we'll use in this article.
Basic LED Control with Independent Keys
#include <REGX52.H>
void main()
{
while(1)
{
if(P3_1==0) // Check if independent key is pressed
{
P2_0=0; // Turn on the first LED
}
else
{
P2_0=1; // Turn off the LED
}
}
}
/* LEDs require positive to positive and negative to negative connections to light up
The LED's right side is already connected to VCC (positive), so the left side
must be at low level (0V) to illuminate it. */
Remember to convert the file to HEX format.
Controlling LED State with Independent Keys
1. What is key bounce?
For mechanical switches, when the contacts open or close, the mechanical elasticity causes the switch to not immediately stabilize when closing, nor immediately break when opening. This results in a series of bounces during the transition. We have two solutions:
- Hardware debouncing (difficult to impelment for our purposes)
- Software debouncing (easier to implement)
Recall our delay function, which we can use to cover the bounce period.
If you've forgotten how to implement delays, refer to the LED blinking tutorial [1-2].
2. Implementing state control with independent keys
#include <REGX52.H>
void Delay(unsigned int xms) //@12.000MHz
{
unsigned char i, j;
while(xms)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
xms--;
}
}
void main()
{
while(1)
{
// P3_1 refers to K1 key
if(P3_1==0)
{
Delay(20); // 20ms covers bounce
while(P3_1==0); // Check if key is released
Delay(20); // Cover release bounce
// Main operation
P2_0=~P2_0; // Bitwise inversion
// P2_0 is initially high (1), so after inversion it becomes low (0)
// causing the LED to light up
}
}
}
The original state of D1 was off (high level = 1), so after inversion it becomes low level (0), causing D1 to light up.
Displaying Binary with Independent Keys
Inserting a knowledge point:
In MCU programming, we typically use unsigned char variables to represent registers because unsigned char is 8 bits, matching register size, with a range of 0~255.
#include <REGX52.H>
void Delay(unsigned int xms) //@12.000MHz
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
void main()
{
// 8-bit binary represents one register
unsigned char LEDValue=0;
while(1)
{
if(P3_1==0)
{
Delay(20); // Software debouncing
while(P3_1==0); // Check for release
Delay(20); // Debounce
LEDValue++;
P2=~LEDValue; // Invert bits and assign to P2
}
}
}
Why write it this way? Because, by default, all LED ports on microcontrollers are high level (1). This applies to the P2 register as well.
If we directly do P2++; we get 0000 0000, right?
What happens when we invert the bits? It becomes 1111 1111, returning P2 to its initial state, causing an infinite loop. Therefore, we use unsigned char LEDValue to represent the register, increment it, then invert and assign to P2 to achieve binary shifting.
Controlling LED Shifting with Independant Keys
#include <REGX52.H>
void Delay(unsigned int xms) //@12.000MHz
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
// Define a global variable
unsigned char LEDPosition; // Register definition
void main()
{
P2=~0x01; // Initialize to light the first LED
if(P3_1==0)
{
Delay(20);
while(P3_1==0);
Delay(20);
// Debounce complete
LEDPosition++;
if(LEDPosition>=8)
{
LEDPosition=0; // Return to start position
}
P2=~(0x01<<LEDPosition);
}
// Right shift LED successful
// Use K2 key for left shift
if(P3_0==0)
{
Delay(20);
while(P3_0==0);
Delay(20);
// Debounce complete and prevent overflow
if(LEDPosition==0)
{
LEDPosition=7; // Return to rightmost position
}
else
{
LEDPosition--;
}
// Perform shift operation
P2=~(0x01<<LEDPosition);
}
}
For the << bit shift operator, you might be unfamiliar. Please refer to the diagram.
Please implement the above operations yourself to reinforce your understanding.
That concludes today's content. Thank you for watching.