[其他ST产品] STM32 C语言编写环形存储区

[复制链接]
1071|17
 楼主| 梵蒂冈是神uy 发表于 2022-11-30 15:43 | 显示全部楼层 |阅读模式
前言
在产品开发中经常碰到帧数据丢失或接收过来非整帧的情况,为增加代码的可靠性,采用环形存储区的方式将数据先行缓存,然后进行帧判断、解析、执行。

一、环形存储区简介
简言之,环形存储区就是我们定义或者动态分配的一段连续的数据存储区域。其工作过程是通过头和尾两个索引在这段连续的存储区域进行数据的读出和写入,就好像将这一块儿连续的数据存储区行程了一个闭环,这就是环形的含义。
当数据写入时尾索引增加,当数据读取时头索引增加。具有FIFO的特性。
由以上可知,要将一个连续存储区域作为环形存储区需要四个元素:连续存储区域首地址、连续存储区域大小、头索引及尾索引。

 楼主| 梵蒂冈是神uy 发表于 2022-11-30 15:44 | 显示全部楼层
环形存储区C语言代码实现
废话不多说,直接贴出代码。本代码亲测通过,希望能够帮助有需要的同学。如果正式你需要的或者能够帮助你希望点个赞呦。
 楼主| 梵蒂冈是神uy 发表于 2022-11-30 15:45 | 显示全部楼层
RingBuff.c文件实现
  1. #include "RingBuff.h"

  2. /**
  3. * [url=home.php?mod=space&uid=247401]@brief[/url] 环形缓冲区初始化
  4. * @param[in] pRingBuff 环形缓冲区结构体地址
  5. * @param[in] buf_size  环形缓存区大小(字节数)
  6. * @return[out]  
  7. */
  8. void RingBuff_Init(RingBuff_t *pRingBuff, unsigned int buf_size)
  9. {
  10.         RingBuff_t                 *ringbuff         = NULL;
  11.         unsigned int         size                 = 0;

  12.         ringbuff = pRingBuff;
  13.         size         = buf_size;
  14.        
  15.         ringbuff->buffer = (uint8_t*)calloc(size, sizeof(uint8_t));
  16.         ringbuff->size = size;
  17.         ringbuff->head = 0;
  18.         ringbuff->tail = 0;       
  19. }


  20. /**
  21. * @brief 判断环形缓冲区是否为空
  22. * @param[in] pRingBuff 环形缓冲区结构体地址
  23. * @return[out]          RING_TRUE                空
  24. *                                         RING_FALSE                非空
  25. */
  26. static unsigned char RingBuff_isEmpty(RingBuff_t *pRingBuff)
  27. {
  28.         RingBuff_t *ringbuff = NULL;

  29.         ringbuff = pRingBuff;

  30.         if(ringbuff->head == ringbuff->tail)
  31.         {
  32.                 return RING_TRUE;
  33.         }
  34.         return RING_FALSE;
  35. }


  36. /**
  37. * @brief 判断环形缓冲区是否为满
  38. * @param[in] pRingBuff 环形缓冲区结构体地址
  39. * @return[out]          RING_TRUE                满
  40. *                                         RING_FALSE                非满
  41. */
  42. static unsigned char RingBuff_isFull(RingBuff_t *pRingBuff)
  43. {
  44.         RingBuff_t *ringbuff = NULL;

  45.         ringbuff = pRingBuff;

  46.         if((ringbuff->tail + 1) % ringbuff->size == ringbuff->head)
  47.         {
  48.                 return RING_TRUE;
  49.         }
  50.         return RING_FALSE;
  51. }


  52. /**
  53. * @brief 从环形缓冲区头部读出一个字节
  54. * @param[in] pRingBuff 环形缓冲区结构体地址
  55. * @param[in] pData         读出缓冲区字节所将要存储的地址
  56. * @return[out]  RING_OK        读出成功,
  57. *                                  RING_ERR        读出失败
  58. */
  59. static unsigned char RingBuff_ReadOneByte(RingBuff_t *pRingBuff, unsigned char *pData)
  60. {
  61.         RingBuff_t                 *ringbuff = NULL;
  62.         unsigned char         *temp = NULL;

  63.         ringbuff = pRingBuff;
  64.         temp         = pData;

  65.         //判空
  66.         if(RING_TRUE == RingBuff_isEmpty(ringbuff))
  67.         {
  68.                 SYSlog("ring buffer is empty!\r\n");
  69.                 return RING_ERR;
  70.         }

  71.         *temp = ringbuff->buffer[ringbuff->head];
  72.         ringbuff->head = (ringbuff->head + 1) % ringbuff->size;
  73.         return RING_OK;
  74. }


  75. /**
  76. * @brief 向环形缓冲区的尾部写入一个字节
  77. * @param[in] pRingBuff 环形缓冲区结构体地址
  78. * @param[in] pData         将要写入缓冲区的字节的地址
  79. * @return[out]  RING_OK        写入成功,
  80. *                                  RING_ERR        写入失败
  81. */
  82. static unsigned char RingBuff_WriteOneByte(RingBuff_t *pRingBuff, unsigned char *pData)
  83. {
  84.         RingBuff_t                 *ringbuff = NULL;
  85.         unsigned char         *temp = NULL;

  86.         ringbuff = pRingBuff;
  87.         temp         = pData;

  88.         //判满
  89.         if(RING_TRUE == RingBuff_isFull(ringbuff))
  90.         {
  91.                 SYSlog("ring buffer is full!\r\n");
  92.                 return RING_ERR;
  93.         }

  94.         ringbuff->buffer[ringbuff->tail] = *temp;
  95.         ringbuff->tail = (ringbuff->tail + 1) % ringbuff->size;
  96.         return RING_OK;
  97. }


  98. /**
  99. * @brief 从环形缓冲区读出多个字节
  100. * @param[in] pRingBuff 环形缓冲区结构体地址
  101. * @param[in] pData         读出缓冲区多字节将要存储的首地址
  102. * @param[in] Size                读出环形缓冲区的字节数
  103. * @return[out]  RING_OK        读出成功,
  104. *                                  RING_ERR        读出失败
  105. */
  106. unsigned char RingBuff_ReadNByte(RingBuff_t *pRingBuff, unsigned char *pData, int Size)
  107. {
  108.         RingBuff_t                 *ringbuff = NULL;
  109.         unsigned char         *temp = NULL;
  110.         int                                size = 0;

  111.         ringbuff = pRingBuff;
  112.         temp         = pData;
  113.         size         = Size;

  114.         for(int i = 0; i < size; i++)
  115.         {
  116.                 if(RingBuff_ReadOneByte(ringbuff, temp + i) == RING_ERR)
  117.                 {
  118.                         return RING_ERR;
  119.                 }
  120.         }
  121.         return RING_OK;
  122. }

  123. //
  124. /**
  125. * @brief 向环形缓冲区写入多个字节
  126. * @param[in] pRingBuff 环形缓冲区结构体地址
  127. * @param[in] pData         将要写入缓冲区多字节的首地址
  128. * @param[in] Size                写入环形缓冲区的字节数
  129. * @return[out]  RING_OK        写入成功,
  130. *                                  RING_ERR        写入失败
  131. */
  132. unsigned char RingBuff_WriteNByte(RingBuff_t *pRingBuff, unsigned char *pData, int Size)
  133. {
  134.         RingBuff_t                 *ringbuff = NULL;
  135.         unsigned char         *temp = NULL;
  136.         int                                size = 0;

  137.         ringbuff = pRingBuff;
  138.         temp         = pData;
  139.         size         = Size;

  140.         for(int i = 0; i < size; i++)
  141.         {
  142.                 if(RingBuff_WriteOneByte(ringbuff, temp + i) == RING_ERR)
  143.                 {
  144.                         return RING_ERR;
  145.                 }
  146.         }
  147.         return RING_OK;
  148. }


  149. /**
  150. * @brief 获取当前环形缓冲区中有效数据的长度
  151. * @param[in] pRingBuff 环形缓冲区结构体地址
  152. * @return[out]          有效数据长度
  153. */
  154. int RingBuff_GetValidLen(RingBuff_t *pRingBuff)
  155. {
  156.         RingBuff_t         *ringbuff         = NULL;
  157.         int                 temp                 = 0;
  158.         ringbuff = pRingBuff;

  159.         if(ringbuff->tail >= ringbuff->head)
  160.         {
  161.                 temp = ringbuff->tail - ringbuff->head;
  162.         }
  163.         else
  164.         {
  165.                 temp =  ringbuff->tail + ringbuff->size - ringbuff->head;
  166.         }

  167.         return temp;
  168. }


  169. /**
  170. * @brief 获取当前环形缓冲区中空闲数据的长度
  171. * @param[in] pRingBuff 环形缓冲区结构体地址
  172. * @return[out]          空闲数据长度
  173. */
  174. int RingBuff_GetIdleLen(RingBuff_t *pRingBuff)
  175. {
  176.         RingBuff_t         *ringbuff         = NULL;
  177.     int                 temp                 = 0;
  178.         ringbuff = pRingBuff;

  179.         if(ringbuff->tail >= ringbuff->head)
  180.         {
  181.                 temp = ringbuff->size - ringbuff->tail + ringbuff->head;
  182.         }
  183.         else
  184.         {
  185.                 temp = ringbuff->head - ringbuff->tail;
  186.         }
  187.        
  188.         return temp;
  189. }


  190. /**
  191. * @brief 获取当前头部数据
  192. * @param[in] pRingBuff 环形缓冲区结构体地址
  193. * @return[out]          当前头部数据
  194. */
  195. unsigned char RingBuff_GetHeadItem(RingBuff_t *pRingBuff)
  196. {
  197.         unsigned char temp = 0;
  198.         RingBuff_t         *ringbuff = NULL;

  199.         ringbuff = pRingBuff;
  200.        
  201.         temp = ringbuff->buffer[ringbuff->head];

  202.         return temp;
  203. }


  204. /**
  205. * @brief 获取指定下标数据
  206. * @param[in] pRingBuff 环形缓冲区结构体地址
  207. * @param[in] index     环形缓冲区下标(环形缓冲区首地址的偏移量)
  208. * @return[out]          环形缓冲区下标指定的数据
  209. */
  210. unsigned char RingBuff_GetIndexItem(RingBuff_t *pRingBuff, int index)
  211. {
  212.         unsigned char res = 0;
  213.         RingBuff_t         *ringbuff = NULL;
  214.         int                 temp          = 0;

  215.         ringbuff = pRingBuff;
  216.         temp         = index;

  217.         res = ringbuff->buffer[temp % ringbuff->size];

  218.         return res;
  219. }


  220. /**
  221. * @brief 释放环形缓冲区
  222. * @param[in] pRingBuff 环形缓冲区结构体地址
  223. * @return[out]         
  224. */
  225. void RingBuff_Release(RingBuff_t *pRingBuff)
  226. {
  227.         RingBuff_t         *ringbuff = NULL;

  228.         ringbuff = pRingBuff;

  229.         free(ringbuff->buffer);
  230.         ringbuff->size = 0;
  231.         ringbuff->head = 0;
  232.         ringbuff->tail = 0;
  233. }
 楼主| 梵蒂冈是神uy 发表于 2022-11-30 15:45 | 显示全部楼层
RingBuff.h文件实现
  1. #ifndef __RingBuff_H_
  2. #define __RingBuff_H_

  3. #include    <stdlib.h>
  4. #include    <string.h>
  5. #include    "main.h"
  6. #include    "usart.h"


  7. enum
  8. {
  9.         RING_FALSE,
  10.         RING_TRUE,
  11. };

  12. enum
  13. {
  14.         RING_ERR,
  15.         RING_OK,
  16. };

  17. typedef struct ringBuff{
  18.     unsigned char *buffer; //数据缓冲区指针
  19.     unsigned int size;     //队列的大小
  20.     unsigned int head;     //队列的头部,读取之后偏移            
  21.     unsigned int tail;     //队列的尾部,写入之后偏移   
  22. }RingBuff_t;

  23. void RingBuff_Init(RingBuff_t *pRingBuff, unsigned int buf_size);
  24. unsigned char RingBuff_ReadNByte(RingBuff_t *pRingBuff, unsigned char *pData, int Size);
  25. unsigned char RingBuff_WriteNByte(RingBuff_t *pRingBuff, unsigned char *pData, int Size);
  26. int RingBuff_GetValidLen(RingBuff_t *pRingBuff);
  27. int RingBuff_GetIdleLen(RingBuff_t *pRingBuff);
  28. unsigned char RingBuff_GetHeadItem(RingBuff_t *pRingBuff);
  29. unsigned char RingBuff_GetIndexItem(RingBuff_t *pRingBuff, int index);
  30. void RingBuff_Release(RingBuff_t *pRingBuff);
  31. #endif /* __RingBuff_H_ */
 楼主| 梵蒂冈是神uy 发表于 2022-11-30 15:46 | 显示全部楼层
总结
以上就是想要分享的内容,感谢大家阅读交流,不对支持敬请指正。
51xlf 发表于 2022-11-30 23:40 | 显示全部楼层
有完整的工程文件吗?
zerorobert 发表于 2022-12-14 10:03 | 显示全部楼层
如何创建环形缓存               
pl202 发表于 2022-12-14 10:58 | 显示全部楼层
这个数据会出现覆盖的吗?              
mikewalpole 发表于 2022-12-17 14:26 | 显示全部楼层
缓冲区其实就是一个存储区域,它是由专门的硬件寄存器所组成的。  
Undshing 发表于 2022-12-17 16:23 | 显示全部楼层
可以分享一下工程文件吗?
iyoum 发表于 2022-12-17 21:40 | 显示全部楼层
环形存储区就是我们定义或者动态分配的一段连续的数据存储区域。
mollylawrence 发表于 2022-12-18 11:23 | 显示全部楼层
调用同一接口如串口时,会出现干涉情况。  
51xlf 发表于 2022-12-18 12:06 | 显示全部楼层
这个可以应用其他的单片机上的吗?
mikewalpole 发表于 2022-12-18 17:03 | 显示全部楼层
环形缓冲区算法在哪里呢              
lihuami 发表于 2022-12-18 17:43 | 显示全部楼层
怎样用c语言实现一个环形缓存区!  
everyrobin 发表于 2022-12-18 19:50 | 显示全部楼层
STM32串口开发之环形缓冲区  
pixhw 发表于 2023-1-14 17:27 | 显示全部楼层
FIFO机制在嵌入式开发中串口数据收发处理相当方便
51xlf 发表于 2023-1-19 13:33 | 显示全部楼层
这个可以shixainFIFO环形存储器吗?
您需要登录后才可以回帖 登录 | 注册

本版积分规则

53

主题

735

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部