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

发布于:2025-03-14 ⋅ 阅读:(20) ⋅ 点赞:(0)

在蓝桥杯物联网平台里面,有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;