【51单片机】独立按键实验和矩阵按键实验

橙色

独立按键实验

按键介绍

按键是一种电子开关, 使用时轻轻按开关按钮就可使开关接通, 当松开手时,开关断开。
在这里插入图片描述

通常的按键所用开关为机械弹性开关,当机械触点断开、 闭合时, 电压信号如下图所示:
在这里插入图片描述
由于机械点的弹性作用, 按键开关在闭合时不会马上稳定的接通, 在断开时也不会一下子断开, 因而在闭合和断开的瞬间均伴随着一连串的抖动。 抖动时间的长短由按键的机械特性决定的, 一般为 5ms 到 10ms。 按键抖动会引起按键被误读多次。 为了确保 CPU 对按键的一次闭合仅作一次处理, 必须进行消抖。

按键消抖有两种方式, 一种是硬件消抖, 另一种是软件消抖。 为了使电路更加简单, 通常采用软件消抖。一般来说一个简单的按键消抖就是先读取按键的状态, 如果得到按键按下之后, 延时 10ms, 再次读取按键的状态, 如果按键还是按下状态, 那么说明按键已经按下。 其中延时 10ms 就是软件消抖处理。

独立按键检测原理

独立按键电路构成是由各个按键的一个管脚连接在一起接地, 按键其他引脚分别接到单片机 IO 口。
我们知道单片机的 IO 口既可作为输出也可作为输入使用, 当检测按键时用的是它的输入功能, 独立按键的一端接地, 另一端与单片机的某个 I/O 口相连,开始时先给该 IO 口赋一高电平, 然后让单片机不断地检测该 I/O 口是否变为低电平, 当按键闭合时, 即相当于该I/O 口通过按键与地相连, 变成低电平,程序一旦检测到 I/O 口变为低电平则说明按键被按下, 然后执行相应的指令。

硬件设计

用到的硬件资源:
(1)LED模块中的D1指示灯
(2)K1按键

在这里插入图片描述

从上图中可以看出, 该电路是独立的, 4 个独立按键的控制管脚直接连接到51 单片机的 P3^ 0~P3^3 IO 上。
如果要想 51 单片机能够检测按键是否按下, 就必须通过单片机管脚来控制独立按键。 由于独立按键模块电路是集成的, 所以使用单片机 P3^0~P33 管脚即可。

软件设计

#include "reg52.h"

typedef unsigned int u16;
typedef unsigned char u8;

sbit k1=P3^1;
sbit led=P2^0;

void delay(u16 i)
{
   
	while(i--);
}

void keypros()
{
   
	if(k1==0)
	{
   
	 	delay(1000); //消除抖动,一般大约10ms
		if(k1==0) //再次判断按键是否按下
		{
   
			led=~led; //led状态取反
		}
		while(!k1);	//检测按键是否松开
	}
}
	

void main()	
{
   
	led=1;
	while(1)
	{
   
		keypros();	
	}
}

当独立按键被按下时,K1=0;当独立按键没有被按下时,K1=1。

首先让 led 设置为高电平, 即熄灭 D1 指示灯。 然后进入 while 循环, 在循环体内执行keypros()按键处理函数。 该函数是根据前面介绍独立按键工作原理所编写, 即判断按键 K1
是否按下, 如果按下则延时 10ms 进行消抖, 再次判断按键 K1 是否按下, 如果K1 确实按下, 则执行 LED 状态翻转控制, 最后判断按键是否松开。

矩阵按键实验

本实验所要实现的功能是: 通过开发板上的矩阵键盘控制静态数码管显示对应的键值 0-F。

矩阵按键介绍

独立键盘与单片机连接时, 每一个按键都需要单片机的一个 I/O 口, 若某单片机系统需较多按键, 如果用独立按键便会占用过多的 I/O 口资源。 单片机系统中 I/O 口资源往往比较宝贵, 当用到多个按键时为了减少 I/O 口引脚, 引入了矩阵键盘。

本章以 4*4 矩阵键盘为例讲解其工作原理和检测方法。 开发板上将 16 个按键排成 4 行 4 列, 第一行将每个按键的一端连接在一起构成行线, 第一列将每个按键的另一端连接在一起构成列线, 这样便一共有 4 行 4 列共 8 根线, 我们将这 8 根线连接到单片机的 8 个 I/O 口上, 通过程序扫描键盘就可检测 16 个键。 用这种方法我们也可实现 3 行 3 列 9 个键、 5 行 5 列 25 个键、 6 行6 列 36 个键甚至更多。

无论是独立键盘还是矩阵键盘, 单片机检测其是否被按下的依据都是一样的, 也就是检测与该键对应的 I/O 口是否为低电平。 独立键盘有一端固定为低电平, 单片机写程序检测时比较方便。 而矩阵键盘两端都与单片机 I/O 口相连,因此在检测时需编程通过单片机 I/O 口送出低电平。 检测方法有多种, 最常用的是行列扫描和线翻转法。

行列扫描法检测时, 先送一列为低电平, 其余几列全为高电平(此时我们确定了列数), 然后立即轮流检测一次各行是否有低电平, 若检测到某一行为低电平(这时我们又确定了行数), 则我们便可确认当前被按下的键是哪一行哪一列的, 用同样方法轮流送各列一次低电平, 再轮流检测一次各行是否变为低电平,这样即可检测完所有的按键, 当有键被按下时便可判断出按下的键是哪一个键。当然我们也可以将行线置低电平, 扫描列是否有低电平。 从而达到整个键盘的检测。

硬件设计

本实验用到硬件资源如下:
(1)动态数码管
(2)4*4矩阵按键

矩阵按键模块电路如下图所示:
在这里插入图片描述

从上图中可以看出, 该电路是集成的, 4*4 矩阵按键引出的 8 根控制管脚直接连接到 51 单片机的 P1 IO 口上。 电路中的 P17 表示矩阵键盘第 1 行, P14 表示矩阵键盘第 1 列。

如果要想 51 单片机能够检测按键是否按下, 就必须通过单片机管脚来控制矩阵按键。 由于矩阵按键模块电路是集成的, 所以使用单片机 P1 管脚即可。

软件设计

#include "reg52.h"

typedef unsigned int u16;
typedef unsigned char u8;

#define GPIO_DIG P0
#define GPIO_KEY P1

u8 KeyValue;//用来存放读取到的键值

u8 code smgduan[17]={
   0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};// 显示0~F的值

void delay(u16 i)
{
   
	while(i--);
}

//在标准的 4x4 矩阵键盘中,低四位用于控制列,高四位用于读取行
void KeyDown(void)
{
   
    char a = 0; // 用于计数的变量

    GPIO_KEY = 0X0f; // 设置键盘的低四位为低电平,高四位为高电平
	//有键被按下,意味着引脚P10-P13、P14-P17各有一个引脚变为低电平
    if(GPIO_KEY != 0x0f) // 如果键盘非空闲状态(有键被按下)
    {
   
        delay(1000); // 延时10ms进行去抖动处理

        if(GPIO_KEY != 0x0f) // 确认键仍然处于按下状态
        {
   
            GPIO_KEY = 0X0F; // 通过设置高四位为低电平,低四位为高电平,以便检测具体哪一列有按键按下

            switch(GPIO_KEY)
            {
   
                case(0X07): KeyValue = 0; break; // 根据具体按下的键所在的列,确定具体按下的键是哪一个
                case(0X0b): KeyValue = 1; break;
                case(0X0d): KeyValue = 2; break;
                case(0X0e): KeyValue = 3; break;
            }

            GPIO_KEY = 0XF0; // 通过设置低四位为低电平,高四位为高电平,以便检测具体哪一行有按键按下

            switch(GPIO_KEY)
            {
   
                case(0X70): KeyValue = KeyValue; break; // 根据具体按下的键所在的行,更新 KeyValue 的值
                case(0Xb0): KeyValue = KeyValue + 4; break;
                case(0Xd0): KeyValue = KeyValue + 8; break;
                case(0Xe0): KeyValue = KeyValue + 12; break;    
            }
        }
    }

    // 检测按键松开,或者超过一定次数的循环
    while((a < 50) && (GPIO_KEY != 0xf0))
    {
   
        delay(100);
        a++;
    }             
}


void main()	
{
   
	KeyValue=0;
	while(1)
	{
   
		KeyDown();
		//取反的目的是为了适应 LED 灯点亮的逻辑。如果 LED 灯需要高电平1来点亮,
		//那么就不需要取反。本开发板通过低电平点亮
		//GPIO_DIG对应的是P0口
		GPIO_DIG=~smgduan[KeyValue];	
	}

}

相关推荐

最近更新

  1. TCP协议是安全的吗?

    2024-01-28 14:28:02       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-01-28 14:28:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-01-28 14:28:02       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-01-28 14:28:02       20 阅读

热门阅读

  1. 39. 组合总和

    2024-01-28 14:28:02       38 阅读
  2. VLM 系列——BLIP——论文解读

    2024-01-28 14:28:02       43 阅读
  3. cenos8.5快速部署开发环境(LAMP)

    2024-01-28 14:28:02       29 阅读
  4. 强化学习原理python篇06——DQN

    2024-01-28 14:28:02       34 阅读
  5. ES6 剩余函数

    2024-01-28 14:28:02       33 阅读
  6. 自定义包的设计与实现

    2024-01-28 14:28:02       29 阅读
  7. k8s实例

    k8s实例

    2024-01-28 14:28:02      26 阅读
  8. 【Docker】Docker学习⑧ - Docker仓库之分布式Harbor

    2024-01-28 14:28:02       33 阅读