<p><iframe name="ifd" src="https://mnifdv.cn/resource/cnblogs/單片機知識點總結/directory.html" frameborder="0" scrolling="auto" width="100%" height="1500"></iframe></p>
環形隊列是啥?
一看到名詞就顯得高大上了!!!
首先哈,對於做程序而言.一看到什么緩存什么隊列,其實就是對數組進行操作.
話說以前有一個數組,這個數組假設是5個的
然后呢有人把這個數組交給了一套程序去管理
調用這套程序就可以往數組里存數據和取數據
但是呢,這套控制程序比較與眾不同.
一開始調用控制程序往里面存一個字符A,A便會存儲到數組的第一個位置
然后再調用控制程序往里面存一個字符B,B便會存儲到數組的第二個位置
然后再調用控制程序往里面存兩個字符C和D,C,D便會存儲到數組的第三,四的位置
然后再調用控制程序讓里面存儲的時候,不能再存了,因為控制
程序默認已經滿了.
-------------------------------------------------------
然后調用控制程序從里面取一個數據
第一個存進去的 A 便會被取出來,然后第一個位置就代表可以再存數據了
然后調用控制程序再從里面取一個數據
第二個存進去的 B 便會被取出來,然后第二個位置就代表可以再存數據了
調用控制程序往里面存一個字符E,E便會存儲到數組的第五個位置
注意前方高能!
然后再調用控制程序往里面存一個字符F,F便會存儲到數組的第一個位置
然后因為現在控制程序又認為滿了,我就再調用控制程序再從里面取一個數據
再調用控制程序往里面存一個字符G,G便會存儲到數組的第二個位置
然后就是這樣子循環.
現在看看實際的
1.環形隊列管理程序
/* V1.0.2: 1.屏蔽printf打印 2.設置不同的返回值,以確定具體錯誤 */ #define LOOPLIST_C_ #include "LoopList.h" #include <string.h> #include <stdio.h> //創建或者說初始化環形緩沖區 void rbCreate(rb_t* rb,void *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;//尾指向數組首地址 } //刪除一個環形緩沖區 void rbDelete(rb_t* rb) { if(NULL == rb) { // printf("ERROR: input rb is NULL\n"); return; } rb->rbBuff = NULL;//地址賦值為空 rb->rbHead = NULL;//頭地址為空 rb->rbTail = NULL;//尾地址尾空 rb->rbCapacity = 0;//長度為空 } //獲取鏈表的長度 int32_t rbCapacity(rb_t *rb) { if(NULL == rb) { // printf("ERROR: input rb is NULL\n"); return -51; } return rb->rbCapacity; } //返回能讀的空間 int32_t rbCanRead(rb_t *rb) { if(NULL == rb) { // printf("ERROR: input rb is NULL\n"); return -31; } if (rb->rbHead == rb->rbTail)//頭與尾相遇 { return 0; } if (rb->rbHead < rb->rbTail)//尾大於頭 { return rb->rbTail - rb->rbHead; } return rbCapacity(rb) - (rb->rbHead - rb->rbTail);//頭大於尾 } //返回能寫入的空間 int32_t rbCanWrite(rb_t *rb) { if(NULL == rb) { // printf("ERROR: input rb is NULL\n"); return -41; } return rbCapacity(rb) - rbCanRead(rb);//總的減去已經寫入的空間 } /* rb--要讀的環形鏈表 data--讀出的數據 count--讀的個數 */ int32_t rbRead(rb_t *rb, void *data, uint32_t count) { int copySz = 0; if(NULL == rb)// printf("ERROR: input rb is NULL\n"); { return -21; } if(NULL == data)// printf("ERROR: input data is NULL\n"); { return -22; } if (rb->rbHead < rb->rbTail)//尾大於頭 { copySz = min(count, rbCanRead(rb));//查看能讀的個數 memcpy(data, rb->rbHead, copySz);//讀出數據到data 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; } } } int32_t rbWrite(rb_t *rb, const void *data, uint32_t count) { int tailAvailSz = 0; if(NULL == rb) { // printf("ERROR: rb is empty \n"); return -11; } if(NULL == data) { // printf("ERROR: data is empty \n"); return -12; } if (count >= rbCanWrite(rb))//如果剩余的空間不夠 { // printf("ERROR: no memory \n"); return -13; } 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; } } /**@} */ /** * @brief 往環形隊列里面寫入數據 * @param rb 環形隊列管理變量 * @param USARTx 控制打開某個串口發送中斷 * @param EnabledUsart 控制打開中斷 * @param buf 發送的數據 * @param len 數據長度 * @retval 負數:錯誤 正數:寫入的數據長度 * @warning * @example **/ int32_t PutData(rb_t *rb ,void *buf, uint32_t len) { int32_t count = 0; if(NULL == buf) { // printf("ERROR: gizPutData buf is empty \n"); return -1; } count = rbWrite(rb, buf, len); if(count != len) { //printf("ERROR: Failed to rbWrite \n"); return -2; } return count; }
#ifndef LOOPLIST_H_ #define LOOPLIST_H_ #ifndef LOOPLIST_C_ #define LOOPLIST_Ex_ extern #else #define LOOPLIST_Ex_ #endif #include <stm32f10x.h> #define min(a, b) (a)<(b)?(a):(b) ///< 獲取最小值 /** 環形緩沖區數據結構 */ typedef struct { uint32_t rbCapacity;//空間大小 char *rbHead; //頭 char *rbTail; //尾 char *rbBuff; //數組的首地址 }rb_t; void rbCreate(rb_t *rb,void *Buff,uint32_t BuffLen);//創建或者說初始化環形緩沖區 void rbDelete(rb_t* rb); int32_t rbCapacity(rb_t *rb);//得到環形大小 int32_t rbCanRead(rb_t *rb);//能讀出數據的個數 int32_t rbCanWrite(rb_t *rb);//還剩余的空間 int32_t rbRead(rb_t *rb, void *data, uint32_t count);//讀取數據 int32_t rbWrite(rb_t *rb, const void *data, uint32_t count); int32_t PutData(rb_t *rb ,void *buf, uint32_t len); #endif
2.創建
3.通過環形隊列函數往數組里面存數據
4.通過環形隊列函數往數組里面存數據
5.取出來幾個數據
咱存儲數據的時候存儲的順序是 1,2,3,4,5,6依次存進去的.
取數據的時候也是先取1 然后取2 然后... 最后取6
其實就是先進先出的原則.
6.通過環形隊列函數往數組里面存數據
咱再接着存的時候是不是形成了一個環形的結構了.轉着圈的存數據.
注意上面的數組黃框位置,黃框位置咱已經調用了取數據函數把里面的數據讀取了.
其實黃框位置在環形隊列管理函數里面認為是空位置.
現在看典型應用
1,說明
首先環形隊列適用於很多場合,尤其是一邊存數據一邊處理數據的場合.
2.使用環形隊列緩存串口數據
主循環讀取緩存的數據,並使用串口1發送出去
3.可能用戶會想就這?
我的所有的項目都是使用的環形隊列做數據處理.
更加典型的應該看下面的鏈接(里面的代碼開源):單片機IAP升級程序
我使用環形隊列接收程序文件,定義的數組只用了 5字節
也就是說就用了5字節大小的數組就完成了升級單片機程序
https://www.cnblogs.com/yangfengwu/p/14620102.html
4.用戶只需要知道,環形隊列就是一個緩存數據的方式
此節代碼中還有使用中斷發送數據,緩存也是使用的環形隊列
其實就是把數據放到環形隊列,然后打開中斷發送,
然后在中斷函數里面讀取數據,發送出去
5.還有我使用環形隊列再次封裝的一套緩存
https://www.cnblogs.com/yangfengwu/p/12228402.html
結語
切莫眼高手低!!!!