【51单片机】程序实验5&6.独立按键-矩阵按键

主要参考学习资料:B站【普中官方】51单片机手把手教学视频

前置知识:C语言

单片机套装:普中STC51单片机开发板A4标准版套餐7

码字不易,求点赞收藏加关注(´•ω•̥`)

有问题欢迎评论区讨论~

目录

独立按键

按键介绍

一个按键拥有四个脚,其中①和②、③和④之间初始导通,而①和③、②和④之间只有按下按键才会导通。

在下拉电阻作用下,按键所处管脚默认为高电平,当按下按键时线路接地变成低电平。

在实际情况中,按键的状态切换过程存在抖动,而不是在高低电平之间瞬时、稳定地切换。由于抖动过程中的电平变化会造成按键状态的误判,因此需要采取消抖措施,有软件消抖和硬件消抖两种方法:

软件消抖根据实际经验估计抖动时间在5~10ms,于是可以在检测到第一次低电平后延时10ms再次检测,若仍为低电平可认为按键已处于按下状态。

硬件消抖在电路上并联滤波电容,利用按下按键后给电容充电的时间来滤除抖动影响。

由于硬件消抖占用的电路面积较大且产生的成本较高,在实际开发应用中通常使用软件消抖。

实验5 独立按键

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

c 复制代码
#include "reg52.h"

typedef unsigned char u8;
typedef unsigned int u16;

//定义四个按键的控制管脚
sbit KEY1 = P3^1;
sbit KEY2 = P3^0;
sbit KEY3 = P3^2;
sbit KEY4 = P3^3;

//定义D1指示灯的控制管脚
sbit LED1 = P2^0;

//延时函数
void delay_10us(u16 time)
{
	while(time --);
}

/*
按键扫描函数
扫描有两种方式:一种只对按下瞬间扫描,不考虑按下后是保持还是松开(点按控制);另一种为持续扫描按键按下的状态(长按控制)
mode参数决定该函数采用哪种扫描,0为点按,1为长按
*/
u8 key_scan(u8 mode)
{
    //定义控制是否检测按下状态的变量,1检测,0不检测,注意静态变量赋值只生效一次
	static u8 key = 1;
    //如果为长按扫描则检测按下状态
	if(mode)
		key = 1;
    //如果需要检测按下状态且有按键按下(低电平),则消抖后再检测具体是哪个按键被按下
	if(key == 1 && (KEY1 == 0 || KEY2 == 0 || KEY3 == 0 || KEY4 == 0))
	{
		key = 0; //重置key变量默认下一次不需要检测按下状态
		delay_10us(1000); //消抖
        
        //检测到哪个按键按下则返回对应的按键序号
		if(KEY1 == 0)
			return 1;
		else if(KEY2 == 0)
			return 2;
		else if(KEY3 == 0)
			return 3;
		else if(KEY4 == 0)
			return 4;
	}
    
    //如果没有按键被按下则下一次继续检测是否有按键被按下
	else if(KEY1 == 1 && KEY2 == 1 && KEY3 == 1 && KEY4 == 1)
	{
		key = 1;
	}
	return 0;
}

void main()
{
	u8 key = 0; //存储按下按键序号的变量,没有按键被按下则为0
	while(1)
	{
		key = key_scan(0); //循环按键扫描函数
		if(key == 1)
			LED1 = !LED1; //如果按键K1被按下则切换D1指示灯状态
	}
}

矩阵按键

矩阵按键介绍

在独立按键中,一个按键占用一个I/O口。当按键数量较多时,如果采用独立按键的接法会占用非常多的I/O资源。单片机为了减少I/O占用的引脚,引入了矩阵按键。

矩阵按键的一端串联在行线路上,另一端串联在列线路上,当按键按下时,按键所在的行线路和列线路接通。所有线路在下拉电阻作用下默认为高电平。

矩阵按键的扫描有两种方法:

行列式扫描按行(列)将矩阵按键拆成多组独立按键,对每一行(列)进行扫描时,将该行(列)设为低电平以达到独立按键中接地的条件,然后按独立按键扫描方法扫描,依次扫描完每一行(列)。

线翻转扫描按先列(行)后行(列)的方式确定按下按键的位置,先将所有行(列)线路接地,检测哪一列(行)有按键被按下,则对应的列(行)接通为低电平;再将所有列(行)线路接地,检测哪一行(列)有按键被按下,结合被按下按键的列(行)坐标确认其序号。

实验6-1 行列式扫描

实现功能:按下矩阵按键S1到S16使数码管第一位显示0到F。

c 复制代码
#include "reg52.h"

typedef unsigned char u8;
typedef unsigned int u16;

//宏定义矩阵按键端口
#define KEY_MATRIX_PORT P1

//宏定义数码管端口
#define SEG_A_DP_PORT P0

//数码管0~F编码
u8 gseg_code[16]={0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71};

//延时函数
void delay_10us(u16 time)
{
	while(time --);
}

//行列式扫描函数
u8 key_matrix_ranks_scan()
{
	u8 key_value = 0; //存储按下按键序号的变量,没有按键被按下则为0
	KEY_MATRIX_PORT = 0xf7; //第一列设为低电平,即P1端口高位到低位输出11110111(前四位为行,后四位为列),再转换为十六进制
	if(KEY_MATRIX_PORT != 0xf7) //如果第一列有按键按下,则具体检测第一列哪一行按键被按下
	{
		delay_10us(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); //点按扫描在按下按键松开之前不再检测
	KEY_MATRIX_PORT = 0xfb; //扫描第二列
	if(KEY_MATRIX_PORT != 0xfb)
	{
		delay_10us(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);
	KEY_MATRIX_PORT = 0xfd; //扫描第三列
	if(KEY_MATRIX_PORT != 0xfd)
	{
		delay_10us(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);
	KEY_MATRIX_PORT = 0xfe; //扫描第四列
	if(KEY_MATRIX_PORT != 0xfe)
	{
		delay_10us(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()
{
	u8 key = 0; //存储按下按键序号的变量,没有按键被按下则为0
	while(1)
	{
		key = key_matrix_ranks_scan(); //循环行列式扫描函数
		if(key != 0)
			SEG_A_DP_PORT = gseg_code[key - 1]; //按下按键将数码管切换到对应的值
	}
}

实验6-2 线翻转扫描

c 复制代码
//线翻转扫描函数,将实验6-1中调用行列式扫描函数的地方替换为该函数即可
u8 key_matrix_flip_scan()
{
	u8 key_value = 0; //存储按下按键序号的变量,没有按键被按下则为0
	KEY_MATRIX_PORT = 0x0f; //将行线路全部接地,即P1端口输出00001111
	if(KEY_MATRIX_PORT != 0x0f) //如果有按键按下则进入具体检测
	{
		delay_10us(1000); //消抖
		if(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 += 0; break; //按键序号 = 列序号 + 4 * (行序号 - 1)
				case 0xb0: key_value += 4; break;
				case 0xd0: key_value += 8; break;
				case 0xe0: key_value += 12; break;
			}
			while(KEY_MATRIX_PORT != 0xf0); //点按扫描在按下按键松开之前不再检测
		}
	}
	return key_value;
}

本篇完

相关推荐
量子-Alex2 分钟前
【多模态聚类】用于无标记视频自监督学习的多模态聚类网络
学习·音视频·聚类
吉大一菜鸡6 分钟前
FPGA学习(基于小梅哥Xilinx FPGA)学习笔记
笔记·学习·fpga开发
森旺电子1 小时前
51单片机仿真摇号抽奖机源程序 12864液晶显示
单片机·嵌入式硬件·51单片机
CCSBRIDGE3 小时前
Magento2项目部署笔记
笔记
爱吃西瓜的小菜鸡3 小时前
【C语言】判断回文
c语言·学习·算法
小A1593 小时前
STM32完全学习——SPI接口的FLASH(DMA模式)
stm32·嵌入式硬件·学习
亦枫Leonlew3 小时前
微积分复习笔记 Calculus Volume 2 - 5.1 Sequences
笔记·数学·微积分
岁岁岁平安3 小时前
spring学习(spring-DI(字符串或对象引用注入、集合注入)(XML配置))
java·学习·spring·依赖注入·集合注入·基本数据类型注入·引用数据类型注入
武昌库里写JAVA4 小时前
Java成长之路(一)--SpringBoot基础学习--SpringBoot代码测试
java·开发语言·spring boot·学习·课程设计
qq_589568104 小时前
数据可视化echarts学习笔记
学习·信息可视化·echarts