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;
相关推荐
辰哥单片机设计14 分钟前
MP3播放器模块(STM32)
stm32·单片机·嵌入式硬件
Zw-awa1 小时前
传感器模块都在交出什么:从模拟电压到数字协议
stm32
悟天特斯1 小时前
AI节能的“精准之道“:从粗放省电到分区分时的精细化调控
人工智能·物联网
Brilliantwxx1 小时前
【STM32】 工程实战 WS2812B 全彩 LED 灯控制(DMA 驱动)
stm32·单片机·嵌入式硬件·mcu
做萤石二次开发的哈哈1 小时前
带摄像头的号角怎么对接?从音视频对讲链路到音频参数配置的实施要点
物联网·音视频·语音对讲·萤石开放平台·蓝海aiot一站式工作台·语音喊话·园区广播
会周易的程序员2 小时前
STVM OSAL 层设计方案
物联网·iot·软plc·iec61131·stvm·open plc
数字新视界2 小时前
国产信创动环监控系统的未来趋势分析
物联网·3d·数字孪生·三维可视化·数据可视化
会周易的程序员2 小时前
STVM OSAL 层架构设计文档
c++·物联网·嵌入式·虚拟机·iot·软plc·iec61131
youshi66683 小时前
平衡车——PID算法优化
stm32·单片机·嵌入式硬件·算法·pid·平衡车
调试优选官3 小时前
2026年物联网应用开发公司上榜品牌解析:D-coding技术纵深、项目规范与长期服务观察
物联网·开发经验·d-coding