環形隊列

 寫完這篇文章想着之後儘可能(應該說必定)使用如今正在使用的LPC系列的單片機寫程序,其實心裏感受仍是LPC作的至關完善,,,,,配置上沒有32那麼的繁瑣....c++

關於串口發送數據,本身之前呢是這樣數組

void Usart_Out_Char(unsigned char *c,uint32_t cnt)
{
    while(cnt--)
    {
    USART_SendData(USART1, *c++);
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET );
  }
}

下面的調用方式緩存

uint8_t aaa[1024]={1,2,3,42,0};

int main(void)
{
  NVIC_Configuration();
    Led_Gpio_Init();
    Timer2_Config();
    uart_init(115200);     //串口初始化爲115200while(1)
    {
    Usart_Out_Char(aaa,1024);
        delay_ms(1000);
        PFout(6) = ~PFout(6); 
    }
}

 

當發送數據的時候,會一直在調用此函數的地方等着,,,,,,直至發送完全部的數據,要知道用串口中斷髮送數據要比這樣發送快的多.......瞎耽誤時間數據結構

假設如今我用中斷髮送函數

 

假設沒有緩衝區ui

void UsartOutChar(unsigned char *Buff,uint32_t cnt)
{
    dat = Buff;//把發送地址給dat
    BuffCnt = cnt;//記錄發送的個數
    USART_ITConfig(USART1, USART_IT_TXE, ENABLE);//打開發送中斷
}
void USART1_IRQHandler(void)                    //串口1中斷服務程序
{
    u8 Res;
  
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中斷(接收到的數據必須是0x0d 0x0a結尾)
    {
       Res =USART_ReceiveData(USART1);    //讀取接收到的數據           
    } 
    if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET)//發送中斷
  {
     if(BuffCnt--)
     {
        USART_SendData(USART1,*dat);//發送數據
        dat++;
    }
    else
    {
      //發送字節結束
      USART_ClearITPendingBit(USART1,USART_IT_TXE);
      USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
      USART_ITConfig(USART1, USART_IT_TC, ENABLE);
    }
  }
  //發送完成
  if (USART_GetITStatus(USART1, USART_IT_TC) != RESET)
  {
    USART_ClearITPendingBit(USART1,USART_IT_TC);
    USART_ITConfig(USART1, USART_IT_TC, DISABLE);
  }
}

 

uint8_t aaa[1024]={1,2,3,42,0};

int main(void)
{
    NVIC_Configuration();
    Led_Gpio_Init();
    Timer2_Config();
    uart_init(115200);     //串口初始化爲115200while(1)
    {
        UsartOutChar(aaa,10);
        delay_ms(10);
    }
}

 

 其實環形隊列就是把一個數據的收尾相接spa

 

 

加一個緩衝區---假設是下面這樣子,中斷髮送的數據從這個緩衝區裏面取指針

而後呢,接着又填入了code

接着blog

假設我又想添加數據,但是呢後面空的那一塊數據空間不夠了......要是能把數組的尾和頭聯繫起來就好啦......

假設加滿了,,,若是能自動的加到前面就好啦.....

 

今天先這樣...太晚啦..如今最大的願望何時能安心睡個早覺..再這樣下去真擔憂會掛了......有空再詳加..

下面是實現程序--實現程序是本身想學Esp8266鏈接機智雲的時候無心中看到的,,,,,記得 天魯哥 曾經說過環形隊列實現的很巧妙,,,改天有空再研究下當初天魯哥給的程序

 往裏面加數據尾指針向右增長...加到頭回到首地址

從裏面讀數據頭指針向右增長...加到頭回到首地址

 

 注意      

仍是在嘮叨嘮叨

 

 

 

 

 

rb_t pRb;            ///< 環形緩衝區結構體變量
uint8_t rbBuf[RB_MAX_LEN]; ///< 環形緩衝區數據緩存區

void rbCreate(rb_t* rb,u8 *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 -1;
    }

    return rb->rbCapacity;
}

int32_t rbCanRead(rb_t *rb)//返回能讀的空間
{
    if(NULL == rb)
    {
        printf("ERROR: input rb is NULL\n");
        return -1;
    }

    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 -1;
    }

    return rbCapacity(rb) - rbCanRead(rb);//總的減去已經寫入的空間
}

/*   
  rb--要讀的環形鏈表
  data--讀出的數據
  count--讀的個數
*/
int32_t rbRead(rb_t *rb, void *data, size_t 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);//讀出數據到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, size_t 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;
    }
}
/**@} */

/**
* @brief 向環形緩衝區寫入數據
* @param [in] buf        : buf地址
* @param [in] len        : 字節長度
* @return   正確 : 返回寫入的數據長度
            失敗 : -1
*/
int32_t PutData(uint8_t *buf, uint32_t len)
{
    int32_t count = 0;

    if(NULL == buf)
    {
        printf("ERROR: gizPutData buf is empty \n");
        return -1;
    }
    
    count = rbWrite(&pRb, buf, len);
    if(count != len)
    {
        printf("ERROR: Failed to rbWrite \n");
        return -1;
    }
    USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
    return count;
}

 

 

#ifndef LOOPLIST_H_
#define LOOPLIST_H_

#ifndef LOOPLIST_C_//若是沒有定義  AnnularArray_C_
#define LOOPLIST_C_ extern
#else
#define LOOPLIST_C_
#endif

#include <stm32f10x.h>

#define size_t uint16_t 

#define RB_MAX_LEN   1024 //緩衝區最大長度
#define min(a, b) (a)<(b)?(a):(b)                   ///< 獲取最小值

/** 環形緩衝區數據結構 */
typedef struct {
    size_t rbCapacity;//空間大小
    uint8_t  *rbHead; //
    uint8_t  *rbTail; //
    uint8_t  *rbBuff; //數組的首地址
}rb_t;

LOOPLIST_C_  rb_t pRb;            ///< 環形緩衝區結構體變量
LOOPLIST_C_  uint8_t rbBuf[RB_MAX_LEN]; ///< 環形緩衝區數據緩存區

LOOPLIST_C_ void rbCreate(rb_t *rb,u8 *Buff,uint32_t BuffLen);//建立或者說初始化環形緩衝區
LOOPLIST_C_  void rbDelete(rb_t* rb);
LOOPLIST_C_  int32_t rbCapacity(rb_t *rb);//獲得環形大小
LOOPLIST_C_  int32_t rbCanRead(rb_t *rb);//能讀出數據的個數
LOOPLIST_C_  int32_t rbCanWrite(rb_t *rb);//還剩餘的空間
LOOPLIST_C_  int32_t rbRead(rb_t *rb, void *data, size_t count);//讀取數據
LOOPLIST_C_  int32_t rbWrite(rb_t *rb, const void *data, size_t count);
LOOPLIST_C_  int32_t PutData(uint8_t *buf, uint32_t len);


#endif

 

使用就很方便了--直接往裏面填數據就好啦

#include "include.h"

uint8_t aaa[50]={1,1,1,1,1,1,1,1,1,1};

uint8_t bbb[50]={3,3,3,3,3,3,3,3,3,3};
int main(void)
{
  NVIC_Configuration();
    Led_Gpio_Init();
    Timer2_Config();
    uart_init(115200);     //串口初始化爲115200
    rbCreate(&pRb,SendBuff,USART_REC_LEN);//建立環形隊列
    while(1)
    {
        PutData(aaa,10);//發送數據
        PutData(bbb,10);//發送數據
        delay_ms(10);
    }
}

 

void USART1_IRQHandler(void)                    //串口1中斷服務程序
{
    u8 Res;
  
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中斷(接收到的數據必須是0x0d 0x0a結尾)
    {
       Res =USART_ReceiveData(USART1);    //讀取接收到的數據           
    } 
    if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET)
  {
    if(rbCanRead(&pRb)>0)//若是裏面的數據個數大於0
    {
      rbRead(&pRb, &SendDat, 1);//讀取一個數據
      USART_SendData(USART1, SendDat);//發送
    }
    else
    {
      //發送字節結束
      USART_ClearITPendingBit(USART1,USART_IT_TXE);
      USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
      USART_ITConfig(USART1, USART_IT_TC, ENABLE);
    }
  }
  //發送完成
  if (USART_GetITStatus(USART1, USART_IT_TC) != RESET)
  {
    USART_ClearITPendingBit(USART1,USART_IT_TC);
    USART_ITConfig(USART1, USART_IT_TC, DISABLE);
  }
} 

 

 其實再完美點就是加上DMA....後期我儘可能用LPC的單片機作....不對是必定要用LPC的單片機作成dma的---

 

  程序連接:http://pan.baidu.com/s/1pLlXDfP 密碼:6kci

相關文章
相關標籤/搜索