51单片机——按键实验

由于机械点的弹性作用,按键开关在闭合时不会马上稳定的接通,在断开时也不会一下子断开,因而在闭合和断开的瞬间均伴随着一连串的抖动。抖动时间的长短由按键的机械特性决定的,一般为 5ms 到 10ms,为了确保 CPU 对按键的一次闭合仅作一次处理,必须进行消抖

普中开发板是采用软件消抖,一般来说一个简单的按键消抖就是先读取按键的状态,如果得到按键按下之后,延时 10ms,再次读取按键的状态,如果按键还是按下状态,那么说明按键已经按下。其中延时10ms 就是软件消抖处理

1、独立按键实验

P3.1控制K1, P3.0控制K2, P3.2控制K3, P3.3控制K4

软件去抖动方法:

(1)先设置 IO 口为高电平(由于开发板 IO 都有上拉电阻,所以默认 IO 为高电平)

(2)读取 IO 口电平确认是否有按键按下

(3)如有 IO 电平为低电平后,延时几个毫秒

(4)再读取该 IO 电平,如果仍然为低电平,说明按键按下

(5)执行按键控制程序

要实现的功能是:通过开发板上的独立按键K1控制D1指示灯亮灭

#include "reg51.h"

typedef unsigned int u16;

typedef unsigned char u8;

void delay(u16 time){

while(time--);

}

//控制D1-D4指示灯

sbit LED1=P2^0;

sbit LED2=P2^1;

sbit LED3=P2^2;

sbit LED4=P2^3;

//使用宏定义的方法定义独立按键的键值

#define KEY1_PRESS 1

#define KEY2_PRESS 2

#define KEY3_PRESS 3

#define KEY4_PRESS 4

#define KEY_UNPRESS 0

//定义按键对应的管脚口

sbit KEY1=P3^1;

sbit KEY2=P3^0;

sbit KEY3=P3^2;

sbit KEY4=P3^3;

//封装一个函数,按键返回一个键值

u8 key_scan(u16 mode){ //mode:模式,有0和1操作,如果操作0,单次扫描;如果操作1,连续扫描

//打一个标志

static u16 key=1;

if(mode==1){

key=1;

}

if(key==1&&(KEY1==0||KEY2==0||KEY3==0||KEY4==0)){

//消抖处理,需要延时5ms-10ms

delay(1000);

key=0;

//如果仍是按下,信号稳定

if(KEY1==0){

return KEY1_PRESS;

}else if(KEY2==0){

return KEY2_PRESS;

}else if(KEY3==0){

return KEY3_PRESS;

}else if(KEY4==0){

return KEY4_PRESS;

}

}else if(KEY1==1&&KEY2==1&&KEY3==1&&KEY4==1){

key=1;

return KEY_UNPRESS;

}

}

void main(){

u8 key=0;

while(1){

key=key_scan(0);

if(key==KEY1_PRESS){

LED1=!LED1;

delay(1000); //加一下延时可以验证单次扫描和连续扫描的情况

}else if(key==KEY2_PRESS){

LED2=!LED2;

}else if(key==KEY3_PRESS){

LED3=!LED3;

}else if(key==KEY4_PRESS){

LED4=!LED4;

}

}

}

2、矩阵按键实验

P1端控制矩阵键盘

P1.7连接矩阵键盘的第1行,P1.6连接矩阵键盘的第2行,P1.5连接矩阵键盘的第3行,P1.4连接矩阵键盘的第4行

P1.3连接矩阵键盘的第1列,P1.2连接矩阵键盘的第2列,P1.1连接矩阵键盘的第3列,P1.0连接矩阵键盘的第4列

0 0 0 0 0 0 0 0


P1.7 P1.6 P1.5 P1.4 P1.3 P1.2 P1.1 P1.0

独立键盘有一端固定为低电平,此种方式编程比较简单。 而矩阵键盘两端都与单片机 I/O 口相连,因此在检测时需编程通过单片机 I/O 口送出低电平。

单片机 I/O 口送出低电平检测方法有多种,最常用的是行列扫描和线翻转法:

(1)行列扫描法:先送一列为低电平,其余几列全为高电平(此时我们确定了列数),然后立即轮流检测一次各行是否有低电平,若检测到某一行为低电平(这时我们又确定了行数),则我们便可确认当前被按下的键是哪一行哪一列的

(2)线翻转法:就是使所有行线为低电平时,检测所有列线是否有低电平,如果有,就记录列线值;然后再翻转,使所有列线都为低电平,检测所有行线的值,由于有按键按下,行线的值也会有变化,记录行线的值。从而就可以检测到全部按键

2.1 行列扫描法

行列扫描法:先送一列为低电平,其余几列全为高电平(此时我们确定了列数),然后立即轮流检测一次各行是否有低电平,若检测到某一行为低电平(这时我们又确定了行数),则我们便可确认当前被按下的键是哪一行哪一列的

#include "reg51.h"

typedef unsigned int u16;

typedef unsigned char u8;

void delay(u16 time){

while(time--);

}

//使用宏定义定义矩阵按键的管脚

#define KEY_MATRIX_PORT P1

//数码管:静态数码管操作

#define SMG_A_DP_PORT P0

//0-F

u16 gmsg_code[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

u16 key_matrix_scan(){

//定义一个变量返回

u16 key_value=0;

//给第一列赋值0,其余全为1

KEY_MATRIX_PORT=0xf7;

if(KEY_MATRIX_PORT!=0xf7){

//消抖

delay(1000);

//检测行

switch(KEY_MATRIX_PORT){

case 0x77:

key_value=1;

break;

case 0xb7:

key_value=5;

break;

case 0xd7:

key_value=9;

break;

case 0xe7:

key_value=13;

break;

}

}

//等待按键松开

while(KEY_MATRIX_PORT!=0xf7);

//给第二列赋值0,其余全为1

KEY_MATRIX_PORT=0xfb;

if(KEY_MATRIX_PORT!=0xfb){

//消抖

delay(1000);

//检测行

switch(KEY_MATRIX_PORT){

case 0x7b:

key_value=2;

break;

case 0xbb:

key_value=6;

break;

case 0xdb:

key_value=10;

break;

case 0xeb:

key_value=14;

break;

}

}

//等待按键松开

while(KEY_MATRIX_PORT!=0xfb);

//给第三列赋值0,其余全为1

KEY_MATRIX_PORT=0xfd;

if(KEY_MATRIX_PORT!=0xfd){

//消抖

delay(1000);

//检测行

switch(KEY_MATRIX_PORT){

case 0x7d:

key_value=3;

break;

case 0xbd:

key_value=7;

break;

case 0xdd:

key_value=11;

break;

case 0xed:

key_value=15;

break;

}

}

//等待按键松开

while(KEY_MATRIX_PORT!=0xfd);

//给第四列赋值0,其余全为1

KEY_MATRIX_PORT=0xfe;

if(KEY_MATRIX_PORT!=0xfe){

//消抖

delay(1000);

//检测行

switch(KEY_MATRIX_PORT){

case 0x7e:

key_value=4;

break;

case 0xbe:

key_value=8;

break;

case 0xde:

key_value=12;

break;

case 0xee:

key_value=16;

break;

}

}

//等待按键松开

while(KEY_MATRIX_PORT!=0xfe);

//返回值

return key_value;

}

void main(){

u16 key=0;

while(1){

key=key_matrix_scan();

if(key!=0){

SMG_A_DP_PORT=gmsg_code[key-1];

}

}

}

2.2 线翻转法

线翻转法,就是使所有行线为低电平时,检测所有列线是否有低电平,如果有,就记录列线值;然后再翻转,使所有列线都为低电平,检测所有行线的值,由于有按键按下,行线的值也会有变化,记录行线的值。从而就可以检测到全部按键

#include "reg51.h"

typedef unsigned int u16;

typedef unsigned char u8;

void delay(u16 time){

while(time--);

}

//使用宏定义定义矩阵按键的管脚

#define KEY_MATRIX_PORT P1

//数码管:静态数码管操作

#define SMG_A_DP_PORT P0

//0-F

u16 gmsg_code[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

u16 key_matrix_flip_scan(){

u16 key_value=0;

//使所有行线为低电平,列线为高电平

KEY_MATRIX_PORT=0x0f;

if(KEY_MATRIX_PORT!=0x0f){

//消抖

delay(1000);

if(KEY_MATRIX_PORT!=0x0f){

//测试列,使所有行线为低电平,列线为高电平

KEY_MATRIX_PORT=0x0f;

switch(KEY_MATRIX_PORT){

case 0x07:

key_value=1; //暂时赋一个值

break;

case 0x0b:

key_value=2;

break;

case 0x0d:

key_value=3;

break;

case 0x0e:

key_value=4;

break;

}

//测试行,使所有列线为低电平,行线为高电平

KEY_MATRIX_PORT=0xf0;

switch(KEY_MATRIX_PORT){

case 0x70:

key_value=key_value;

break;

case 0xb0:

key_value=key_value+4;

break;

case 0xd0:

key_value=key_value+8;

break;

case 0xe0:

key_value=key_value+12;

break;

}

while(KEY_MATRIX_PORT!=0xf0);

}else{

key_value=0;

}

return key_value;

}

}

void main(){

u16 key=0;

while(1){

key=key_matrix_flip_scan();

if(key!=0){

SMG_A_DP_PORT=gmsg_code[key-1];

}

}

}

相关推荐
aloneboyooo12 分钟前
PWR-STM32电源控制
stm32·单片机·嵌入式硬件
韦东山27 分钟前
zephyr移植到STM32
stm32·单片机·嵌入式硬件·zephyr
知困勉行的Allen6 小时前
MCS-51单片机常用汇编指令和特殊功能寄存器~
c语言·汇编·数据结构·单片机·嵌入式硬件·51单片机·学习方法
1101 110110 小时前
STM32-笔记36-ADC(模拟/数字转换器)
笔记·stm32·嵌入式硬件
youcans_11 小时前
【动手学电机驱动】STM32-MBD(3)Simulink 状态机模型的部署
stm32·单片机·嵌入式硬件·matlab·代码生成
end_SJ11 小时前
初学STM32 --- USMART
stm32·单片机·嵌入式硬件
我想学LINUX13 小时前
【stm32+K210项目】基于K210与STM32协同工作的智能垃圾分类系统设计与实现(完整工程资料源码)
stm32·单片机·嵌入式硬件·毕业设计·课程设计·项目
JoneMaster13 小时前
[读书日志]8051软核处理器设计实战(基于FPGA)第五篇:8051软核处理器主体框架搭建(verilog)
嵌入式硬件·fpga开发·硬件架构
end_SJ13 小时前
初学stm32 --- RTC实时时钟
stm32·嵌入式硬件·实时音视频
森旺电子13 小时前
STM32+WIFI获取网络时间+8位数码管显示+0.96OLED显
stm32·单片机·嵌入式硬件