前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >环形队列

环形队列

作者头像
杨奉武
发布2018-04-18 16:11:46
1.3K0
发布2018-04-18 16:11:46
举报
文章被收录于专栏:知识分享

 写完这篇文章想着以后尽量(应该说一定)使用现在正在使用的LPC系列的单片机写程序,其实内心感觉还是LPC做的相当完善,,,,,配置上没有32那么的繁琐....

关于串口发送数据,自己以前呢是这样

代码语言:javascript
复制
void Usart_Out_Char(unsigned char *c,uint32_t cnt)
{
    while(cnt--)
    {
    USART_SendData(USART1, *c++);
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET );
  }
}

下面的调用方式

代码语言:javascript
复制
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); 
    }
}

当发送数据的时候,会一直在调用此函数的地方等着,,,,,,直至发送完所有的数据,要知道用串口中断发送数据要比这样发送快的多.......瞎耽误时间

假设现在我用中断发送

假设没有缓冲区

代码语言:javascript
复制
void UsartOutChar(unsigned char *Buff,uint32_t cnt)
{
    dat = Buff;//把发送地址给dat
    BuffCnt = cnt;//记录发送的个数
    USART_ITConfig(USART1, USART_IT_TXE, ENABLE);//打开发送中断
}
代码语言:javascript
复制
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);
  }
}
代码语言:javascript
复制
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);
    }
}

加一个缓冲区---假设是下面这样子,中断发送的数据从这个缓冲区里面取

然后呢,接着又填入了

接着

假设我又想添加数据,可是呢后面空的那一块数据空间不够了......要是能把数组的尾和头联系起来就好啦......

假设加满了,,,如果能自动的加到前面就好啦.....

今天先这样...太晚啦..现在最大的愿望什么时候能安心睡个早觉..再这样下去真担心会挂了......有空再详加..

下面是实现程序--实现程序是自己想学Esp8266连接机智云的时候无意中看到的,,,,,记得 天鲁哥 曾经说过环形队列实现的很巧妙,,,改天有空再研究下当初天鲁哥给的程序

 往里面加数据尾指针向右增加...加到头回到首地址

从里面读数据头指针向右增加...加到头回到首地址

 注意 

还是在唠叨唠叨

代码语言:javascript
复制
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;
}
代码语言:javascript
复制
#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

使用就很方便了--直接往里面填数据就好啦

代码语言:javascript
复制
#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);
    }
}
代码语言:javascript
复制
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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017-05-08 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档