1.理论分析
1.1键盘扫描方式
我们所用到的键盘为4×4矩阵键盘,先分析矩阵键盘的威廉希尔官方网站
连接方式及其扫描方式。根据威廉希尔官方网站
可知
- 第1 ~ 4行按键的一端分别为P30 ~ P33引脚
- 第1 ~ 4列按键的另一端分别为P34 ~ P37引脚
我们将矩阵键盘的接口分别定义为GPIO端口
- P30-P33(行)引脚分别定义为PD8-PD11(GPIOD端口),且模式为上拉输入(即有按键按下时为0,没有按键按下时为1)
- P34-P37(列)引脚分别定义为PB12-PB15(GPIOB端口),且模式为推挽输出
我们这里采用将列置0,然后扫描行,当哪一行被按下后,对应的电平置0,此时该按键导通,即可读取到按键值。
1.2行扫描逻辑
首先我们需要定义一个数组用来存放行扫描的结果。
分别存放PD8~PD11的电平值
- 从GPIOD端口获取行扫描值
- 判断行扫描值的二进制数
- 返回对应是第几行按键按下
行扫描程序执行流程
其中该程序在进行按键扫描时,同样需要进行按键消抖,已经在前一篇中说明,这里就不再赘述。
行扫描结果对应的按键值
[tr]PD 8PD 9PD10PD11按键结果[/tr]
0 | 1 | 1 | 1 | 第一行被按下 |
1 | 0 | 1 | 1 | 第二行被按下 |
1 | 1 | 0 | 1 | 第三行被按下 |
1 | 1 | 1 | 0 | 第四行被按下 |
1.3列扫描逻辑
列扫描的执行过程
- 将每一列依次置0
- 将行扫描函数返回值赋值给定义的变量key_row_num
- 判断该变量是否为0
- 得出按键值
列扫描程序执行流程
2.程序编写
2.1按键扫描程序
2.1.1按键初始化
void key_init(){
GPIO_InitTypeDef GPIO_InitStruture;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//打开PB时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);//打开PD时钟
//定义PB12、PB13、PB14、PB15为推挽输出、分别定义为列
GPIO_InitStruture.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruture.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;
GPIO_InitStruture.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStruture);
//定义PD8、PD9、PD10、PD11为上拉输入、分别定义为四行
GPIO_InitStruture.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStruture.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11;
GPIO_Init(GPIOD,&GPIO_InitStruture);
}
2.1.2按键扫描程序头文件
头文件中我们编写了按键的行引脚分别对应P8 ~ P11端口,以及按键列引脚的高低电平,分别对应PB12 ~ PB15端口。
#ifndef _KEY16_H
#define _KEY16_H
#include "sys.h"
#include "stm32f10x.h"
#include
//定义行按键的引脚
#define key_row0_Pin GPIO_Pin_8//定义P8为行1
#define key_row1_Pin GPIO_Pin_9//定义P9为行2
#define key_row2_Pin GPIO_Pin_10//定义P10为行3
#define key_row3_Pin GPIO_Pin_11//定义P11为行4
//行扫描函数、列扫描函数、初始化函数声明
void key_init();
char key_row_scan(void);
char key_scan(void);
//定义列的低电平输出
#define KEY_CLO0_OUT_LOW GPIO_WriteBit(GPIOB,GPIO_Pin_12,Bit_RESET)
#define KEY_CLO1_OUT_LOW GPIO_WriteBit(GPIOB,GPIO_Pin_13,Bit_RESET)
#define KEY_CLO2_OUT_LOW GPIO_WriteBit(GPIOB,GPIO_Pin_14,Bit_RESET)
#define KEY_CLO3_OUT_LOW GPIO_WriteBit(GPIOB,GPIO_Pin_15,Bit_RESET)
//定义列的高电平输出
#define KEY_CLO0_OUT_HIGH GPIO_WriteBit(GPIOB,GPIO_Pin_12,Bit_SET)
#define KEY_CLO1_OUT_HIGH GPIO_WriteBit(GPIOB,GPIO_Pin_13,Bit_SET)
#define KEY_CLO2_OUT_HIGH GPIO_WriteBit(GPIOB,GPIO_Pin_14,Bit_SET)
#define KEY_CLO3_OUT_HIGH GPIO_WriteBit(GPIOB,GPIO_Pin_15,Bit_SET)
#endif
2.1.3行扫描函数
char key_row_scan(void){
key_row[0] = GPIO_ReadInputDataBit(GPIOD, key_row0_Pin)<<3;//读取PD8/第1行
key_row[0] = key_row[0] | (GPIO_ReadInputDataBit(GPIOD, key_row1_Pin)<<2);//读取PD9/第2行
key_row[0] = key_row[0] | (GPIO_ReadInputDataBit(GPIOD, key_row2_Pin)<<1);//读取PD10/第3行
key_row[0] = key_row[0] | (GPIO_ReadInputDataBit(GPIOD, key_row3_Pin));//读取PD11/第4行
if(key_row[0] != 0x0f)
{
delay_ms(10);
if(key_row[0] != 0x0f)
{
switch(key_row[0])
{
case 0x07: //0111 第1行被按下
return 1;
case 0x0b: //1011 第2行被按下
return 2;
case 0x0d: //1101 第3行被按下
return 3;
case 0x0e: //1110 第4行被按下
return 4;
default :
return 0; //没有按键被按下
}
}else return 0;
}else return 0;
}
2.1.3列扫描函数
char key_scan(void){
char key_num=0; //1-16对应的按键数
char key_row_num=0; //行扫描结果记录
KEY_CLO0_OUT_LOW;
if( (key_row_num=key_row_scan()) != 0 )
{
while(key_row_scan() != 0); //消抖
key_num = 0 + key_row_num;
}
KEY_CLO0_OUT_HIGH;
KEY_CLO1_OUT_LOW;
if( (key_row_num=key_row_scan()) != 0 )
{
while(key_row_scan() != 0);
key_num = 4 + key_row_num;
//printf("Key_Clo_2rn");
}
KEY_CLO1_OUT_HIGH;
KEY_CLO2_OUT_LOW;
if( (key_row_num=key_row_scan()) != 0 )
{
while(key_row_scan() != 0);
key_num = 8 + key_row_num;
//printf("Key_Clo_3rn");
}
KEY_CLO2_OUT_HIGH;
KEY_CLO3_OUT_LOW;
if( (key_row_num=key_row_scan()) != 0 )
{
while(key_row_scan() != 0);
key_num = 12 + key_row_num;
}
KEY_CLO3_OUT_HIGH;
return key_num;
}
2.2主程序
主程序通过调用行扫描函数和列扫描函数来输出按键值。
#include "stm32f10x.h"
#include "delay.h"
#include "led.h"
#include "key16.h"
#include "stdio.h"
#include "usart.h"
int main(void)
{
char key_num_end;
delay_init();
key_init();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
uart_init(115200);//波特率
while(1)
{
key_num_end = key_scan();
if(key_num_end>0&&key_num_end<17){
printf("Key_NUM = %d rn",key_num_end); //按下1-16个按键的操作
printf("= = = = = = = = = = = rn");
}
}
}
1.理论分析
1.1键盘扫描方式
我们所用到的键盘为4×4矩阵键盘,先分析矩阵键盘的威廉希尔官方网站
连接方式及其扫描方式。根据威廉希尔官方网站
可知
- 第1 ~ 4行按键的一端分别为P30 ~ P33引脚
- 第1 ~ 4列按键的另一端分别为P34 ~ P37引脚
我们将矩阵键盘的接口分别定义为GPIO端口
- P30-P33(行)引脚分别定义为PD8-PD11(GPIOD端口),且模式为上拉输入(即有按键按下时为0,没有按键按下时为1)
- P34-P37(列)引脚分别定义为PB12-PB15(GPIOB端口),且模式为推挽输出
我们这里采用将列置0,然后扫描行,当哪一行被按下后,对应的电平置0,此时该按键导通,即可读取到按键值。
1.2行扫描逻辑
首先我们需要定义一个数组用来存放行扫描的结果。
分别存放PD8~PD11的电平值
- 从GPIOD端口获取行扫描值
- 判断行扫描值的二进制数
- 返回对应是第几行按键按下
行扫描程序执行流程
其中该程序在进行按键扫描时,同样需要进行按键消抖,已经在前一篇中说明,这里就不再赘述。
行扫描结果对应的按键值
[tr]PD 8PD 9PD10PD11按键结果[/tr]
0 | 1 | 1 | 1 | 第一行被按下 |
1 | 0 | 1 | 1 | 第二行被按下 |
1 | 1 | 0 | 1 | 第三行被按下 |
1 | 1 | 1 | 0 | 第四行被按下 |
1.3列扫描逻辑
列扫描的执行过程
- 将每一列依次置0
- 将行扫描函数返回值赋值给定义的变量key_row_num
- 判断该变量是否为0
- 得出按键值
列扫描程序执行流程
2.程序编写
2.1按键扫描程序
2.1.1按键初始化
void key_init(){
GPIO_InitTypeDef GPIO_InitStruture;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//打开PB时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);//打开PD时钟
//定义PB12、PB13、PB14、PB15为推挽输出、分别定义为列
GPIO_InitStruture.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruture.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;
GPIO_InitStruture.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStruture);
//定义PD8、PD9、PD10、PD11为上拉输入、分别定义为四行
GPIO_InitStruture.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStruture.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11;
GPIO_Init(GPIOD,&GPIO_InitStruture);
}
2.1.2按键扫描程序头文件
头文件中我们编写了按键的行引脚分别对应P8 ~ P11端口,以及按键列引脚的高低电平,分别对应PB12 ~ PB15端口。
#ifndef _KEY16_H
#define _KEY16_H
#include "sys.h"
#include "stm32f10x.h"
#include
//定义行按键的引脚
#define key_row0_Pin GPIO_Pin_8//定义P8为行1
#define key_row1_Pin GPIO_Pin_9//定义P9为行2
#define key_row2_Pin GPIO_Pin_10//定义P10为行3
#define key_row3_Pin GPIO_Pin_11//定义P11为行4
//行扫描函数、列扫描函数、初始化函数声明
void key_init();
char key_row_scan(void);
char key_scan(void);
//定义列的低电平输出
#define KEY_CLO0_OUT_LOW GPIO_WriteBit(GPIOB,GPIO_Pin_12,Bit_RESET)
#define KEY_CLO1_OUT_LOW GPIO_WriteBit(GPIOB,GPIO_Pin_13,Bit_RESET)
#define KEY_CLO2_OUT_LOW GPIO_WriteBit(GPIOB,GPIO_Pin_14,Bit_RESET)
#define KEY_CLO3_OUT_LOW GPIO_WriteBit(GPIOB,GPIO_Pin_15,Bit_RESET)
//定义列的高电平输出
#define KEY_CLO0_OUT_HIGH GPIO_WriteBit(GPIOB,GPIO_Pin_12,Bit_SET)
#define KEY_CLO1_OUT_HIGH GPIO_WriteBit(GPIOB,GPIO_Pin_13,Bit_SET)
#define KEY_CLO2_OUT_HIGH GPIO_WriteBit(GPIOB,GPIO_Pin_14,Bit_SET)
#define KEY_CLO3_OUT_HIGH GPIO_WriteBit(GPIOB,GPIO_Pin_15,Bit_SET)
#endif
2.1.3行扫描函数
char key_row_scan(void){
key_row[0] = GPIO_ReadInputDataBit(GPIOD, key_row0_Pin)<<3;//读取PD8/第1行
key_row[0] = key_row[0] | (GPIO_ReadInputDataBit(GPIOD, key_row1_Pin)<<2);//读取PD9/第2行
key_row[0] = key_row[0] | (GPIO_ReadInputDataBit(GPIOD, key_row2_Pin)<<1);//读取PD10/第3行
key_row[0] = key_row[0] | (GPIO_ReadInputDataBit(GPIOD, key_row3_Pin));//读取PD11/第4行
if(key_row[0] != 0x0f)
{
delay_ms(10);
if(key_row[0] != 0x0f)
{
switch(key_row[0])
{
case 0x07: //0111 第1行被按下
return 1;
case 0x0b: //1011 第2行被按下
return 2;
case 0x0d: //1101 第3行被按下
return 3;
case 0x0e: //1110 第4行被按下
return 4;
default :
return 0; //没有按键被按下
}
}else return 0;
}else return 0;
}
2.1.3列扫描函数
char key_scan(void){
char key_num=0; //1-16对应的按键数
char key_row_num=0; //行扫描结果记录
KEY_CLO0_OUT_LOW;
if( (key_row_num=key_row_scan()) != 0 )
{
while(key_row_scan() != 0); //消抖
key_num = 0 + key_row_num;
}
KEY_CLO0_OUT_HIGH;
KEY_CLO1_OUT_LOW;
if( (key_row_num=key_row_scan()) != 0 )
{
while(key_row_scan() != 0);
key_num = 4 + key_row_num;
//printf("Key_Clo_2rn");
}
KEY_CLO1_OUT_HIGH;
KEY_CLO2_OUT_LOW;
if( (key_row_num=key_row_scan()) != 0 )
{
while(key_row_scan() != 0);
key_num = 8 + key_row_num;
//printf("Key_Clo_3rn");
}
KEY_CLO2_OUT_HIGH;
KEY_CLO3_OUT_LOW;
if( (key_row_num=key_row_scan()) != 0 )
{
while(key_row_scan() != 0);
key_num = 12 + key_row_num;
}
KEY_CLO3_OUT_HIGH;
return key_num;
}
2.2主程序
主程序通过调用行扫描函数和列扫描函数来输出按键值。
#include "stm32f10x.h"
#include "delay.h"
#include "led.h"
#include "key16.h"
#include "stdio.h"
#include "usart.h"
int main(void)
{
char key_num_end;
delay_init();
key_init();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
uart_init(115200);//波特率
while(1)
{
key_num_end = key_scan();
if(key_num_end>0&&key_num_end<17){
printf("Key_NUM = %d rn",key_num_end); //按下1-16个按键的操作
printf("= = = = = = = = = = = rn");
}
}
}
举报