zoukankan      html  css  js  c++  java
  • 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
    ");
                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
    ");
            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
    ");
            return -51;
        }
    
        return rb->rbCapacity;
    }
    
    //返回能读的空间
    int32_t rbCanRead(rb_t *rb)
    {
        if(NULL == rb)
        {
    //        printf("ERROR: input rb is NULL
    ");
            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
    ");
            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
    ");
        {
            return -21;
        }
    
        if(NULL == data)//        printf("ERROR: input data is NULL
    ");
        {
            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 
    ");
            return -11;
        }
    
        if(NULL == data)
        {
    //        printf("ERROR: data is empty 
    ");
            return -12;
        }
    
        if (count >= rbCanWrite(rb))//如果剩余的空间不够
        {
    //        printf("ERROR: no memory 
    ");
            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 
    ");
            return -1;
        }
        
        count = rbWrite(rb, buf, len);
        if(count != len)
        {
            //printf("ERROR: Failed to rbWrite 
    ");
            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

    结语

    切莫眼高手低!!!!

  • 相关阅读:
    Beta 冲刺day 6
    Beta冲刺day5
    Beta冲刺day4
    Beta 冲刺day3
    Beta 冲刺day2
    Beta冲刺day1
    Beta预备
    城市安全风险管理项目Postmortem结果
    项目总结
    Alpha冲刺置顶随笔
  • 原文地址:https://www.cnblogs.com/yangfengwu/p/14734949.html
Copyright © 2011-2022 走看看