您的位置:首页 > 移动开发

【ESP8266】app_IR_TxRx_demo中的RingBuf代码透析

2016-08-13 10:43 281 查看
在裸机单片机开发中,有时候需要用到先入先出队列(FIFO),可是一般的裸机开发环境是没有一个库函数给开发者使用队列的,这个时候需要自己写队列函数。后来,我在开发ESP8266和基于cc2530的contiki系统时,都发现这些系统下面有一个RingBuf文件,说明这个RingBuf就是为了解决裸机单片机开发中队列的问题。下面我来分析一下ESP8266中的RingBuf代码。

阅读代码时第一步都是先看数据结构,那么来看看RINGBUF数据结构。

typedef struct{
uint8_t* p_o;               /**< Original pointer */
uint8_t* volatile p_r;      /**< Read pointer */
uint8_t* volatile p_w;      /**< Write pointer */
volatile int32_t fill_cnt;  /**< Number of filled slots */
int32_t size;               /**< Buffer size */
}RINGBUF;


该结构体很简单,p_o是用来保存初始地址的指针,p_r是读取指针,p_w是写入指针,fill_cnt用来计数的,每写入一个数据就加1,size是保存该数组队列的大小。

初始化函数RINGBUF_Init:

/*
* \brief init a RINGBUF object
* \param r pointer to a RINGBUF object
* \param buf pointer to a byte array
* \param size size of buf
* \return 0 if successfull, otherwise failed
*/
int16_t RINGBUF_Init(RINGBUF *r, uint8_t* buf, int32_t size)
{
if (r == NULL || buf == NULL || size < 2)
return -1;                  //如果r和buf传入的参数为空、size数组大小小于2,则初始化失败

r->p_o = r->p_r = r->p_w = buf; //初始化p_o,p_r,p_w
r->fill_cnt = 0;                //初始化fill_cnt
r->size = size;                 //初始化size

return 0;
}


写入一个数据RINGBUF_Put:

/**
* \brief put a character into ring buffer
* \param r pointer to a ringbuf object
* \param c character to be put
* \return 0 if successfull, otherwise failed
*/
int16_t RINGBUF_Put(RINGBUF *r, uint8_t c)
{
if (r->fill_cnt >= r->size){
printf("BUF FULL\n");
return -1;                  // 如果缓冲区满了,则返回-1错误
}

r->fill_cnt++;                  // 每写入一个字节,则加1计数

*r->p_w++ = c;                  // 把数据放入缓冲区,并指向下一个地址

if (r->p_w >= r->p_o + r->size) // 如果写入指针超过了缓冲区末尾,则
r->p_w = r->p_o;            // 把指针指向原点,这就是RING的含义

return 0;
}


读取数据RINGBUF_Get:

/**
* \brief get a character from ring buffer
* \param r pointer to a ringbuf object
* \param c read character
* \return 0 if successfull, otherwise failed
*/
int16_t RINGBUF_Get(RINGBUF *r, uint8_t* c, int32_t length)
{
int32_t cnt = 0;
if (r->fill_cnt <= 0)
return -1;             // 如果缓冲区为空,则返回-1错误

if (length>r->fill_cnt){
length = r->fill_cnt;  // 最大只能读取缓冲区拥有数据的长度
}

int i;
cnt = r->fill_cnt;
for (i = 0; i<length; i++)
{
r->fill_cnt--;                  // 每读取一个字节,计数减1
*c = *r->p_r++;                 // 返回数据给*c
*c++;
if (r->p_r >= r->p_o + r->size) // 如果读取指针超过了缓冲区末尾,则
r->p_r = r->p_o;            // 把指针指向原点
}
return 0;
}


主函数及其他,这里使用VS2013开发环境测试该RingBuf:

#define RX_RCV_LEN 128
RINGBUF IR_RX_BUFF;
uint8_t ir_rx_buf[RX_RCV_LEN];
#define READ10CHAR_TEST 0

int _tmain(int argc, _TCHAR* argv[])
{
//RINGBUF初始化
//把ir_rx_buf初始化为一个RingBuf,使用IR_RX_BUFF结构体保存信息,长度为sizeof(ir_rx_buf)
RINGBUF_Init(&IR_RX_BUFF, ir_rx_buf, sizeof(ir_rx_buf));

int i = 10;
while (i--){
#if READ10CHAR_TEST
RINGBUF_Put(&IR_RX_BUFF, '1'+i);
#else
RINGBUF_Put(&IR_RX_BUFF, i);    //放入10个字节到IR_RX_BUFF中
#endif
}

#if READ10CHAR_TEST
uint8_t data[11] = {0};
RINGBUF_Get(&IR_RX_BUFF, data, 10); //从IR_RX_BUFF读取1个字节
printf("RingBuf pop : %s \r\n", data);  //打印该字节
#else
uint8_t data;
while (IR_RX_BUFF.fill_cnt){
i = 10;
while (i--){
RINGBUF_Get(&IR_RX_BUFF, &data, 1); //从IR_RX_BUFF读取1个字节
printf("RingBuf pop : %d \r\n", data);  //打印该字节
}
}
#endif

return 0;
}


当READ10CHAR_TEST置0时,每次从RINGBUF读取一字节,打印出的信息为:

RingBuf pop : 9

RingBuf pop : 8

RingBuf pop : 7

RingBuf pop : 6

RingBuf pop : 5

RingBuf pop : 4

RingBuf pop : 3

RingBuf pop : 2

RingBuf pop : 1

RingBuf pop : 0

请按任意键继续…

当READ10CHAR_TEST置1时,一次性从RINGBUF读取10字节,打印出的信息为:

RingBuf pop : :987654321

请按任意键继续…

扩展

后面扩展了一下这个RingBuf的功能,增加了两个函数。

//清空缓冲区
int16_t RINGBUF_Clr(RINGBUF *r)
{
memset(r->p_o, 0, r->size);
r->p_r = r->p_w = r->p_o;
r->fill_cnt = 0;

return 0;
}

//读取第index个数据
uint8_t RINGBUF_Read(RINGBUF *r, int32_t index)
{
uint8_t data = 0;

if (r->fill_cnt <= 0)
return 0;             // 如果缓冲区为空,则返回0

if (index > r->fill_cnt){
index = r->fill_cnt;  // 最大只能读取缓冲区拥有数据的长度
}

if (r->p_r + index >= r->p_o + r->size){ // 如果读取的index超过了缓冲区末尾,则
//r->p_r = r->p_o;                      // 从头开始计算index
index = index - (r->p_o + r->size - r->p_r);
}

data = r->p_r[index];   //读取第index个数据

return data;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: