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

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)上拉电阻问题

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

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

       


http://www.kler.cn/a/599434.html

相关文章:

  • STM32学习笔记之常用外设接口(原理篇)
  • 8.BST的缺陷解决方案:平衡树*****
  • 什么是索引?为什么要使用B树作为索引数据结构?
  • 股指期权最后交易日是哪一天?
  • Flask(一)概述与快速入门
  • 蓝桥杯备考:学会使用方向向量
  • Pyserial库使用
  • HRP方法全文总结与模型流程解析
  • Flutter 输入组件 Radio 详解
  • Blender4.4正式发布:核心更新与渲染101云渲染平台应用指南
  • TCP/IP协议的三次握手和四次挥手
  • 《大语言模型赋能证券业开发安全:海云安技术方案在上交所专刊发表》
  • spring boot项目中Lombok注解失效问题
  • 初阶数据结构(C语言实现)——6.2选择排序详解(思路图解+代码实现)
  • 机器学习之回归
  • CES Asia 2025:科技企业出海的领航灯塔
  • Go常见问题与回答(上)
  • 大数据平台各组件功能与协同作用全解析
  • 【AndroidRTC-11】如何理解webrtc的Source、TrackSink
  • 100天精通Python(爬虫篇)——第122天:基于selenium接管已启动的浏览器(反反爬策略)