当前位置: 首页 > news >正文

Extend module 01:Keyboard

目录

一、Keyboard

(1)资源介绍

        🔅原理图

        🔅扫描原理

(2)STM32CubeMX 软件配置

(3)代码编写

(4)实验现象

二、Keyboard接口函数封装

三、踩坑日记

(1)上拉电阻问题


一、Keyboard

(1)资源介绍

        🔅原理图

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

图1        拓展接口

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

图2        Keyboard电路原理图

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

表1 引脚资源配置情况
KeyboardMCU
COLUMN_1PB3
COLUMN_2PA15
COLUMN_3PA0
ROW_1PA12
ROW_2PA11
        🔅扫描原理

        1️⃣行扫描:所有行线作为输入端口,列线作为输出端口。逐个拉低列线输出,检测对应行是否读到低电平,若有即可确定按键触发位置;

        2️⃣列扫描:与行扫描相反。所有列线作为输入端口,行线作为输出端口。逐个拉低行线输出,检测对应列是否读到低电平,从而确定按键触发位置;

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

(2)STM32CubeMX 软件配置


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

【蓝桥杯——物联网设计与开发】Part1:GPIOhttps://blog.csdn.net/m0_63116406/article/details/144894900?spm=1001.2014.3001.55011️⃣点击引脚 PA12 PA11 → 选择 GPIO_Input 模式;

2️⃣点击"System Core""GPIO", 将 PA12 PA11 "GPIO Pull-up/Pull-down" 栏修改为 "Pull-up" ,即将 PA12 PA11 引脚初始化为带上拉电阻的输入引脚;

图3        输入引脚配置

3️⃣点击引脚 PA0 、 PA15  PB3 → 选择 GPIO_Output 模式;

4️⃣点击"System Core""GPIO", 将 PA0 、 PA15  PB3 "GPIO output level" 栏修改为 "High",即将 PA0 、 PA15  PB3 引脚初始化为高电平

图4        输出引脚配置

5️⃣配置 OLED

6️⃣生成代码即可;

(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_val = 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_I2C1_Init();
  /* USER CODE BEGIN 2 */
	OLED_Init();
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  key_val = ' ';
	  /* 按键扫描 */
	  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET);	//	第一列
	  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_SET);
	  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);
	  if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_12) == 0)
	  {
		  HAL_Delay(10);	// 延时消抖
		  if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_12) == 0)
		  {
			  key_val = '1';
			  while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_12) == 0);	//	抬手检测
		  }
	  }
	  if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_11) == 0)
	  {
		  HAL_Delay(10);	// 延时消抖
		  if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_11) == 0)
		  {
			  key_val = '4';
			  while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_11) == 0);	//	抬手检测
		  }
	  }
	  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_SET);	
	  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_RESET);	//	第二列
	  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);
	  if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_12) == 0)
	  {
		  HAL_Delay(10);	// 延时消抖
		  if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_12) == 0)
		  {
			  key_val = '2';
			  while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_12) == 0);	//	抬手检测
		  }
	  }
	  if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_11) == 0)
	  {
		  HAL_Delay(10);	// 延时消抖
		  if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_11) == 0)
		  {
			  key_val = '5';
			  while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_11) == 0);	//	抬手检测
		  }
	  }
	  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_SET);	
	  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_SET);	
	  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);	//	第三列
	  if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_12) == 0)
	  {
		  HAL_Delay(10);	// 延时消抖
		  if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_12) == 0)
		  {
			  key_val = '3';
			  while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_12) == 0);	//	抬手检测
		  }
	  }
	  if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_11) == 0)
	  {
		  HAL_Delay(10);	// 延时消抖
		  if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_11) == 0)
		  {
			  key_val = '6';
			  while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_11) == 0);	//	抬手检测
		  }
	  }
	  /* 键值显示 */
	  sprintf((char*)puc_oled, "  Key value:%c   ", key_val);
	  OLED_ShowString(0, 0, puc_oled, 16);
    /* USER CODE END WHILE */

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

(4)实验现象

        按下按键后,OLED 屏幕上会显示对应键值。


二、Keyboard接口函数封装

🟡️Keyboard扫描函数

uint8_t key_read(void)
{
	uint8_t key_val = 0;
	/* 按键扫描 */
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET);	//	第一列
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);
	if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_12) == 0)
		key_val = '1';
	else if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_11) == 0)
		key_val = '4';
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_SET);	
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_RESET);	//	第二列
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);
	if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_12) == 0)
		key_val = '2';
	else if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_11) == 0)
		key_val = '5';
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_SET);	
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_SET);	
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);	//	第三列
	if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_12) == 0)
		key_val = '3';
	else if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_11) == 0)
		key_val = '6';
	return key_val;
}

🔴Keyboard接口函数调用实例

/* 按键处理任务函数 */
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, "  Key value:%c   ", key_down);
		OLED_ShowString(0, 0, puc_oled, 16);
	}
}

三、踩坑日记

(1)上拉电阻问题

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

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

       

相关文章:

  • 具身系列——NLP工程师切入机器人和具身智能方向
  • LabVIEW液压振动锤控制系统
  • 清华大学.智灵动力-《DeepSeek行业应用实践报告》附PPT下载方法
  • 查询操作是否需要使用事务?
  • 软件测试面试:支付功能如何测试?
  • 基于Python的机器学习入门指南
  • 【Pandas】pandas Series plot.line
  • TCP netstat TIME_WAIT CLOSE_WAIT
  • 利用dify打造命令行助手
  • 基于SpringBoot + Vue 的垃圾分类管理系统
  • Qt信号与槽机制入门详解:从基础语法到界面交互实战
  • 测试用例组成及设计方法
  • Zotero·Awesome GPT配置
  • 基于CentOS系统搭建Samba服务
  • 提高库存周转率的重要性
  • 风格混合增强的解纠缠学习在医学图像分割的无监督域自适应中的应用|文献速递-医学影像人工智能进展
  • 【USTC 计算机网络】第三章:传输层 - 可靠数据传输的原理
  • MAC terminal
  • 2025-3-23 leetcode刷题情况(动态规划)
  • 不能解析域名怎么回事?
  • 空间站第八批科学实验样品返抵地球并交付科学家
  • 韩国检方结束对尹锡悦私宅的扣押搜查
  • 迪卡侬回应出售中国业务30%股份传闻:始终扎根中国长期发展
  • 视频丨中国海警位中国黄岩岛领海及周边区域执法巡查
  • 人社部:将制定提前领取个人养老金相关办法
  • “不意外”和“不遗余力”,直击上海商超对接外贸企业