笔记16:STM32矩阵按键控制IO口完整代码

一 .矩阵按键原理
矩阵按键有两种扫描方式:
方法一:
逐行扫描:我们可以通过低四位轮流输出低电平来对矩阵键盘进行逐行扫描,当高四位接收到的数据不全为1的时候,说明有按键按下,然后通过接收到的数据是哪一位为0来判断是哪一个按键被按下。
方法二:
行列扫描:我们可以通过高四位全部输出低电平,低四位输出高电平。当接收到的数据,低四位不全为高电平时,说明有按键按下,然后通过接收的数据值,判断是哪一列有按键按下,然后再反过来,高四位输出高电平,低四位输出低电平,然后根据接收到的高四位的值判断是那一行有按键按下,这样就能够确定是哪一个按键按下了。
此次采用的是行扫描方式,与单片机连接如下:
在这里插入图片描述
C4 -->PB7 C3–>PB6 C2–>PB5 C1–>PB4
R1–>PB3 R2–>PB2 R3–>PB1 R4–>PB0

**二.完整程序**
最开始我使用的是GPIOD的Pin0-Pin5,但是导致了LCD无法正常使用,猜测是GPIOD中的某个IO在LCD中也使用了,导致冲突,具体是哪一个还不知道(技术太菜,LCD里面太多内容,看不懂.....)
1.MatrixButton.h头文件:
#ifndef __MatrixButton_H
#define __MatrixButton_H
#include "sys.h"
#define DelayTimes 10
void GPIOF_Int_Init(void);
void GPIOB_Int_Init(void);
void KEY_Scan(void);
void Multiple_Control(void);
#endif

2.MatrixButton.c文件代码:

#include "MatrixButton.h"
#include "delay.h"
u16 KeyValue=17;//17只是为了在没有按键按下的时候给一个数值让LCD显示
void GPIOF_Int_Init(void) //(这个函数不属于矩阵按键配置,初始化所要控制的IO口)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE);//使能GPIOF时钟
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5;//IO输出引脚选用PF0-PF5
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT;//输出模式
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;//输出速度50MHZ
	GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//推挽输出
	GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_DOWN;//下拉
	GPIO_Init(GPIOF,&GPIO_InitStructure);//初始化GPIOF
}
void GPIOB_Int_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);//使能GPIOB的时钟
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_OUT;//输出模式
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;
	GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_UP;
	GPIO_Init(GPIOB,&GPIO_InitStruct);
	
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN;//输入模式,用来检测哪一行按下
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_UP;
	GPIO_Init(GPIOB,&GPIO_InitStruct);
		
}
void KEY_Scan(void)				//(行列扫描方式的矩阵按键配置)					
{
	GPIO_ResetBits(GPIOB,GPIO_Pin_3); 	//第一行检测
	GPIO_SetBits(GPIOB,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2);                              
	if(((GPIOB->IDR )&0xF0)!=0xF0)	 //说明PD4-PD7状态发生变化,列检测
	{
		delay_ms(DelayTimes);			//按键消抖
		if(((GPIOB->IDR )&0xF0)!=0xF0) 		//再次判断是否有按键按下
		{
			switch((GPIOB->IDR )&0xF7)//检测输入数据寄存器PB4-PB7对应位的电平状态
			{ 
				case 0xE7:KeyValue=1;break;//说明PB4接收到低电平,第一行第一列对应第一个按键
				case 0xD7:KeyValue=2;break; 
				case 0xB7:KeyValue=3;break;
				case 0x77:KeyValue=4;break; 
				default:break;
			}

		 }	
	 }
	GPIO_ResetBits(GPIOB,GPIO_Pin_2); 
	GPIO_SetBits(GPIOB,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_3);
	if(((GPIOB->IDR )&0xF0)!=0xF0)	 //说明PD4-PD7状态发生变化,列检测
	{
		delay_ms(DelayTimes);									//按键消抖
		if(((GPIOB->IDR )&0xF0)!=0xF0) 		//再次判断是否有按键按下
		{
			switch((GPIOB->IDR )&0xFB)
			{ 
				case 0xEB:KeyValue=5;break;
				case 0xDB:KeyValue=6;break; 
				case 0xBB:KeyValue=7;break;
				case 0x7B:KeyValue=8;break; 
				default:break;
			}

		}		
	 }
	 GPIO_ResetBits(GPIOB,GPIO_Pin_1);		//Pin1输出低电平
	 GPIO_SetBits(GPIOB,GPIO_Pin_0|GPIO_Pin_2|GPIO_Pin_3);//Pin0,Pin2,Pin3输出高电平
	 if(((GPIOB->IDR )&0xF0)!=0xF0)	 //说明PD4-PD7状态发生变化,列检测
	{
		delay_ms(DelayTimes);									//按键消抖
		if(((GPIOB->IDR )&0xF0)!=0xF0)		//再次判断是否有按键按下
		{
			switch((GPIOB->IDR )&0xFD)
				 { 
					case 0xED:KeyValue=9;break;
					case 0xDD:KeyValue=10;break; 
					case 0xBD:KeyValue=11;break;
					case 0x7D:KeyValue=12;break; 
					default: break;
				}

		 }	
	 }	

	GPIO_ResetBits(GPIOB,GPIO_Pin_0); 			//Pin0输出低电平
	GPIO_SetBits(GPIOB,GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3);//Pin1-Pin3输出高电平
	if(((GPIOB->IDR )&0xF0)!=0xF0)	 //说明PD4-PD7状态发生变化,列检测
	{
		delay_ms(DelayTimes);									//按键消抖
		if(((GPIOB->IDR )&0xF0)!=0xF0) 		//再次判断是否有按键按下
		{
			switch((GPIOB->IDR )&0xFE)
				{ 
					case 0xEE:KeyValue=13;break; 
				    case 0xDE:KeyValue=14;break; 
				    case 0xBE:KeyValue=15;break; 
				    case 0x7E:KeyValue=16;break; 
					default:break;
				} 
		 }
	 }
	
	
							 
}
void Multiple_Control(void)//控制IO口输出(这个函数通过矩阵键盘的按键控制IO口输出)
{
	if(KeyValue!=17)	 //说明有按键按下
	{
		switch(KeyValue) 
		{ 
			case 1:
			{
				GPIO_ResetBits(GPIOF,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2);break;//000
			}
			case 2:
			{
				GPIO_ResetBits(GPIOF,GPIO_Pin_1|GPIO_Pin_2);
				GPIO_SetBits(GPIOF,GPIO_Pin_0);break;//001
			}
			case 3:
			{
				GPIO_ResetBits(GPIOF,GPIO_Pin_0|GPIO_Pin_2);
				GPIO_SetBits(GPIOF,GPIO_Pin_1);break;//010
			}
			case 4:
			{
				GPIO_ResetBits(GPIOF,GPIO_Pin_2);
				GPIO_SetBits(GPIOF,GPIO_Pin_0|GPIO_Pin_1);break;//011
			}
			case 5:
			{
				GPIO_ResetBits(GPIOF,GPIO_Pin_0|GPIO_Pin_1);
				GPIO_SetBits(GPIOF,GPIO_Pin_2);break;//100
			}
			case 6:
			{
				GPIO_ResetBits(GPIOF,GPIO_Pin_1);
				GPIO_SetBits(GPIOF,GPIO_Pin_0|GPIO_Pin_2);break;//101
								
			}
			case 7:
			{
				GPIO_ResetBits(GPIOF,GPIO_Pin_0);
				GPIO_SetBits(GPIOF,GPIO_Pin_1|GPIO_Pin_2);break;//110
								
			}
			case 8:
			{
				GPIO_SetBits(GPIOF,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2);break;//111
			}
			case 9:
			{
				GPIO_ResetBits(GPIOF,GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5);break;//000
			}
			case 10:
			{
				GPIO_ResetBits(GPIOF,GPIO_Pin_4|GPIO_Pin_5);
				GPIO_SetBits(GPIOF,GPIO_Pin_3);break;//001
			}
			case 11:
			{
				GPIO_ResetBits(GPIOF,GPIO_Pin_3|GPIO_Pin_5);
				GPIO_SetBits(GPIOF,GPIO_Pin_4); break;//010
			}
			case 12:
			{
				GPIO_ResetBits(GPIOF,GPIO_Pin_5);
				GPIO_SetBits(GPIOF,GPIO_Pin_3|GPIO_Pin_4);break;//011
			}
			case 13:
			{
				GPIO_ResetBits(GPIOF,GPIO_Pin_3|GPIO_Pin_4);
				GPIO_SetBits(GPIOF,GPIO_Pin_5);break;//100
			}
			case 14:
			{
				GPIO_ResetBits(GPIOF,GPIO_Pin_4);
				GPIO_SetBits(GPIOF,GPIO_Pin_5|GPIO_Pin_3);break;//101
			}
			case 15: 
			{
				GPIO_ResetBits(GPIOF,GPIO_Pin_3);
				GPIO_SetBits(GPIOF,GPIO_Pin_4|GPIO_Pin_5);break;//110
			}
			case 16:
			{
				GPIO_SetBits(GPIOF,GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5);break;//111
			}
		}
		
	}
	
}
	

3.主函数main.c:

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "MatrixButton.h"
#include "lcd.h"
extern u16 KeyValue;
int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);		//设置系统中断优先级分组2
	delay_init(168);   								    //初始化延时函数
	uart_init(115200);									//初始化串口波特率为115200
	LED_Init();											//初始化LED 
	GPIOF_Int_Init();
	LED0=0;
	LCD_Init();         								//初始化LCD接口
	GPIOB_Int_Init();									//初始化矩阵键盘所连接IO口
	LCD_Display_Dir(1);							    	//横屏显示	
	POINT_COLOR=RED; 
	
	while(1)
	{
		if(KeyValue!=KeyValue)//按键值改变时才清屏
			LCD_Clear(WHITE);
		LCD_ShowString(30,150,200,16,16,"KeyValue_is:"); //这里显示了KeyValue_is:
		KEY_Scan();		//行扫描矩阵按键
		LCD_ShowxNum(134,150,KeyValue,2,16,0); 
		Multiple_Control();			//矩阵按键控制IO口输出
		LED0=!LED0;
		delay_ms(50);
		
	}
}




STM32IO映射是指将GPIO复用为内置外设的功能引脚。每个GPIO都可以被配置为不同的功能,比如ADC、DAC、串、定时器等。当一个GPIO被配置为某个内置外设的功能引脚时,就称为复用。例如,当PA9和PA10被配置为串1时,它们就是复用为串功能的引脚。在配置IO映射时,需要进行一系列的设置,包括使能GPIO时钟、使能复用外设时钟、配置GPIO为复用功能,并将IO连接到所需的复用功能。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* [STM32学习笔记IO引脚复用和映射](https://blog.csdn.net/xiaolaoban0413/article/details/108367539)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [【STM32IO引脚复用器和映射原理与配置](https://blog.csdn.net/qq_44744164/article/details/106577986)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [STM32学习(正点原子23):IO引脚复用和映射](https://blog.csdn.net/zimengsss/article/details/120490597)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值