前面我博客写了一篇《STM32 串口传输最佳处理方式 FreeRTOS+队列+DMA+IDLE(一)》就是利用RingBuff环形缓存数组来存数据,大家可以看着那边代码来看。
详细描述一下里面的原理:看一下入队函数

static uint16_t ps_tbwr_Blue=0;//缓存所在指针//入队的结构体
typedef struct
{uint16_t start_addr;  //入队开始位置uint16_t len;    // 入队长度
}BufferLoopData_Typedefvoid USART1_SendData(uint8_t *ps,uint16_t len)
{uint16_t i;        BufferLoopData_Typedef buffer_loop;buffer_loop.start_addr = ps_tbwr_Blue;buffer_loop.len = len;for (i=0;i<len;i++){if (ps_tbwr_Blue >= MAX_FRAME_COMM_BUFFER_SIZE){ps_tbwr_Blue = 0;}        txbuf_Blue_DMA[ps_tbwr_Blue] = *(ps+i);//txbuf_Blue_DMA为ps_tbwr_Blue++;        }xQueueSendToBack(xQueue_Blue_tx,(void *)&buffer_loop,portMAX_DELAY);
}

大家注意了,buffer_loop.start_addr 是循环数组入队地址,buffer_loop.start_addr是在ps_tbwr_Blue累加之前的被赋值。所以,它每次入队都是上一次缓存完的位置。即出队时,数据取出的位置。ps_tbwr_Blue是一个静态变量,会一直递增过去。

出队函数如下:

void USART1_SendTask(void const * argument)
{uint16_t i;BufferLoopData_Typedef buffer_loop;extern uint8_t txbuf_Blue_tmp[MAX_FRAME_COMM_LEN];   for (;;){xQueueReceive(xQueue_Blue_tx,&buffer_loop,portMAX_DELAY);  //SCB_CleanDCache();for (i=0;i<buffer_loop.len;i++){if (buffer_loop.start_addr >= MAX_FRAME_COMM_BUFFER_SIZE){buffer_loop.start_addr = buffer_loop.start_addr - MAX_FRAME_COMM_BUFFER_SIZE;}txbuf_Blue_tmp[i] = txbuf_Blue_DMA[buffer_loop.start_addr];buffer_loop.start_addr += 1;}   //SCB_CleanInvalidateDCache();Uart1_DMASend_Start(&txbuf_Blue_tmp[0],buffer_loop.len);//通过DMA发送xSemaphoreTake(BinarySem_UART1_tx_finish_Handle,portMAX_DELAY); //等待DMA发送成功taskYIELD();  }
}

工作如下:


第一次入队时,addr1,lenth1。
此时addr=0;ps=lenth1
第二次入队时addr2,lenth2。
此时addr2=ps=lenth1; ps=lenth1+lenth2
第三次入队时addr3,lenth3。
此时addr3=ps=lenth1+len2; ps=lenth1+lenth2+lenth2.
……
所以说,就想上面说的。addr是在ps累加之前被赋值了。它就是这样一个循环的过程。
上面是环形缓存数组的一种方法,有一点点拗口,但是非常的简介,实用。
出来上面方法还有一种利用链表的方法。具体如下

方法二:
利用链表`

/** 环形缓存区数据结构 */
typedef struct {size_tt rbCapacity;//空间大小uint8_t  *rbHead; //头uint8_t  *rbTail; //尾uint8_t  *rbBuff; //数据首地址
}rb_t;//第一步,创建环形队列,Wifi_rb_tx就是上面环形结构体
rbCreate(&Wifi_rb_tx,Wifi_RingBuff,Wifi_TX_FRAME_MAX_SIZE);//源码:
void rbCreate(rb_t* rb,uint8_t *Buff,uint32_t BuffLen)
{if(NULL == rb){printf("ERROR: input rb is NULL\n");return;}rb->rbCapacity = BuffLen;rb->rbBuff = Buff;rb->rbHead = rb->rbBuff;rb->rbTail = rb->rbBuff;
//第二步,向环形队列写入数据
rbWrite(&Wifi_rb_tx, data+1024*idx, (size_tt) 1024);
//源码:
int32_t rbWrite(rb_t *rb, const void *data, size_tt count)
{int tailAvailSz = 0;if(NULL == rb){printf("ERROR: rb is empty \n");return -1;}if(NULL == data){printf("ERROR: data is empty \n");return -1;}if (count >= rbCanWrite(rb)){printf("ERROR: no memory \n");return -1;}if (rb->rbHead <= rb->rbTail){tailAvailSz = rbCapacity(rb) - (rb->rbTail - rb->rbBuff);if (count <= tailAvailSz){memcpy(rb->rbTail, data, count);rb->rbTail += count;if (rb->rbTail == rb->rbBuff+rbCapacity(rb)){rb->rbTail = rb->rbBuff;}return count;}else{memcpy(rb->rbTail, data, tailAvailSz);rb->rbTail = rb->rbBuff;        return tailAvailSz + rbWrite(rb, (char*)data+tailAvailSz, count-tailAvailSz);}}else {memcpy(rb->rbTail, data, count);rb->rbTail += count;return count;}
}
}//第三步骤:从环形队列读出数据
rbRead((rb_t*)&Wifi_rb_tx,Wifi_TxRing_Temp,buffer_loop.len);
//源码
int32_t rbRead(rb_t *rb, void *data, size_tt count)
{int copySz = 0;if(NULL == rb){printf("ERROR: input rb is NULL\n");return -1;}if(NULL == data){printf("ERROR: input data is NULL\n");return -1;}if (rb->rbHead < rb->rbTail){copySz = min(count, rbCanRead(rb));memcpy(data, rb->rbHead, copySz);rb->rbHead += copySz;return copySz;}else {if (count < rbCapacity(rb)-(rb->rbHead - rb->rbBuff)){copySz = count;memcpy(data, rb->rbHead, copySz);//rb->rbHead += copySz;return copySz;}else{copySz = rbCapacity(rb) - (rb->rbHead - rb->rbBuff);memcpy(data, rb->rbHead, copySz);rb->rbHead = rb->rbBuff;copySz += rbRead(rb, (char*)data+copySz, count-copySz);return copySz;}}
}

配合FreeRTOS队列操作,只需将长度入队,出队即可。 上面方法模块性强,更为复杂,但逻辑上更为简单,可作为模块化调用。

好了,总上所述。上面两种RingBuff各有所长。萝卜青菜各有所爱;两个都爱,一起拿走。

2.12 FreeRTOS_RingBuff 环形缓存数组的使用相关推荐

  1. 从uart到serial-ringbuff(环形缓存)

    最近在写一个serial 的应用想起以前写过的一些单片机上的uart 程序,有着许许多多的圈圈点点的,也就来扒一扒串口机制的事情了. 学习单片机都会接触到串口这个东西,多数的教程都是讲讲如何把寄存器配 ...

  2. C语言--环形缓存区

    环形缓存区工作原理 环形缓冲区是固定大小的缓冲区,工作原理就像内存是连续的且可循环.在生成和使用内存时,不需要将原来的数据全部清理掉,只要调整head/tail指针即可.当添加数据时,head指针前进 ...

  3. 结对开发——环形一维数组求最大子数组和

    题目:返回一个整数数组中最大子数组的和. 要求: (1)输入一个整形数组,数组里有正数也有负数. (2)数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和. (3)如果数组A[0]--A[ ...

  4. (12)System Verilog 数组查找常数

    (12)System Verilog 数组查找常数 1.1 目录 1)目录 2)FPGA简介 3)System Verilog简介 4)System Verilog 数组查找常数 5)结语 1.2 F ...

  5. 【原创】VBA学习笔记(12)VBA的数组 array---基础知识(1)

    一 数组 array 1.1 什么是数组?具体的例子 以这个语句为例子 arr1=array(1, 2, 3) 左边:变量名=数组名 右边:数组,集合,多个元素集合,多个数据集合, 右边的单个内容,1 ...

  6. 数组状态将在iOS 12 Safari中缓存。这是一个错误或功能吗?

    本文翻译自:Array state will be cached in iOS 12 Safari. Is it a bug or feature? Update at 2018.10.31 更新于2 ...

  7. c语言环形存储,环形缓存区bufferC语言实现

    buffer[iput]=z; iput = addring(iput); n++; } else printf("Buffer is full\n"); } int main{v ...

  8. java 环形缓存_shuffle 中环形缓冲区

    shuffle中环形缓冲区使用于map shuffle阶段存放map的缓存数据,当缓冲区的数据达到一定比率(80%)就会将缓冲区的数据刷写到磁盘文件中,在刷盘之前,会对数据分区.排序.合并,对缓冲区的 ...

  9. 牛课网--走格子(环形遍历数组并且找出指定步数的位置)

    题目链接:https://www.nowcoder.com/acm/contest/114/A 代码: #include<cstdio> #include<iostream> ...

最新文章

  1. 如何消费WCF Data Services定义的服务操作
  2. 网站设计师必备50教程
  3. Android --- SharedPreferences的详细介绍
  4. 幻像类型提高了编译时的安全性
  5. 李开复:有三个AI专家就能估值7亿的时代过去了
  6. 广告学计算机平面设计(1)形考5,中等职业学校计算机平面设计专业教学标准 (1)...
  7. 知乎 2019 新知青年大会开幕,用问题改变世界的方向
  8. java map 集合实例_Java之集合类【HashMap】【入门版,实例解析】
  9. 【Java架构师入门到精通】架构师图谱
  10. 二维连续傅里叶变换对
  11. 珞珈老师PPT教学-笔记
  12. ug冲模标准件库_UG标准件库|标准件库下载|3DSource零件库|海量CAD模型
  13. koreader下载_Koreader —— Kindle 的 PDF 文档重排插件
  14. 射影几何----蝴蝶定理的证明
  15. Android启动之BOOT_COMPLETED广播
  16. 【OpenCV】将图片黑色背景变成透明背景
  17. 阿里巴巴2021校招
  18. 摩羯座|摩羯座性格分析
  19. Python制作桑基图
  20. 基于51单片机ds1302时钟、ds18b20、lcd12864的恒温器

热门文章

  1. 高校校园无线认证计费解决方案
  2. 外部链接跳转到微信,以及外部跳转到微信小程序(精华)
  3. Rolling back JDBC Connection [org.sqlite.jdbc4.JDBC4Connection
  4. Cisco路由器基本配置
  5. 浅析C#Image类
  6. stata:应用stata学习计量经济学原理 practice 6 边际效用 Marginal effect
  7. Oracle数据库cmd命令基本命令
  8. [31] FatMouse and Cheese
  9. 巧用计算机方法,第四课 巧用计算器教案.doc
  10. 职业梦想是计算机的英语作文,我梦想的职业高中英语作文