在线客服:
亚博电子竞技 亚博电子竞技
全国服务热线:010-93914935
您的位置:首页 > 新闻中心 >

STM32操作矩阵键盘扫描和中断的两种方法

浏览 157次 来源:【jake推荐】 作者:-=Jake=-    时间:2021-02-15 02:25:25
[摘要] 最近在准备电赛,有一道题要求设计一个简易的信号发生器,需要用到矩阵键盘来输入待生成信号的类型、频率和幅值等参数,【代码链接请戳这里】因此写下本文来总结我试验过的单片机操作矩阵键盘的两种方法。二、扫描式矩阵键盘的原理和实现三、中断式矩阵键盘的原理和实现

内容

最近为电子竞赛做准备,存在一个问题,需要设计一个简单的信号发生器。您需要使用矩阵键盘输入要生成的信号的类型,频率和幅度。 [代码链接足球外围 ,请单击此处]。写以下文章总结了我尝试过的两种单片机操作矩阵键盘的方法。

一、矩阵键盘的结构和原理

实际的矩阵键盘可能看起来像这样:

键盘记录器 西宇软件_32 矩阵键盘_32 矩阵键盘

在这里插入图片描述

它也可能像这样:

在这里插入图片描述

32 矩阵键盘_32 矩阵键盘_键盘记录器 西宇软件

无论外观如何,它们的内部结构都相似:

在这里插入图片描述

每个矩阵键盘具有8个信号端口,其中四个连接到行,其余四个连接到列。当按下某个按钮时,相应的行和列端口将被该按钮短路。如何使用此功能让STM32确定按下了哪个按钮?作者总结了以下两种常用方法。

32 矩阵键盘_键盘记录器 西宇软件_32 矩阵键盘

二、扫描矩阵键盘的原理和实现

首先,请明确将STM32 GPIO配置为开漏输出+上拉电阻时,具有准双向IO的功能。

使用扫描方法判断键盘按下的基本思想是:首先将所有行设置为低,将所有列设置为高32 矩阵键盘,读取每一行的级别,然后将最高的行设置为被按下的行;设置为低凤凰体育 ,将所有行设置为高,读取每一列的级别,高的为下一列。代码如下:

32 矩阵键盘_键盘记录器 西宇软件_32 矩阵键盘

三、中断矩阵键盘的原理和实现

类似地,首先要阐明GPIO的配置。在中断模式下,四行应配置为推挽输出,四列应配置为输入+上拉电阻+下降沿中断模式。当然,行和列的交换也是可能的。

中断矩阵键盘的基本思想是在初始化期间将四行拉低。当按下一个键时,该列的相应端口将检测到下降沿,程序将进入该列的中断服务功能。在服务功能中,将四行拉高,然后依次向下拉每行。同时,检查列的端口是否为低。如果为低亚博直播 ,则表明已按下行和列。代码如下:

32 矩阵键盘_键盘记录器 西宇软件_32 矩阵键盘

//矩阵键盘端口初始化 
//PF1~4接列 PF5~8接行
void MatrixKEY_Init(void)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);//使能GPIOF时钟
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//通用输出模式
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100M
  GPIO_Init(GPIOF, &GPIO_InitStructure);//初始化GPIOF5678
	GPIO_ResetBits(GPIOF,GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8);//初始化输出置低
	 
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//普通输入模式
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100M
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;//上拉
  GPIO_Init(GPIOF, &GPIO_InitStructure);//初始化GPIOF1234
	
}
*/
//第一行
void EXTI1_IRQHandler(void){
		 u8 i;
	  delay_ms(50);
	
	 if(PFin(1)==0){/第一行
		 EXTIX1_4_disable();//关闭矩阵键盘的中断
			for(i=5;i<9;i++){
			GPIO_SetBits(GPIOF,GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8);//置为高电平
			PFout(i)=0;
				delay_ms(50);
				if(PFin(1)==0){
      switch(i){
					case(5):
						num=1;
						break;
					case(6): 
					  num=2;
					  break;
					case(7): 
						num=3;
						break;
					case(8):
						num=12;
						break;
				default:num=16;
				} }				
			}
	GPIO_ResetBits(GPIOF,GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8);//置为低电平
	EXTIX1_4_enable();
		}
	EXTI_ClearITPendingBit(EXTI_Line1);//清除中断标志位*/
	
}
void EXTI2_IRQHandler(void){
			 u8 i;
	  delay_ms(50);
	
	if(PFin(2)==0){/第二行
		EXTIX1_4_disable();//关闭矩阵键盘的中断
			for(i=5;i<9;i++)
		{
			GPIO_SetBits(GPIOF,GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8);//置为高电平
			PFout(i)=0;
			delay_ms(50);
			if(PFin(2)==0){
				switch(i){
					case(5):
						num=4;
						break;
					case(6):
						num=5;
						break;
					case(7):
						num=6;
						break;
					case(8):
						num=13;
						break;
					default:num=16;
				}}
			}
	GPIO_ResetBits(GPIOF,GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8);//置为低电平
	EXTIX1_4_enable();
		}
	
	EXTI_ClearITPendingBit(EXTI_Line2);//清除中断标志位*/
	
}
void EXTI3_IRQHandler(void){
	  u8 i;
	  delay_ms(50);
  if(PFin(3)==0){第三行
	EXTIX1_4_disable();//关闭矩阵键盘的中断
			for(i=5;i<9;i++)
		{
			
			GPIO_SetBits(GPIOF,GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8);//置为高电平
			PFout(i)=0;
			delay_ms(50);
			if(PFin(3)==0){
				switch(i){
					case(5):
						num=7;
						break;
					case(6): 
						num=8;
					  break;
					case(7): 
						num=9;
						break;
					case(8):
						num=14;
						break;
					default: num=16;
				}}
			}
	GPIO_ResetBits(GPIOF,GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8);//置为低电平
	EXTIX1_4_enable();
		}
	
	EXTI_ClearITPendingBit(EXTI_Line3);//清除中断标志位*/
}
void EXTI4_IRQHandler(void){
			 u8 i;
	  delay_ms(50);
	
	if(PFin(4)==0){第四列
			EXTIX1_4_disable();//关闭矩阵键盘的中断
	  for(i=5;i<9;i++)
		{
			GPIO_SetBits(GPIOF,GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8);//置为高电平
			PFout(i)=0;
			delay_ms(50);
			if(PFin(4)==0){
				switch(i){
					case(5):
							num=10;	
						break;
					case(6):
							num=0;	
						break;
					case(7): 
						num=11;
						break;
					case(8): 
						num=15;
						break;
					default:num=16;
				}}
			}
	GPIO_ResetBits(GPIOF,GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8);//置为低电平
	EXTIX1_4_enable();
		}
	
	EXTI_ClearITPendingBit(EXTI_Line4);//清除中断标志位*/
	
}
//中断优先级配置
void NVICx_Init(void)
{
	NVIC_InitTypeDef   NVIC_InitStructure;
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
	
	NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;//外部中断1
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//抢占优先级2
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;//子优先级2
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//中断通道使能
	NVIC_Init(&NVIC_InitStructure);
	
	NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;//外部中断2
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//抢占优先级2
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//子优先级2
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//中断通道使能
	NVIC_Init(&NVIC_InitStructure);
	
	NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;//外部中断3
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//抢占优先级2
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;//子优先级2
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//中断通道使能
	NVIC_Init(&NVIC_InitStructure);
	
	NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;//外部中断4
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//抢占优先级2
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;//子优先级2
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//中断通道使能
	NVIC_Init(&NVIC_InitStructure);
	
}
//外部中断初始化程序
//初始化PF1~4为中断输入.
void EXTIX_Init(void)
{
	
	EXTI_InitTypeDef   EXTI_InitStructure;
	
	NVICx_Init();
	
	MatrixKEY_Init(); //按键对应的IO口初始化
 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);//使能SYSCFG时钟
	
 
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOF, EXTI_PinSource1);//PF1 连接到中断线1
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOF, EXTI_PinSource2);//PF2 连接到中断线2
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOF, EXTI_PinSource3);//PF3 连接到中断线3
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOF, EXTI_PinSource4);//PF4 连接到中断线4
	
	/* 配置EXTI_Line1,2,3,4 */
	EXTI_InitStructure.EXTI_Line = EXTI_Line1 | EXTI_Line2 | EXTI_Line3 | EXTI_Line4;
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断事件
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;//中断线使能
  EXTI_Init(&EXTI_InitStructure);//配置
}
//关闭外部中断pF1~4
void EXTIX1_4_disable(void)
{
	EXTI_InitTypeDef   EXTI_InitStructure;
	
	/* 配置EXTI_Line1,2,3,4 */
	EXTI_InitStructure.EXTI_Line = EXTI_Line1 | EXTI_Line2 | EXTI_Line3 | EXTI_Line4;
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断事件
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发
  EXTI_InitStructure.EXTI_LineCmd = DISABLE;//中断线失能
  EXTI_Init(&EXTI_InitStructure);//配置
	
}
//开启外部中断pb1~4
void EXTIX1_4_enable(void)
{
	EXTI_InitTypeDef   EXTI_InitStructure;
	
	/* 配置EXTI_Line1,2,3,4 */
	EXTI_InitStructure.EXTI_Line = EXTI_Line1 | EXTI_Line2 | EXTI_Line3 | EXTI_Line4;
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断事件
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;//中断线使能
  EXTI_Init(&EXTI_InitStructure);//配置
}

四、两种方案的优缺点

扫描方法占用的资源较少,但是随着工程复杂度的增加,密钥变得非常不敏感;

中断方法占用了相当多的资源(四个中断行)亚博网页版 ,但是当工程复杂度增加时32 矩阵键盘,它可以很好地保持键的敏感性。

老王
本文标签:矩阵,stm32,矩阵键盘

推荐阅读

最新评论