STM32定时器按键扫描检测(按下松开执行程序)并执行其他内容的源码

文章目录


前言:这里20ms消抖,按键定时器消抖就是在刚刚按下的时候会出现抖动,然后在这20ms内,我设置定时器20ms才进入检测按键是否按下,这20ms已经把抖动抵消了,在20ms后再进入程序判断是否变为低电平(也就是按键按下),这时候我已经记录了按键几按下了,存在一个变量里面,然后等待它升起变成高电平才返回按键值,如果一直长按着就不会返回按键值,按键则不会执行程序,松开的时候定时器定时检测也正好消抖了松开的时候产生的抖动。

main.c

#include "stm32f10x.h"                  // Device header
#include "Key.h"
#include "LED.h"
#include "Timer.h"

int main(void)
{
	Timer_Init();//1ms
	LED_Init();
	Key_Init();
	while(1)
	{
		switch(KeyFlag)//按下松手即可开始实现功能
        	{
            	case KEY0_PRES://1
					LED_Green=!LED_Green;
                	KeyFlag = 0;//注意按键标志清零,防止程序跑飞		
                	break;

            
        	}
		if(BEEP_TIME>=500)//这里必须写大于,按的某个时刻有可能计数值大于500,这里是定时器计时实现亮灭
		{
				LED_Red =!LED_Red;
				BEEP_TIME =0;
		}
	}
}

sys.c


sys.h

#ifndef __SYS_H
#define __SYS_H	
#include "stm32f10x.h"

//位带操作,实现51类似的GPIO控制功能
//具体实现思想,参考<>第五章(87页~92页).
//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 
//IO口地址映射
#define GPIOA_ODR_Addr    (GPIOA_BASE+12) //0x4001080C 
#define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C 
#define GPIOC_ODR_Addr    (GPIOC_BASE+12) //0x4001100C 
#define GPIOD_ODR_Addr    (GPIOD_BASE+12) //0x4001140C 
#define GPIOE_ODR_Addr    (GPIOE_BASE+12) //0x4001180C 
#define GPIOF_ODR_Addr    (GPIOF_BASE+12) //0x40011A0C    
#define GPIOG_ODR_Addr    (GPIOG_BASE+12) //0x40011E0C    

#define GPIOA_IDR_Addr    (GPIOA_BASE+8) //0x40010808 
#define GPIOB_IDR_Addr    (GPIOB_BASE+8) //0x40010C08 
#define GPIOC_IDR_Addr    (GPIOC_BASE+8) //0x40011008 
#define GPIOD_IDR_Addr    (GPIOD_BASE+8) //0x40011408 
#define GPIOE_IDR_Addr    (GPIOE_BASE+8) //0x40011808 
#define GPIOF_IDR_Addr    (GPIOF_BASE+8) //0x40011A08 
#define GPIOG_IDR_Addr    (GPIOG_BASE+8) //0x40011E08 
 
//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //输出 
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入 

#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //输出 
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //输入 

#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //输出 
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //输入 

#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //输出 
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //输入 

#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //输出 
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //输入

#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //输出 
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //输入

#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //输出 
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //输入


#endif



Key.h

#ifndef __KEY_H
#define __KEY_H
#include "stm32f10x.h"                  // Device header
#include "sys.h"

#define Key0 PEin(4)
#define Key1 PEin(3)
#define Key2 PEin(2)

#define KEY    ((Key0) && (Key1) && (Key2))//两个条件都为真时结果才为真,否则为假,我们按键只能按一个,无法同时按,人手速度没有这么快,所以始终无论哪个按键按下KEY都是0
#define KEY0_PRES 1
#define KEY1_PRES 2
#define KEY2_PRES 3

extern uint8_t KeyFlag;    //按键标志
void Key_Init(void);
uint8_t Key_Scan(void);    /*按键扫描函数*/

#endif

Key.c

#include "stm32f10x.h"                  // Device header
#include "Key.h"
uint8_t KeyFlag = 0;    //按键标志

typedef enum//按键状态
{
    KEY_CHECK =0,//检测
    KEY_CONFIRM = 1,//确认
    KEY_RELEASE = 2//释放
}KEY_STATE;

KEY_STATE KeyState = KEY_CHECK;     //初始化按键状态为检测状态,KeyState是变量,KEY_CHECK是数值,初始化为0


void Key_Init()
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_6;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOE,&GPIO_InitStruct);
}


uint8_t Key_Scan(void)
{
	static uint8_t KeyFlag = 0;    //按键标志
    switch(KeyState)//按键状态KeyState为0,1,2其中一个
    {
		case KEY_CHECK://按键状态:0
            if(!KEY)//如果按键值为0,说明按键被按下,切换状态,if是为1才能进入,按键按下了变为0,反转为1才进入
            {
                KeyState = KEY_CONFIRM;//按键状态从0切换为1
            }
            break;
        case KEY_CONFIRM://按键状态:1
            if(!KEY)//判断当前按键值是否为0,确认是否按下
            {
                KeyState = KEY_RELEASE;//按键状态从1切换为2
                if(0 == Key0)//KEY0被按下
                {
                    KeyFlag = KEY0_PRES;//KEY0_PRES=1,KeyFlag=1
                }
                if(0 == Key1)//KEY1被按下
                {
                    KeyFlag = KEY1_PRES;//KEY1_PRES=2,KeyFlag=2
                }
				if(0 == Key2)//KEY2被按下
                {
                    KeyFlag = KEY2_PRES;//KEY2_PRES=3,KeyFlag=3
                }
            }
            else//按键没有被按下,返回上一状态
            {
                KeyState = KEY_CHECK;
            }
            break;
        case KEY_RELEASE://按键状态:2
            if(KEY)//当前按键值为1,说明按键已经释放,切换到开始状态
            {
                KeyState = KEY_CHECK;//按键状态从2切换为0,以便下一次使用
				return KeyFlag;//释放以后才把按键数值返回
            }
            break;
    }
		return 0;
}






Timer.h

#ifndef __TIMER_H
#define __TIMER_H
#include "stm32f10x.h"                  // Device header

extern volatile uint32_t global_times;
extern volatile uint32_t BEEP_TIME;

void Timer_Init(void);

#endif

Timer.c

#include "stm32f10x.h"                  // Device header
#include "LED.h"
#include "Key.h"

volatile uint32_t global_times = 0;
volatile uint32_t BEEP_TIME = 0;


void Timer_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
	
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 1000 - 1;
	TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM4, &TIM_TimeBaseInitStructure);
	
	TIM_ClearFlag(TIM4, TIM_FLAG_Update);
	TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStructure);
	
	TIM_Cmd(TIM4, ENABLE);
}


void TIM4_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM4, TIM_IT_Update) == SET)//1ms
	{
		global_times++;
		BEEP_TIME ++;
		if(global_times ==20)//20ms进入检测按键一次
		{
			KeyFlag =Key_Scan();
			global_times=0;
		}
		TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
	}
}

LED.h

#ifndef __LED_H
#define __LED_H
#include "sys.h"
void LED_Init(void);
#define LED_Red   PBout(5)
#define LED_Green PEout(5)
#define Beep   PCout(12)

#endif

LED.c

#include "stm32f10x.h"                  // Device header
#include "LED.h"

void LED_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;	
	GPIO_Init(GPIOB,&GPIO_InitStruct);
	GPIO_SetBits(GPIOB,GPIO_Pin_5);
	
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_12;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;	
	GPIO_Init(GPIOC,&GPIO_InitStruct);
	GPIO_SetBits(GPIOC,GPIO_Pin_12);
	
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;	
	GPIO_Init(GPIOE,&GPIO_InitStruct);
	GPIO_SetBits(GPIOE,GPIO_Pin_5);
}

你可能感兴趣的:(stm32,嵌入式硬件,单片机)