循环buffer

  反码表示法规定:正数的反码与其原码相同;负数的反码是对其原码逐位取反,但符号位除外。
  补码表示法规定:正数的补码与其原码相同;负数的补码是在其反码的末位加1。

  循环buffer即循环缓冲区,顾名思义,就是可以不断写不断读的一个局域,在缓冲区写满之后,如果还没有读取就不能继续写了,否则会把原来的覆盖掉。

这里写图片描述

所以说这是个循环读写的过程,写指针写一个字节移动一次,读指针读一个字节移动一次,移动到buff的末尾位置,又从开始位置进行读写。

重点代码分析:

1、计算空闲空间/数据空间大小:

设定总空间为size-1,始终保留1个字节,如果剩余一个字节空间,就表示buff已满。

先看看负数的二进制我们来求-1的二进制:

1、先取1的原码:00000000 00000000 00000000 00000001
2、得反码:     11111111 11111111 11111111 11111110
3、得补码:     11111111 11111111 11111111 11111111

可见,-1在计算机里用二进制表达就是全1。16进制为:0xFFFFFF

所以这里如果涉及到负数运算就需要注意了!

int rb_data_size (Ringbuff *rb)    //计算数据空间大小
{
    return ( (rb->wr_pointer - rb->rd_pointer) & (rb->size -1));   
}

int rb_free_size (Ringbuff *rb)   //计算空闲空间大小
{
    return ( rb->size - 1 - rb_data_size(rb));
}

这里读写都是对于8的整数倍buf来操作的,所以定义的buf空间必须是8的整数倍。


2、写操作

数据写如是靠写指针来指定从哪里开始写,所以写指针的位置有决定性作用。
流程:

  • 判断写入的数据len是否大于循环buff空间
  • 如果超出,自动截断写入的数据
  • 写指针加上len之后是否超过buff末尾,超过之后需要把多余的循环写入前面的空闲buff中
  • 最后重新设置写指针位置

这里写图片描述

int rb_write (Ringbuff *rb, u_char *buf, int len)
{
    int rb_freesize = rb_free_size(rb);  //空闲空间大小
    int pos = 0;          //读指针位置

    if (len > rb_freesize)     
    {
        len = rb_freesize;  //输入超过空闲空间,自动截断
    }
    else
    {
        rb_freesize = len;
    }

    pos = rb->wr_pointer;

    if (pos + len > rb->size)    //如果写入的数据加上超过循环buff大小
    {
        memcpy(rb->buff + pos, buf, rb->size - pos);   //先拷贝未超过那部分,剩下的写入前面那部分空闲空间
        buf += rb->size-pos;  //移动buf
        len -= rb->size-pos;  //剩余那部分长度
        pos = 0;   //将读指针重新放在最开始位置
    }

    memcpy(rb->buff + pos,buf,len);
    rb->wr_pointer = pos + len;   //设置写指针位置
    return rb_freesize;
}

写过程和读过程是个相反的过程,思想是一样的。


完整代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct ring_buff
{
    u_char *buff;        //定义buff空间,用于存储数据 
    int wr_pointer;      //写指针
    int rd_pointer;      //读指针   
    int size;
};
typedef struct ring_buff Ringbuff;

int rb_data_size (Ringbuff *rb)    //计算数据空间大小
{
    return ( (rb->wr_pointer - rb->rd_pointer) & (rb->size -1));
}

int rb_free_size (Ringbuff *rb)   //计算空闲空间大小
{
    return ( rb->size - 1 - rb_data_size(rb));
}

void rb_init (Ringbuff *rb,u_char *buf,int size)
{
   memset(rb,0,sizeof(Ringbuff)); 
   rb->rd_pointer = 0;
   rb->wr_pointer = 0;
   rb->buff = buf;    
   rb->size = size;
}

void clear (Ringbuff *rb)
{
    memset(rb->buff,0,rb->size);
    rb->rd_pointer = 0;
    rb->wr_pointer = 0;
}

int rb_write (Ringbuff *rb, u_char *buf, int len)
{
    int rb_freesize = rb_free_size(rb);  //空闲空间大小
    int pos = 0;          //读指针位置

    if (len > rb_freesize)     
    {
        len = rb_freesize;  //输入超过空闲空间,自动截断
    }
    else
    {
        rb_freesize = len;
    }

    pos = rb->wr_pointer;

    if (pos + len > rb->size)    //如果写入的数据加上超过循环buff大小
    {
        memcpy(rb->buff + pos, buf, rb->size - pos);   //先拷贝未超过那部分,剩下的写入前面那部分空闲空间
        buf += rb->size-pos; 
        len -= rb->size-pos;
        pos = 0;
    }

    memcpy(rb->buff + pos,buf,len);
    rb->wr_pointer = pos + len;   //设置写指针位置
    return rb_freesize;
}

int rb_read (Ringbuff *rb, u_char * buf, int max)
{
    int datasize=rb_data_size(rb);
    int pos = 0;

    if (max > datasize)
    {
        max = datasize;
    }
    else 
    {
        datasize = max;
    }

    pos = rb->rd_pointer;

    if (pos + max > rb->size)
    {
        memcpy(buf,rb->buff + pos,rb->size - pos);
        buf +=rb->size;
        max -=rb->size;
        pos = 0;
    }

    memcpy(buf,rb->buff + pos,max);
    rb->rd_pointer = pos + max;

    return datasize;
}

int main()
{
    Ringbuff *ring=(Ringbuff *)malloc(sizeof(Ringbuff));
    u_char a[20]="abcdefghijklmno";
    u_char buff[8]={0};       //定义循环buff
    u_char mybuff[12]={0};    //用来存储从循环buff中读出的数据

    rb_init (ring, buff, sizeof(buff));   //8

    int w_res=0,r_res=0;
    int i=0;

    printf("--------------写------------\n");

    w_res = rb_write (ring, a, 4);   //先从a中写入四个字节到循环buff
    printf("写入四个字节后,写指针所在位置:%d\n",ring->wr_pointer); 

    printf("当前空余空间:%d\n",rb_free_size(ring));
    printf("当前数据所占空间:%d\n",rb_data_size(ring));

    printf("\n");
    printf("--------------读-------------\n");
    r_res = rb_read (ring, mybuff, 3);
    printf("第一次读取的数据:%s\n",mybuff);
    printf("\n");


    printf("------------第二次写---------------\n");
    w_res = rb_write (ring, &a[4], 6);
    printf("第二次写入6个字节,写指针所在位置:%d\n",ring->wr_pointer); 
    printf("读指针所在位置:%d\n",ring->rd_pointer); 

    printf("当前空余空间:%d\n",rb_free_size(ring));
    printf("当前数据所占空间:%d\n",rb_data_size(ring));

    // printf("%d\n",ring->wr_pointer);
    printf("\n");
    printf("-------------第二次读--------------\n");
    r_res = rb_read (ring, &mybuff[3], 2);
   // printf("%d \t %d\n",w_res,r_res);
    printf("\n");
    printf("第二次读到的数据:%s\n",mybuff);

    return 0; 

}

运行结果:

这里写图片描述

串口循环buffer是一种用于缓存数据的机制,常用于串口通信中。它通过循环队列的方式,将接收到的数据流先缓存到循环buffer中,然后再从循环buffer中取出数据进行后续处理。这种机制可以有效地避免解析数据帧时繁琐的拼接处理。在WINCE开发中,循环buffer常被用于串口通信,以提高数据处理效率。\[2\]在串口通信中,接收到的数据会按照循环的方式存储在循环buffer中,当循环buffer存满后,新的数据会从循环buffer的起始位置重新存储,形成一个循环的结构。\[3\]这种循环buffer的实现方式可以确保数据的连续性和高效性。 #### 引用[.reference_title] - *1* *2* [Buffer循环机制](https://blog.csdn.net/weixin_45264425/article/details/130233405)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [高效的串口循环Buffer接收处理思路及代码2](https://blog.csdn.net/zz603976046/article/details/121827631)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值