蓝桥杯嵌入式学习记录——按键的使用

目录

一、按键原理简介

二、cubeMX的配置

三、按键的短按代码

四、按键的长按代码


一、按键原理简介

        在STM32中,按键连接通常使用GPIO(通用输入/输出)端口来实现。当按键未被按下时,GPIO端口处于高电平状态(即1),当按键被按下时,GPIO端口会被拉低(即0)。因此,通过检测GPIO端口的电平状态变化,可以检测到按键是否被按下。

        为了防止按键抖动,通常需要使用软件消抖。消抖的方法通常是在检测到按键被按下时,等待一段时间,并再次检测GPIO端口的状态,只有当GPIO端口仍然处于低电平状态时,才认为按键被有效触发。同时,还可以通过使用外部上拉电阻或下拉电阻,以确保GPIO端口在未连接按键时处于稳定状态。上拉电阻将GPIO端口拉高,下拉电阻将GPIO端口拉低,这样可以避免未连接按键时的漂浮状态。

        总结来说,STM32按键的工作原理是通过检测GPIO端口的电平状态变化来判断按键是否被按下,并通过软件消抖和外部上拉/下拉电阻来确保按键的稳定性。

二、cubeMX的配置

        在cubeMX中,我们除了需要配置四个按键引脚的模式外,还需要配置定时器相关的参数等。我们用定时器来实现按键消抖,即通过定时器每过10ms检测一次按键引脚的电平。具体配置操作如下:

1、打开cubeMX软件,将开发板上的四个按键对应的引脚设置为输入模式,即将PA0、PB0、PB1、PB2设置为GPIO_Input

2、点击左边的GPIO,选中PA0、PB0、PB1、PB2四个GPIO口,并如图设置为上拉模式,即按下时GPIO口为低电平(0)

3、点击Timers,选择一个定时器,我选择的是通用定时器TIM3,如图设置时钟源为内部时钟。再设置定时器的预分频器值和计数器重载值,由于我们设置的定时器时钟频率为80MHz,通过定时器的计算公式,当我们想要定时10ms时,我们需要将预分频器值设置为80-1数器重载值设置为10000-1.公式如下:

定时时间 = (预分频器值\times计数器重载值)/ 定时器时钟频率

三、按键的短按代码

interrupt.h

代码后已经注释了代码的大致含义

// interrupt.h

#ifndef _INTERRUPT_H
#define _INTERRUPT_H

#include "main.h"      // 在main.h中宏定义uchar、uint

struct keys            // 定义一个结构体,设置三个状态变量
{
	uchar judge_sta;   // 设置标志位,反应定时器中断服务函数进行到哪一步
	uchar key_sta;     // 检测按键引脚的电平并保存到key_sta,当按键按下时key_sta为0
	uchar flag;        // 当按键真正按下后,让flag = 1
};

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);  // 中断服务函数

#endif

interrupt.c

        这里主要就是编写定时器的中断服务函数,首先读取四个按键引脚的电平,通过定时器每过10ms检测一次电平,当第一次检测为低电平时,等待10ms后再检测一次,若仍为低电平,则视为按键真的按下,即令flag = 1.

// interrupt.c

#include "interrupt.h"

struct keys key[4] = {0, 0, 0, 0};

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance == TIM3)       // 使用定时器TIM3
	{
        // 读取四个按键引脚的电平
		key[0].key_sta = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0);  
		key[1].key_sta = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1);
		key[2].key_sta = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2);
		key[3].key_sta = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0);
	}
	
	for(int i=0; i<4; i++)  // 循环扫描四个按键的状态
	{
		switch (key[i].judge_sta)
		{
			case 0:
			{
				if(key[i].key_sta == 0)
				{
					key[i].judge_sta = 1;
				}
			}
			break;
			case 1:
			{
				if(key[i].key_sta == 0)
				{
                  key[i].flag = 1;
				  key[i].judge_sta = 2;
				}
				else  key[i].judge_sta = 0;
			}
			break;
			case 2:
			{
				if(key[i].key_sta == 1)
				{
					key[i].judge_sta = 0;
				}
			}
			break;
		}
			
	}
	
}

main.c

        主函数中我只展示与按键相关的代码,首先需要声明一个全局变量extern struct keys key[]来方便后面使用key[i].flag进行判断

        然后需要打开定时器中断服务函数,使用HAL_TIM_Base_Start_IT(&htim3);

        最后在while循环中用key[i].flag判断按键是否真的按下,当按键真的按下时执行一系列指令

// main.c
#include "main.h"
#include "tim.h"
#include "gpio.h"

#include "led.h"
#include "interrupt.h"

extern struct keys key[];

HAL_TIM_Base_Start_IT(&htim3);

while (1)
  {
		if(key[0].flag == 1)
		{
			LED(0x01);
			key[0].flag = 0;
		}
		if(key[1].flag == 1)
		{
			LED(0x00);
			key[1].flag = 0;
		}
  }

四、按键的长按代码

interrupt.h

与短按相比,长按的头文件只是在结构体中多定义两个变量:key_time和long_flag

key_time用来判断按键按下的时间长短

long_flag用来判断按键是否长按

// interrupt.h

#ifndef _INTERRUPT_H
#define _INTERRUPT_H

#include "main.h"

struct keys
{
	uchar judge_sta;
	uchar key_sta;
	uchar flag;
	uint key_time;
	uchar long_flag;       
};

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);

#endif

interrupt.c

        与短按类似,只是当第一次判断按键按下后,key[i].time开始自加,直到按键松开后判断key[i].time的时间,大于70ms视为长按,小于70ms视为短按

// interrupt.c

#include "interrupt.h"

struct keys key[4] = {0, 0, 0, 0};

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance == TIM3)
	{
		key[0].key_sta = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0);
		key[1].key_sta = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1);
		key[2].key_sta = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2);
		key[3].key_sta = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0);
	}
	
	for(int i=0; i<4; i++)
	{
		switch (key[i].judge_sta)
		{
			case 0:
			{
				if(key[i].key_sta == 0)
				{
					key[i].judge_sta = 1;
					key[i].key_time = 0;
				}
			}
			break;
			case 1:
			{
				if(key[i].key_sta == 0)
				{
				  key[i].judge_sta = 2;
				}
				else
				{
					key[i].judge_sta = 0;
				}
			}
			break;
			case 2:
			{
				if(key[i].key_sta == 1)
				{
					key[i].judge_sta = 0;
					if(key[i].key_time < 70)
					key[i].flag = 1;
				}
				else key[i].key_time++;
				if(key[i].key_time > 70) key[i].long_flag = 1;
			}
			break;
		}
			
	}
	
}

main.c

主函数除了while循环的判断之外,都与短按类似

  while (1)
  {
		if(key[0].flag == 1)
		{
			LED(0x00);
			key[0].flag = 0;
		}
		if(key[1].long_flag == 1)
		{
			LED(0x01);
			key[1].long_flag = 0;
		}
  }

  • 32
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
### 回答1: 蓝桥杯是全国性的计算机大赛,旨在提高大学生的计算机技术水平和创新能力。嵌入式STM32G431是一款嵌入式芯片,具有高性能和低功耗的特点。第十二届第一场省赛停车计费系统是蓝桥杯的一道工程题目,要求参赛选手设计一个停车场计费系统。 停车计费系统是指通过嵌入式技术实现对车辆进入和离开停车场的自动检测、计时和计费的系统。对于这个题目,参赛选手可以根据题目要求,使用STM32G431芯片设计一个具有以下功能的系统: 1. 车辆进入检测:使用车辆传感器检测车辆的进入,触发计时。 2. 车辆离开检测:使用车辆传感器检测车辆的离开,停止计时。 3. 计时功能:使用内部时钟模块获取进入和离开的时间,并计算停车时间。 4. 计费功能:根据停车时间,按照一定的计费规则进行计费。 5. 显示功能:使用液晶显示屏显示当前的停车信息,如车牌号、停车时间、费用等。 6. 数据存储功能:使用闪存等储存介质将停车数据进行存储,以便后续的数据分析和查询。 设计一个停车计费系统涉及到硬件设计和软件编程两个方面。硬件方面,参赛选手需要选择合适的传感器、显示屏、存储介质等,以及设计电路和接口进行连接。软件方面,需要使用C语言或者汇编语言编写程序,对芯片进行编程,实现各项功能。 通过此次比赛,选手们可以锻炼嵌入式系统的设计能力和编程能力,了解实际应用中嵌入式系统的工作原理和应用场景。同时,也能提升对STM32G431芯片的理解和运用能力。这对于培养嵌入式技术人才,推动物联网技术的发展都具有积极意义。 ### 回答2: 蓝桥杯是面向计算机爱好者的智力竞赛,而嵌入式STM32G431是一款嵌入式系统开发板。第十二届第一场省赛的停车计费系统真题工程,则是要求参赛选手设计并实现一个能够进行停车计费的系统。 停车计费系统是一种用于自动计费和管理停车场的系统。这个系统可以通过识别车辆的进出以及停车的时间,自动计算并收费。在这个工程中,选手需要使用嵌入式STM32G431开发板以及相关的硬件和软件,来设计一个能够实现停车计费功能的系统。 首先,选手需要使用传感器或摄像头来实现车辆进出的检测。当车辆进入或离开停车场时,传感器会发出信号并通过STM32G431进行检测。接着,选手需要编程实现识别车辆的算法,以便能够识别不同的车辆。当车辆停放时,系统会通过计时器记录停车的时间。 然后,选手需要编写计费算法,根据停车的时间来计算费用。这个算法可以根据停车场的规则来确定费用的计算方式,例如按小时计费或按照不同的时间段采用不同的费率。 最后,选手还需要设计一个界面,使得系统能够与用户进行交互。用户可以通过该界面查询停车费用,并进行付款。同时,选手还需要保证系统的稳定性和安全性,确保数据的准确性和保密性。 总而言之,蓝桥杯嵌入式STM32G431第十二届第一场省赛停车计费系统真题工程要求选手使用硬件和软件开发能力,设计并实现一个完整的停车计费系统。这需要选手具备嵌入式系统开发、传感器技术、算法设计和界面设计等多方面的知识和技能。 ### 回答3: 蓝桥杯嵌入式stm32g431——第十二届第一场省赛停车计费系统真题工程是一个基于STM32G431开发板的停车计费系统设计题目。该系统的主要功能是实现停车场的车辆进入、出场的计费管理。 首先,该系统需要实现一个车辆进入检测的功能。当车辆进入停车场时,系统会通过传感器检测到车辆的到达,并记录下进入的时间。 然后,系统需要实现一个车辆出场的功能。当车辆准备离开停车场时,系统会通过传感器检测到车辆的离开,并记录下离开的时间。 接下来,系统需要计算车辆停留的时间。通过进入时间和离开时间的差值计算得出车辆停留的时长。 最后,系统需要计算停车费用。根据停车场的计费规则,根据车辆停留的时长计算出停车费用,并将费用显示在屏幕上。 在实现上述功能的过程中,需要运用STM32G431开发板的各种功能和模块,包括GPIO口、定时器、中断、串口通信等。通过编写相应的代码,实现按钮的控制、传感器检测、时间的计算以及屏幕的显示等功能。 该项目的设计需要考虑多种情况,比如车辆重复进入出场、车辆进入出场顺序错乱等,要充分考虑这些异常情况并进行相应的处理。在代码编写过程中,还需注意代码的优化和资源的合理利用,以提高系统的性能和效率。 通过完成这个项目的设计与实现,可以加深对STM32G431嵌入式系统的了解和应用,并提升嵌入式系统开发的能力。同时,也能锻炼自己的逻辑思维、问题解决能力和团队合作精神。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

KAIs32

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值