文章目录

  • 前言
  • 一、电路图和控制逻辑:
  • 二、状态机思路:
    • 1、状态机代码实现:Key.c
    • 2.按键状态机头文件 Key.h
    • 3.滴答定时器配置
    • 4、主函数main


前言

最近在做关于裸机开发的一个stm32按键检测小项目,总结了一种可以快速检测多个按键长短按的思路:使用状态机,消抖使用滴答定时器中断,可以实现非阻塞式消抖。


一、电路图和控制逻辑:

示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。

KEY1短按LED1切换状态,长按LED1和LED2均点亮
KEY2短按LED2切换状态,长按LED1和LED2均熄灭

二、状态机思路:

定义几个变量:
①开关引脚电平记为 KEY_IN ,高电平松开,低电平按下。
②时间戳:定义于SysTick.c变量tick ,滴答定时器每1ms进中断,tick自增1。
每次进入按键扫描函数KEY_Scan()都获取当前时间戳tick(current_tick),在状态转换中仅需要判断按键的输入电平、当前状态时间戳current_tick与上一状态时间戳last_tick的差值Δtick,即可进行下一状态的状态的判断。
在这里插入图片描述

1、状态机代码实现:Key.c

两个开关的GPIO都配置为上拉输入,按键松开(默认状态)下为高电平。

#include "stm32f10x.h"                  // Device header
#include "Key.h"
#include "SysTick.h"
#include "stdio.h"
//按键状态
typedef enum 
{
    KEY_STATE_RELEASED,//按键松开
    KEY_STATE_DEBOUNCE,//按键消抖
    KEY_STATE_PRESSED,//按键确认按下
    KEY_STATE_LONGPRESS//按键长按
}KEY_State;



//按键结构体
typedef struct
{
    GPIO_TypeDef* GPIOx;//按键所在GPIO
    uint16_t GPIO_Pin;//按键所在引脚
    KEY_State state;//按键当前状态
    uint16_t last_tick;//上次状态变化的时间戳
    
}Key;
#define DEJITTED_TIME 30 //消抖时间30ms
#define KEY_LONG_TIME 500//长按时间500ms
 
Key key1 = {GPIOB,GPIO_Pin_13,KEY_STATE_RELEASED,0};
Key key2 = {GPIOB,GPIO_Pin_15,KEY_STATE_RELEASED,0};



void Key_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//默认高电平
	GPIO_InitStructure.GPIO_Pin = key1.GPIO_Pin | key2.GPIO_Pin;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
}
//按键状态机 2:按键长按 1:按键确认按下  0:按键松开 

uint8_t KEY_Scan(Key *key)
{
    uint8_t KEY_IN  = GPIO_ReadInputDataBit(key->GPIOx,key->GPIO_Pin);
    uint32_t current_tick = Get_tick();
    
    switch(key->state)
    {
        case KEY_STATE_RELEASED://按键松开
            if(KEY_IN  == 0)//检测到低电平
            {
                key->state = KEY_STATE_DEBOUNCE;//进入按键消抖
                key->last_tick = current_tick;
                
            }
            break;
        case KEY_STATE_DEBOUNCE://消抖检测
            if((current_tick - key->last_tick) >=DEJITTED_TIME)//如果消抖超过30ms,再次读取端口电平
            {
                
                if(KEY_IN  == 0)//低电平(默认上拉输入),有电平按下
                {
                    
                    key->state = KEY_STATE_PRESSED;
                    
                }
                else 
                    key->state = KEY_STATE_RELEASED;//扔进入按键消抖
                
            }
            break;
            
        case KEY_STATE_PRESSED://按键稳定按下
            if(KEY_IN  == 1) //端口高电平,按键松开
            {
                
                key->state = KEY_STATE_RELEASED;
                return 1;
            }
            else if((current_tick-key->last_tick >= KEY_LONG_TIME)&&KEY_IN  == 0)//长按
            {
                key->state = KEY_STATE_LONGPRESS;
                return 2;
                
            }
                
            break;
        case KEY_STATE_LONGPRESS://长按已触发
            if(KEY_IN  == 1) //端口高电平,按键松开
            {
                key->state = KEY_STATE_RELEASED;
            }
            break;
        
    }
    return 0;
}
uint8_t KEY1_State(void)
{
    return KEY_Scan(&key1);
}

uint8_t KEY2_State(void)
{
    return KEY_Scan(&key2);
}




2.按键状态机头文件 Key.h

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


void Key_Init(void);
uint8_t KEY1_State(void);
uint8_t KEY2_State(void);

#endif

3.滴答定时器配置

  1. SysTick.c
#include "stm32f10x.h"                  // Device header
volatile uint32_t tick;//时间戳定义
void SysTick_Init(void)
{
    if(SysTick_Config(SystemCoreClock/1000))//1ms中断
    {
        while(1);
    }

}
void SysTick_Handler(void)
{
    tick++;
    if(tick>=5000) tick = 0;//每5秒自动清零,防止定时器溢出
}

uint32_t Get_tick(void)
{
    return tick;
}




  1. SysTick.h
#include "stm32f10x.h"                  // Device header

uint32_t Get_tick(void);
void SysTick_Init(void);

4、主函数main

KEY1短按LED1切换状态,长按LED1和LED2均点亮
KEY2短按LED2切换状态,长按LED1和LED2均熄灭

#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "Key.h"
#include "SysTick.h"
#include "LED.h"
uint32_t count;
uint8_t KEY1,KEY2;
int main(void)
{
	OLED_Init();
    SysTick_Init();
    Key_Init();
    LED_Init();
    OLED_ShowString(1, 1, "HelloWord:");

	
	while (1)
	{
        KEY1 = KEY1_State();
        KEY2 = KEY2_State();
        
        if(KEY1 == 1)   LED1_Turn(); 
        if(KEY2 == 1)   LED2_Turn();
        if(KEY1 == 2) 
        {
            LED1_ON();
            LED2_ON();
        }
        if(KEY2 == 2) 
        {
            LED1_OFF();
            LED2_OFF();
        }
        



	}
}


演示

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐