IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> STM32 FIFO RINGBUFF -> 正文阅读

[嵌入式]STM32 FIFO RINGBUFF

目录

1、FIFO概述

1.1什么是FIFO

1.2什么时候使用FIFO

1.3FIFO最基本元素

2.FIFO的实现及相关函数

2.1FIFO结构体定义

2.2创建FIFO

2.3删除FIFO

2.4向FIFO中写入元素

2.5从FIFO中读取元素

2.6从FIFO中拷贝元素

2.7从FIFO中删除元素

2.8比较FIFO中的内容

2.9从FIFO接收内容中查找1

2.10从FIFO接收内容中查找2


1、FIFO概述

1.1什么是FIFO

? ? ? ? FIFO(fist in first out)中文直译先进先出,对应的有LIFO(last?in?first?out)。

1.2什么时候使用FIFO

? ? ? ? FIFO主要用来解决速率不匹配的问题而设计。以STM32中串口应用为例,串口以115200的波特率进行数据接收,接收一个字节大概需要87us,接收一帧数据100字节,需要耗时为870us(约等于1kHz)。以SMT32F407为例,单片机运行主频可达160MHz。单片机处理速度远高于串口的接收速度。所以此时就需要将数据接收到FIFO中进行暂存。

1.3FIFO最基本元素

? ? ? ? 该文所讲述的FIFO主要为后续的STM32串口所使用,所以涉及的数据宽度均为8位。一个FIFO需要的最基本元素如下。

  • 深度
  • 缓存地址
  • 写位置
  • 读位置
  • 使用量(或满标志位)

????????查看有一些关于C语言FIFO实现的文章中没有进行使用量(满标志)的定义,而是使用了写位置和读位置来进行FIFO使用量的计算。但是存在一个问题,当读取位置等于写入位置时,无法实现使用量的计算。因为FIFO为空时和FIFO为满时读取位置均等于写入位置。

? ? ? ? 考虑到FIFO使用的安全性还需要增加一个FIFO进行了初始化的标志位。因为后续文章中的FIFO缓存地址及FIFO地址均使用malloc申请内存进行处理,若FIFO没初始化,程序容易指向不确定位置造成错误。

2.FIFO的实现及相关函数

? ? ? ? 该文章所描述的FIFO主要用来后续STM32的串口通信使用,所以FIFO实现为数据可覆盖模式即当FIFO写入满时,再次进行写入对原有数据会进行覆盖。

2.1FIFO结构体定义

? ? ? ? 我们使用结构体来表示FIFO,具体定义如下

typedef struct
{
	INT16U				Depth;				//number of element can be stored 
	INT8U*	 			Buf;				//address of the buffer
	INT8U				InitFlag;			//flag of initialization
	//use volatile to limit,prevent errors when reading and writing at the same time
	volatile INT16U		Push;				//position of the push position
	volatile INT16U 	Pull;				//position of the pull position
	volatile INT16U 	CntUsed;			//number of the used element
}FifoTypeDef;

2.2创建FIFO

/**
***************************************************
* @brief   func_fifo_Create
* @note    创建FIFO,动态申请内存
* @param   depth        FIFO可存放元素的个数
* @retval  0:          申请内存失败
*          else:     	FIFO的地址
* @data    2021.07.01
* @auth    WXL
* @his     1.0.0.0     2021.07.01     WXL
* 				新建
***************************************************
**/
FifoTypeDef* func_fifo_Create(const INT16U depth)
{
	FifoTypeDef* p = malloc(sizeof(FifoTypeDef));
	if(p == NULL)
		return NULL;
	p->Buf = malloc(depth);
	if(p->Buf == NULL)
	{
		free(p);
		return NULL;
	}
	p->Depth 	= depth;
	p->CntUsed 	= 0;
	p->Push 	= 0;
	p->Pull 	= 0;
	p->InitFlag = FIFO_INITIAL;
	return p;
}

2.3删除FIFO

? ? ? ? FIFO删除前先进行FIFO初始化判断,若FIFO未初始化意味着FIFO创建失败或者未创建,指针不明确不进行操作。

/**
***************************************************
* @brief   func_fifo_Free
* @note    删除FIFO
* @param   p      指向待操作的FIFO
* @retval  EnumFifoErr
* @data    2021.07.01
* @auth    WXL
* @his     1.0.0.0     2021.07.01     WXL
* 				create
***************************************************
**/
FIFO_ERR_FAILED func_fifo_Free(FifoTypeDef* const p)
{
	if(p->InitFlag == FIFO_INITIAL)
	{
		free(p->Buf);
		free(p);
		return FIFO_ERR_OK;
	}
	return FIFO_ERR_FAILED;
}

2.4向FIFO中写入元素

? ? ?此函数为FIFO常规写入时调用。需要注意以下几个问题

  1. 写入到缓存末尾时需要重头进行写入
  2. 写入数据量大于FIFO深度时,只写入待写入数据的最后FIFO深度个数据
/**
***************************************************
* @brief   func_fifo_Push
* @note    向FIFO中写入数据
* @param   p      指向待操作FIFO
*          num    写入的字节数
*          data   指向写入数据的内存地址
* @retval  EnumFifoErr
* @data    2021.07.01
* @auth    WXL
* @his     1.0.0.0     2021.07.01     WXL
* 				create
***************************************************
**/
FIFO_ERR_FAILED func_fifo_Push(FifoTypeDef* const p,const INT16U num,const INT8U* const data)
{
	INT16U	offset = 0;
	INT16U	len2end = 0;

	if(p->InitFlag != FIFO_INITIAL)
		return FIFO_ERR_FAILED;

	//写入数据量大于FIFO的容量,存在多次覆盖的情况,仅写入最后的FIFO大小个元素
	if(num > p->Depth)
	{
		//计算写入数据的偏移地址
		offset = num - p->Depth;
		//计算写入位置
		p->Push = (p->Push + offset) % p->Depth;
		//若写入位置刚好位于buf的开始,进行fifo大小数据量的写入
		if(p->Push == 0)
			memcpy(p->Buf , data+offset , p->Depth);
		//写入位置不在头部
		else
		{
			//计算写入到末尾可写入的数量
			len2end = p->Depth - p->Push;
			//写入到buf末尾
			memcpy(p->Buf + p->Push , data+offset , len2end);
			//从头继续写入
			memcpy(p->Buf , data + offset + len2end , p->Depth - len2end);
		}
		//FIFO数据发生了覆盖
		p->Pull 		= p->Push;
		p->CntUsed 		= p->Depth;
	}
	//写入数据量不大于FIFO容量,全部数据可以写入到FIFO中。
	else
	{
		len2end = p->Depth - p->Push;
	    //从PUSH位置到BUFF末尾可容纳写入数据
		if(len2end >= num)
			memcpy(p->Buf + p->Push , data , num);
		//不能容纳,需要从头写入
		else
		{
			memcpy(p->Buf + p->Push , data , len2end);
			memcpy(p->Buf , data + len2end , num - len2end);
		}
		p->Push = (p->Push + num) % p->Depth;
		p->CntUsed += num;
		//FIFO被写满,发生覆盖现象。
		if(p->CntUsed >= p->Depth)
		{
			p->Pull 		= p->Push;
			p->CntUsed 		= p->Depth;
		}
	}
	return FIFO_ERR_OK;
}

下面的写入函数用于STM32的串口使用DMA模式接收时,将DMA的缓冲器地址直接指向FIFO地址,数据会自动进行写入,但是FIFO的PULL,PUSH等相关变量不会自动更新。需要在接收数据完成后记性相关变量的操作。

/**
***************************************************
* @brief   func_fifo_push_nodata
* @note    不进行数据的写入,只操作fifo相关参数,用于DMA直接写入FIFO数据时,中断中处理FIFO参数
* @param   p      指向待操作FIFO
*          num    写入数据量
* @retval  NONE
* @data    2021.07.01
* @auth    WXL
* @his     1.0.0.0     2021.07.01     WXL
* 				create
***************************************************
**/
void func_fifo_PushNoData(FifoTypeDef* const p,const INT16U num)
{
	p->Push = (p->Push + num) % p->Depth;
	p->CntUsed += num;
	if(p->CntUsed >= p->Depth)
	{
		p->Pull 		= p->Push;
		p->CntUsed 		= p->Depth;
	}
}

2.5从FIFO中读取元素

/**
***************************************************
* @brief   func_fifo_pull
* @note    从FIFO中读取数据
* @param   p      指向待操作FIFO
*          num    读取数据的长度
*          buff   读取数据的缓冲区
* @retval  EnumFifoErr
* @data    2021.07.01
* @auth    WXL
* @his     1.0.0.0     2021.07.01     WXL
* 				create
***************************************************
**/
EnumFifoErr func_fifo_Pull(FifoTypeDef* const p,const INT16U num,const void* const buff)
{
	//读取大于使用量或者未初始化
	if(num > p->CntUsed || p->InitFlag != FIFO_INITIAL)
		return FIFO_ERR_FAILED;

	//计算到末尾可读取数量
	INT8U len2end = p->Depth - p->Pull;
	//读取到buff结尾满足num数量
	if(len2end > num)
	{
		memcpy(buff , p->Buf + p->Pull , num);
		memset(p->Buf + p->Pull , 0 , num);
	}
	//需要从头读取
	else
	{
		memcpy(buff , p->Buf + p->Pull , len2end);
		memset(p->Buf + p->Pull , 0 , len2end);

		memcpy(buff + len2end , p->Buf , num-len2end);
		memset(p->Buf , 0 , num-len2end);
	}
	p->Pull = (p->Pull + num) % p->Depth;
	p->CntUsed -= num;
	return FIFO_ERR_OK;
}

2.6从FIFO中拷贝元素

? ? ? ? 不同于上面的读取函数,改函数只进行元素的拷贝,不对FIFO的参数进行修改。?

/**
***************************************************
* @brief   func_fifo_Copy
* @note    拷贝FIFO中PULL位置后的第ind开始的len个数据到data
* @param   p      	指向待操作FIFO
*          ind	  	pull后面的第ind个元素
*          len		数据长度
*          data		指向存储较数据
* @retval  FIFO_ERR_OK	 		 成功
*          FIFO_ERR_FAILED      失败
* @data    2021.07.01
* @auth    WXL
* @his     1.0.0.0     2021.07.01     WXL
* 				create
***************************************************
**/
EnumFifoErr func_fifo_Copy(FifoTypeDef* const p,const INT16U ind, const INT16U len, const INT8U* data)
{
	if(ind + len > p->CntUsed || p->InitFlag != FIFO_INITIAL)
		return FIFO_ERR_FAILED;

	INT8U* point = p->Buf + p->Pull + ind;
	INT8U* end_position = p->Buf + p->Depth - 1;

	if(point > end_position)
	{
		point = point - p->Depth;
		memcpy(data,point,len);
		return FIFO_ERR_OK;
	}
	else
	{
		INT16U len2end = end_position - point + 1;
		if(len2end >= len)
		{
			memcpy(data,point,len);
			return FIFO_ERR_OK;
		}
		else
		{
			memcpy(data,point,len2end);
			memcmp(data+len2end,p->Buf,len-len2end);
			return FIFO_ERR_OK;
		}
	}
}

2.7从FIFO中删除元素

? ? ? ? 功能类似于上面的读取元素,但是读取元素时需要指明读取元素的存放地址。该函数不需要。直接操作FIFO,删除num个元素。同样需要注意指针回头问题。

/**
***************************************************
* @brief   func_fifo_DeleteElement
* @note    删除FIFO中的元素,对FIFO结构体进行相应操作
* @param   p      指向待操作FIFO
*          num    删除的数量
* @retval  EnumFifoErr
* @data    2021.07.01
* @auth    WXL
* @his     1.0.0.0     2021.07.01     WXL
* 				create
***************************************************
**/
EnumFifoErr func_fifo_DeleteElement(FifoTypeDef* const p,const INT16U num)
{
	if(num > p->CntUsed || p->InitFlag != FIFO_INITIAL)
		return FIFO_ERR_FAILED;

	INT8U len2end = p->Depth - p->Pull;
	if(len2end > num)
		memset(p->Buf + p->Pull , 0 , num);
	else
	{
		memset(p->Buf + p->Pull , 0 , len2end);
		memset(p->Buf , 0 , num - len2end);
	}
	p->CntUsed -= num;
	p->Pull = (p->Pull+num) % p->Depth;
	return FIFO_ERR_OK;
}

2.8比较FIFO中的内容

? ? ? ? 从FIFO中PULL位置开始的第ind个元素长度为len的数据是否与data相等。

/**
***************************************************
* @brief   func_fifo_Cmp
* @note    从FIFO的PULL开始的第ind个数据与len长度的data进行比较
* @param   p      	指向待操作FIFO
*          ind	  	pull后面的第ind个元素
*          len		比较的数据长度
*          data		指向待比较数据
* @retval  EnumFifoErr
* @data    2021.07.01
* @auth    WXL
* @his     1.0.0.0     2021.07.01     WXL
* 				create
***************************************************
**/
EnumFifoErr func_fifo_Cmp(FifoTypeDef* const p,const INT16U ind, const INT16U len, const INT8U* data)
{
	if(ind + len > p->CntUsed || p->InitFlag != FIFO_INITIAL)
		return FIFO_ERR_FAILED;

	INT8U* point = p->Buf + p->Pull + ind;
	INT8U* end_position = p->Buf + p->Depth - 1;

	if(point > end_position)
	{
		point = point - p->Depth;
		if(memcmp(data,point,len) == 0)
			return FIFO_ERR_OK;
		else
			return FIFO_ERR_FAILED;
	}
	else
	{
		INT16U len2end = end_position - point + 1;
		if(len2end >= len)
		{
			if(memcmp(data,point,len) == 0)
				return FIFO_ERR_OK;
			else
				return FIFO_ERR_FAILED;
		}
		else
		{
			if(memcmp(data,point,len2end) == 0 && memcmp(data+len2end,p->Buf,len-len2end) == 0 )
				return FIFO_ERR_OK;
			else
				return FIFO_ERR_FAILED;
		}
	}
}

2.9从FIFO接收内容中查找1

? ? ? ? 从FIFO中查找长度为len的data数据,对不符合的内容进行删除。

/**
***************************************************
* @brief   func_fifo_FindDataDelete
* @note    从FIFO中查找长度为len的data数据对不符合数据进行删除
* @param   p      	指向待操作FIFO
*          len	            查找数据的长度
*          data		指向查找数据
* @retval  EnumFifoErr
* @data    2021.07.01
* @auth    WXL
* @his     1.0.0.0     2021.07.01     WXL
* 				create
***************************************************
**/
EnumFifoErr func_fifo_FindDataDelete(FifoTypeDef* const p, const INT16U len, const INT8U* data)
{
	while(p->CntUsed >= len  || p->InitFlag != FIFO_INITIAL)
	{
		if(func_fifo_Cmp(p,0,len,data) == FIFO_ERR_OK)
			return FIFO_ERR_OK;
		else
			func_fifo_DeleteElement(p,1);
	}
	return FIFO_ERR_FAILED;
}

2.10从FIFO接收内容中查找2

/**
***************************************************
* @brief   func_fifo_FindData
* @note    从FIFO中查找长度为len的data数据对,将查找到的序号赋值给pos
* @param   p      	指向待操作FIFO
*          ind		pull后面的第几个
*          len	            查找数据的长度
*          data		指向查找数据
*          pos		查找到的位置
* @retval  FIFO_ERR_OK	 		 成功
*          FIFO_ERR_FAILED      失败
* @data    2021.07.01
* @auth    WXL
* @his     1.0.0.0     2021.07.01     WXL
* 				create
***************************************************
**/
EnumFifoErr func_fifo_FindData(FifoTypeDef* const p, const INT16U ind, const INT8U* data,INT16U len, INT16U* pos)
{
	INT16U times = 0;
	INT16U cycle = 0;

	if(p->CntUsed >= ind + len  || p->InitFlag == FIFO_INITIAL)
	{
		times = p->CntUsed - ind - len + 1;
		while(cycle < times)
		{
			if(func_fifo_Cmp(p,ind+cycle,len,data) == FIFO_ERR_OK)
			{
				*pos = cycle;
				return FIFO_ERR_OK;
			}
			cycle++;
		}
		return FIFO_ERR_FAILED;
	}
	return FIFO_ERR_FAILED;
}

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-07-10 14:41:08  更:2021-07-10 14:41:36 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/3 16:38:54-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码