本实验使用4*4矩阵键盘进行应用。为了节省引脚占用,矩阵键盘提供了多行多列排列成矩形组合的按键,因此它是矩阵按键或矩阵键盘。如图:
矩阵键盘
本实验使用stm32和矩阵按钮来点亮LED并以二进制显示。例如,二进制的 0000 表示所有四个 LED 均关闭;二进制0001表示第四个LED亮,其他三个灭,以此类推;即1为开,0为关。 0.96英寸OLED显示反馈按键值(两个单位),如key1-01、key5--05、key11-11...;按键响应相应的键值和二进制显示LED。矩阵按钮实现方法: 1.响应相应的中断方法。 2、行列扫描法。本实验主要采用第二种方法,比较容易理解。
示意图
走线和行扫描方式:
矩阵按键扫描方式理解图如下:
说明:左边理解为水平,右边的padding理解为水平。纵向理解。
首先可以看到0x00ff,表示行与行中的按键没有接触。 0x00fe 垂直1110表示第一行接触,然后等待第一行的哪一列进行下一次接触。当第一行第一列同时响应触点时,表示第一行第一列对应的LED显示二进制0001,即第四个灯亮。
0x00fd 垂直1101表示第二行接触,然后等待第二行哪一列进行下一次接触。当第二行第三列同时响应触点时,则表示第二行第三列对应的LED以二进制1101显示,即第一、二、四灯点亮。 ?三行第一、三列对应的LED以二进制0101显示,即第二、第四灯点亮。
第四行同样可以得到。
keys.c
#include“stm32f10x.h”
#include“keys.h”
#include“延迟.h”
//
//**************************************************** **********************************
u8 标志=0;
void KEY_4x4_Init(void) //IO初始化
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,启用);GPIO_InitStructure.GPIO_Pin = KEY_HANG; //行0123
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(KEY_PROT, &GPIO_InitStructure);
GPIO_SetBits(KEY_PROT,KEY_HANG);
//init GPIOA上拉输入
GPIO_InitStructure.GPIO_Pin = KEY1|KEY2|KEY3|KEY4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(KEY_PROT, &GPIO_InitStructure);
GPIO_SetBits(KEY_PROT,KEY1|KEY2|KEY3|KEY4);
}
无效 KEY_Scan(u8 *key)
{
GPIO_Write(KEY_PROT,0x00fe);//第一行
if((KEY1_Input==RESET)||(KEY2_Input==RESET)||(KEY3_Input==RESET)||(KEY4_Input==RESET))
{
delay_ms(10);//去睡觉
如果(KEY1_输入==重置)
{
标志=1;
*键= 1;
while(!GPIO_ReadInputDataBit(KEY_PROT,KEY1));
}
否则如果(KEY2_Input==RESET)
{
标志=1;
*键= 2;
while(!GPIO_ReadInputDataBit(KEY_PROT,KEY2));
}
否则如果(KEY3_Input==RESET)
{
标志=1;
*键= 3;while(!GPIO_ReadInputDataBit(KEY_PROT,KEY3));
}
否则如果(KEY4_Input==RESET)
{
标志=1;
*键= 4;
while(!GPIO_ReadInputDataBit(KEY_PROT,KEY4));
}别的
{
标志=0;
GPIO_Write(KEY_PROT,0x00ff);
}
}
GPIO_Write(KEY_PROT,0x00fd);//第二行
if((KEY1_Input==RESET)||(KEY2_Input==RESET)||(KEY3_Input==RESET)||(KEY4_Input==RESET))
{
delay_ms(10);//去睡觉
如果(KEY1_输入==重置)
{
标志=1;
*键= 5;
while(!GPIO_ReadInputDataBit(KEY_PROT,KEY1));
}
否则如果(KEY2_Input==RESET)
{
标志=1;
*键= 6;
while(!GPIO_ReadInputDataBit(KEY_PROT,KEY2));
}
否则如果(KEY3_Input==RESET)
{
标志=1;
*键= 7;
while(!GPIO_ReadInputDataBit(KEY_PROT,KEY3));
}
否则如果(KEY4_Input==RESET)
{
标志=1;
*键= 8;
while(!GPIO_ReadInputDataBit(KEY_PROT,KEY4));
}别的
{
标志=0;GPIO_Write(KEY_PROT,0x00ff);
}
}
GPIO_Write(KEY_PROT,0x00fb);//第三行
if((KEY1_Input==RESET)||(KEY2_Input==RESET)||(KEY3_Input==RESET)||(KEY4_Input==RESET))
{
delay_ms(10);//去睡觉
如果(KEY1_输入==重置)
{
标志=1;
*键= 9;
while(!GPIO_ReadInputDataBit(KEY_PROT,KEY1));
}
否则如果(KEY2_Input==RESET)
{
标志=1;
*键= 10;
while(!GPIO_ReadInputDataBit(KEY_PROT,KEY2));
}
否则如果(KEY3_Input==RESET)
{
标志=1;
*键= 11;
while(!GPIO_ReadInputDataBit(KEY_PROT,KEY3));
}
否则如果(KEY4_Input==RESET)
{
标志=1;
*键= 12;
while(!GPIO_ReadInputDataBit(KEY_PROT,KEY4));
}别的
{
标志=0;
GPIO_Write(KEY_PROT,0x00ff);
}
}
GPIO_Write(KEY_PROT,0x00f7);//第四行
if((KEY1_Input==RESET)||(KEY2_Input==RESET)||(KEY3_Input==RESET)||(KEY4_Input==RESET))
{
delay_ms(10);//去睡觉
如果(KEY1_输入==重置)
{标志=1;
*键= 13;
while(!GPIO_ReadInputDataBit(KEY_PROT,KEY1));
}
否则如果(KEY2_Input==RESET)
{
标志=1;
*键= 14;
while(!GPIO_ReadInputDataBit(KEY_PROT,KEY2));
}
否则如果(KEY3_Input==RESET)
{
标志=1;
*键= 15;
while(!GPIO_ReadInputDataBit(KEY_PROT,KEY3));
}
否则如果(KEY4_Input==RESET)
{
标志=1;
*键= 16;
while(!GPIO_ReadInputDataBit(KEY_PROT,KEY4));
}别的
{
标志=0;
GPIO_Write(KEY_PROT,0x00ff);
}
}
}
keys.h
#ifndef __KEYS_H
#定义__KEYS_H
//
//**************************************************** **********************************
//V1.1修改说明
//修改按键扫描函数,使整个代码可以支持SWD下载。
//
#include“stm32f10x.h”
#定义KEY_HANG 0x000f //0123
#定义KEY1 GPIO_Pin_4
#定义KEY2 GPIO_Pin_5
#定义KEY3 GPIO_Pin_6
#定义KEY4 GPIO_Pin_7
#define KEY1_Input GPIO_ReadInputDataBit(KEY_PROT,KEY1)#define KEY2_Input GPIO_ReadInputDataBit(KEY_PROT,KEY2)
#define KEY3_Input GPIO_ReadInputDataBit(KEY_PROT,KEY3)
#define KEY4_Input GPIO_ReadInputDataBit(KEY_PROT,KEY4)
#定义KEY_PROT GPIOA
外部 u8 标志;
void KEY_4x4_Init(void);//IO初始化
//u8 KEY_Scan(void);
无效 KEY_Scan(u8 *key); //按键扫描函数
#万一
main.c
#include“stm32f10x.h”
#include“led.h”
#include“延迟.h”
#包括“sys.h”
#include“keys.h”
//#include“usart.h”
#include“OLED.h”
/*接线说明
PA0~PA3----R4~R1 //OK
PA4~PA7-----C4~C1 //柱
*/
u8键=0;
u8i;
int 主函数(无效)
{
LED_Init();
延迟初始化();
KEY_4x4_Init();
//uart_init(115200);
OLED_Init();
/*OLED初始化接口*/
OLED_ShowChar(1, 1, 'A');
OLED_ShowString(1, 3, "HelloWorld!");
OLED_ShowNum(2, 1, 12345, 5);
OLED_ShowSignedNum(2, 7, -66, 2);
OLED_ShowHexNum(3, 1, 0xAA55, 4);
OLED_ShowBinNum(4, 1, 0xAA55, 16);
同时(1)
{
KEY_Scan(&key); //获取键值keyif(FLAG == 1) // 按键
{
标志=0;
OLED_Clear();
OLED_ShowNum(2, 1, 键, 2); //显示键值key
//Printf("KEY = %d\r\n",key);
if(key==1) //0001
{
GPIO_SetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14);
GPIO_ResetBits(GPIOB,GPIO_Pin_15);
}
if(key==2) //0010
{
GPIO_SetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_15);
GPIO_ResetBits(GPIOB,GPIO_Pin_14);
}
if(key==3) //0011
{
GPIO_SetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_13);
GPIO_ResetBits(GPIOB,GPIO_Pin_14|GPIO_Pin_15);
}
if(key==4) //0100
{
GPIO_SetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_14|GPIO_Pin_15);
GPIO_ResetBits(GPIOB,GPIO_Pin_13);
}
if(key==5) //0101
{
GPIO_SetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_14);
GPIO_ResetBits(GPIOB,GPIO_Pin_13|GPIO_Pin_15);
}
if(key==6) //0110
{
GPIO_SetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_15);GPIO_ResetBits(GPIOB,GPIO_Pin_13|GPIO_Pin_14);
}
if(key==7) //0111
{
GPIO_SetBits(GPIOB,GPIO_Pin_12);
GPIO_ResetBits(GPIOB,GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);
}
if(key==8) //1000
{
GPIO_SetBits(GPIOB,GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);
GPIO_ResetBits(GPIOB,GPIO_Pin_12);
}
if(key==9) //1001
{
GPIO_SetBits(GPIOB,GPIO_Pin_13|GPIO_Pin_14);
GPIO_ResetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_15);
}
if(key==10) //1010
{
GPIO_SetBits(GPIOB,GPIO_Pin_13|GPIO_Pin_15);
GPIO_ResetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_14);
}
if(key==11) //1011
{
GPIO_SetBits(GPIOB,GPIO_Pin_13);
GPIO_ResetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_14|GPIO_Pin_15);
}
if(key==12) //1100
{
GPIO_SetBits(GPIOB,GPIO_Pin_14|GPIO_Pin_15);
GPIO_ResetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_13);
}
if(key==13) //1101{
GPIO_SetBits(GPIOB,GPIO_Pin_14);
GPIO_ResetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_15);
}
if(key==14) //1110
{
GPIO_SetBits(GPIOB,GPIO_Pin_15);
GPIO_ResetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14);
}
if(key==15) //1111
{
GPIO_ResetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);
}
if(key==16) //来回触发4次
{
for(i=0;i<4;i++)
{
GPIO_ResetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_13);
GPIO_SetBits(GPIOB,GPIO_Pin_14|GPIO_Pin_15);
延迟毫秒(1000);
GPIO_SetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_13);
GPIO_ResetBits(GPIOB,GPIO_Pin_14|GPIO_Pin_15);
延迟毫秒(1000);
}
}
//LCD12864_Write_Number(0x8d,键);
}
}
}
矩阵键盘实验效果:
矩阵键盘
总结:
根据以上内容,学习矩阵按钮与触摸按钮类似,很容易理解。输入信号给stm32,驱动LED相应点亮或熄灭。矩阵按键主要用于需要多个按键来解决管脚少的问题的应用。
总结一下调试代码或硬件可能出现的问题:
(1)出现按键响应慢:因为矩阵按键模块的触发采用行列扫描,比中断触发快响应速度慢;代码部分按键扫描延迟太高,或者可能出现去抖(10ms~20ms)。
(2)按键硬件无反应:可能是键盘模块引脚与stm32引脚接线错误或接反;也可能是对应管脚冲突和占用造成的,需要调用AFIO口复用转换为正常I/O,或许可以解决;也可能是硬件损坏的问题,或者是裸露的铜造成的短路。
扩展: 您可以使用矩阵键盘模块进行简单计算器、密码锁、功能键等实验。那么就分享在这里,大胆尝试实践探索,欢迎讨论。
今天就这样。你要有信心一步步积累理论和实践经验。一起来学习吧!
链接:参考
链接:参考视频
链接:矩阵按钮视频分享
链接:源代码例程
提取码:3232