矩阵按键行列扫描法与反转扫描法:原理、代码实现

news2024/12/26 22:23:41

矩阵按键:行列扫描法与反转扫描法
通常情况下,按键按下时会产生低电平信号,按键一般用低电平表示按下状态。

当按键没有被按下时,通常处于高电平状态,这是因为按键连接到电路时,内部的上拉电阻或外部的上拉电阻会将按键未按下的状态拉高为高电平。当按键被按下时,按键内部会导通,使连接到电路的引脚处于低电平状态,从而表示按键被按下。

这种低电平表示按下的设计方式是常见的,因为在数字电路中,低电平通常被认为是逻辑“0”,而高电平被认为是逻辑“1”。通过使用低电平表示按下,可以更容易地进行逻辑判断和控制。当然,也可以根据特定应用的需求,在设计中采用高电平表示按下,只需根据相应的逻辑处理即可。


1、矩阵按键行列扫描法:


原理:

矩阵按键行列扫描法是一种简单直观的按键扫描方法。在矩阵按键行列扫描法中,键盘的按键是通过行和列的交叉连接来构成一个矩阵。每个按键都位于一个行和一个列的交点上。通过轮询扫描的方式,逐个检测按键的状态。当有按键按下时,通过判断对应的行和列,可以确定按下的是哪一个按键。

一般来说:
行扫描,行线为低电平,列线为高电平。(就STC89C5类型的机子来说,一般都是用列扫描,以为行线端口有可能被其他的引脚占用(复用)(B站江协大的教学视频中的51单片机不建议用行扫描))
列扫描,行线为高电平,列线为低电平。

优点:

矩阵按键行列扫描法简单易懂,实现成本较低,适用于较小规模的键盘矩阵。


缺点:

随着键盘规模的增大,扫描效率会降低,因为需要逐一扫描每个按键。

矩阵按键行列扫描法(假设使用GPIO控制引脚):

#include <stdio.h>
#include <stdbool.h>

// 定义行列数量
#define NUM_ROWS 4
#define NUM_COLS 4

// 定义行列引脚
int rows[NUM_ROWS] = {R0, R1, R2, R3};        //数组中为具体引脚
int cols[NUM_COLS] = {C0, C1, C2, C3};         //数组中为具体引脚

// 初始化引脚状态
void setup() {
    for (int i = 0; i < NUM_ROWS; i++) {
        pinMode(rows[i], OUTPUT);        //行配置为输出模式,
        digitalWrite(rows[i], LOW);        //行初始化电平为低电平
    }
    for (int i = 0; i < NUM_COLS; i++) {
        pinMode(cols[i], INPUT_PULLUP);        //列配置为输入模式、上拉
    }
}

// 扫描键盘状态
void scanKeypad() {
    for (int col = 0; col < NUM_COLS; col++) {
        // 将当前列引脚设置为低电平
        digitalWrite(cols[col], LOW);
        for (int row = 0; row < NUM_ROWS; row++) {
            // 检测行引脚状态,如果为低电平,则说明该按键被按下
            if (digitalRead(rows[row]) == LOW) {
                // 在这里处理按键按下的逻辑
                // ...
            }
        }
        // 将当前列引脚设置为高电平,准备扫描下一列
        digitalWrite(cols[col], HIGH);
    }
}

int main() {
    setup();
    while (true) {
        scanKeypad();
    }
    return 0;


2. 反转扫描法


原理:

反转扫描法是另一种常见的按键扫描方法。在反转扫描法中,将行和列的引脚分开连接,行引脚设置为输出,列引脚设置为输入。然后,将行引脚逐个设置为高电平,检测列引脚的状态来确定按键的状态。

优点:

反转扫描法的扫描效率相对较高,适用于大规模的键盘矩阵,因为只需逐一扫描行引脚。


缺点:

相比矩阵按键行列扫描法,反转扫描法在硬件连接上稍微复杂一些。


反转扫描法(假设使用GPIO控制引脚):


#include <stdio.h>
#include <stdbool.h>

// 定义行列数量
#define NUM_ROWS 4
#define NUM_COLS 4

// 定义行列引脚
int rows[NUM_ROWS] = {R0, R1, R2, R3};
int cols[NUM_COLS] = {C0, C1, C2, C3};

// 初始化引脚状态
void setup() {
    for (int i = 0; i < NUM_COLS; i++) {
        pinMode(cols[i], OUTPUT);
        digitalWrite(cols[i], HIGH);
    }
    for (int i = 0; i < NUM_ROWS; i++) {
        pinMode(rows[i], INPUT_PULLUP);
    }
}

// 扫描键盘状态
void scanKeypad() {
    for (int row = 0; row < NUM_ROWS; row++) {
        // 将当前行引脚设置为低电平
        digitalWrite(rows[row], LOW);
        for (int col = 0; col < NUM_COLS; col++) {
            // 检测列引脚状态,如果为低电平,则说明该按键被按下
            if (digitalRead(cols[col]) == LOW) {
                // 在这里处理按键按下的逻辑
                // ...
            }
        }
        // 将当前行引脚设置为高电平,准备扫描下一行
        digitalWrite(rows[row], HIGH);
    }
}

int main() {
    setup();
    while (true) {
        scanKeypad();
    }
    return 0;
}

 实例:

有一51矩阵按键的原理图如下:

 #define KEY_MATRIX_PORT P1

//行列选中法:

unsigned char key_matrix_ranks_scan(void)
{
    unsigned char key_value=0;

    KEY_MATRIX_PORT=0xf7;//给第一列赋值0
    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;//给第二列赋值0,其余全为1
    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;//给第三列赋值0,其余全为1
    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;//给第四列赋值0,其余全为1
    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;        
}

//线反转法:

unsigned char key_matrix_flip_scan(void)
{
    static unsigned char key_value=0;

    KEY_MATRIX_PORT=0x0f;//给所有行赋值0,列全为1
    if(KEY_MATRIX_PORT!=0x0f)//判断按键是否按下
    {
        delay_10us(1000);//消抖
        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;
            }
            while(KEY_MATRIX_PORT!=0xf0);//等待按键松开    
        }
    }
    else
        key_value=0;        
    return key_value;        
}

 


 

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

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

相关文章

快速创建vue3+vite+ts项目

安装nodejs 创建项目 npm init vitelatest 默认之后回车 选择项目名字my-vue-project 选择vue框架 选择ts 运行项目 cd my-vue-project npm install --registryhttps://registry.npm.taobao.org npm run dev

2023年第四届“华数杯”数学建模思路 - 案例_ ID3-决策树分类算法

文章目录 0 赛题思路1 算法介绍2 FP树表示法3 构建FP树4 实现代码 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 算法介绍 FP-Tree算法全称是FrequentPattern Tree算法&#xff0c;就是频繁模式树算法&…

容器技术:Docker搭建(通俗易懂)

目录 Docker搭建环境准备Docker安装1、查看服务器是否安装Docker2、卸载Docker3、安装Dokcer依赖环境4、配置Docker国内阿里云镜像5、安装Docker6、查看Docker信息7、配置阿里云镜像加速8、镜像安装10、运行实例11、查看实例状态12、测试 Docker命令集合 Docker搭建 环境准备 …

华为OD机试真题 JavaScript 实现【云短信平台优惠活动】【2023Q1 200分】,附详细解题思路

目录 一、题目描述二、输入描述三、输出描四、解题思路五、JavaScript算法源码六、效果展示1、输入2、输出3、说明 华为OD机试 2023B卷题库疯狂收录中&#xff0c;刷题点这里 刷的越多&#xff0c;抽中的概率越大&#xff0c;每一题都有详细的答题思路、详细的代码注释、样例测…

Linux - 进程概念

1.冯诺依曼体系结构 我们常见的计算机&#xff0c;如笔记本。我们不常见的计算机&#xff0c;如服务器&#xff0c;大部分都遵守冯诺依曼体系 截至目前&#xff0c;我们所认识的计算机&#xff0c;都是由一个个的硬件组件组成 ● 输入单元&#xff1a;包括键盘, 鼠标&#xff0…

VMWare vSphere 7.0.3环境通过PowerCLI批量修改虚拟机网卡的连接状态及开机连接设置

为避免网络IP冲突&#xff0c;虚拟机模板的网卡设置是连接中断、开机连接中断的&#xff0c;在通过PowerCLI批量发布虚拟机后&#xff0c;本文尝试PowerCLI通过PowerCLI批量修改虚拟机网卡的连接状态及开机连接设置。 一、PowerCLI环境搭建 详见前文 VMWare vSphere 7.0.3环…

MySQL 在CentOS下安装

yum安装 1、yum源安装 yum install mariadb-server2、启动MySQL服务 systemctl start mariadb3、查看运行状态 systemctl status mariadb4、设置初始密码 mysql -u rootuse mysql;update user set passwordpassword("root")where userroot;flush privileges;e…

AI为图像构建测谎仪

互联网上充斥着有趣的假照片——从汽车上飞驰的鲨鱼和奶牛到令人眼花缭乱的名人混搭。然而&#xff0c;卷积神经网络&#xff08;CNNs&#xff09;生成的超现实图像和视频赝品绝非笑料——事实上&#xff0c;它们可能非常危险。Deepfake色情在2018年抬头&#xff0c;世界领导人…

DataSphere Studio- 1.1.1 安装部署(自动化脚本)

DSSLinkis Ansible一键安装脚本 DSS1.1.1 & Linkis 1.3.0 Ansible 一键部署脚本 作者&#xff1a;wubolive Q Q&#xff1a;1049635685 邮箱&#xff1a;wubolivefoxmai.com Github&#xff1a;https://github.com/wubolive/dss-linkis-ansible 一、简介 为解决繁琐…

Linux - 进程概念(进程状态、优先级)

1.进程状态 操作系统中进程有多种状态模型 三态模型 进程状态分为 就绪态&#xff0c;执行态&#xff0c;阻塞态。 就绪(Ready)状态&#xff1a;指进程已处于准备好运行的状态&#xff0c;即进程已分配到除CPU以外的所有必要资源后&#xff0c;只要再获得CPU&#xff0c;便可立…

分布式服务高可用实现:复制 | 京东物流技术团队

1. 为什么需要复制 我们可以考虑如下问题&#xff1a; 当数据量、读取或写入负载已经超过了当前服务器的处理能力&#xff0c;如何实现负载均衡&#xff1f; 希望在单台服务器出现故障时仍能继续工作&#xff0c;这该如何实现&#xff1f; 当服务的用户遍布全球&#xff0c;…

迅为iTOP-RK3568开发板是怎么样的呢

迅为iTOP-RK3568开发板是怎么样的呢 CPU方面&#xff1a;iTOP-3568开发板采用瑞芯微RK3568处理器&#xff0c;内部集成了四核64位Cortex-A55处理器。主频高达2.0Ghz&#xff0c;RK809动态调频。集成了双核心架构GPU&#xff0c;ARM G52 2EE、支持OpenGLES1.1/2.0/32OpenCL 2.0…

Simulink仿真模块 - Saturation

目录 说明 实例 模块特性 Saturation将输入信号限制在饱和上界和下界值之间 在仿真库中的位置为:Simulink / 常用模块Simulink / Discontinuities模型为: 说明 Saturation 模块产生输出信号,该信号是在饱和上界和下界值之间的输入信号值。上界和下界由参数 Upper limit 和…

今年嵌入式行情怎么样?

我不了解其它行业可能描述有些片面&#xff0c;但总的来说&#xff0c;我对嵌入式是很看好的&#xff0c;因为你可以感受到你能实际的做出产品而不是类似前端和互联网只是数字数据。 并且嵌入式的学习过程充满乐趣&#xff0c;你可以接触到从沙子到开关管到逻辑门到芯片架构到…

C# Blazor 学习笔记(6):热重置问题解决

文章目录 前言热重置问题描述解决方法演示 总结 前言 我最近在使用Blazor的时候&#xff0c;使用了BootstrapBlazor&#xff08;以下简称BB&#xff09;创建模板的时候&#xff0c;发现热重置无效。经过了一上午的折腾&#xff0c;我终于解决了这个问题。 热重置 问题描述 …

【深度学习环境】安装anaconda、tensorflow、pycharm

目录 1.安装anaconda 2.安装tensorflow-gpu 3.安装pycharm 4.VNC操作 5.安装Pytorch PS: linux下常见的操作&#xff1a; 1.Linux下强制关闭程序&#xff1a; 2.导出环境 2.1.pip导出 2.2.conda导出 2.3.其他 3.windows下的环境安装 & pycharm远程配置 4.bash…

最新版本JDK安装配置及多版本JDK切换

一、JDK安装 1、先说最新的JDK版本&#xff0c;一般指的是JDK 9以及其后的版本&#xff1b; 2、JDK安装分为安装版和免安装版。免安装版必须要配置环境变量才能使用&#xff0c;环境变量配置后面介绍&#xff1b; 3、安装版&#xff1a;最新版本的JDK安装后不需要再配置环境…

SQL语句嵌套查询

嵌套查询的意思是&#xff0c;一个查询语句(select-from-where)查询语句块可以嵌套在另外一个查询块的where子句中&#xff0c;称为嵌套查询。其中外层查询也称为父查询&#xff0c;主查询。内层查询也称子查询&#xff0c;从查询。 嵌套查询的工作方式是&#xff1a;先处理内查…

Cpp学习——动态内存管理

目录 一&#xff0c;new 1.malloc,realloc,calloc的使用不便之处 2.new的好处 3.opreator new 二&#xff0c;delete 1.为什么要有delete? 2.为什么要匹配使用&#xff1f; 一&#xff0c;new 1.malloc,realloc,calloc的使用不便之处 在C语言中&#xff0c;为了申请堆上…