STM32實現按鍵功能之短按加一次而長按連續加的功能

Warning:寫作不易,請勿轉載,感謝。

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(u8 mode);

#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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章