本文实现的代码是基于STM32HAL库的基础上的,不过标准库也可以用,只是调用的库函数不同,逻辑跟配置是一样的,按我这里的逻辑来配置即可。

1、键盘原理图:

 

  原理举例:先把 F0-F7 内部拉高,这样这个8个引脚都是高电平,然后就进行列扫描。例如:假如按下3按钮,Y3 列扫描,把F4先拉低,然后读取F0-F3的状态,就会读出为1110,这就可  以知道是F3行拉低了,同时这时候是程序控制F4拉低的,这样就可以知道是F4列导致它转态变化了的,这样就可以定位出是F4列F3行的按键按下了;其他的列也是这样子扫描,就可以实现了。

2、STM32 cubemx 引脚配置图:

  

  这里用外部晶振内部晶振都可以,时钟对这个没什么影响,不用开中断,所以其他的配置就不细说了,下面再说一下这8个GPIO的配置。

  

  4个引脚配推挽输出,这4个配输出的引脚内部上下拉不用配置;另外4个配成输入,内部上拉。

3、生成代码后,开始编写逻辑:

  编写之前我们先做一下头文件的定义,把一些要用到的宏定义好:

#ifndef __HW_key_H__
#define __HW_key_H__ #include "main.h"
#include "stm32f1xx_hal.h"
#include <string.h> char KEY_SCAN(void);
char KEY_ROW_SCAN(void);
void HW_KEY_FUNCTION(void); #define KEY_CLO0_OUT_LOW HAL_GPIO_WritePin(GPIOE,GPIO_PIN_7,GPIO_PIN_RESET)
#define KEY_CLO1_OUT_LOW HAL_GPIO_WritePin(GPIOE,GPIO_PIN_8,GPIO_PIN_RESET)
#define KEY_CLO2_OUT_LOW HAL_GPIO_WritePin(GPIOE,GPIO_PIN_9,GPIO_PIN_RESET)
#define KEY_CLO3_OUT_LOW HAL_GPIO_WritePin(GPIOE,GPIO_PIN_10,GPIO_PIN_RESET) #define KEY_CLO0_OUT_HIGH HAL_GPIO_WritePin(GPIOE,GPIO_PIN_7,GPIO_PIN_SET)
#define KEY_CLO1_OUT_HIGH HAL_GPIO_WritePin(GPIOE,GPIO_PIN_8,GPIO_PIN_SET)
#define KEY_CLO2_OUT_HIGH HAL_GPIO_WritePin(GPIOE,GPIO_PIN_9,GPIO_PIN_SET)
#define KEY_CLO3_OUT_HIGH HAL_GPIO_WritePin(GPIOE,GPIO_PIN_10,GPIO_PIN_SET) #endif

  然后包含头文件以及定义一些要用到的变量数组:

#include "HW_key.h"
uint8_t Key_row[]={0xff}; //保存按键行扫描情况的状态数组

  接着可以写扫描逻辑了,先编写横扫描的代码:

/***
*函数名:KEY_ROW_SCAN
*功 能:按键行扫描
*返回值:1~4,对应1~4行按键位置
*/
char KEY_ROW_SCAN(void)
{
//读出行扫描状态
Key_row[] = HAL_GPIO_ReadPin(GPIOE,KEY_row0_Pin)<<;
Key_row[] = Key_row[] | (HAL_GPIO_ReadPin(GPIOE,KEY_row1_Pin)<<);
Key_row[] = Key_row[] | (HAL_GPIO_ReadPin(GPIOE,KEY_row2_Pin)<<);
Key_row[] = Key_row[] | (HAL_GPIO_ReadPin(GPIOE,KEY_row3_Pin)); if(Key_row[] != 0x0f) //行扫描有变化,判断该列有按键按下
{
HAL_Delay(); //消抖
if(Key_row[] != 0x0f)
{
//printf("Key_Row_DATA = 0x%x\r\n",Key_row[0]);
switch(Key_row[])
{
case 0x07: //0111 判断为该列第1行的按键按下
return ;
case 0x0b: //1011 判断为该列第2行的按键按下
return ;
case 0x0d: //1101 判断为该列第3行的按键按下
return ;
case 0x0e: //1110 判断为该列第4行的按键按下
return ;
default :
return ;
}
}
else return ;
}
else return ;
}

  这个函数,可以判断哪一行有按键按下,并返回有按键按下的行数。

  接着编写列扫描的代码,这里的思想是,先扫描第一列,接着判断第一列有没有行被按下,有的话就可以直接定位到这一列的哪一行,其他4列逻辑一样,这样就可以定位到哪个按键按下了。

/***
*函数名:KEY_SCAN
*功 能:4*4按键扫描
*返回值:0~16,对应16个按键
*/
char KEY_SCAN(void)
{
char Key_Num=; //1-16对应的按键数
char key_row_num=; //行扫描结果记录 KEY_CLO0_OUT_LOW;
if( (key_row_num=KEY_ROW_SCAN()) != )
{
while(KEY_ROW_SCAN() != ); //消抖
Key_Num = + key_row_num;
//printf("Key_Clo_1\r\n");
}
KEY_CLO0_OUT_HIGH; KEY_CLO1_OUT_LOW;
if( (key_row_num=KEY_ROW_SCAN()) != )
{
while(KEY_ROW_SCAN() != );
Key_Num = + key_row_num;
//printf("Key_Clo_2\r\n");
}
KEY_CLO1_OUT_HIGH; KEY_CLO2_OUT_LOW;
if( (key_row_num=KEY_ROW_SCAN()) != )
{
while(KEY_ROW_SCAN() != );
Key_Num = + key_row_num;
//printf("Key_Clo_3\r\n");
}
KEY_CLO2_OUT_HIGH; KEY_CLO3_OUT_LOW;
if( (key_row_num=KEY_ROW_SCAN()) != )
{
// Key_row[0] = HAL_GPIO_ReadPin(GPIOE,KEY_col0_Pin)<<3;
// Key_row[0] = Key_row[0] | (HAL_GPIO_ReadPin(GPIOE,KEY_col1_Pin)<<2);
// Key_row[0] = Key_row[0] | (HAL_GPIO_ReadPin(GPIOE,KEY_col2_Pin)<<1);
// Key_row[0] = Key_row[0] | (HAL_GPIO_ReadPin(GPIOE,KEY_col3_Pin));
// printf("Key_Clo4_DATA = 0x%x\r\n",Key_row[0]);
while(KEY_ROW_SCAN() != );
Key_Num = + key_row_num;
//printf("Key_Clo_4\r\n");
}
KEY_CLO3_OUT_HIGH; return Key_Num;
}

 这个函数就可以直接返回1-16个按键的按键数了,按下第一个按键就返回1,第2个就返回2,以此类推。下面可以调用这个函数做按键按下的操作了:

/***
*函数名:KEY_ROW_SCAN
*功 能:执行按下按键后的操作
*返回值:无
*/
void HW_KEY_FUNCTION(void)
{
char key_confirm;
key_confirm = KEY_SCAN();
if( < key_confirm && key_confirm < )
{
printf("Key_NUM = %d \r\n",key_confirm); //按下1-16个按键的操作
printf("= = = = = = = = = = = \r\n");
}
}

  我这里就是用串口助手打印出来查看哪个按键按下的,实测可用。

  

4、总结:

(1)先配置8个引脚,4个配置输入,上拉;4个配置成推挽(PP)输出,不用上下拉,输出高电平;

(2)软件逻辑:

  a. 先说一下行扫描的原理,因为如果有按键按下的话,某一个输入的引脚就会跟对应的输出引脚连接,因为输出为高电平,所以对应的输入引脚会被拉高,读取引脚的状态,判断哪个引脚被拉高就可以知道哪一行有按键按下了;总的来说是通过高四位输出高电平来对矩阵键盘进行逐行扫描,当低四位接收到的数据不全为1的时候,说明有按键按下,然后通过接收到的数据是哪一位为0来判断是哪一行按键被按下;

  b. 列扫描原理:思路是先把第一列输出低电平,接着读取高4位的电平转态,单不全为1时,说明这一列有按键按下,同时结合行扫描判断出来的行数定位到按下的按键。程序里是扫描第一列的时候第一列给低电平,接着进行行扫描判断,因为输入输出引脚都是高电平了,只有第一列的引脚是低电平,所以当第一列有按键按下的时候,行扫描读到的4个引脚就不全为1,这时因为第一列的电平是我们自己给的,所以就可以直接判断这一列有按键按下;接着利用行扫描原理定位哪一行有按键按下,这样就可以判断出第一列的某一行的按键被按下了,其他3列同理,然后轮流扫描4列就可以判断16个按键了。

  通俗点说,就是如果我给这一列低电平,造成了行扫描有变化,那就直接知道这一列有按键按下,接着查看行变化的电平变化,推算出哪一行变化了,就可以知道这一列的第几个按键被按下了。

STM32 实现 4*4 矩阵键盘扫描(HAL库、标准库 都适用)的更多相关文章

  1. 4x4矩阵键盘扫描

    4x4矩阵键盘扫描 Windows 10 IoT Core 是微软针对物联网市场的一个重要产品,与以往的Windows版本不同,是为物联网设备专门设计的,硬件也不仅仅限于x86架构,同时可以在ARM架 ...

  2. 4X4矩阵键盘扫描程序

    4X4矩阵键盘扫描: 1. 4根行线的GIO均设为Output,根列线的GIO均设为Input: 2. 4根行线的GIO分别置为0111.1011.1101.1110,读逐一读取列线GIO的值,可确定 ...

  3. Win10 IoT C#开发 6 - 4x4矩阵键盘扫描

    Windows 10 IoT Core 是微软针对物联网市场的一个重要产品,与以往的Windows版本不同,是为物联网设备专门设计的,硬件也不仅仅限于x86架构,同时可以在ARM架构上运行. 上一章我 ...

  4. stm32矩阵键盘扫描数据通过USB发送

                   Keyboard.c #include "keyboard.h"#include "my_usb.h"#include " ...

  5. 4x4矩阵键盘 扫描程序

    一:不排除第四位异常处理 uchar JuzhenkeyScan() { // P3=0xfe; // temp=P3; // while(temp!=0xfe) // { // temp=P3; / ...

  6. STM32 的 printf() 函数串口重定向(HAL库标准库都适用)

    1.建立工程 2.核心:添加新文件usar_fputc.c (名字随便自己命名),把文件添加到项目中去 #include "stdio.h" #include "stm3 ...

  7. 【STM32学习笔记】STM32f407 使用4*4矩阵键盘

    作者:李剀 出处:https://www.cnblogs.com/kevin-nancy/ 欢迎转载,但也请保留上面这段声明.谢谢! 写在前面: 这是本人第一次开始写博客,可能写的不是很好,也请大家谅 ...

  8. AVR单片机教程——矩阵键盘

    本文隶属于AVR单片机教程系列.   开发板上有4个按键,我们可以把每一个按键连接到一个单片机引脚上,来实现按键状态的检测.但是常见的键盘有104键,是每一个键分别连接到一个引脚上的吗?我没有考证过, ...

  9. ARM开发(3)基于STM32的矩阵键盘控制蜂鸣器

    一 矩阵键盘控制蜂鸣器原理:  1.1 本实验实现8*7矩阵键盘上按键控制蜂鸣器响.  1.2 实验思路:根据电路图原理,找出矩阵键盘行列所对应的引脚,赋予对应的按键值,然后控制蜂鸣器响.  1.3 ...

随机推荐

  1. E20180115-hm

    auxiliary  adj. 辅助的; 备用的,补充的; 附加的; 副的;                n. 助动词; 辅助者,辅助人员; 附属机构,附属团体; 辅助设备;  departure  ...

  2. LaTex简历排版

    为了写好简历,倒腾了好几天的Latex,主要是因为中文支持问题还有morderncv的更新问题... 1.  http://www.ctex.org/CTeXDownload/ 建议下载v2.9.2. ...

  3. 【杂文】C++头文件加速

    [杂文]C++头文件加速 骚年,冲钱送开挂哦,可以助你超神于OI战场 如果你发现你的暴力超时了的话,可以尝试用一下头文件加速,说不定就过了呢! #pragma once//只编译一次 #pragma ...

  4. 2017 ACM-ICPC 亚洲区(南宁赛区)网络赛 The Heaviest Non-decreasing Subsequence Problem

    Let SS be a sequence of integers s_{1}s​1​​, s_{2}s​2​​, ......, s_{n}s​n​​Each integer is is associ ...

  5. GIT学习之路最终日 标签管理+总结

    本文参考廖雪峰老师的博客进行总结,完整学习请转廖雪峰博客 6.1 创建标签 命令git tag (name)用于新建一个标签,默认为HEAD,也可以指定一个commit id: git tag -a ...

  6. viewpager滑动时页面不能刷新

    有一种解决方法就是覆盖PagerAdapter中的getItemPosition()方法,这种方案虽然简单,但是因为这种方法是让每次呼叫PagerAdapter时,都会遍历childView,通过ge ...

  7. 百度AI车牌识别测试

    测试背景 百度已发布诸多AI应用,其中包含车牌识别,免费使用量是200次/日.付费的话,按月调用次数在20万次到50万次之间,每日10000次,月费用为0.0035*300000=1050元. 详见: ...

  8. ElasticSearch学习笔记--一些规范,会持续更新

    我们在ElasticSearch中存储的数据一般是采用json的格式存储,所以ElasticSearch中有一个叫Mapper的东西用来定义jsonschema来规范这个json 但是这个mapper ...

  9. [Windows Server 2008] IP安全策略限制端口方法

    ★ 欢迎来到[护卫神·V课堂],网站地址:http://v.huweishen.com ★ 护卫神·V课堂 是护卫神旗下专业提供服务器教学视频的网站,每周更新视频. ★ 本节我们将带领大家:限制143 ...

  10. codeforces_455B

    B. A Lot of Games time limit per test 1 second memory limit per test 256 megabytes input standard in ...