4-1-關於環形隊列


<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

 

 

 

結語

切莫眼高手低!!!!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM