STM32上使用的环形FIFO队列,用于缓存待发送数据

C语言实现的环形FIFO队列,用于线程异步通信,数据发送非常方便,比如GPRS发送数据,一个线程将数据写入到FIFO,发送线程不停的从FIFO中读取数据,然后发送,又比如上位机中,数据接收线程不停的接收数据,写入到FIFO,另一个异步的处理线程不停的读取数据,进行处理。


  
  
  1. /*************************************************************************************************************
  2. * 文件名: SendDataFIFO.c
  3. * 功能: 实时数据发送缓冲区
  4. * 作者: cp1300@139.com
  5. * 创建时间: 2015-08-09
  6. * 最后修改时间: 2017-08-26
  7. * 详细: 用于数据发送缓冲区
  8. 2017-08-26:增加溢出回调函数,可以对溢出的数据进行处理,用于FIFO嵌套
  9. *************************************************************************************************************/
  10. #include "system.h"
  11. #include "usart.h"
  12. #include "led.h"
  13. #include "main.h"
  14. #include "SendDataFIFO.h"
  15. #include "SYSMalloc.h"
  16. #define FIFO_INIT_STATUS_ID 0x354789d //用于标示是否初始化
  17. //初始化缓冲区
  18. bool FIFO_Init(FIFO_HANDLE *pHandle,u16 OneSize, u16 MaxCnt, void (*FullCallBack)(void *pData), bool isExtSRAM)
  19. {
  20. if(pHandle == NULL) return FALSE;
  21. if(isExtSRAM == TRUE) //是否使用外部缓冲区
  22. {
  23. pHandle->pFifoBuff = (u8 *)mymalloc(SRAMEX, OneSize*MaxCnt); //缓冲区指针,申请内存
  24. pHandle->pByteCntBuff = (u16 *)mymalloc(SRAMEX, sizeof(u16)*MaxCnt); //数据大小记录缓冲区,申请内存
  25. }
  26. else
  27. {
  28. pHandle->pFifoBuff = (u8 *)mymalloc(SRAMIN, OneSize*MaxCnt); //缓冲区指针,申请内存
  29. pHandle->pByteCntBuff = (u16 *)mymalloc(SRAMIN, sizeof(u16)*MaxCnt); //数据大小记录缓冲区,申请内存
  30. }
  31. //uart_printf("pHandle->pFifoBuff=0x%X\r\n", (u32)pHandle->pFifoBuff);
  32. //uart_printf("pHandle->pByteCntBuff=0x%X\r\n", (u32)pHandle->pByteCntBuff);
  33. if(pHandle->pFifoBuff== NULL)
  34. {
  35. DEBUG( "pHandle->pFifoBuff申请内存出错\r\n");
  36. }
  37. if(pHandle->pByteCntBuff== NULL)
  38. {
  39. DEBUG( "pHandle->pByteCntBuff申请内存出错\r\n");
  40. }
  41. pHandle->InitStatus = 0; //初始化成功状态无效
  42. if((pHandle->pFifoBuff== NULL)||(pHandle->pByteCntBuff== NULL)) return FALSE;
  43. pHandle->OneSize = OneSize; //单条数据大小
  44. pHandle->Cnt = MaxCnt; //缓冲区总数据容量(条数)
  45. pHandle->ReadCnt = 0; //读取位置
  46. pHandle->WriteCnt = 0; //写位置
  47. pHandle->NotReadCnt = 0; //未读取数量
  48. pHandle->FullCallBack = FullCallBack; //溢出回调函数
  49. pHandle->InitStatus = FIFO_INIT_STATUS_ID; //初始化成功状态有效
  50. return TRUE;
  51. }
  52. //写入一条数据
  53. //当缓冲区满了后,缓存最新的数据,丢掉最早的数据
  54. bool FIFO_Write(FIFO_HANDLE *pHandle,u8 *pBuff, u16 ByteCnt)
  55. {
  56. u16 cnt;
  57. #ifdef _UCOS_II_
  58. OS_CPU_SR cpu_sr;
  59. #endif
  60. if(pHandle == NULL) return FALSE;
  61. if(pHandle->InitStatus != FIFO_INIT_STATUS_ID) return FALSE; //没有初始化
  62. if (pHandle->NotReadCnt >= pHandle->Cnt) //发送溢出
  63. {
  64. cnt = pHandle->WriteCnt; //先将写指针后移,占位,防止多线程写冲突
  65. if(pHandle->FullCallBack!= NULL) pHandle->FullCallBack(&pHandle->pFifoBuff[cnt * pHandle->OneSize]);
  66. if (ByteCnt > pHandle->OneSize) ByteCnt = pHandle->OneSize; //限制单条数据大小
  67. pHandle->WriteCnt++;
  68. if (pHandle->WriteCnt >= pHandle->Cnt) pHandle->WriteCnt = 0; //环形FIFO
  69. pHandle->ReadCnt++; //读取数量增加
  70. if (pHandle->ReadCnt >= pHandle->Cnt) pHandle->ReadCnt = 0; //环形FIFO,把读写指针都增加,但是剩余数据数量不变
  71. pHandle->pByteCntBuff[cnt] = ByteCnt; //记录数据大小
  72. memcpy(&pHandle->pFifoBuff[cnt * pHandle->OneSize], pBuff, ByteCnt); //拷贝数据到缓冲区
  73. return FALSE; //数据已经满了
  74. }
  75. else
  76. {
  77. if (ByteCnt > pHandle->OneSize) ByteCnt = pHandle->OneSize; //限制单条数据大小
  78. //先将写指针后移,占位,防止多线程写冲突
  79. cnt = pHandle->WriteCnt;
  80. pHandle->WriteCnt++;
  81. if (pHandle->WriteCnt >= pHandle->Cnt) pHandle->WriteCnt = 0; //环形FIFO
  82. pHandle->pByteCntBuff[cnt] = ByteCnt; //记录数据大小
  83. memcpy(&pHandle->pFifoBuff[cnt * pHandle->OneSize], pBuff, ByteCnt); //拷贝数据到缓冲区
  84. /*{
  85. u16 i;
  86. printf("\r\n写入的数据测试[读%d/写:%d]:\r\n",pHandle->ReadCnt,pHandle->WriteCnt);
  87. for(i = 0;i < ByteCnt;i ++)
  88. {
  89. pHandle->pFifoBuff[cnt * pHandle->OneSize+i] = pBuff[i];
  90. printf("%02X\t",pBuff[i]);
  91. if(pHandle->pFifoBuff[cnt * pHandle->OneSize+i] != pBuff[i])
  92. {
  93. printf("拷贝检测错误,数据丢失了\r\n");
  94. }
  95. }
  96. printf("\r\n检测写入的数据测试:\r\n");
  97. for(i = 0;i < ByteCnt;i ++)
  98. {
  99. printf("%02X\t",pHandle->pFifoBuff[cnt * pHandle->OneSize+i]);
  100. }
  101. printf("\r\n");
  102. }*/
  103. #ifdef _UCOS_II_
  104. OS_ENTER_CRITICAL(); //关闭系统中断
  105. #endif
  106. pHandle->NotReadCnt ++; //没有读取的数量增加
  107. #ifdef _UCOS_II_
  108. OS_EXIT_CRITICAL(); //开启系统中断
  109. #endif
  110. return TRUE;
  111. }
  112. }
  113. //读取一条数据,返回指针,无需复制数据
  114. bool FIFO_ReadNotCopy(FIFO_HANDLE *pHandle,u8 **pBuff, u16 *pByteCnt)
  115. {
  116. u16 cnt;
  117. printf( "\r\n读取数据[读%d/写:%d]:\r\n",pHandle->ReadCnt,pHandle->WriteCnt);
  118. if(pHandle == NULL) return FALSE;
  119. if(pHandle->InitStatus != FIFO_INIT_STATUS_ID) return FALSE; //没有初始化
  120. if (pHandle->NotReadCnt == 0) return FALSE; //数据为空
  121. cnt = pHandle->pByteCntBuff[pHandle->ReadCnt]; //获取数据大小
  122. if (cnt > pHandle->OneSize) cnt = pHandle->OneSize; //限制单条数据大小
  123. *pBuff = &pHandle->pFifoBuff[pHandle->ReadCnt * pHandle->OneSize]; //数据缓冲区指针
  124. *pByteCnt = cnt;
  125. return TRUE;
  126. }
  127. //未读取数据减少一次,用于读取数据返回指针后调用
  128. u16 FIFO_ReduceOne(FIFO_HANDLE *pHandle)
  129. {
  130. #ifdef _UCOS_II_
  131. OS_CPU_SR cpu_sr;
  132. #endif
  133. if(pHandle == NULL) return FALSE;
  134. if(pHandle->InitStatus != FIFO_INIT_STATUS_ID) return FALSE; //没有初始化
  135. if (pHandle->NotReadCnt == 0) return FALSE;
  136. pHandle->ReadCnt++; //读取数量增加
  137. if (pHandle->ReadCnt >= pHandle->Cnt) pHandle->ReadCnt = 0; //环形FIFO
  138. #ifdef _UCOS_II_
  139. OS_ENTER_CRITICAL(); //关闭系统中断
  140. #endif
  141. pHandle->NotReadCnt--; //没有读取的数量减少
  142. #ifdef _UCOS_II_
  143. OS_EXIT_CRITICAL(); //开启系统中断
  144. #endif
  145. return pHandle->NotReadCnt; //返回没有读取的数据数量
  146. }
  147. //清除FIFO
  148. bool FIFO_Clear(FIFO_HANDLE *pHandle)
  149. {
  150. if(pHandle == NULL) return FALSE;
  151. if(pHandle->InitStatus != FIFO_INIT_STATUS_ID) return FALSE; //没有初始化
  152. pHandle->ReadCnt = 0; //FIFO读取位置
  153. pHandle->WriteCnt = 0; //FIFO写入位置
  154. pHandle->NotReadCnt = 0; //FIFO内没有读取的数据数量为0
  155. return TRUE;
  156. }
  157. //获取FIFO中数据数量
  158. u16 FIFO_GetDataNumber(FIFO_HANDLE *pHandle)
  159. {
  160. if(pHandle == NULL) return 0;
  161. if(pHandle->InitStatus != FIFO_INIT_STATUS_ID) return 0; //没有初始化
  162. return pHandle->NotReadCnt; //FIFO内没有读取的数据数量
  163. }

  
  
  1. /*************************************************************************************************************
  2. * 文件名: SendDataFIFO.h
  3. * 功能: 实时数据发送缓冲区
  4. * 作者: cp1300@139.com
  5. * 创建时间: 2015-08-09
  6. * 最后修改时间: 2017-08-26
  7. * 详细: 用于数据发送缓冲区
  8. 2017-08-26:增加溢出回调函数,可以对溢出的数据进行处理
  9. *************************************************************************************************************/
  10. #ifndef __SEND_DATA_FIFO_H__
  11. #define __SEND_DATA_FIFO_H__
  12. #include "system.h"
  13. typedef struct
  14. {
  15. u8 *pFifoBuff; //缓冲区指针
  16. u16 *pByteCntBuff; //记录数据大小的缓冲区
  17. u16 OneSize; //单条数据大小
  18. u16 Cnt; //缓冲区总数据容量(条数)
  19. u16 ReadCnt; //读取位置
  20. u16 WriteCnt; //写位置
  21. u16 NotReadCnt; //未读取数量
  22. u32 InitStatus; //初始化状态
  23. void (*FullCallBack)( void *pData); //缓冲区满回调函数
  24. }FIFO_HANDLE;
  25. bool FIFO_Init(FIFO_HANDLE *pHandle,u16 OneSize, u16 MaxCnt, void (*FullCallBack)(void *pData), bool isExtSRAM); //初始化缓冲区
  26. bool FIFO_Write(FIFO_HANDLE *pHandle,u8 *pBuff, u16 ByteCnt); //写入一条数据
  27. bool FIFO_ReadNotCopy(FIFO_HANDLE *pHandle,u8 **pBuff, u16 *pByteCnt); //读取一条数据,返回指针,无需复制数据
  28. u16 FIFO_ReduceOne(FIFO_HANDLE *pHandle); //未读取数据减少一次,用于读取数据返回指针后调用
  29. bool FIFO_Clear(FIFO_HANDLE *pHandle); //清除FIFO
  30. u16 FIFO_GetDataNumber(FIFO_HANDLE *pHandle); //获取FIFO中数据数量
  31. #endif //__SEND_DATA_FIFO_H__

示例,比如定时发送数据,将数据定时拷贝到FIFO中,另一个线程定时启动,发送数据:


  
  
  1. //拷贝实时数据到发送缓冲区中,进行立即发送数据(注意功能码必须为8位)
  2. void CopyTempDataToFIFO(u8 Fun)
  3. {
  4. u8 i;
  5. //写入需要发送的数据的功能码
  6. g_TempRealData.Fun = Fun; //功能码
  7. g_TempRealData.SerialNumber = 0; //流水号设置为0,自动分配
  8. g_TempRealData.Time[ 0] = timer.w_year -2000; //拷贝实时时间
  9. g_TempRealData.Time[ 1] = timer.w_month; //拷贝实时时间
  10. g_TempRealData.Time[ 2] = timer.w_date; //拷贝实时时间
  11. g_TempRealData.Time[ 3] = timer.hour; //拷贝实时时间
  12. g_TempRealData.Time[ 4] = timer.min; //拷贝实时时间
  13. g_TempRealData.Time[ 5] = 0; //拷贝实时时间
  14. //循环将数据写入到4个中心站的发送FIFO中(如果中心站端口为0,则认为中心站无效,不进行发送)
  15. for(i= 0;i< 4;i++)
  16. {
  17. //服务器配置有效才写入数据到缓冲区
  18. if(g_SYS_Config.ServerPort[i] > 0)
  19. {
  20. FIFO_Write(&g_SendFifoBuff[i], (u8 *)&g_TempRealData, sizeof(REAL_DATA)); //写入数据到发送缓冲区
  21. }
  22. else
  23. {
  24. FIFO_Clear(&g_SendFifoBuff[i]); //不用发送的站点,清除缓冲区
  25. FIFO_Clear(&g_SendCacheFifoBuff[i]); //不用发送的站点,清除Cache缓冲区
  26. }
  27. }
  28. }

发送数据,从FIFO中读取


  
  
  1. isFifoStatus = FIFO_ReadNotCopy(pFifoHandle, (u8 **)&pTempRealData, &ByteLen);
  2. if(isFifoStatus==TRUE) //有数据要发送 //实时缓冲区中没有数据,检查Cache中是否有数据
  3. {...... /*发送数据逻辑*/ FIFO_ReduceOne(pFifoHandle); //发送结束后,清除当前读取过的数据
  4. }


引用提供了一个关于FIFO(First-In-First-Out)的功能函数的示例代码。这段代码实现了FIFO的初始化、数据读取和状态查询等功能。FIFO是一种常用的数据缓存机制,用于在数据的输入和输出之间进行临时存储。 在引用中,有一段代码展示了如何从FIFO中读取数据进行发送。代码中使用FIFO_ReadNotCopy函数从FIFO中读取数据,并将读取到的数据发送出去。发送完成后,使用FIFO_ReduceOne函数清除已读取过的数据。 而在引用中,展示了一个示例函数CopyTempDataToFIFO用于将实时数据拷贝到发送缓冲区中。该函数将实时数据按照一定的格式写入到FIFO中,以供后续发送使用。 综上所述,stm32fifo数据缓存可以通过使用FIFO机制来实现。可以根据具体需求,使用FIFO的初始化、读取和写入函数,将数据按照先进先出的原则进行缓存。这样可以确保数据在发送过程中的顺序和完整性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [stm32 串口+DMA+环形FIFO缓存收发数据](https://blog.csdn.net/weixin_43862847/article/details/87194718)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [STM32使用环形FIFO队列用于缓存发送数据](https://blog.csdn.net/cp1300/article/details/79822476)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值