STM32--矩阵键盘的设计实现

关于STM32的矩阵键盘实现

项目开发或者日常实验中有时候需要用到多个按键,但单片机IO口资源本身并不多,如果为每一个按键都分配一个IO的话未免太过浪费,所以使用矩阵键盘可以尽可能的节省单片机IO口资源。

开发准备:

1.系统:Windows
2.软件:Keil5
3.单片机:STM32F103C8T6

矩阵键盘与普通的一个IO对应一个按键的普通键盘不同。如图所示,16个按键通过图中的电路连接,构成了行和列,而只仅仅引出了8条线路,所以只需要8个IO口就能识别16个按键。与之类似的还有4x2矩阵键盘、3x3矩阵键盘等。4x4矩阵键盘电路图
扫描矩阵键盘的键值可以使用逐行(列)扫描法。在STM32中,4个行IO设置为上拉输入,4个列IO设置为推挽输出低电平。当其中一个按键按下时,该按键对应的行IO口会被置为低电平,这时,将4个列IO逐个拉高,每拉高一个的同时检测行IO的电平,如果行IO的电平随着变化的话,就能确定哪个按键按下。当然,设置列IO为输入,或者下拉也是可以的,原理同上。

实验里使用2x4的矩阵键盘检测(原理一样,只是少了两行扫描而已)。

/*****GPIO口配置*****/
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOB_CLK_ENABLE();

  /*Configure GPIO pins : Rowline1_Pin Rowline2_Pin */		
  GPIO_InitStruct.Pin = Rowline1_Pin|Rowline2_Pin;	//行IO下拉输入
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_PULLDOWN;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /*Configure GPIO pins : Column1_Pin Column2_Pin Column3_Pin Column4_Pin */
  GPIO_InitStruct.Pin = Column1_Pin|Column2_Pin|Column3_Pin|Column4_Pin;//列IO推挽输出,无上下拉
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOB, Column1_Pin|Column2_Pin|Column3_Pin|Column4_Pin, GPIO_PIN_SET);
}
/*********列IO操作宏定义*********/
#define Column1_OUT_Low  HAL_GPIO_WritePin(Column1_GPIO_Port, Column1_Pin, GPIO_PIN_RESET)
#define Column2_OUT_Low  HAL_GPIO_WritePin(Column2_GPIO_Port, Column2_Pin, GPIO_PIN_RESET)
#define Column3_OUT_Low  HAL_GPIO_WritePin(Column3_GPIO_Port, Column3_Pin, GPIO_PIN_RESET)
#define Column4_OUT_Low  HAL_GPIO_WritePin(Column4_GPIO_Port, Column4_Pin, GPIO_PIN_RESET)

#define Column1_OUT_High  HAL_GPIO_WritePin(Column1_GPIO_Port, Column1_Pin, GPIO_PIN_SET)
#define Column2_OUT_High  HAL_GPIO_WritePin(Column2_GPIO_Port, Column2_Pin, GPIO_PIN_SET)
#define Column3_OUT_High  HAL_GPIO_WritePin(Column3_GPIO_Port, Column3_Pin, GPIO_PIN_SET)
#define Column4_OUT_High  HAL_GPIO_WritePin(Column4_GPIO_Port, Column4_Pin, GPIO_PIN_SET)

/*********行IO操作宏定义*********/
#define Rowline1_INPUT_Read  HAL_GPIO_ReadPin(Rowline1_GPIO_Port, Rowline1_Pin)
#define Rowline2_INPUT_Read  HAL_GPIO_ReadPin(Rowline2_GPIO_Port, Rowline2_Pin)



uint8_t key_scan(void){
	uint8_t i, keynum = 0;
	if (Rowline1_INPUT_Read == GPIO_PIN_SET){			//当有按键按下		
		for (i = 1; i <= 4; i++){
			if (i == 1) Column1_OUT_Low;		//逐个拉低每列的IO
			else if (i == 2) Column2_OUT_Low;
			else if (i == 3) Column3_OUT_Low;
			else if (i == 4) Column4_OUT_Low;
			if (Rowline1_INPUT_Read == GPIO_PIN_RESET){	//如果检测到行IO电平跟着变化,则判断为该按键按下			
				keynum = i;							
				if (i == 1) Column1_OUT_High;
				else if (i == 2) Column2_OUT_High;
				else if (i == 3) Column3_OUT_High;	//每次列IO电平操作之后记得复原
				else if (i == 4) Column4_OUT_High;
				break;				
			}
		}
	}else if (Rowline2_INPUT_Read == GPIO_PIN_SET){
		for (i = 1; i <= 4; i++){
			if (i == 1) Column1_OUT_Low;
			else if (i == 2) Column2_OUT_Low;
			else if (i == 3) Column3_OUT_Low;
			else if (i == 4) Column4_OUT_Low;
			if (Rowline2_INPUT_Read == GPIO_PIN_RESET){				
				KeyValue.keynum = i+4;			
				if (i == 1) Column1_OUT_High;
				else if (i == 2) Column2_OUT_High;
				else if (i == 3) Column3_OUT_High;
				else if (i == 4) Column4_OUT_High;
				break;
			}			
		}
	}
	return keynum;
}

上述代码可以检测到哪个按键按下,但在实际项目开发途中,按下以及松开都需要进行一系列的消抖操作来判断到底是真的按下跟真的松开。关于这个问题,下文STM32–按键抖动问题的探讨会详细的描述。

  • 2
    点赞
  • 2
    评论
  • 21
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 游动-白 设计师:白松林 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值