stm32f103按键操作的另一种实现——状态机(代码片段)

a1314521531 a1314521531     2022-12-12     706

关键词:

#ifndef _KEY_H_
#define _KEY_H_

#include "HAL_gpio.h" // 换成STM32F103对应的GPIO库
#include "type.h"     // type.h主要是一些类型的重命名

#define KEY_UP_GRP         GPIOA
#define KEY_UP_IDX         GPIO_Pin_9
#define KEY_UP_IS_DOWN()   GPIO_ReadInputDataBit(KEY_UP_GRP, KEY_UP_IDX)
#define KEY_UP_CONFIG()    GPIOConfig(KEY_UP_GRP, KEY_UP_IDX, GPIO_Mode_IPU) // 这个函数我在之前帖子里面写过

#define KEY_DOWN_GRP       GPIOA
#define KEY_DOWN_IDX       GPIO_Pin_10
#define KEY_DOWN_IS_DOWN() GPIO_ReadInputDataBit(KEY_DOWN_GRP, KEY_DOWN_IDX)
#define KEY_DOWN_CONFIG()  GPIOConfig(KEY_DOWN_GRP, KEY_DOWN_IDX, GPIO_Mode_IPU)

#define KEY_FUNC_GRP       GPIOA
#define KEY_FUNC_IDX       GPIO_Pin_11
#define KEY_FUNC_IS_DOWN() GPIO_ReadInputDataBit(KEY_FUNC_GRP, KEY_FUNC_IDX)
#define KEY_FUNC_CONFIG()  GPIOConfig(KEY_FUNC_GRP, KEY_FUNC_IDX, GPIO_Mode_IPU) 

#define KEY_TURN_GRP       GPIOA
#define KEY_TURN_IDX       GPIO_Pin_12 | GPIO_Pin_13
#define KEY_TURN_IS_DOWN() GPIO_ReadInputDataBit(KEY_TURN_GRP, KEY_TURN_IDX)
#define KEY_TURN_CONFIG()  GPIOConfig(KEY_TURN_GRP, KEY_TURN_IDX, GPIO_Mode_IPU)

//====================================================================================
typedef enum

  CONFIRM_KEY = 1,
  FUNC_KEY,
  UP_KEY,
  DOWN_KEY
 key_event_t;

#define state_keyUp         0       //初始状态,未按键
#define state_keyDown       1       //键被按下
#define state_keyLong       2       //长按
#define state_keyTime       3       //按键计时态

#define return_keyUp        0x00    //初始状态
#define return_keyPressed   0x01    //键被按过,普通按键
#define return_keyLong      0x02    //长按
#define return_keyAuto      0x04    //自动连发

#define key_down            0       //按下
#define key_up              0xf0    //未按时的key有效位键值
#define key_longTimes       100     //10ms一次,200次即2秒,定义长按的判定时间
#define key_autoTimes       20      //连发时间定义,20*10=200,200毫秒发一次


#define KEYS1_VALUE         0xe0    //keyS1 按下
#define KEYS2_VALUE         0xd0    //keyS2 按下
#define KEYS3_VALUE         0xb0    //keyS3 按下
#define KEYS4_5_VALUE       0x70    //keyS4_5 按下

//====================================================================================
void KeyProcess(void);  //T0定时器调用的工作函数
void KeyTimerInit(void);

#endif /* _KEY_H_ */
#include <stdio.h>
#include "key.h"
#include "timer.h" // STM32F103定时器的配置

static uint8_t
key_get(void)       //获取P3口值

  if(KEY_UP_IS_DOWN() == key_down)
  
    return KEYS1_VALUE;
  
  if(KEY_DOWN_IS_DOWN() == key_down)
  
    return KEYS2_VALUE;
  
  if(KEY_FUNC_IS_DOWN() == key_down)
  
    return KEYS3_VALUE;
  
  if(KEY_TURN_IS_DOWN() == key_down)
  
    return KEYS4_5_VALUE;
  

  return key_up ;    //0xf0  没有任何按键


//函数每20ms被调用一次,而我们弹性按键过程时一般都20ms以上
//所以每次按键至少调用本函数2次
static uint8_t
key_read(uint8_t* pKeyValue)

  static uint8_t  s_u8keyState = 0;        //未按,普通短按,长按,连发等状态
  static uint16_t s_u16keyTimeCounts = 0;  //在计时状态的计数器
  static uint8_t  s_u8LastKey = key_up ; //保存按键释放时的P3口数据

  uint8_t keyTemp = 0;              //键对应io口的电平
  int8_t key_return = 0;          //函数返回值
  keyTemp = key_up & key_get();  //提取所有的key对应的io口

  switch(s_u8keyState)           //这里检测到的是先前的状态
  
  case state_keyUp:   //如果先前是初始态,即无动作
  
    if(key_up != keyTemp) //如果键被按下
    
      s_u8keyState = state_keyDown; //更新键的状态,普通被按下
    
  
  break;

  case state_keyDown: //如果先前是被按着的
  
    if(key_up != keyTemp) //如果现在还被按着
    
      s_u8keyState = state_keyTime; //转换到计时态
      s_u16keyTimeCounts = 0;
      s_u8LastKey = keyTemp;     //保存键值
    
    else
    
      s_u8keyState = state_keyUp; //键没被按着,回初始态,说明是干扰
    
  
  break;

  case state_keyTime:  //如果先前已经转换到计时态(值为3)
  
    //如果真的是手动按键,必然进入本代码块,并且会多次进入
    if(key_up == keyTemp) //如果未按键
    
      s_u8keyState = state_keyUp;
      key_return = return_keyPressed;    //返回1,一次完整的普通按键
      //程序进入这个语句块,说明已经有2次以上10ms的中断,等于已经消抖
      //那么此时检测到按键被释放,说明是一次普通短按
    
    else  //在计时态,检测到键还被按着
    
      if(++s_u16keyTimeCounts > key_longTimes) //时间达到2秒
      
        s_u8keyState = state_keyLong;  //进入长按状态
        s_u16keyTimeCounts = 0;      //计数器清空,便于进入连发重新计数
        key_return = return_keyLong;   //返回state_keyLong
      
      //代码中,在2秒内如果我们一直按着key的话,返回值只会是0,不会识别为短按或长按的
    
  
  break;

  case state_keyLong:  //在长按状态检测连发  ,每0.2秒发一次
  
    if(key_up == keyTemp)
    
      s_u8keyState = state_keyUp;
    
    else //按键时间超过2秒时
    
      if(++s_u16keyTimeCounts > key_autoTimes)//10*20=200ms
      
        s_u16keyTimeCounts = 0;
        key_return = return_keyAuto;  //每0.2秒返回值的第2位置位(1<<2)
      //连发的时候,肯定也伴随着长按
    
    key_return |= return_keyLong;  //0x02是肯定的,0x04|0x02是可能的
  
  break;

  default:
    break;
  
  *pKeyValue = s_u8LastKey ; //返回键值
  return key_return;


// 这个函数就是要在中断中调用的。主要是使用事件队列的方式。
void
KeyProcess(void)

  uint8_t key_stateValue;
  uint8_t keyValue = 0;
  uint8_t* pKeyValue = &keyValue;

  key_stateValue = key_read(pKeyValue);

  if ((return_keyPressed == key_stateValue) && (*pKeyValue == KEYS1_VALUE))
  
    //短按keyS1时改变对时状态,将其加入队列,队列的基本操作在将队列的时候写过。
    if(QueueEventIsEmpty(g_state_manager.process->key_event) ||
        (!QueueEventIsEmpty(g_state_manager.process->key_event) &&
         !QUEUE_EVENT_IS_EQUEL(g_state_manager.process->key_event, UP_KEY)))
    
      QueueEventPush(g_state_manager.process->key_event, UP_KEY);
    
  


//======================================================================================
void
KeyTimerInit(void)

  KEY_UP_CONFIG();
  KEY_DOWN_CONFIG();
  KEY_FUNC_CONFIG();
  KEY_TURN_CONFIG();

  // 20ms
  TimerConfig(KEY_TIMER, KEY_TIMER_DIV, KEY_TIMER_PERIOD);
  TimerDisable(KEY_TIMER);
  TimerEnable(KEY_TIMER);
主要是描述一下按键状态机的思维,使用定时器中断的方法,按键按下将其加入队列中,在主函数的循环中实现出队。亲测可用。


stm32f103你学不会系列(十七)电容触摸按键实现(代码片段)

...TM32F103五分钟入门系列(十五)输入捕获电容触摸按键前言一、电容触摸按键原理1、原理图分析2、原理分析二、例1-为例2做准备1、题2、分析3、代码实现(1)cap.h、cap.c代码(2)tpad.h、tpad.c代码(3&# 查看详情

stm32的意思是啥呢?

...板级编程。如果从软件上讲,就是要学习基于ARM处理器的操作系统层面的驱动、移植了。硬件的寄存器类的东西还是要能看懂的,掌握基于板级的汇编和C编程。主要需要学习的有:基础操作:GPIO操作,串口操作,定时器操作,N... 查看详情

基于stm32f103入门2——按键点灯(代码片段)

STM32按键点灯程序1:按键不带锁存1.1例程2:按键带锁存2.1例程3:按键用外部中断来做步骤:1.配置GPIO(配置结构体的相关东西)2.设置EXTI(触发方式:上升沿、下降沿、上下都触发)。3.设置NV... 查看详情

基于stm32f103——矩阵按键+串口打印(代码片段)

STM32F103-矩阵按键+串口打印基本介绍代码matrix_key.cmatrix_key.hmain.c项目演示基本介绍最近做了一个门禁卡小玩意,用到了4X4矩阵按键,在这里也单独的记录一下。矩阵按键图思路:矩阵按键读取键值写法多样,有一行... 查看详情

stm32f103c8t6实现串口通信+按键点灯(代码片段)

1、实现的效果芯片复位,串口调试助手打印出:芯片的唯一ID为:67075433-49568770-670FF52芯片flash的容量为:64K 按下S2,灯翻转,同时打印OK在串口助手命令端,发送命令,打印该命令  2、main.c/***************************************... 查看详情

stm32f103基于w5500实现modbus简单tcp通信(代码片段)

文章目录一、Modbus/TCP协议1.查询报文2.响应报文二、从机代码1.初始化从机网络2.简单响应函数3.main函数循环等待连接三、效果四、总结五、源码一、Modbus/TCP协议功能码作用01读取线圈状态02读取输入状态03读取保持寄存器04读取输... 查看详情

基于stm32f103的智能门禁系统

....96寸四针OLED显示模块(IIC)用于界面显示54x4矩阵按键(优信电子的)按键解锁6HC-05蓝牙模块发验证码7继电器模拟开锁8蜂鸣器开锁响声9面包板拓展电源接口3.实现功能OLED锁屏界面1.1按键退出主界面指纹解锁刷卡... 查看详情

stm32f103(十八)adc总结(贼详细)

...器实验(库函数+寄存器)STM32F103五分钟入门系列(五)按键实验(库函数+寄存器)STM32F103五分钟入门系列(六)时钟框图+相关寄存器总结+系统时钟来源代码(寄存器) 查看详情

stm32f103实现iap在线升级应用程序(代码片段)

...ationProgramming”,中文解释为“在程序中编程”。IAP是一种对通过微控制器的对外接口 查看详情

stm32f103(二十三)通用同步异步收发器(usart)

...器实验(库函数+寄存器)STM32F103五分钟入门系列(五)按键实验(库函数+寄存器)STM32F103五分钟入门系列(六)时钟框图+相关寄存器总结+系统时钟来源代码(寄存器) 查看详情

精通《iic通信》

...器实验(库函数+寄存器)STM32F103五分钟入门系列(五)按键实验(库函数+寄存器)STM32F103五分钟入门系列(六)时钟框图+相关寄存器总结+系统时钟来源代码(寄存器) 查看详情

stm32f103zet6引脚说明

 stm32f103zet6是一种嵌入式-微控制器的集成电路(IC),是由ST公司开发的STM32F1系列的其中一种,芯体尺寸是32位,速度是72MHz,程序存储器容量是256KB,程序存储器类型是FLASH,RAM容量是48K。   stm32f103zet6详细参数如下: ... 查看详情

stm32f103(二十六)spi通信(+两块stm32之间的spi通信)

...器实验(库函数+寄存器)STM32F103五分钟入门系列(五)按键实验(库函数+寄存器)STM32F103五分钟入门系列(六)时钟框图+相关寄存器总结+系统时钟来源代码(寄存器) 查看详情

stm32f103移植freemodbus主机协议实现modbus主机

...Enable();2.在一个大循环中调用​​eMBMasterPoll​​​。三、操作从机usModbusUserData[0 查看详情

基于stm32f103的智能门禁系统

....96寸四针OLED显示模块(IIC)用于界面显示54x4矩阵按键(优信电子的)按键解锁6HC-05蓝牙模块发验证码7继电器模 查看详情

stm32f103(二十五)完美解决usart发送接收floatu16u32数据

...器实验(库函数+寄存器)STM32F103五分钟入门系列(五)按键实验(库函数+寄存器)STM32F103五分钟入门系列(六)时钟框图+相关寄存器总结+系统时钟来源代码(寄存器) 查看详情

stm32f103(二十七)超长篇解读stm32访问外部flash(代码片段)

...数+寄存器)STM32F103五分钟入门系列(五)按键实验(库函数+寄存器)STM32F103五分钟入门系列(六)时钟框图+相关寄存器总结+系统时钟来源代码(寄存器)STM32F103五分钟入门系列(七)... 查看详情

stm32学习笔记二基于stm32f103c8t6和stm32cubemx实现uart串口通信数据收发(代码片段)

系列文章目录一、基于STM32F103C8T6最小系统板和STM32CubeMX实现LED灯循环闪烁二、基于STM32F103C8T6和STM32CubeMX实现UART串口通信数据收发三、实战小例程基于STM32F103C8T6最小系统板和STM32CubeMX驱动WS2812B光立方四、基于STM32F103C8T6最小系统板... 查看详情