STM32 >> 矩阵键盘(代码风格优美,简明易懂)
时间:2019-01-23
本文章向大家介绍STM32 >> 矩阵键盘(代码风格优美,简明易懂),主要包括STM32 >> 矩阵键盘(代码风格优美,简明易懂)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
本文有关矩阵键盘的使用原理适用于所有微机控制器,同时也适用于所有规格的矩阵键盘。
key.h
/**
******************************************************************************
* @file bsp_key.h
* @author Waao
* @version V1.0.0
* @date 20-Dec-2018
* @brief This file contains some board support package's definition for the KEY.
*
******************************************************************************
* @attention
*
* None
*
******************************************************************************
*/
#ifndef __BSP_KEY_H_
#define __BSP_KEY_H_
#include <stm32f4xx.h>
#include <bsp_systick.h>
#include <bsp_usart.h>
// Column2, Column3, Column4
#define C1_PIN GPIO_Pin_2
#define C1_GPIO_PORT GPIOE
#define C1_GPIO_CLK RCC_AHB1Periph_GPIOE
#define C2_PIN GPIO_Pin_3
#define C2_GPIO_PORT GPIOE
#define C2_GPIO_CLK RCC_AHB1Periph_GPIOA
#define C3_PIN GPIO_Pin_4
#define C3_GPIO_PORT GPIOE
#define C3_GPIO_CLK RCC_AHB1Periph_GPIOA
#define C4_PIN GPIO_Pin_5
#define C4_GPIO_PORT GPIOE
#define C4_GPIO_CLK RCC_AHB1Periph_GPIOE
// Row1, Row2, Row3
#define R1_PIN GPIO_Pin_12
#define R1_GPIO_PORT GPIOB
#define R1_GPIO_CLK RCC_AHB1Periph_GPIOB
#define R2_PIN GPIO_Pin_13
#define R2_GPIO_PORT GPIOB
#define R2_GPIO_CLK RCC_AHB1Periph_GPIOB
#define R3_PIN GPIO_Pin_14
#define R3_GPIO_PORT GPIOB
#define R3_GPIO_CLK RCC_AHB1Periph_GPIOB
#define R4_PIN GPIO_Pin_15
#define R4_GPIO_PORT GPIOB
#define R4_GPIO_CLK RCC_AHB1Periph_GPIOB
// detect and output
#define DETECT_C1 GPIO_ReadInputDataBit(C1_GPIO_PORT, C1_PIN)
#define DETECT_C2 GPIO_ReadInputDataBit(C2_GPIO_PORT, C2_PIN)
#define DETECT_C3 GPIO_ReadInputDataBit(C3_GPIO_PORT, C3_PIN)
#define DETECT_C4 GPIO_ReadInputDataBit(C4_GPIO_PORT, C4_PIN)
#define DETECT_R1 GPIO_ReadInputDataBit(R1_GPIO_PORT, R1_PIN)
#define DETECT_R2 GPIO_ReadInputDataBit(R2_GPIO_PORT, R2_PIN)
#define DETECT_R3 GPIO_ReadInputDataBit(R3_GPIO_PORT, R3_PIN)
#define DETECT_R4 GPIO_ReadInputDataBit(R4_GPIO_PORT, R4_PIN)
#define S1 0x77
#define S2 0xB7
#define S3 0xD7
#define S4 0xE7
#define S5 0x7B
#define S6 0xBB
#define S7 0xDB
#define S8 0xEB
#define S9 0x7D
#define S10 0xBD
#define S11 0xDD
#define S12 0xED
#define S13 0x7E
#define S14 0xBE
#define S15 0xDE
#define S16 0xEE
void GPIO_RCC_Config(void);
void ROCI_GPIO_Config(void);
void RICO_GPIO_Config(void);
void KEY_GPIO_ConfigAndDetect(void);
#endif
有关输入输出管脚的选择可以多试验几组,有的管脚即使你配置成上拉输入,当你松开按键之后依然不会返回高电平,我在此就因为这个问题被卡了一阵子
关于我的矩阵键盘检测的原理简明阐述如下:
- 首先设置为行输出低电平,列上拉输入(即无外部干扰时保持高电平);
- 检测到按键按下,此时通过检测列的电平情况从而得知哪一列有按键被按下;
- 然后确定有按键被按下后,设置为列输出低电平,行上拉输入;
- 通过检测行的电平情况从而得知哪一行有按键被按下;
- 最后通过“不平行的两条直线相交于一点”原理,推知具体被按下的按键。
key.c
/**
******************************************************************************
* @file bsp_key.c
* @author Waao
* @version V1.0.0
* @date 20-Dec-2018
* @brief This file contains some board support package's functions for the KEY.
*
******************************************************************************
* @attention
*
* None
*
******************************************************************************
*/
#include <bsp_key.h>
/**
* @brief Initialize the RCC of the 8 GPIO line.
* @param None
* @retval None
*/
void GPIO_RCC_Config(void)
{
RCC_AHB1PeriphClockCmd(C1_GPIO_CLK, ENABLE);
RCC_AHB1PeriphClockCmd(C2_GPIO_CLK, ENABLE);
RCC_AHB1PeriphClockCmd(C3_GPIO_CLK, ENABLE);
RCC_AHB1PeriphClockCmd(C4_GPIO_CLK, ENABLE);
RCC_AHB1PeriphClockCmd(R1_GPIO_CLK, ENABLE);
RCC_AHB1PeriphClockCmd(R2_GPIO_CLK, ENABLE);
RCC_AHB1PeriphClockCmd(R3_GPIO_CLK, ENABLE);
RCC_AHB1PeriphClockCmd(R4_GPIO_CLK, ENABLE);
}
/**
* @brief Initialize the Row out Column in.
* @param None
* @retval None
*/
void ROCI_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_Structure;
//============ Column =============
GPIO_Structure.GPIO_Mode = GPIO_Mode_IN;
GPIO_Structure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Structure.GPIO_OType = GPIO_OType_PP;
GPIO_Structure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Structure.GPIO_Pin = C1_PIN;
GPIO_Init(C1_GPIO_PORT, &GPIO_Structure);
GPIO_Structure.GPIO_Pin = C2_PIN;
GPIO_Init(C2_GPIO_PORT, &GPIO_Structure);
GPIO_Structure.GPIO_Pin = C3_PIN;
GPIO_Init(C3_GPIO_PORT, &GPIO_Structure);
GPIO_Structure.GPIO_Pin = C4_PIN;
GPIO_Init(C4_GPIO_PORT, &GPIO_Structure);
//============== Row ===============
GPIO_Structure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Structure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Structure.GPIO_OType = GPIO_OType_PP;
GPIO_Structure.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_Structure.GPIO_Pin = R1_PIN;
GPIO_Init(R1_GPIO_PORT, &GPIO_Structure);
GPIO_Structure.GPIO_Pin = R2_PIN;
GPIO_Init(R2_GPIO_PORT, &GPIO_Structure);
GPIO_Structure.GPIO_Pin = R3_PIN;
GPIO_Init(R3_GPIO_PORT, &GPIO_Structure);
GPIO_Structure.GPIO_Pin = R4_PIN;
GPIO_Init(R4_GPIO_PORT, &GPIO_Structure);
GPIO_ResetBits(R1_GPIO_PORT, R1_PIN);
GPIO_ResetBits(R2_GPIO_PORT, R2_PIN);
GPIO_ResetBits(R3_GPIO_PORT, R3_PIN);
GPIO_ResetBits(R4_GPIO_PORT, R4_PIN);
}
/**
* @brief Initialize the Row in Column out.
* @param None
* @retval None
*/
void RICO_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_Structure;
//============== Row ==================
GPIO_Structure.GPIO_Mode = GPIO_Mode_IN;
GPIO_Structure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Structure.GPIO_OType = GPIO_OType_PP;
GPIO_Structure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Structure.GPIO_Pin = R1_PIN;
GPIO_Init(R1_GPIO_PORT, &GPIO_Structure);
GPIO_Structure.GPIO_Pin = R2_PIN;
GPIO_Init(R2_GPIO_PORT, &GPIO_Structure);
GPIO_Structure.GPIO_Pin = R3_PIN;
GPIO_Init(R3_GPIO_PORT, &GPIO_Structure);
GPIO_Structure.GPIO_Pin = R4_PIN;
GPIO_Init(R4_GPIO_PORT, &GPIO_Structure);
//============ Column ================
GPIO_Structure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Structure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Structure.GPIO_OType = GPIO_OType_PP;
GPIO_Structure.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_Structure.GPIO_Pin = C1_PIN;
GPIO_Init(C1_GPIO_PORT, &GPIO_Structure);
GPIO_Structure.GPIO_Pin = C2_PIN;
GPIO_Init(C2_GPIO_PORT, &GPIO_Structure);
GPIO_Structure.GPIO_Pin = C3_PIN;
GPIO_Init(C3_GPIO_PORT, &GPIO_Structure);
GPIO_Structure.GPIO_Pin = C4_PIN;
GPIO_Init(C4_GPIO_PORT, &GPIO_Structure);
GPIO_ResetBits(C1_GPIO_PORT, C1_PIN);
GPIO_ResetBits(C2_GPIO_PORT, C2_PIN);
GPIO_ResetBits(C3_GPIO_PORT, C3_PIN);
GPIO_ResetBits(C4_GPIO_PORT, C4_PIN);
}
/**
* @brief Configure the GPIO, and detect whether the key was pressed down
* @param None
* @retval None
*/
void KEY_GPIO_ConfigAndDetect(void)
{
u8 TEMP_COMBINE = 0, TEMP_ROCI = 0, TEMP_RICO = 0;
GPIO_RCC_Config();
printf("\nWhy so serious ?\tThe game just begin!");
while(1)
{
ROCI_GPIO_Config();
TEMP_ROCI = (u8)(((u8)DETECT_C1) << 3) |
(((u8)DETECT_C2) << 2) |
(((u8)DETECT_C3) << 1) |
(((u8)DETECT_C4) << 0);
if(TEMP_ROCI != 0x0f)
{
Delay(1000); // Eliminate the shaking.
if(TEMP_ROCI != 0x0f) // Ensure one of the keys was pressed down indeed.
{
RICO_GPIO_Config();
TEMP_RICO = (u8)(((u8)DETECT_R1) << 3) |
(((u8)DETECT_R2) << 2) |
(((u8)DETECT_R3) << 1) |
(((u8)DETECT_R4) << 0);
TEMP_COMBINE = (u8)((TEMP_ROCI << 4) | TEMP_RICO); // Combine the two situation and we can know which key was pressed down.
switch(TEMP_COMBINE)
{
case S1:
printf("\nS1 was pressed down!");
break;
case S2:
printf("\nS2 was pressed down!");
break;
case S3:
printf("\nS3 was pressed down!");
break;
case S4:
printf("\nS4 was pressed down!");
break;
case S5:
printf("\nS5 was pressed down!");
break;
case S6:
printf("\nS6 was pressed down!");
break;
case S7:
printf("\nS7 was pressed down!");
break;
case S8:
printf("\nS8 was pressed down!");
break;
case S9:
printf("\nS9 was pressed down!");
break;
case S10:
printf("\nS10 was pressed down!");
break;
case S11:
printf("\nS11 was pressed down!");
break;
case S12:
printf("\nS12 was pressed down!");
break;
case S13:
printf("\nS13 was pressed down!");
break;
case S14:
printf("\nS14 was pressed down!");
break;
case S15:
printf("\nS15 was pressed down!");
break;
case S16:
printf("\nS16 was pressed down!");
break;
default:
break;
}
while(TEMP_RICO != 0x0F)
{
TEMP_RICO = (u8)(((u8)DETECT_R1)<<3) |
(((u8)DETECT_R2)<<2) |
(((u8)DETECT_R3)<<1) |
(((u8)DETECT_R4)<<0);
}
}
}
}
}
- 如何在EHAB(EntLib)中定义”细粒度”异常策略?
- MVC、MVP以及Model2[下篇]
- Dora.Interception: 一个为.NET Core度身定制的AOP框架
- 为了支持AOP的编程模式,我为.NET Core写了一个轻量级的Interception框架[开源]
- 关于Expression Tree和IL Emit的所谓的"性能差别"
- 采用一个自创的"验证框架"实现对数据实体的验证[扩展篇]
- 采用一个自创的"验证框架"实现对数据实体的验证[改进篇]
- Flash XSS检测脚本的简单实现
- 采用一个自创的"验证框架"实现对数据实体的验证[设计篇]
- 采用一个自创的"验证框架"实现对数据实体的验证[编程篇]
- 谈谈你最熟悉的System.DateTime[上篇]
- 12步轻松搞定Python装饰器
- 实用小工具,教你轻松转化Python通用数据格式
- 数据工程师常用的几个小工具(附python源代码)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Gentoo发行版系统基础使用记录
- Ubuntu-20.04-LTS桌面版与服务器版基础初始配置
- Snap容器基础入门使用
- zabbix入门学习
- 突击并发编程JUC系列-ReentrantReadWriteLock
- Qt音视频开发33-ffmpeg安卓版
- Vue.js|Nuxt仿制探探堆叠滑动|vue仿Tinder卡片效果
- Elasticsearch:透彻理解 Elasticsearch 中的 Bucket aggregation
- html+js开发模拟考试在线评分系统
- iOS音视频接入 - TRTC接入实时视频通话
- LRU缓存淘汰机制C++实现
- ant-design-vue运行时动态切换主题色
- 使用electron将vue-cli3.x项目打包为桌面应用
- Ubuntu 16.04下安装服务器端Shadowsocks
- 解决vue cli3.x打包上线静态资源找不到路径问题