一、 概述:
串口使用时一般包含两个缓冲区,即发送缓冲区和接收缓冲区。发送数据时,先将数据存在发送缓冲区,然后通过串口发送;接收数据时,先将接收的数据存在接收缓冲区,然后再进行读取。
合理恰当的使用缓冲区,不仅可以使不同设备间正常通信,而且还有助于节约内存,提高效率。
二、缓冲区分配管理:
方法一:
通过内存池实现
1、数据结构:
struct
{
[BUF_SZ];
u32 free_bitmap;
};
参数含义:struct _CHN_POOL_MGR:内存池的数据类型
buffer:缓冲区,大小为BUF_SZ 192
free_bitmap:标志位。
注意:缓冲区又分为若干块,每块大小BLK_SZ
free_bitmap标志缓冲区块中的空闲块和被使用块,1表示空闲,0表示被使用
注:阴影部分表示存放着数据
free_bitmap初始化为(1 << (sizeof(chn_pool_mgr.buffer) / BLK_SZ)) -1即(1 << (2^10/2^6)) -1,即二进制数11111...11111b,共16个1,缓冲区块全部空闲
alloc_a_slot()函数分配缓冲区块:检测free_bitmap值,将空闲的缓冲区块标号较小的块分配,返回分配的缓冲区块的标号
free_bitmap值 | 分配的缓冲区块标号 | alloc_a_slot()返回值 |
1111...111111 | 0 | 0 |
1111...111100 | 2 | 2 |
1111...110010 | 1 | 1 |
1111...000100 | 2 | 2 |
//不是太明白????
struct
{
s16 tx;
s16 rx;
/*the current count of this channel */
s16 data_cnt;
s16 data_max;
};
参数含义:struct
tx:记录缓冲区块标号和数据的写入位置(具体存放如图所示)
rx:记录缓冲区块标号和数据的读取位置(具体存放如图所示)
data_cnt:记录缓冲区中未读取的数据量
data_max:向缓冲区中写入数据时,缓冲区中允许存在的最大数据量
tx,rx数据含义:
2,实例分析
1)向缓冲区中写数据:
向缓冲区中写数据,每次写90个字节,写两次。
初始状态:
假设struct
内存池的状态如下:
写数据:
alloc_a_slot()分配缓冲区块:
检测free_bitmap,分配缓冲区块标号为2的块;
tx记录缓冲区块标号及写入数据位置(0x80);
缓冲区块最后一个字节置为INVALID_BLK_NO;
变为如下状态:
写入90个数据:
由于90 > BLK_SZ-1(一个块存放数据的最大字节数),所以再次调用alloc_a_slot()分配缓冲区块
检测free_bitmap,分配缓冲区块标号为4的块;
tx记录缓冲区块标号及写入数据位置(0x100);
缓冲区块最后一个字节置为INVALID_BLK_NO;
此外,还要使标号为2的块的最后一个字节记录下一块的标号(4),最后将剩余的数据写入,tx记录数据位置(0x11B)
写入完成后,各参数状态如下:
第二次写入数据:
与上面类似,根据tx记录的缓冲区块标号及数据位置继续向后写。
最终变为如下状态:
3)从缓冲区中读数据
从缓冲区中读数据,每次读40个,读完为止。
假设此时缓冲区状态,及各参数如下:
data_cnt为180
此时开始读取数据,rx记录缓冲区标号及数据位置,成功读取40个数据后变为:
继续读数据,标号为2的缓冲区块内的数据读完,由该块内最后一个字节得知下一缓冲区块的标号,rx记录,此时,各参数状态如下:
继续读取,data_cnt变为0,读取结束。
小结:
由以上分析可知,使用内存池的方法,通过检测free_bitmap可使缓冲区被多个任务共同使用,节约空间。
方法二:
利用循环队列实现
1、数据类型:
struct
{
int
u8 buf[BUFFER_LEN];
};
参数含义:
tx:记录缓冲区写入位置
rx:记录缓冲区读取位置
buf:缓冲区
2、方法实现:
每存入一个字节,tx后移一位,每取走一个字节,rx后移一位
当tx移至缓冲区结尾时,若缓冲区头部已读取,则tx会继续在头部存放数据,如下:
当(rx + 1) % BUFFER_LEN == tx时,缓冲区存满
三、两种方法的比较:
比较内容 | 方法一 | 方法二(循环队列式) |
使用缓冲区的任务数 | 允许多任务 | 只能单任务 |
空间利用率 | 高 | 低 |
缓冲区的使用顺序 | 优先使用低地址处的缓冲区块 | 由低地址到高地址循环使用 |
不能存放数据的字节数 | 缓冲区块数 | 1B |
编程复杂度 | 略微复杂 | 简单 |
注:方法一不能存放数据的字节数用于记录下一缓冲区块的位置;循环队列式,不能存放数据的字节数用于循环使用缓冲区
方法一最大的好处在于可同时被多个任务共同使用,互不影响,有助于节约内存;而且每次分配空间时,会优先使用低地址处的空闲块,数据集中,有利于减少内存池的占用;某一任务释放的空间可被另一任务使用,提高了利用率,但编程略微复杂。
循环队列式编程简单,容易理解,特别适合单任务的使用,但缓冲区的利用率不是很高,且无法多任务使用。