stm32 蓝桥杯 物联网 独立键盘的使用

在蓝桥杯物联网平台里面,有5个外接设备,其中有一个就是6个独立按键。首先,我们先看一下按键有关的电路图。

电路图与cubemx设定

由图可见,独立键盘组由两行三列构成,我们通过行列来锁定要访问的独立按键在哪。ROW1挂载在CN1的2上,对应PA12,其他的几条线也是如此。

先通过stm32 cubemx来初始化io口,因为按下去对应的是down,因此我们默认输入口为pull-up。在这里我们选择扫描两次,每次扫描三个按键。因此我们设定两个ROW为输出口,COL1~COL3为输入口。

task.h设定

首先,因为我们要使用原先按键的三段式防抖结构,因此我们需要定义好各个按键的的属性。因为该开发板是模块化设计,除了6个独立按键外还可能会使用其他的模块(温度等),因此我们需要进行一次区分,如果是使用独立按键,我们就define Using_BTN,如果不是用这个,就注释掉即可。屏幕的状态也需进行改变,增加了一个State_Key用于显示我们按下独立按键后的变化。

复制代码
#define KB1 0x11
#define KB2 0x12
#define KB3 0x13
#define KB4 0x14
#define KB5 0x15
#define KB6 0x16
#define Using_BTN
void Oled_Proc();
void Key_Proc();
extern uint16_t Time_Num; 
typedef enum      //oled屏幕的状态(状态机
{
	State_Main = 0,
	State_Time_Num,
	State_Key            //新了一个key的状态
}interface;

task.c设定

初始化函数的编写

前文说过,我们用Using_BTN来判断是否有用到独立按键,如果用到独立按键,那就初始化独立按键相关的GPIO属性,如果没有,那就不初始化。这些初始化的代码直接从GPIO初始化代码中剪贴即可。

复制代码
void BSP_Init()
{
	OLED_Init();
	#ifdef Using_BTN				//若有使用独立键盘,则初始化独立键盘相关gpio
	  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
	  /*Configure GPIO pin : COL1_Pin */
	HAL_GPIO_WritePin(GPIOA, ROW2_Pin|ROW1_Pin, GPIO_PIN_RESET);
  GPIO_InitStruct.Pin = COL1_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  HAL_GPIO_Init(COL1_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pins : COL3_Pin COL2_Pin */
  GPIO_InitStruct.Pin = COL3_Pin|COL2_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
	
	/*Configure GPIO pins : ROW2_Pin ROW1_Pin */
  GPIO_InitStruct.Pin = ROW2_Pin|ROW1_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
	
	#endif 

}

按键处理函数的改动

按键处理函数的改动主要在于对独立按键的判断,并且因为题目需求额外定义了一个Key_Num用于储存要在第三显示屏上显示的数据。

重头戏也就是按键扫描功能。当确定有用了独立按键组,则开始独立按键的扫描。因为我设定的是每周期扫描两组,每组扫描三个,因此用到了两个if逻辑。先判断ROW1,当到这行以后再去判断对应的每一列。ROW2也是如此。当某个按键被按下(某个地方的gpio为RESET)时,就把Key_Value值更改为之前对应的KB系列定义即可。

接着就是经典三段防抖,然后是判断哪个按键被按下了,显示数值修改为想要值即可。

复制代码
uint16_t Key_Num;

void Key_Proc()
{
		if(task_time.Key_Time < Key_Min_Time)	return;						//判断是否到key_proc的刷新时间
		task_time.Key_Time = 0;
		uint16_t Key_Value;
		if(HAL_GPIO_ReadPin(ASW1_GPIO_Port,ASW1_Pin) == GPIO_PIN_RESET)      //判断按下的是不是asw1,如果是,就赋值,如果不是甚至没按,就为0
		{
			Key_Value = Asw_1;
		}
		else   
		{
			Key_Value = Asw_None;
		}
		
		#ifdef Using_BTN			//如果使用了独立键盘,就开启独立键盘扫描功能
		if(Key_Value == Asw_None)
		{
			HAL_GPIO_WritePin(ROW1_GPIO_Port,ROW2_Pin,GPIO_PIN_SET);
			HAL_GPIO_WritePin(ROW2_GPIO_Port,ROW1_Pin,GPIO_PIN_RESET);
		
			if(HAL_GPIO_ReadPin(COL1_GPIO_Port,COL1_Pin) == GPIO_PIN_RESET) Key_Value = KB1;
			else if(HAL_GPIO_ReadPin(COL2_GPIO_Port,COL2_Pin) == GPIO_PIN_RESET) Key_Value = KB2;
			else if(HAL_GPIO_ReadPin(COL3_GPIO_Port,COL3_Pin) == GPIO_PIN_RESET) Key_Value = KB3;		
			else Key_Value = Asw_None;
		}
		
		if(Key_Value == Asw_None)
		{
			HAL_GPIO_WritePin(ROW2_GPIO_Port,ROW1_Pin,GPIO_PIN_SET);
			HAL_GPIO_WritePin(ROW1_GPIO_Port,ROW2_Pin,GPIO_PIN_RESET);
		
			if(HAL_GPIO_ReadPin(COL1_GPIO_Port,COL1_Pin) == GPIO_PIN_RESET) Key_Value = KB4;
			else if(HAL_GPIO_ReadPin(COL2_GPIO_Port,COL2_Pin) == GPIO_PIN_RESET) Key_Value = KB5;
			else if(HAL_GPIO_ReadPin(COL3_GPIO_Port,COL3_Pin) == GPIO_PIN_RESET) Key_Value = KB6;		
			else Key_Value = Asw_None;
		}
		#endif
		
		Key.Key_Up = Key_Value &(Key_Value ^ Key.Key_Old);					//三段经典消除按键抖动
		Key.Key_Down = ~Key_Value &(Key_Value ^ Key.Key_Old);	
		Key.Key_Old = Key_Value;
	
	if(Key.Key_Down == Asw_1)																		//确定按下了,就开始切换工作
	{
		if(state == State_Main) state = State_Time_Num;
		else if(state == State_Time_Num)state = State_Key;
		else state = State_Main;
		Key.Key_Down = Asw_None;																		//复位key_down
	}

	if(Key.Key_Down == KB1)//请务必用if,别一串的else if
	{
		Key_Num = 1;
	}
	
	if(Key.Key_Down == KB2)
	{
		Key_Num = 2;
	}
	if(Key.Key_Down == KB3)
	{
	Key_Num = 3;
	}
	if(Key.Key_Down == KB4)
	{
		Key_Num = 4;
	}
	if(Key.Key_Down == KB5)
	{
	Key_Num = 5;
	}
	if(Key.Key_Down == KB6)
	{
		Key_Num = 6;
	}
	
}

OLED显示函数

OLED就没啥好说了,就在switch里多加个键盘的case就行。

复制代码
case State_Key:

				if(state!=old_state)
				{
					old_state = state;
					OLED_Clear();
				}
				sprintf((char*)Oled_buf_line1,"Key:%03d",Key_Num);
				break;
相关推荐
梁山1号5 小时前
【ESP32】3.串口的发送与接受
单片机·物联网
星辰pid9 小时前
STM32实现四自由度机械臂(SG90舵机)多功能控制(软件篇freertos)
stm32·单片机·嵌入式硬件·机械臂
小殷学长16 小时前
【单片机毕业设计17-基于stm32c8t6的智能倒车监测系统】
stm32·单片机·课程设计
TESmart碲视18 小时前
HKS201-M24 大师版 8K60Hz USB 3.0 适用于 2 台 PC 1台显示器 无缝切换 KVM 切换器
单片机·嵌入式硬件·物联网·游戏·计算机外设·电脑·智能硬件
花落已飘19 小时前
STM32中实现shell控制台(shell窗口输入实现)
stm32·单片机·嵌入式硬件
花落已飘19 小时前
STM32中实现shell控制台(命令解析实现)
stm32·shell
没有钱的钱仔19 小时前
STM32低功耗模式全面指南
css·stm32·css3
TDengine (老段)20 小时前
TDengine STMT2 API 使用指南
java·大数据·物联网·时序数据库·iot·tdengine·涛思数据
牵牛老人21 小时前
Qt处理USB摄像头开发说明与QtMultimedia与V4L2融合应用
stm32·单片机·qt
和风化雨1 天前
stm32的三种开发方式
stm32·单片机·嵌入式硬件