【51单片机快速入门指南】2.3:GPIO读取矩阵键盘 8个IO读16键

目录

  • 硬知识
    • 矩阵键盘介绍
  • 测试程序
    • Key_Board.c
    • Key_Board.h
    • main.c
  • 实验现象

普中51-单核-A2
STC89C52
Keil uVision V5.29.0.0
PK51 Prof.Developers Kit Version:9.60.0.0


硬知识

选自《普中51单片机开发攻略_V1.2》

矩阵键盘介绍

       独立按键与单片机连接时,每一个按键都需要单片机的一个 I/O 口,若某单片机系统需较多按键,如果用独立按键便会占用过多的 I/O 口资源。单片机系统中 I/O 口资源往往比较宝贵,当用到多个按键时为了减少 I/O 口引脚,便引入了矩阵按键。
       以 4x4 矩阵键盘为例讲解其工作原理和检测方法。开发板上将 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 口送出低电平。检测方法有多种,最常用的是行列扫描和线翻转法。
       行列扫描法检测时,先送一列为低电平,其余几列全为高电平(此时我们确定了列数),然后立即轮流检测一次各行是否有低电平,若检测到某一行为低电平(这时我们又确定了行数),则我们便可确认当前被按下的键是哪一行哪一列的,用同样方法轮流送各列一次低电平,再轮流检测一次各行是否变为低电平, 这样即可检测完所有的按键,当有键被按下时便可判断出按下的键是哪一个键。 当然我们也可以将行线置低电平,扫描列是否有低电平。从而达到整个键盘的检测。
       线翻转法,就是使所有行线为低电平时,检测所有列线是否有低电平,如果有,就记录列线值;然后再翻转,使所有列线都为低电平,检测所有行线的值, 由于有按键按下,行线的值也会有变化,记录行线的值。从而就可以检测到全部按键。
在这里插入图片描述

测试程序

本程序修改自官方例程《9-矩阵按键实验》

stdint.h见【51单片机快速入门指南】1:基础知识和工程创建

Key_Board.c

#include <REGX52.H>
#include "intrins.h"
#include "stdint.h"#define KEY_MATRIX_PORT	P1	//使用宏定义矩阵按键控制口	#define KEY_BOARD_WHILE_FLAG 0void Key_Board_Delay()	//20ms @11.0592MHz
{unsigned char i, j;i = 36;j = 217;do{while (--j);} while (--i);
}/*******************************************************************************
* 函 数 名       : key_matrix_ranks_scan
* 函数功能		 : 使用行列式扫描方法,检测矩阵按键是否按下,按下则返回对应键值
* 输    入       : 无
* 输    出    	 : key_value:1-16,对应S1-S16键,0:按键未按下
*******************************************************************************/
uint8_t key_matrix_ranks_scan(void)
{uint8_t key_value=0;KEY_MATRIX_PORT=0xf7;//给第一列赋值0,其余全为1if(KEY_MATRIX_PORT!=0xf7)//判断第一列按键是否按下{if(key_value)Key_Board_Delay();//消抖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;}}
#if KEY_BOARD_WHILE_FLAGwhile(KEY_MATRIX_PORT!=0xf7);//等待按键松开	
#endif	KEY_MATRIX_PORT=0xfb;//给第二列赋值0,其余全为1if(KEY_MATRIX_PORT!=0xfb)//判断第二列按键是否按下{if(key_value)Key_Board_Delay();//消抖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;}}
#if KEY_BOARD_WHILE_FLAGwhile(KEY_MATRIX_PORT!=0xfb);//等待按键松开	
#endif		KEY_MATRIX_PORT=0xfd;//给第三列赋值0,其余全为1if(KEY_MATRIX_PORT!=0xfd)//判断第三列按键是否按下{if(key_value)Key_Board_Delay();//消抖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;}}
#if KEY_BOARD_WHILE_FLAGwhile(KEY_MATRIX_PORT!=0xfd);//等待按键松开	
#endif	KEY_MATRIX_PORT=0xfe;//给第四列赋值0,其余全为1if(KEY_MATRIX_PORT!=0xfe)//判断第四列按键是否按下{if(key_value)Key_Board_Delay();//消抖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;}}
#if KEY_BOARD_WHILE_FLAGwhile(KEY_MATRIX_PORT!=0xfe);//等待按键松开
#endif	return key_value;		
}/*******************************************************************************
* 函 数 名       : key_matrix_flip_scan
* 函数功能		 : 使用线翻转扫描方法,检测矩阵按键是否按下,按下则返回对应键值
* 输    入       : 无
* 输    出    	 : key_value:1-16,对应S1-S16键,0:按键未按下
*******************************************************************************/
uint8_t key_matrix_flip_scan(void)
{static uint8_t key_value=0;KEY_MATRIX_PORT=0x0f;//给所有行赋值0,列全为1if(KEY_MATRIX_PORT!=0x0f)//判断按键是否按下{if(key_value)Key_Board_Delay();//消抖if(KEY_MATRIX_PORT!=0x0f){//测试列KEY_MATRIX_PORT=0x0f;switch(KEY_MATRIX_PORT)//保存行为0,按键按下后的列值	{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)//保存列为0,按键按下后的键值	{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;}
#if KEY_BOARD_WHILE_FLAGwhile(KEY_MATRIX_PORT!=0xf0);//等待按键松开	
#endif}}elsekey_value=0;		return key_value;		
}

Key_Board.h

#ifndef KEY_BOARD_H_
#define KEY_BOARD_H_#include "stdint.h"uint8_t key_matrix_ranks_scan(void);
uint8_t key_matrix_flip_scan(void);#endif

main.c

#include <REGX52.H>
#include "intrins.h"
#include "stdint.h"
#include "Key_Board.h"sbit D1 = P2^0;void Delay63ms()		//@11.0592MHz
{unsigned char i, j;i = 113;j = 242;do{while (--j);} while (--i);
}void main(void)
{	uint8_t Key_Flag = 0;uint8_t i = 0;while(1){Key_Flag = key_matrix_flip_scan(); if(Key_Flag){D1 = 1;for(i = 0; i < Key_Flag; ++i)Delay63ms();D1 = 0;for(i = 0; i < Key_Flag; ++i)Delay63ms();}elseD1 = 1;}
}

实验现象

按住键盘上不同的按键,D0将以不同的频率闪烁。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/400522.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

wordpress数据库表详解

表名&#xff1a;wp_commentmeta 仅存储Akismet或手工审核的评论是否为垃圾评论的判断结果。 字段注释meta_id自增唯一IDcomment_id对应评论IDmeta_keymeta_value表名&#xff1a;wp_comments 存储评论信息&#xff0c;如评论内容、评论所属文章、评论人昵称、邮箱、URL等&…

搭建LAMP

RPM包和源码包存放位置 /usr/local/src源码包编译安装位置 /usr/local/apache/usr/local/mysql/usr/local/php默认MySQL 数据库位置 /usr/local/mysql/var默认网站根目录 /usr/local/apache/htdocs2 LAMP环境搭建搭建的工作包括 mysql、apache、PHP。可以按照这个顺序来搭建环境…

JavaScript 计时器

1.定义计时器 (1).setInteral(函数名或代码,时间间隔). 注&#xff1a;每隔你定义的时间间隔执行一次你定义的函数或代码。 (2).setTimeout(函数名或代码,时间间隔). 注&#xff1a;setTimeout();严格意义上说不是定时器&#xff0c;它只是让代码延后执行&#xff0c;只会执行一…

【51单片机快速入门指南】2.4:74HC595、LED点阵屏及其SPI控制

目录硬知识IO 口扩展方式-串转并74HC595 芯片介绍硬件设计测试源码HC74595.cHC74595.hmain.h实验现象SPI控制普中51-单核-A2 STC89C52 Keil uVision V5.29.0.0 PK51 Prof.Developers Kit Version:9.60.0.0 硬知识 选自《普中51单片机开发攻略_V1.2》 IO 口扩展方式-串转并 …

Mongodb 安装和启动

一.首先去官网下载对应的的mongodb ,本人的操作系统是win7 64位 mongodb-win32-x86_64-2.0.6.rar 解压安装&#xff1a;进入到bin目录下&#xff0c;会看到N多的.exe文件 二.启动mongodb mongod.exe --dbpathd:\mongo\data\db --logpathd:\mongo\log\log.txt, 通过浏览器访问…

【51单片机快速入门指南】3:中断系统

目录硬知识中断概念中断系统中断结构中断优先级中断处理普中51-单核-A2 STC89C52 Keil uVision V5.29.0.0 PK51 Prof.Developers Kit Version:9.60.0.0 硬知识 选自《普中51单片机开发攻略_V1.2》、《STC89C52系列单片机器件手册》 中断概念 中断是为使单片机具有对外部或内…

正能量之项目经理的自我修养

正能量之项目经理的自我修养 作者&#xff1a;张子良 版权所有&#xff0c;转载请注明出处 引子 还记得曾经看过的《喜剧之王》么&#xff1f;还记的那曾经经典的台词么&#xff1a;“我不是死跑龙套的”&#xff0c;“人如果没有理想&#xff0c;和咸鱼又有什么区别呢&#xf…

20170505

RAID级别 raid0 为带区阵列&#xff1b;raid1 为镜像阵列raid01 为四块磁盘实现的荣誉磁盘阵列&#xff1b;raid5 至少三块&#xff0c;容量为&#xff08;n-1&#xff09;/n 广泛用于各种服务器&#xff1a;文件&#xff0c;数据库&#xff0c;web&#xff0c;邮件服务器 1.gi…

MVC4下配置log4net 五部曲

第一步&#xff1a;把log4net.dll 编译成Framework 4.0 第二步&#xff1a;找到项目的Properties下的AssemblyInfo。在最下面添加&#xff1a;[assembly: log4net.Config.XmlConfigurator(Watch true)]。 第三步&#xff1a;Web.config <configuration><configSectio…

算法,俄罗斯方块

炮姐的88行代码,亮瞎了..有待研究 #include <windows.h> #include <stdio.h> #include <time.h> #include <conio.h> #include <stdlib.h> char gcText[] " 1LJTSZ#"; struct tetris {int _pool[16][32], (*pool)[32], tmap[8][4][16…

利用D触发器和异或门实现两个IO解读电机编码器的计数值和方向

目录反转变正转正转变反转iPad Pro 2020 14.8.1 仿真软件&#xff1a;iCircuit 突发奇想&#xff0c;做个记录。应该可以用于诸如51单片机、Arduino或是电赛中可能用到的MSP430G2553这类外设十分稀缺的单片机上。一个想法&#xff0c;啊&#xff0c;不一定对。 黄色波形是编码…

TCP协议的三次握手和四次分手

HTTP连接 HTTP协议即超文本传送协议(Hypertext Transfer Protocol )&#xff0c;是Web联网的基础&#xff0c;也是手机联网常用的协议之一&#xff0c;HTTP协议是建立在TCP协议之上的一种应用。HTTP连接最显著的特点是客户端发送的每次请求都需要服务器回送响应&#xff0c;在请…

CountDownLatch线程同步辅助

2019独角兽企业重金招聘Python工程师标准>>> http://bughope.iteye.com/blog/2081935 在上一篇文章中写道用一个静态的变量保存线程的执行状态,并用时间等待的方法后来仔细考虑,其实是 线程不安全的.多个线程同时执行这个类时,这个静态变量的值就不能保证了. 用一个…

SQLServer链接服务器至Oracle

1. 我方服务器必须安装msdtc服务&#xff0c;并进行相应配置。 2. 我方服务器必须安装oracle client&#xff0c;这个要对应中心站oracle版本的客户端。 3. 我方服务器必须安装Oracle Services For Microsoft Transaction Server [版本] Oracle Provid…

【51单片机快速入门指南】3.1:配置外部中断触发方式和中断优先级

目录源码EXTI.cEXTI.hmain.c实验现象普中51-单核-A2 STC89C52 Keil uVision V5.29.0.0 PK51 Prof.Developers Kit Version:9.60.0.0 源码 stdint.h见【51单片机快速入门指南】1&#xff1a;基础知识和工程创建 中断知识见【51单片机快速入门指南】3&#xff1a;中断系统 将…

(转)工厂方法模式

转自&#xff1a;http://www.jellythink.com/archives/62 问题描述 之前讲到了C设计模式——简单工厂模式&#xff0c;由于简单工厂模式的局限性&#xff0c;比如&#xff1a;工厂现在能生产ProductA、ProductB和ProductC三种产品了&#xff0c;此时&#xff0c;需要增加生产Pr…

一种父线程阻塞等待子线程的有效方法

最近在做一个查询优化时&#xff0c;考虑到一次查询耗时较多&#xff0c;所以打算用多线程来做&#xff0c;之前是串行查询。比如一个用户查询触发50个线程&#xff0c;在只有一个用户的情况下&#xff0c;性能比串行查询确实提高了许多&#xff0c;但当多个用户同时触发查询的…

C语言利用循环队列实现滑动平均值滤波器,提高计算速度

目录源码Filter.cFilter.h使用效果普中51-单核-A2 STC89C52 Keil uVision V5.29.0.0 PK51 Prof.Developers Kit Version:9.60.0.0 串口示波器&#xff1a;Vofa 1.3.10 网上查到的滑动平均值滤波器在计算平均值的时候还要再for累加一遍&#xff0c;这太浪费时间了&#xff0c…

iOS 计算文字宽度的一个细节

设计师给到的图&#xff0c;经常是 “按钮的左边距离文字右边5px” 这样子的标注。于是我们需要计算文字的宽度。 有两种方法&#xff1a; 用 label 或 button 的 sizetofit 方法 [label sizeToFit]; NSLog("label size is %",[NSValue valueWithCGSize:label.boun…

Exchange Server 2013日记功能

9.6 日记9.6.1 日记功能为什么很重要首先&#xff0c;了解日记功能与存档功能之间的区别十分重要&#xff1a;首先&#xff0c;了解日记功能与存档功能之间的区别十分重要&#xff1a; “日记”可以记录组织中的所有通信&#xff08;包括电子邮件通信&#xff09;&#xff0c;以…