【蓝桥杯——物联网设计与开发】拓展模块1 - 矩阵键盘

目录

一、矩阵键盘

(1)资源介绍

       🔅原理图 

       🔅扫描原理

(2)STM32CubeMX 软件配置

(3)代码编写

(4)实验现象

二、矩阵键盘接口函数封装

三、踩坑日记

(1)上拉电阻问题


一、矩阵键盘

(1)资源介绍

       🔅原理图 

        蓝桥杯物联网竞赛实训平台提供了一个拓展接口 CN2,所有拓展模块均可直接安装在 Lora 终端上使用;

图1        拓展接口

        2×3 矩阵键盘模块电路原理图如下所示:

图2        矩阵键盘电路原理图

        通过两张电路图连接可知,引脚资源配置情况为:

表1 引脚资源配置情况
KeyboardMCU
COLUMN_1PB1
COLUMN_2PB0
COLUMN_3PA8
ROW_1PB6
ROW_2PB7

⚠️注意:PA8 引脚为 OLED 显示屏 I2C_SCL 信号,在同时使用 OLED 屏幕和 2×3 矩阵键盘模块时,在每次矩阵键盘扫描任务前、后,需要重置 PA8 到相应的工作模式和状态;或放弃使用 PA8 对应列(B3 按键、B6 按键),使用 2×3 矩阵键盘功能。

       🔅扫描原理

        1️⃣行扫描:将所有行线拉低(清 0),列线拉高(置 1)。当有按键触发时,对应列线拉低(清 0),即可得出此次按键触发所在列;

        2️⃣列扫描:与行扫描相反。列扫描则是将所有列线拉低(清 0),行线拉高(置 1)。当有按键触发时,对应行线拉低(清 0),即可得出此次按键触发所在行;

        本文将介绍列扫描方式使用矩阵键盘模块;

(2)STM32CubeMX 软件配置

🔅“工程建立、时钟树配置、Debug 串行线配置、代码生成配置” 在下文中有讲解,这里不再赘述❗️

【蓝桥杯——物联网设计与开发】基础模块1- GPIO输出icon-default.png?t=N7T8https://blog.csdn.net/m0_63116406/article/details/135604705?spm=1001.2014.3001.5502

1️⃣点击引脚 PB1 → 选择 GPIO_Output 模式;

图3        PB1 配置


2️⃣点击引脚 PB0 → 选择 GPIO_Output 模式;

图4        PB0 配置



3️⃣点击引脚 PB6 → 选择 GPIO_Input 模式;

图5        PB6 配置



4️⃣点击引脚 PB7 → 选择 GPIO_Input 模式;

图6        PB7 配置

5️⃣点击 "GPIO" → 点击引脚 PB7、PB7 → 分别将 "GPIO Pull-up/Pull-down" 栏修改为 "Pull-up",即将 PB7、PB7 引脚初始化为带上拉电阻

图7        输入模式配置

6️⃣初始化 OLED;(配置步骤在下文中有讲解,这里不再赘述)

【蓝桥杯——物联网设计与开发】基础模块6 - OLEDicon-default.png?t=N7T8https://blog.csdn.net/m0_63116406/article/details/136196071?spm=1001.2014.3001.5501

图8        OLED 初始化

7️⃣生成代码即可;

(3)代码编写

🟢️main 函数

/* USER CODE BEGIN Includes */
#include "oled.h"
#include <stdio.h>
/* USER CODE END Includes */

/* USER CODE BEGIN PV */
uint8_t puc_oled[17];
/* USER CODE END PV */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
	uint8_t key_down, key_tmp;	// 按键下降沿、按键当前值
	static uint8_t key_old = 0;	// 按键上一次值
  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_I2C3_Init();
  /* USER CODE BEGIN 2 */
	OLED_Init();	// 初始化 OLED
	OLED_Clear();	// OLED 清屏
	
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET);	// 拉高 PB1
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);	// 拉高 PB0
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
		/* 按键检测 */
		key_tmp = 0;	// 当前值清零
		// 第一列扫描
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
		if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6) == 0)
			key_tmp = '1';
		if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7) == 0)
			key_tmp = '4';
		// 第二列扫描
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET);
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
		if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6) == 0)
			key_tmp = '2';
		if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7) == 0)
			key_tmp = '5';
		// 三行代码
		key_down = key_tmp & (key_tmp ^ key_old);
		key_old = key_tmp;
		// 下降沿逻辑处理
		if(key_down)
		{
			sprintf((char *)puc_oled, "KeyValue: %c", key_down);
			OLED_ShowString(0, 0, puc_oled, 16);
		}
		HAL_Delay(10);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

(4)实验现象

        按下前两列按键,OLED 显示屏会显示对应的键值;

图9        实验现象

二、矩阵键盘接口函数封装

🟡️按键扫描函数

uint8_t key_read(void)
{
	uint8_t key_value = 0;
	// 第一列扫描
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
	if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6) == 0)
		key_value = '1';
	if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7) == 0)
		key_value = '4';
	// 第二列扫描
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
	if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6) == 0)
		key_value = '2';
	if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7) == 0)
		key_value = '5';
	return key_value;
}

🔴矩阵键盘接口函数调用实例

void task_keys(void)
{
	uint8_t key_down, key_tmp;
	static uint8_t key_old = 0;
	// 10ms 调用一次
	if(cnt_10ms < 10)	return;
	cnt_10ms = 0;
	// 三行代码
	key_tmp = key_read();
	key_down = key_tmp & (key_tmp ^ key_old);
	key_old = key_tmp;
	// 下降沿逻辑处理
	if(key_down)
	{
		OLED_Clear();
		sprintf((char *)puc_oled, "KeyValue:%c", key_down);
		OLED_ShowString(0, 0, puc_oled, 16);
	}
}

三、踩坑日记

(1)上拉电阻问题

  • 列扫描时,对应的引脚需配置为带上拉电阻的输入模式
  • 行扫描时,对应的引脚需配置为带上拉电阻的输入模式

        🔅如果不带有上拉电阻,则在按键未按下的时候,输入引脚的电平处于不确定的状态,导致读入数据不稳定;而带有上拉电阻,可将引脚电平钳制为高电平,在按键按下时才变化为低电平;

### 关于2025年蓝桥杯竞赛中单片机矩阵键盘的原理 对于2025年的蓝桥杯竞赛而言,虽然具体的比赛题目尚未公布,但从以往的比赛内容可以推测出有关单片机矩阵键盘设计原则不会发生根本性的变化。 #### 矩阵键盘的工作机制 矩阵键盘设计的核心在于节约I/O资源的同时支持多按键操作。具体来说,在一个典型的4×4矩阵键盘布局里,共有16个独立按键被安排在一个行列交叉结构之中[^2]。每一行和列分别连接到微控制器的不同引脚上。当某个特定位置上的按钮被按下时,对应的行列之间形成导通路径,使得原本处于不同逻辑状态下的电平发生变化,进而触发相应的中断或者改变输入端口的状态来识别按下了哪个键[^3]。 #### 扫描方法 为了有效地监测是否有任意一个按键被激活,采用逐行扫描的方式是最常见也是最有效的方法之一。例如,假设当前正在测试第R2行,则会将其设置为低电平输出模式;此同时监听所有列线上的电压情况。一旦发现某一根列线上出现了预期之外的变化(即由原来的高变为了低),就可以断定位于这一交点处的开关正处于闭合状态。 #### 实际电路构建建议 尽管无法提供确切针对2025年度赛事的具体图纸,但可以根据上述描述绘制类似的简化版原理图: ```plaintext +---+---+---+ | C1| C2| C3| +---+---+---+ |R1 | | | +---+---+---+ |R2 | * | | <- 当前正扫描此行并检测到了C3变为低电平时表示*号键被按下 +---+---+---+ |R3 | | | +---+---+---+ |R4 | | | +---+---+---+ 注:'*' 表示实际存在的按键, 'Rn/Cm'代表行/列编号. ``` 在此基础上,参赛者还需要考虑如何处理防抖动措施以及区分单次点击还是连续快速两次点击等问题以完善整个系统的功能特性[^1]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

逝灮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值