矩阵键盘的学习只是为了做一个简单的遥控器,主要目标还是后续的遥控器控制小车实现简单而精准的直行和转弯,加上前面的模块,锻炼自己PID的调试和理解能力。但毕竟矩阵键盘也算个模块嘛,就也记录一下,分享给有需要的同志。
(此代码是基于MSP430F5529系列,其他系列MCU均可用,自己修改引脚,配置IO口即可)
1.基本原理
矩阵键盘主要方便在16个按键只需要8个引脚即可实现控制,根据我们所学的4*4的矩阵可以很容易理解他的原理,无非就是先确定行(列),再确定列,即可确定某个具体的键位。方法自然而然也有很多种,用的比较多的就是行扫描法和列扫描法。
例如,我们确定第三行,第四列的键位该如何确定呢?我们利用行扫描法。将四个关于行的引脚设置为输出模式,四个关于列的引脚设置为输入模式(这里一定要是上拉输入)。随后,对四个关于行的引脚轮流给出低电平,给到第一行的时候,此时因为第一行的四个列引脚电平读取均为高,即证明第一行没有按键按下,当低电平给到第三行的时候,第四列电平读取为低电平,此时便可以确定是三行四列的按键按下!大概的流程便是如此。
2.上代码
/*
* matrix_keybord.c
*
* Created on: 2022年7月20日
* Author: S10
*/
#include "matrix_keyboard.h"
#include "oled.h"
/* 设置为列输入,行输出
* 无入口参数
* 无返回值
*/
void ROCI_Init(void)
{
GPIO_setAsOutputPin(R1_Port,R1_Pin);
GPIO_setAsOutputPin(R2_Port,R2_Pin);
GPIO_setAsOutputPin(R3_Port,R3_Pin);
GPIO_setAsOutputPin(R4_Port,R4_Pin);
GPIO_setAsInputPinWithPullUpResistor(C1_Port,C1_Pin);
GPIO_setAsInputPinWithPullUpResistor(C2_Port,C2_Pin);
GPIO_setAsInputPinWithPullUpResistor(C3_Port,C3_Pin);
GPIO_setAsInputPinWithPullUpResistor(C4_Port,C4_Pin);
}
/* 设置为行输入,列输出
* 无入口参数
* 无返回值
*/
void RICO_Init(void)
{
GPIO_setAsInputPinWithPullUpResistor(R1_Port,R1_Pin);
GPIO_setAsInputPinWithPullUpResistor(R2_Port,R2_Pin);
GPIO_setAsInputPinWithPullUpResistor(R3_Port,R3_Pin);
GPIO_setAsInputPinWithPullUpResistor(R4_Port,R4_Pin);
GPIO_setAsOutputPin(C1_Port,C1_Pin);
GPIO_setAsOutputPin(C2_Port,C2_Pin);
GPIO_setAsOutputPin(C3_Port,C3_Pin);
GPIO_setAsOutputPin(C4_Port,C4_Pin);
}
int key_scan_column(void)
{
if(GPIO_getInputPinValue(C1_Port,C1_Pin) == GPIO_INPUT_PIN_LOW)
return 5;
else if(GPIO_getInputPinValue(C2_Port,C2_Pin) == GPIO_INPUT_PIN_LOW)
return 6;
else if(GPIO_getInputPinValue(C3_Port,C3_Pin) == GPIO_INPUT_PIN_LOW)
return 7;
else if(GPIO_getInputPinValue(C4_Port,C4_Pin) == GPIO_INPUT_PIN_LOW)
return 8;
else return 0;
}
char key_detect(void)
{
ROCI_Init();//置为列输入,行输出
GPIO_setOutputLowOnPin(R1_Port,R1_Pin);//设置第一行为低电平
GPIO_setOutputHighOnPin(R2_Port,R2_Pin);//设置第二行为高电平
GPIO_setOutputHighOnPin(R3_Port,R3_Pin);//设置第三行为高电平
GPIO_setOutputHighOnPin(R4_Port,R4_Pin);//设置第四行为高电平
OLED_ShowNum(0,0,key_scan_column(),2,10);
if(key_scan_column() != 0)//扫描存在按键按下
{
// __delay_cycles(160000);
delay_ms(10);//按键消抖
if(key_scan_column() != 0 )//若依然判断有低电平,则确实有按键按下
{
switch(key_scan_column())
{
case 5: return '1';
case 6: return '2';
case 7: return '3';
case 8: return '4';
default:break;
}
}
}
GPIO_setOutputHighOnPin(R1_Port,R1_Pin);//设置第一行为高电平
GPIO_setOutputHighOnPin(R2_Port,R2_Pin);//设置第二行为高电平
GPIO_setOutputHighOnPin(R3_Port,R3_Pin);//设置第三行为高电平
GPIO_setOutputHighOnPin(R4_Port,R4_Pin);//设置第四行为高电平
GPIO_setOutputHighOnPin(R1_Port,R1_Pin);//设置第一行为高电平
GPIO_setOutputLowOnPin(R2_Port,R2_Pin);//设置第二行为低电平
GPIO_setOutputHighOnPin(R3_Port,R3_Pin);//设置第三行为高电平
GPIO_setOutputHighOnPin(R4_Port,R4_Pin);//设置第四行为高电平
if(key_scan_column() !=0 )//扫描存在按键按下
{
delay_ms(10);//按键消抖
if(key_scan_column() !=0 )//若依然判断有低电平,则确实有按键按下
{
switch(key_scan_column())
{
case 5: return '5';
case 6: return '6';
case 7: return '7';
case 8: return '8';
default: break;
}
}
}
GPIO_setOutputHighOnPin(R1_Port,R1_Pin);//设置第一行为高电平
GPIO_setOutputHighOnPin(R2_Port,R2_Pin);//设置第二行为高电平
GPIO_setOutputHighOnPin(R3_Port,R3_Pin);//设置第三行为高电平
GPIO_setOutputHighOnPin(R4_Port,R4_Pin);//设置第四行为高电平
GPIO_setOutputHighOnPin(R1_Port,R1_Pin);//设置第一行为高电平
GPIO_setOutputHighOnPin(R2_Port,R2_Pin);//设置第二行为高电平
GPIO_setOutputLowOnPin(R3_Port,R3_Pin);//设置第三行为低电平
GPIO_setOutputHighOnPin(R4_Port,R4_Pin);//设置第四行为高电平
if(key_scan_column() !=0 )//扫描存在按键按下
{
delay_ms(10);//按键消抖
if(key_scan_column() !=0 )//若依然判断有低电平,则确实有按键按下
{
switch(key_scan_column())
{
case 5: return '9';
case 6: return 'a';
case 7: return 'b';
case 8: return 'c';
default: break;
}
}
}
GPIO_setOutputHighOnPin(R1_Port,R1_Pin);//设置第一行为高电平
GPIO_setOutputHighOnPin(R2_Port,R2_Pin);//设置第二行为高电平
GPIO_setOutputHighOnPin(R3_Port,R3_Pin);//设置第三行为高电平
GPIO_setOutputHighOnPin(R4_Port,R4_Pin);//设置第四行为高电平
GPIO_setOutputHighOnPin(R1_Port,R1_Pin);//设置第一行为高电平
GPIO_setOutputHighOnPin(R2_Port,R2_Pin);//设置第二行为高电平
GPIO_setOutputHighOnPin(R3_Port,R3_Pin);//设置第三行为高电平
GPIO_setOutputLowOnPin(R4_Port,R4_Pin);//设置第四行为低电平
if(key_scan_column() != 0 )//扫描存在按键按下
{
delay_ms(10);//按键消抖
if(key_scan_column() != 0 )//若依然判断有低电平,则确实有按键按下
{
switch(key_scan_column())
{
case 5: return 'd';
case 6: return 'e';
case 7: return 'f';
case 8: return 'g';
default: break;
}
}
}
GPIO_setOutputHighOnPin(R1_Port,R1_Pin);//设置第一行为高电平
GPIO_setOutputHighOnPin(R2_Port,R2_Pin);//设置第二行为高电平
GPIO_setOutputHighOnPin(R3_Port,R3_Pin);//设置第三行为高电平
GPIO_setOutputHighOnPin(R4_Port,R4_Pin);//设置第四行为高电平
return '0';
}
/*
* matrix_keyboard.h
*
* Created on: 2022年7月20日
* Author: S10
*/
#ifndef MATRIX_KEYBOARD_H_
#define MATRIX_KEYBOARD_H_
#include "driverlib.h"
#define C1_Port GPIO_PORT_P1
#define C1_Pin GPIO_PIN6
#define C2_Port GPIO_PORT_P6
#define C2_Pin GPIO_PIN6
#define C3_Port GPIO_PORT_P3
#define C3_Pin GPIO_PIN2
#define C4_Port GPIO_PORT_P2
#define C4_Pin GPIO_PIN7
#define R1_Port GPIO_PORT_P6
#define R1_Pin GPIO_PIN2
#define R2_Port GPIO_PORT_P6
#define R2_Pin GPIO_PIN3
#define R3_Port GPIO_PORT_P6
#define R3_Pin GPIO_PIN4
#define R4_Port GPIO_PORT_P7
#define R4_Pin GPIO_PIN0
#define CPU_CLOCK 16000000
#define delay_us(us) __delay_cycles(CPU_CLOCK/1000000*(us))
#define delay_ms(ms) __delay_cycles(CPU_CLOCK/1000*(ms))
void ROCI_Init(void);
void RICO_Init(void);
int key_scan_column(void);
char key_detect(void);
#endif /* MATRIX_KEYBOARD_H_ */
在主函数中直接调用即可,有不懂的地方可以在评论区提出来或者私信我,知无不答!