碎思杂文我爱编程

循环缓冲区RingBuffer

2017-03-16  本文已影响3806人  athorn

stm32和外设通信的时候,需要对外设发来的串行数据做同步。参考过下面这个链接的方法:串口通信帧的同步方法(识别一帧数据的起始结束)

/**
  * USART2_IRQHandler
  */
void USART2_IRQHandler(void)
{
    uint8_t value = 0;
    if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
    {
        USART_ClearITPendingBit(USART2,USART_IT_RXNE);
        value = USART_ReceiveData(USART2);

        if(1 == syncFlag)
        {
            if(cnt <= 7)
            {
                pm_buf[cnt++] = value;
            }
            else
            {
                cnt = 0;
                syncFlag = 0;
                syncHead[1] = 0xFF;
                syncHead[0] = 0xFF;
            }
        }
        else
        {
            //Syncing......
            syncHead[1] = syncHead[0];
            syncHead[0] = value;
            
            if(syncHead[1] == 0xAA && syncHead[0] == 0xC0)
                syncFlag = 1;
        }
    }
}

然而这样做有个问题。中断服务程序需要做大量的工作,在这短暂的时间中,就可能会丢失串口发来的数据,因为串口的数据是源源不断的。所以应该需要一个类似缓冲区的东西。这样的话,IRQHandler只负责相应的数据,而中断服务程序去完成真正的操作。

在查看很多文档之后,发现这个就归属于经典的生产者和消费者问题。我认为FIFO队列和循环缓冲区应该是一种互补的关系。

/**
  * USART2_IRQHandler
  */
void USART2_IRQHandler(void)
{
    uint8_t value = 0;
    if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
    {
        USART_ClearITPendingBit(USART2,USART_IT_RXNE);
        value = USART_ReceiveData(USART2);
        if(rb_can_write(&u_ring_buff) > 0)
        {
            rb_write(&u_ring_buff, &value, 1);
            //printf("Interrupt\n\r");
        }
    }
}
#define min(a, b) (a)<(b)?(a):(b)

void rb_new(RingBuffer* rb)
{
    //RingBuffer *rb = (RingBuffer *)buff;//malloc(sizeof(RingBuffer) + capacity);
    //if (rb == NULL) return NULL;
    
    rb->rb_capacity = MAX_RINGBUFFER_LEN;//-sizeof(RingBuffer);//capacity;
    //rb->rb_buff     = buff+sizeof(RingBuffer);//(char*)rb + sizeof(RingBuffer);
    rb->rb_head     = rb->rb_buff;
    rb->rb_tail     = rb->rb_buff;
    
        //return rb;
};

void  rb_free(RingBuffer *rb)
{
    //free((char*)rb);
}

size_t     rb_capacity(RingBuffer *rb)
{
    //assert(rb != NULL);
    return rb->rb_capacity;
}
size_t     rb_can_read(RingBuffer *rb)
{
    //assert(rb != NULL);
    if (rb->rb_head == rb->rb_tail) return 0;
    if (rb->rb_head < rb->rb_tail) return rb->rb_tail - rb->rb_head;
    return rb_capacity(rb) - (rb->rb_head - rb->rb_tail);
}
size_t     rb_can_write(RingBuffer *rb)
{
    //assert(rb != NULL);
    return rb_capacity(rb) - rb_can_read(rb);
}

size_t     rb_read(RingBuffer *rb, void *data, size_t count)
{
    //assert(rb != NULL);
    //assert(data != NULL);
    if (rb->rb_head < rb->rb_tail)
    {
        int copy_sz = min(count, rb_can_read(rb));
        memcpy(data, rb->rb_head, copy_sz);
        rb->rb_head += copy_sz;
        return copy_sz;
    }
    else
    {
        if (count < rb_capacity(rb)-(rb->rb_head - rb->rb_buff))
        {
            int copy_sz = count;
            memcpy(data, rb->rb_head, copy_sz);
            rb->rb_head += copy_sz;
            return copy_sz;
        }
        else
        {
            int copy_sz = rb_capacity(rb) - (rb->rb_head - rb->rb_buff);
            memcpy(data, rb->rb_head, copy_sz);
            rb->rb_head = rb->rb_buff;
            copy_sz += rb_read(rb, (char*)data+copy_sz, count-copy_sz);
            return copy_sz;
        }
    }
}

size_t     rb_write(RingBuffer *rb, const void *data, size_t count)
{
    //assert(rb != NULL);
    //assert(data != NULL);
    
    if (count >= rb_can_write(rb)) 
            return -1;
    
    if (rb->rb_head <= rb->rb_tail)
    {
        int tail_avail_sz = rb_capacity(rb) - (rb->rb_tail - rb->rb_buff);
        if (count <= tail_avail_sz)
        {
            memcpy(rb->rb_tail, data, count);
            rb->rb_tail += count;
            if (rb->rb_tail == rb->rb_buff+rb_capacity(rb))
                rb->rb_tail = rb->rb_buff;
            return count;
        }
        else
        {
            memcpy(rb->rb_tail, data, tail_avail_sz);
            rb->rb_tail = rb->rb_buff;
            
            return tail_avail_sz + rb_write(rb, (char*)data+tail_avail_sz, count-tail_avail_sz);
        }
    }
    else
    {
        memcpy(rb->rb_tail, data, count);
        rb->rb_tail += count;
        return count;
    }
}
typedef struct {
    size_t rb_capacity;
    char  *rb_head;
    char  *rb_tail;
    char  rb_buff[64];
}RingBuffer;
//struct RingBuffer;

// RingBuffer* rb_new(size_t capacity);
void rb_new(RingBuffer* rb);
void        rb_free(RingBuffer *rb);

size_t     rb_capacity(RingBuffer *rb);
size_t     rb_can_read(RingBuffer *rb);
size_t     rb_can_write(RingBuffer *rb);

size_t     rb_read(RingBuffer *rb, void *data, size_t count);
size_t     rb_write(RingBuffer *rb, const void *data, size_t count);

static void GetFrame()
{
    if(rb_can_read(&u_ring_buff) >= 1)
    {
      if(1 == syncFlag)
        {
            if(cnt <= 7)
            {
                rb_read(&u_ring_buff, &curValue, 1);
                //printf("cnt:%d\t",cnt);
                pm_buf[cnt++] = curValue;
                //printf("Interrupt_value:%2X\r\n\r\n",curValue);
            }
            else
            {
                //memset(pm_buf, 0, 8);
                cnt = 0;
                syncFlag = 0;
                syncHead[1] = 0xFF;
                syncHead[0] = 0xFF;
            }
        }
        else
        {
            //printf("Syncing......\r\n");
            rb_read(&u_ring_buff, &curValue, 1);
            syncHead[1] = syncHead[0];
            syncHead[0] = curValue;
            
            if(syncHead[1] == 0xAA && syncHead[0] == 0xC0)
                syncFlag = 1;
        }
    }
}

用了循环缓冲区后,发现用到一段时间后,之前还能正常提取数据的数据帧,过了一段时间数据就乱掉了,逻辑没搞清楚吗?

上一篇下一篇

猜你喜欢

热点阅读