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;
相关推荐
羽获飞4 分钟前
51单片机UART-串口通讯的配置方法
stm32·单片机·嵌入式硬件
猫猫的小茶馆7 分钟前
【Linux 驱动开发】一. 搭建开发环境
linux·汇编·arm开发·驱动开发·stm32·嵌入式硬件·mcu
猫猫的小茶馆29 分钟前
【Linux 驱动开发】嵌入式 Linux 开发概念
linux·服务器·arm开发·stm32·单片机·嵌入式硬件·mcu
兆龙电子单片机设计42 分钟前
【STM32项目开源】STM32单片机智能宠物喂养系统
stm32·单片机·开源·毕业设计·电子信息
Y1rong43 分钟前
STM32之串口(三)
stm32·单片机·嵌入式硬件
Y1rong1 小时前
STM32之串口(二)
stm32·单片机·嵌入式硬件
Y1rong1 小时前
STM32之串口(一)
网络·stm32·嵌入式硬件
旭意1 小时前
数据结构-红黑树和set
数据结构·c++·算法·蓝桥杯
想睡觉的树1 小时前
解决keil5编译慢的问题-亲测有效-飞一般的感觉
c语言·stm32·嵌入式硬件
__万波__1 小时前
STM32L475串口打印改为阻塞式打印兼DMA, 两种打印方式实时切换
stm32·单片机·嵌入式硬件