注:此单片机型号为 STC15F2K60S2.
目录标题
- 独立按键
- 原理
-
- 代码
- 入门代码
- 进阶代码
- 消抖改进(按一下只执行一次,长按也一样)
- 补充
独立按键
原理
![来源:我自己:)](https://img-blog.csdnimg.cn/97955712d50b4217935c8ae1ce7f651c.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBATW9xaW0=,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)
这是一个矩阵按键的电路图,要使得其进入独立按键模式,就要把跳线帽连接2、3.
![来源:我自己:)](https://img-blog.csdnimg.cn/2859f4f27f694ff78b8e166ea2267c54.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBATW9xaW0=,size_10,color_FFFFFF,t_70,g_se,x_16#pic_center)
(注:跳线帽是外部可移动的元件。)
此时,即为独立按键模式。
![来源:我自己:)](https://img-blog.csdnimg.cn/733d04782521478393f07d6fbf97ee0e.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBATW9xaW0=,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)
按键原理
以 S7 按键为例,其左端连接接地,右端连接 P30,由于一开始所有 P 口都默认为高电平,则只要检测到 P30 为低电平,则说明按键 S7 被按下。
消抖
![在这里插入图片描述](https://img-blog.csdnimg.cn/207b0867fa71484fb0e405c7db433c84.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBATW9xaW0=,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)
当按键被按下的时候,电路导通接地,I/O口为低电平;
当按键未被按下时,电路断开,I/O口保持高电平。
但一般的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。因而在闭合及断开的瞬间均伴随有一连串的抖动,假如不加以处理,会导致按键被识别为按下多次。为了不产生这种现象而作的措施就是按键消抖。
消抖有硬件消抖和软件消抖两种方法,但我们不可能去更换硬件,所以主要采用软件消抖 —— 写一个延迟 5ms 左右的函数。
参考资料:@我要糖 —— 单片机之按键消抖
代码
入门代码
//key.c
#include "key.h"
sbit S7 = P3^0;
sbit S6 = P3^1;
sbit S5 = P3^2;
sbit S4 = P3^3;
unsigned char Key_Scan(void)
{
if (S4 == 0)
{
Key_Delay(10);
if (S4 == 0)
return 4;
}
else if (S5 == 0)
{
Key_Delay(10);
if (S5 == 0)
return 5;
}
else if (S6 == 0)
{
Key_Delay(10);
if (S6 == 0)
return 6;
}
else if (S7 == 0)
{
Key_Delay(10);
if (S7 == 0)
return 7;
}
return 0;
}
void Key_Delay(unsigned int num)
{
int i, j;
for (i = 0; i<num; i++)
for(j = 0; j<625; j++);
}
//key.h
#ifndef __KEY_H
#define __KEY_H
#include "stc15f2k60s2.h"
unsigned char Key_Scan(void);
void Key_Delay(unsigned int num);
#endif
//main.c
#include "stc15f2k60s2.h"
#include "led.h"
#include "seg.h"
#include "key.h"
void Delay_ms(unsigned int num);
void Key_Disp(void);
int main(void)
{
LED_Init();
SEG_Init();
while (1)
{
Key_Disp();
}
}
void Key_Disp(void)
{
static unsigned char Key_Val = 0;
static int i = 0;
Key_Val = Key_Scan();
switch (Key_Val)
{
case 4:i = 4;break;
case 5:i = 5;break;
case 6:i = 6;break;
case 7:i = 7;break;
default:i = 0;break;
}
if (i > 0)
{
LED_Ctrl(0x01 << i - 1);
smg1 = i;
}
else
{
LED_Ctrl(0x00);
smg1 = 0;
}
SEG_Scan();
Delay_ms(200);
}
void Delay_ms(unsigned int num)
{
int i, j;
for(i = 0; i<num; i++)
{
for(j = 0; j<625; j++);
}
}
LED 和 SEG 代码请参考之前博客。
进阶代码
void key_press(int* p)
{
if (P30 == 0) {
delay(5);
if (P30 == 0)
(*p)++;
while (P30 == 0);
}
}
但上述代码有一个缺点,即长按按键会一直执行程序,
所以,改进代码如下——
void key_press(int* p)
{
bit S7 = 0;
if ((P30 == 0)&&(S7 == 0)) {
delay(5);
if ((P30 == 0) && (S7 == 0))
S7 = 1;
}
if ((P30 == 1) && (S7 == 1)) {
(*p)++;
S7 = 0;
}
}
这样,每次按完一次才会执行一次,长按则不会影响。
参考资料:bilibili@一蓑烟雨任平生 a—— 基于蓝桥杯单片机的 STC15 学习教程。
消抖改进(按一下只执行一次,长按也一样)
来源:上课认真听讲。
u8 flag = 0;
if(key_read == 4 && flag == 0){
flag = 1;
}
if(flag == 1 && key_read() != 4){
flag = 0;
}
u8 last_key_value = 0;
u8 current_key_value = key_read();
if(current_key_value > last_key_value && current_key_value == 4){
}
last_key_value = current_key_value;
u8 key_val = 0;
u8 last_key_value = 0;
u8 current_key_value = 0;
current_key_value = key_read();
key_val = current_key_value ^ last_key_value & current_key_value;
last_key_value = current_key_value;
switch(key_val){
case 4:if(++ work_state == 4)work_state = 1;break;
case 5:
case 6:
case 7:
}
补充
2022.04.04
我现在常用的:
void Key_Proc(void){
static unsigned char ucKey_Val = 0;
static unsigned char ucKey_Down = 0;
static unsigned char ucKey_Old = 0;
ucKey_Val = Key_Scan();
ucKey_Down = ucKey_Val & (ucKey_Val ^ ucKey_Old);
ucKey_Old = ucKey_Val;
switch(ucKey_Down){
case 4:break;
default:break;
}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)