STM32实现按键功能之短按加一次而长按连续加的功能

题目要求

在蓝桥杯嵌入式第九届的省赛题出现了这样一个功能要求,每短按B3键一次,数字递增一次;按住B3键超过0.8s,则数字快速递增,直到松开。

思路过程

最初看到这道题的时候,我想的是在Key_Scan()函数里面加入很多个时间很短的延时,并且每次在延时的后面有一个判断,如果说还在按下就继续加,如果不按下就退出。但是这样操作会造成很多的问题,第一是太浪费资源了,延时的时候除了中断什么都不能干;第二是不准确不能保证是0.8s,因为现在是机审所以要严谨一些;第三是真的太蠢了!!!后面我自问了我一下,可不可以在万能的定时中断里做文章,答案是可以的,并且可以说非常的完美(当然是自认为,哈哈)。

解决过程

这个需要用到32的两个东西,一个是定时器,另外一个是按键。废话不多说直接上文件!

anjian.c

#include "anjian.h"
_Bool Key_Flag=1;
void Key_Init(void){
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_8;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
}

u8 Key_Scan(void){
	if((Key1==0||Key2==0||Key3==0||Key4==0)&&Key_Flag){
		Delay_Ms(10);
		Key_Flag=0;
		if(Key1==0) return 1;
		else if(Key2==0) return 2;
		else if(Key3==0) return 3;
		else if(Key4==0) return 4;
	}
	else if(Key1==1&&Key2==1&&Key3==1&&Key4==1) Key_Flag=1;
	return 0;
}

注意

  1. Key_Init()这就是一个初始化,自己去做就可以了,不多讲。
  2. Key_Scan()这个函数的实现应该很多人都清楚了,就是做到每按一次只加一次,无论你按得时间有多长永远只会返回一次真实按键值,那是因为有Key_Flag这个标志位的存在。具体因为是你第一次按下的时候,Key_Flag的值是1,然后就是判断查找是那一个按键,然后返回相应的数值并且对标志位Key_Flag清0。如果说你的手还在按个按键,开始第二次进入这个函数,这个时候由于Key_Flag是0就不能进入到后面的判断按键和返回值了,只能返回0代表没有按下。只有当你按键全部松开的时候,变量Key_Flag才可以再次置1,才可以再一次进入到判断哪个按键,并且返回相应的值。

anjian.h

#ifndef __ANJIAN_H
#define __ANJIAN_H
extern _Bool Key_Flag;
/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"

#define Key1 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)
#define Key2 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_8)
#define Key3 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)
#define Key4 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_2)

void Key_Init(void);
u8 Key_Scan(void);

#endif

timer.c

#include "timer.h"

void Timer2_Init(void){
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

	TIM_TimeBaseStructure.TIM_Period = 999;
	TIM_TimeBaseStructure.TIM_Prescaler = 71;
	TIM_TimeBaseStructure.TIM_ClockDivision = 0;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

	NVIC_Init(&NVIC_InitStructure);

	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
	TIM_Cmd(TIM2, ENABLE);
}
u32 Timer2_AnjianFlag=0;
void TIM2_IRQHandler(void)
{
  if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
  {
	if(Key2==0){
		Timer2_AnjianFlag++;
		if(Timer2_AnjianFlag>=800){
			Key_Flag=1;		//这个变量就是Key_Scan()里面的标志位
		}
	}
	else if(Key1==1&&Key2==1&&Key3==1&&Key4==1){
		Timer2_AnjianFlag=0;
	}
	TIM_ClearITPendingBit(TIM2, TIM_IT_Update);	
  }
}

注意

  1. Timer2_Init()函数是定时器2的定时模式,定时为每1ms进一次中断。这个很简单,我就不多讲了。
  2. 在定时器中断函数里,有个变量很重要就是Timer2_AnjianFlag,他是用来记录你按下按键的时间,如果超过0.8s,那么以后每1ms进入中断都会令Key_Scan()里的标志位Key_Flag=1,相当于把那道每按一次才能加一次的门槛给弄走了,现在是每次进入Key_Scan()函数都可以进行按键的判断了。这样就实现了长按连续加,短按就加一次。

timer.h

#ifndef __TIMER_H
#define __TIMER_H

/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include "anjian.h"

void Timer2_Init(void);

#endif

评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值