stm32 F103C8T6 4x4矩阵键盘使用
首先感谢 江科大 的stm32入门课程 受益匪浅。推荐有兴趣的朋友去看看。
先看看我用的矩阵键盘是啥样的(很常见的一种)

接线如图(其他型号根据自己需求接上GPIO口)
代码基于stm大善人的代码修改而来,讲的很详细,非常感谢。
直接上代码:
头文件Key4x4.h
#ifndef __KEY4x4_H
#define __KEY4x4_H void KEY_4x4_Init(void);
void KEY_Scan(void);
u16 Key_Read(void); #endif
主体文件Key4x4.c
#include "stm32f10x.h"
#include "Delay.h" u8 anxia = 0;
u8 key = 1;
u16 line[4] = {0x00fe , 0x00fd , 0x00fb ,0x00f7};
u16 off = 0x00ff; // 全部引脚置为1
u16 keys[16] = {
49, 50, 51, 65,
52, 53, 54, 66,
55, 56, 57, 67,
42, 48, 35, 68,
}; void KEY_4x4_Init(void){ GPIO_InitTypeDef GPIO_InitStructre;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE); // 使能 GPIOA 的时钟 // 第一组
GPIO_InitStructre.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
GPIO_InitStructre.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出
GPIO_InitStructre.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA , &GPIO_InitStructre);
GPIO_SetBits(GPIOA , GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3);
// 第二组数据
GPIO_InitStructre.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStructre.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA , &GPIO_InitStructre);
GPIO_SetBits(GPIOA , GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7); } void Do_Click(uint16_t gpio_pin_x , u8 num){
anxia = 1;
key = num;
while(!GPIO_ReadInputDataBit(GPIOA , gpio_pin_x));
} void KEY_Click_Listener(u8 num){
if((GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_4)==0)||(GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_5)==0)||(GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_6)==0)||(GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_7)==0)){
Delay_ms(10);
if(0 == GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_4)){
Do_Click(GPIO_Pin_4 , num+0);
}else if(0 == GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_5)){
Do_Click(GPIO_Pin_5 , num+1);
}else if(0 == GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_6)){
Do_Click(GPIO_Pin_6 , num+2);
}else if(0 == GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_7)){
Do_Click(GPIO_Pin_7 , num+3);
}else {
anxia = 0;
GPIO_Write(GPIOA , off);
}
}
} void KEY_Scan(){
// 第一行 1111 1110
GPIO_Write(GPIOA , line[0]);
KEY_Click_Listener(1);
// 第二行
GPIO_Write(GPIOA , line[1]);
KEY_Click_Listener(5);
// 第三行
GPIO_Write(GPIOA , line[2]);
KEY_Click_Listener(9);
// 第四行
GPIO_Write(GPIOA , line[3]);
KEY_Click_Listener(13);
} u16 Key_Read(){
return keys[key-1];
}
主要代码说明:
初始化配置 (KEY_4x4_Init):
- 使能GPIOA模块的时钟。
- 配置GPIOA的前四个引脚(GPIO_Pin_0至GPIO_Pin_3)为推挽输出模式,用于键盘行线的扫描。
- 设置GPIOA的后四个引脚(GPIO_Pin_4至GPIO_Pin_7)为上拉输入模式,用于检测键盘列线的状态。
// 第一组
GPIO_InitStructre.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
GPIO_InitStructre.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出
GPIO_InitStructre.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA , &GPIO_InitStructre);
GPIO_SetBits(GPIOA , GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3);
// 第二组数据
GPIO_InitStructre.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStructre.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA , &GPIO_InitStructre);
GPIO_SetBits(GPIOA , GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);
按键检测 (KEY_Click_Listener):
- 检测列线状态,如果有键按下,则调用
Do_Click函数记录按键信息并等待按键释放。 - 使用延时函数
Delay_ms来消除抖动。
void KEY_Click_Listener(u8 num){
if((GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_4)==0)||(GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_5)==0)
||(GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_6)==0)||(GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_7)==0)){
Delay_ms(10);
if(0 == GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_4)){
Do_Click(GPIO_Pin_4 , num+0);
}else if(0 == GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_5)){
Do_Click(GPIO_Pin_5 , num+1);
}else if(0 == GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_6)){
Do_Click(GPIO_Pin_6 , num+2);
}else if(0 == GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_7)){
Do_Click(GPIO_Pin_7 , num+3);
}else {
anxia = 0;
GPIO_Write(GPIOA , off);
}
}
}
void Do_Click(uint16_t gpio_pin_x , u8 num){
anxia = 1;
key = num;
while(!GPIO_ReadInputDataBit(GPIOA , gpio_pin_x));
}
扫描过程 (KEY_Scan):
- 循环扫描每一行,通过改变行线的状态来检测是否有键按下。
- 调用
KEY_Click_Listener函数来处理每一行的按键检测。
读取按键值 (Key_Read):
- 返回当前按下的键对应的数值。
补充说明:
u16 line[4] = {0x00fe , 0x00fd , 0x00fb ,0x00f7};
u16 off = 0x00ff; // 全部引脚置为1
u16 keys[16] = {
49, 50, 51, 65,
52, 53, 54, 66,
55, 56, 57, 67,
42, 48, 35, 68,
};
line 定义 了4个16进制的数值分别转成二进制
0000 0000 1111 1110 0x00fe
0000 0000 1111 1101 0x00fd
0000 0000 1111 1011 0x00fb
0000 0000 1111 0111 0x00f7
低4位为行 高四位为列
设置0就是给对应行设置低电平
这样我们在scan的代码就能看出来 扫描的做法就是先给传入的行line[x] 设置低电平
所有列都是高电平当扫描到某一列为低电平时就说明这一列被点击了。

循环从第一列到第四列设置低电平直到检测到某一列也变成低电平
假设1被点击 则1这一列也是低电平
就变成第一行 第一列低电平

这样就能确定1被点击。给对应参数赋值1即可
再根据定义的keys (askII 码表对应数值 )
主要代码就是上面这些,其他代码只要复制 江科大OLED的课件源码即可
使用方式 man.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Key4x4.h" int main(void)
{ /*模块初始化*/
OLED_Init(); //OLED初始化
KEY_4x4_Init(); /*OLED显示*/
OLED_ShowString(1, 1, "in put:"); //1行1列显示字符A
u8 num = 0;
while (1)
{
KEY_Scan();
num = Key_Read();
OLED_ShowChar(1 ,8 ,num);
}
}
stm32 F103C8T6 4x4矩阵键盘使用的更多相关文章
- Win10 IoT C#开发 6 - 4x4矩阵键盘扫描
Windows 10 IoT Core 是微软针对物联网市场的一个重要产品,与以往的Windows版本不同,是为物联网设备专门设计的,硬件也不仅仅限于x86架构,同时可以在ARM架构上运行. 上一章我 ...
- 4x4矩阵键盘扫描
4x4矩阵键盘扫描 Windows 10 IoT Core 是微软针对物联网市场的一个重要产品,与以往的Windows版本不同,是为物联网设备专门设计的,硬件也不仅仅限于x86架构,同时可以在ARM架 ...
- 基于FPGA的4x4矩阵键盘驱动调试
好久不见,因为博主最近两个月有点事情,加上接着考试,考完试也有点事情要处理,最近才稍微闲了一些,这才赶紧记录分享一篇博文.FPGA驱动4x4矩阵键盘.这个其实原理是十分简单,但是由于博主做的时候遇到了 ...
- 4X4矩阵键盘扫描程序
4X4矩阵键盘扫描: 1. 4根行线的GIO均设为Output,根列线的GIO均设为Input: 2. 4根行线的GIO分别置为0111.1011.1101.1110,读逐一读取列线GIO的值,可确定 ...
- 「雕爷学编程」Arduino动手做(26)——4X4矩阵键盘模块
37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器和模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里 ...
- 4x4矩阵键盘 扫描程序
一:不排除第四位异常处理 uchar JuzhenkeyScan() { // P3=0xfe; // temp=P3; // while(temp!=0xfe) // { // temp=P3; / ...
- MCU软件最佳实践——矩阵键盘驱动
1.矩阵键盘vs独立按键 在mcu应用开发过程中,独立按键比较常见,但是在需要的按键数比较多时,使用矩阵键盘则可以减少io占用,提高系统资源利用率.例如,某mcu项目要求有16个按钮,如果采用独立按键 ...
- 【STM32学习笔记】STM32f407 使用4*4矩阵键盘
作者:李剀 出处:https://www.cnblogs.com/kevin-nancy/ 欢迎转载,但也请保留上面这段声明.谢谢! 写在前面: 这是本人第一次开始写博客,可能写的不是很好,也请大家谅 ...
- STM32 实现 4*4 矩阵键盘扫描(HAL库、标准库 都适用)
本文实现的代码是基于STM32HAL库的基础上的,不过标准库也可以用,只是调用的库函数不同,逻辑跟配置是一样的,按我这里的逻辑来配置即可. 1.键盘原理图: 原理举例:先把 F0-F7 内部拉高,这样 ...
- ARM开发(3)基于STM32的矩阵键盘控制蜂鸣器
一 矩阵键盘控制蜂鸣器原理: 1.1 本实验实现8*7矩阵键盘上按键控制蜂鸣器响. 1.2 实验思路:根据电路图原理,找出矩阵键盘行列所对应的引脚,赋予对应的按键值,然后控制蜂鸣器响. 1.3 ...
随机推荐
- vitepress使用createContentLoader时遇到["vitepress" resolved to an ESM file. ESM file cannot be loaded by `require`.]报错
在使用vitepress构建一个所有博客的概览页的时候,使用到了createContentLoader这个api,但是在index.data.ts中定义并导出后,在md文件中调用遇到了下面这个问题: ...
- 幻想领域图床系统V1.2正式版发布
Tips:当你看到这个提示的时候,说明当前的文章是由原emlog博客系统搬迁至此的,文章发布时间已过于久远,编排和内容不一定完整,还请谅解` 幻想领域图床系统V1.2正式版发布 日期:2018-4-1 ...
- 简约博客V1.1版本上线 + 一套新主题
Tips:当你看到这个提示的时候,说明当前的文章是由原emlog博客系统搬迁至此的,文章发布时间已过于久远,编排和内容不一定完整,还请谅解` 简约博客V1.1版本上线 + 一套新主题 日期:2017- ...
- iterrows()
iterrows() 是 Pandas 库中 DataFrame 对象的一个方法,它允许你迭代 DataFrame 的行.当你有一个 DataFrame 并且想要逐行访问数据(或者基于每一行的数据做一 ...
- 10-Python进程与线程
Python进程 创建新进程 from multiprocessing import Process import time def run_proc(name): #子进程要执行的代码 for i ...
- MYSQL中怎么查询LONGBLOB类型数据的大小
在MySQL中,LONGBLOB 是一种二进制大对象(BLOB)数据类型,用于存储大量的二进制数据.但是,LONGBLOB 数据类型本身并不直接存储数据的大小(长度).它存储的是二进制数据的实际内容. ...
- LaTeX 编辑协作平台 Overleaf 安装和使用教程
在学术界和科技行业,LaTeX 已成为撰写高质量文档的标准工具.然而,传统的 LaTeX 使用体验常常伴随着以下挑战: 学习曲线陡峭 环境配置复杂 多人协作困难 实时预览不便 当然,市面上不乏很多在线 ...
- C#开发单实例应用程序并响应后续进程启动参数
C#默认的WinForm模板是不支持设置单实例的,也没有隔壁大哥VB.NET那样有个"生成单个实例应用程序"的勾选选项(VB某些时候要比C#更方便),实现单实例可以有多种方法: 检 ...
- Spring之拦截器和过滤器
Spring拦截器 拦截器简介 Spring拦截器是一种基于AOP的技术,本质也是使用一种代理技术,它主要作用于接口请求中的控制器,也就是Controller. 因此它可以用于对接口进行权限验证控制. ...
- javaweb上传图片存到本地,并存储地址到数据库
前端使用layui的图片上传,将文件base64编码,然后在后端使用转码类来操作base64编码,并保存图片到本地,继而获取文件地址,将文件地址保存到数据库中 1.使用layui的图片上传 infos ...