STM32高级篇—按键FIFO

想成问一名非常优秀的嵌入式软件工程师,是需要掌握很多知识的。
完成STM32的基础内容的学习后,我们也进入到学习STM32高级的内容上。
本人也是一名嵌入式的初级入坑人,写的内容可能会有错误,或者不正确的地方也请大家多多指教,我们一起努力。

一、FIFO(先进先出)

1.1 按键FIFO的意义

通常情况下,我们再判断按键是否按下的时候,是采用中断的方式进行设计的,过多的使用中断,会导致程序实现的不稳定,因此需要设计FIFO按键模式,设计按键FIFO主要有几方面的好处:
1)可以有效地记录按键事件的发生,尤其使对按键的按下,长按,弹起等事件的发生,使用FIFO的方式实现是一种非常好的思路。
2)系统是非阻塞的,这样系统在检测到按键按下的情况下,由于机械按键抖动的原因不需要再这里等待一段事件,然后再确定按键是否按下。

1.2 FIFO的实现

FIFO的基本思想,就是先进先出,还是比较好理解的,我们以几张图为代表,就可以轻松的搞定。我们以5个字节的FIFO空间为例子。Read和Write分别表示读和写指针。
在这里插入图片描述分别按下按键,K1,K2,K3按键被按下的事件将进入FIFO当中。如下所示。这个时候写指针会根据写入的事件从而发生改变。
在这里插入图片描述
通过读指针,实现对按键事件的读写操作。
在这里插入图片描述

二、按键FIFO的实现

2.1 按键FIFO的初始化

/* 
******************************************************************************************* 
* 函 数 名: KeyFifoVar_Init 
* 功能说明: 初始化每一个按键对应的结构体
* 形    参:  无 
* 返 回 值: 无 
*******************************************************************************************
*/
static void KeyFifoVar_Init(void)
{
	uint8_t i;
	
	// 初始化读写指针
	s_tKey.Read = 0;
	s_tKey.Write = 0;  
	
	// 给每个按键结构体成员变量赋一组值
	for(i = 0; i < KEY_NUM; i++)
	{
		s_tBtn[i].LongTime = KEY_LONG_TIME;
		s_tBtn[i].Count = KEY_FILTER_TIME;
		s_tBtn[i].State = 0;
		s_tBtn[i].RepeatCount = 0;
		s_tBtn[i].RepeatSpeed = 0;
		s_tBtn[i].LongTime = 0; 
	}
	 
  /* 如果需要单独更改某个按键的参数,可以在此单独重新赋值 */ 
  /* 比如,我们希望按键1按下超过1秒后,自动重发相同键值 */ 
  s_tBtn[1].LongTime = 100; 
  s_tBtn[1].RepeatSpeed = 5; /* 每隔50ms自动发送键值 */ 
	
	s_tBtn[0].IsKeyDownFunc = IsKeyDown1;
	s_tBtn[1].IsKeyDownFunc = IsKeyDown2;
	s_tBtn[2].IsKeyDownFunc = IsKeyDown3;
	s_tBtn[3].IsKeyDownFunc = IsKeyDown4;
}
// 定义键值代码,必须按如下的顺序设计每一个案件的按下, 弹起,和长按
typedef enum
{
	KEY_NONE = 0,   // 0 表示按键事件
	KEY_1_DOWN,
	KEY_1_UP,
	KEY_1_LONG,
	
	KEY_2_DOWN,
	KEY_2_UP,
	KEY_2_LONG,
	
	KEY_3_DOWN,
	KEY_3_UP,
	KEY_3_LONG,
	
	KEY_4_DOWN,
	KEY_4_UP,
	KEY_4_LONG,
}KEY_ENUM;

2.2 按键FIFO功能的实现

/* 
******************************************************************************************* 
* 函 数 名: Fifo_PutKey 
* 功能说明: 将1个键值压入按键FIFO缓冲区。可用于模拟一个按键。
* 形    参:  _KeyCode:按键代码 
* 返 回 值: 无 
*******************************************************************************************
*/
void Fifo_PutKey(uint8_t _KeyCode)
{
	s_tKey.Buff[s_tKey.Write] = _KeyCode;
	
	if(++s_tKey.Write >= KEY_FIFO_SIZE)
	{
		s_tKey.Write = 0;
	}
}
/* 
******************************************************************************************* 
* 函 数 名: Fifo_GetKey 
* 功能说明: 从按键FIFO缓冲区读取一个键值。
* 形    参: 无
* 返 回 值: 按键代码 
*******************************************************************************************
*/
uint8_t Fifo_GetKey(void)
{
	uint8_t ret;
	
	if(s_tKey.Read == s_tKey.Write)
	{
		return KEY_NONE;
	}
	else
	{
		ret = s_tKey.Buff[s_tKey.Read];
		if(++s_tKey.Read >= KEY_FIFO_SIZE)
		{
			s_tKey.Read = 0;
		}
		return ret;
	}
}

2.3 按键扫描功能实现

/* 
******************************************************************************************* 
* 函 数 名: DetectKey 
* 功能说明: 按键检测
* 形    参:  无 
* 返 回 值: 无 
*******************************************************************************************
*/
static void DetectKey(uint8_t i)
{
	KEY_T *pBtn;
	pBtn = &s_tBtn[i];
	
	if(pBtn->IsKeyDownFunc()) 
	{
		if(pBtn->Count < KEY_FILTER_TIME)
		{
			pBtn->Count = KEY_FILTER_TIME;
		}
		else if(pBtn->Count < 2 * KEY_FILTER_TIME)
		{
			pBtn->Count++;
		}
		else
		{
			if(pBtn->State == 0)
			{
				pBtn->State = 1;
				
				// 如FIFO
				Fifo_PutKey((uint8_t)(3*i + 1)); 
			}
			// 判断按键是否长按
			if(pBtn->LongTime >0)
			{
				if(pBtn->LongCount < pBtn->LongTime)
				{
					if(++pBtn->LongCount == pBtn->LongTime)
					{
						Fifo_PutKey((uint8_t)(3*i + 3));
					}
				}
				else
				{
					if(pBtn->RepeatSpeed > 0)
					{
						if(pBtn->RepeatCount >= pBtn->RepeatSpeed)
						{
							pBtn->RepeatCount = 0;
							// 常安按键,每隔10ms发送1个按键
							Fifo_PutKey((uint8_t)(3*i + 1));
						}
					}
				}
			}
		}
	}
	else
	{
		if(pBtn->Count > KEY_FILTER_TIME)
		{
			pBtn->Count = KEY_FILTER_TIME;
		}
		else if(pBtn->Count != 0)
		{
			pBtn->Count--;
		}
		else
		{
			if(pBtn->State == 1)
			{
				pBtn->State = 0;
				
				// 发送按键弹起的消息
				Fifo_PutKey((uint8_t)(3*i + 2));
			}
		}
		pBtn->LongCount = 0;
		pBtn->RepeatCount = 0;
	}
}
/* 
******************************************************************************************* 
* 函 数 名: KeyScan 
* 功能说明: 按键扫描
* 形    参: 无
* 返 回 值: 按键代码 
*******************************************************************************************
*/
void KeyScan_Task(void)
{
	uint8_t i;
	for(i = 0 ; i < KEY_NUM; i++)
	{
		DetectKey(i);
	}
}

相关推荐

  1. stm32高级定时器

    2024-06-12 09:38:02       20 阅读
  2. STM32 CAN发送邮箱和接收FIFO

    2024-06-12 09:38:02       26 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-12 09:38:02       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-12 09:38:02       100 阅读
  3. 在Django里面运行非项目文件

    2024-06-12 09:38:02       82 阅读
  4. Python语言-面向对象

    2024-06-12 09:38:02       91 阅读

热门阅读

  1. 【神经网络】资源

    2024-06-12 09:38:02       29 阅读
  2. css连续动画(动画组)

    2024-06-12 09:38:02       25 阅读
  3. Solidity智能合约事件(event)

    2024-06-12 09:38:02       32 阅读
  4. 镜像没有包含 shell 导致无法进入容器

    2024-06-12 09:38:02       25 阅读
  5. openssl工具国际/国密签名命令行流程

    2024-06-12 09:38:02       27 阅读
  6. 互联网摸鱼日报(2024-06-11)

    2024-06-12 09:38:02       31 阅读
  7. 安装TensorFlow2.12.0

    2024-06-12 09:38:02       32 阅读
  8. Linux信号基础

    2024-06-12 09:38:02       26 阅读
  9. 介绍 TensorFlow 的基本概念和使用场景。

    2024-06-12 09:38:02       34 阅读