独立按键
独立按键:通过SW1、SW2、SW3、SW4四个独立按键分别控制LED1、LED2、LED3、LED4的亮灭,具体要求是,按一下(按下并松开)SW,LED点亮,再按一下SW,LED熄灭。
- 芯片和按键接法:
- 原理图:
- 按键抖动:这个现象是由按键的物理特性导致的,由于按键内部的弹簧和触点具有弹性,当按键被按下或释放时,这些弹性材料会震动,从而导致触点在短时间内反复接触和断开。所以表面上我们虽然只按了一次按键,但实际上是按了多次。如果实际按下的次数是奇数,那么LED就会按照预期点亮或熄灭;而如果是偶数,LED最终还是会回到按下按键之前的状态。
- 按键消抖:当我们检测到信号为0时,不能莽撞的认为按键已经被按下了,而是要稍微等一段时间(约10ms),等按键稳定之后,再次检测,如果信号仍然为0,才可以确定按键确实被按下了。
- 示意图:
- 代码实现:
// Int_Key.h
#ifndef __INT_KEY_H__
#define __INT_KEY_H__
#include "Com_Util.h"
#include <STC89C5xRC.H>
#define SW1 P42
#define SW2 P43
#define SW3 P32
#define SW4 P33
bit Int_Key_IsSW1Pressed();
bit Int_Key_IsSW2Pressed();
bit Int_Key_IsSW3Pressed();
bit Int_Key_IsSW4Pressed();
#endif /* __INT_KEY_H__ */
// Int_Key.c
#include "Int_key.h"
bit Int_Key_IsSW1Pressed() {
if(SW1 == 0) {
Com_Util_Delay1ms(10);
if (SW1 == 0) {
while (SW1 == 0);
return 1;
}
}
return 0;
}
bit Int_Key_IsSW2Pressed() {
if (SW2 == 0) {
Com_Util_Delay1ms(10);
if (SW2 == 0) {
while (SW2 == 0);
return 1;
}
}
return 0;
}
bit Int_Key_IsSW3Pressed() {
if (SW3 == 0) {
Com_Util_Delay1ms(10);
if (SW3 == 0) {
while (SW3 == 0);
return 1;
}
}
return 0;
}
bit Int_Key_IsSW4Pressed()
{
if (SW4 == 0) {
Com_Util_Delay1ms(10);
if (SW4 == 0) {
while (SW4 == 0);
return 1;
}
}
return 0;
}
// main.c
#include "Int_Key.h"
#define LED1 P00
#define LED2 P01
#define LED3 P02
#define LED4 P03
void main()
{
while (1) {
if (Int_Key_IsSW1Pressed()) {
LED1 = ~LED1;
}
if (Int_Key_IsSW2Pressed()) {
LED2 = ~LED2;
}
if (Int_Key_IsSW3Pressed()) {
LED3 = ~LED3;
}
if (Int_Key_IsSW4Pressed()) {
LED4 = ~LED4;
}
}
}
矩阵按键
按下按键矩阵中的SW5到SW20按键后,数码管显示对应的按键编号。
- 实现思路:借用动态扫描的思想,将按钮循环得连接。
- 单片机引脚构造: 弱上拉强下拉;
原理图:
代码实现:
// Int_DigitalTube.c
#include "Int_DigitalTube.h"
#include <STC89C5xRC.H>
static u8 s_codes[11] = {
0x3F, // 0
0x06, // 1
0x5B, // 2
0x4F, // 3
0x66, // 4
0x6D, // 5
0x7D, // 6
0x07, // 7
0x7F, // 8
0x6F, // 9
0x40 // -
};
// 存放显示的数的缓存
static u8 s_buffer[8];
// 打开数码管的输入使能
void Int_DigitalTube_Init()
{
SMG_EN = 0;
LED_EN = 0;
}
static void Int_DigitalTube_DisplaySingle(u8 position, u8 num_code)
{
// 关闭当前数码管 否则数码管将有重影
P0 = 0x00;
// 位选
// 先将要显示的数左移 3 位
position <<= 3;
// 按位与 将P1 的 p13、P14、P15 位置的数变为0
P1 &= 0xC7;
// 按位或 | 将 P1 的 p13、P14、P15 位置和 position 相应位置数交换
P1 |= position;
// 段选 需要放置的数字
P0 = num_code;
}
// 将显示的数放在缓存里
void Int_DigitalTube_DisplayNum(s32 num)
{
u8 i;
// 将显存清零
for (i = 0; i < 8; i++) {
s_buffer[i] = 0x00;
}
if (num < 0) { // 这个功能不需要考虑
num = -num; // 取绝对值
i = 7; // 从最右侧开始显示数字
// 将每个位上的数放入显存,从右向左填充
while (num > 0) {
s_buffer[i] = s_codes[num % 10];
num /= 10;
i--;
}
// 如果是负数,将负号放在数字之前的一位
if (i < 7) {
s_buffer[i] = s_codes[10]; // s_codes[10] 对应负号 '-'
}
} else if (num > 0) {
i = 7; // 正数从最右侧开始显示
while (num > 0) {
s_buffer[i] = s_codes[num % 10];
num /= 10;
i--;
}
} else {
// 如果 num == 0 ,将0 放在最右边
s_buffer[7] = s_codes[0];
}
}
// 循环多次刷新数码管
void Int_DigitalTube_Refresh()
{
u8 i;
for (i = 0; i < 8; i++) {
Int_DigitalTube_DisplaySingle(i, s_buffer[i]);
Com_Util_Delay1ms(1); // 延时
}
}
// Int_DigitalTube.h
#ifndef __INT_DIGITALTUBE_H__
#define __INT_DIGITALTUBE_H__
#define SMG_EN P36
#define LED_EN P34
#include "Com_Util.h"
void Int_DigitalTube_Init();
void Int_DigitalTube_DisplayNum(s32 num);
void Int_DigitalTube_Refresh();
#endif /* __INT_DIGITALTUBE_H__ */
// Int_keyMatrix.h
#ifndef __INT_KEYMATRIX_H__
#define __INT_KEYMATRIX_H__
#include "Com_Util.h"
#include <STC89C5xRC.H>
u8 Int_KeyMatrix_CheckSW();
#endif /* __INT_KEYMATRIX_H__ */
// Int_KeyMatrix.c
#include "Int_KeyMatrix.h"
u8 Int_KeyMatrix_CheckSW() {
u8 i, j;
u8 lines[4] = {0xFE, 0xFD, 0xFB, 0xF7};
u8 columns[4] = {0x10, 0x20, 0x40, 0x80};
for (i = 0; i < 4; i++) {
P2 = lines[i];
for ( j = 0; j < 4; j++) {
if ((P2 & columns[j]) == 0x00) {
Com_Util_Delay1ms(10);
if ((P2 & columns[j]) == 0x00) {
while ((P2 & columns[j]) == 0x00);
return 5 + j + 4 * i;
}
}
}
}
return 0;
}
// main.c
#include "Int_DigitalTube.h"
#include "Int_KeyMatrix.h"
void main()
{
u8 key;
Int_DigitalTube_Init();
while (1) {
key = Int_KeyMatrix_CheckSW();
if (key) {
Int_DigitalTube_DisplayNum(key);
}
Int_DigitalTube_Refresh();
}
}
- 在Int_DigitalTube_Refresh()函数中,最后加上延迟函数 Com_Util_Delay1ms(1); 不加延时函数,会出现数码管上前一个数字会比后一个数字的亮度暗很多,这是因为主函数执行时,一直做循环,当第一次执行Int_DigitalTube_Refresh函数,先将最后一个数字显示出来,然后执行下次循环,将下一个数字显示出来,在这个过程中,执行Int_DigitalTube_Refresh需要时间,执行一条命令是微妙级的,执行最后一次命令就会和第一次体现出时间相差较大,所以第一次显示的会比最后显示的亮一些,可以加上延迟函数,减小它们之间的时间差,使亮度基本一致。
- 在数码管上显示时,当按下一个按键不松开,他会显示上一次数字的最后一位数字。当按下不松开时,主函数执行Int_KeyMatrix_CheckSW()函数,在执行里面的for 循环语句时,会执行while ((P2 & columns[j]) == 0x00)这句代码,它会一直等待松开按键,程序就会在次阻塞,主函数中的Int_DigitalTube_Refresh也不会执行,会显示Int_DigitalTube_Refresh函数上一次刷新的数字的最后一位。
按键位移
// Int_DigitalTube.c
// 二进制显示函数
void Int_DigitalTube_DisplayBinary(u8 num)
{
u8 i;
for (i = 0; i < 8; i++) {
s_buffer[i] = s_codes[(num & (0x80 >> i)) == 0x00 ? 0 : 1]; // 判断位置上是0还是1
}
}
// main.c
#include "Int_DigitalTube.h"
#include "Int_key.h"
void main() {
u8 init = 0xFF;
Int_DigitalTube_Init(); // 初始化数码管
Int_DigitalTube_DisplayBinary(init);
while (1) {
// 检测按键状态并更新相应的pair值
if (Int_Key_IsSW1Pressed()) {
init <<= 1;
Int_DigitalTube_DisplayBinary(init);
}
// 检测按键状态并更新相应的pair值
if (Int_Key_IsSW2Pressed()) {
init >>= 1;
Int_DigitalTube_DisplayBinary(init);
}
// 检测按键状态并更新相应的pair值
if (Int_Key_IsSW3Pressed()) {
init += 1;
Int_DigitalTube_DisplayBinary(init);
}
// 检测按键状态并更新相应的pair值
if (Int_Key_IsSW4Pressed()) {
init = 0x00;
Int_DigitalTube_DisplayBinary(init);
}
// 更新显示
Int_DigitalTube_Refresh();
}
}
按键记数
// main.c
#include "Int_DigitalTube.h"
#include "Int_key.h"
u8 num1 = 0;
u8 num2 = 0;
u8 num3 = 0;
u8 num4 = 0;
u32 getSum() {
return 1000000 * num1 + 10000L * num2 + 100 * num3 + num4;
}
void main() {
Int_DigitalTube_Init(); // 初始化数码管
while (1) {
// 检测按键状态并更新相应的pair值
if (Int_Key_IsSW1Pressed()) {
Int_DigitalTube_Init();
num1++;
if (num1 > 99) {
num1 = 0;
}
Int_DigitalTube_DisplayNum(getSum());
}
if (Int_Key_IsSW2Pressed()) {
Int_DigitalTube_Init();
num2++;
if (num2 > 99) {
num2 = 0;
}
Int_DigitalTube_DisplayNum(getSum());
}
if (Int_Key_IsSW3Pressed()) {
Int_DigitalTube_Init();
num3++;
if (num3 > 99) {
num3 = 0;
}
Int_DigitalTube_DisplayNum(getSum());
}
if (Int_Key_IsSW4Pressed()) {
Int_DigitalTube_Init();
num4++;
if (num4 > 99) {
num4 = 0;
}
Int_DigitalTube_DisplayNum(getSum());
}
// 更新显示
Int_DigitalTube_Refresh();
}
}