C语言数据结构之管道浅析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_37787043/article/details/81476928

管道是什么?
管道是先进先出的数据结构,相当于一个缓冲区;
数据长度一般是1Byte,这里设置管道缓冲区为512Byte;
管道的作用是?
有时候需要一定长度的数据,不仅仅是1Byte;
实现思路:申请缓冲区
—》使用两个指针分别指向缓冲区的首地址和尾地址,例如begin,end
—》要实现随时找到管道中任意一个成员,使用两个指针分别指向第一个成员(head)和最后一个成员(tail)
—》使用环形缓冲区存储数据

如何使用管道?
以下程序的管道 = 管道结构体+缓冲区;

//定义一个管道结构体
typedef struct _Pipe_t {
    uint8_t * beginPtr; //管道内存块首地址
    uint8_t * headPtr;      //管道元素首部,指向下一个要存储的地址
    uint8_t * tailPtr;      //管道元素尾部,指向下一个要读取的地址
    uint8_t * endPtr;   //管道内存块尾部 ,最后一个内存地址+1
}  Pipe_t;

//初始化管道,申请缓冲区
//参数1:结构体指针
//参数2:缓冲区(数组)首地址
//参数3:缓冲区大小
//示例:pipe_init(&TLSR8266_pipe, (uint8_t *)Usart3_buff,USART3_BUFF_SIZE);
void pipe_init(Pipe_t *pipe, uint8_t * buffer, uint16_t size)
{   
    (*pipe).beginPtr = buffer;  
    (*pipe).headPtr = buffer;       
    (*pipe).tailPtr = buffer;   
    (*pipe).endPtr = buffer+size;
}

//从管道中读取数据
//参数1:管道名
//参数2:读取数值,存放到value
//示例:pipe_read(&TLSR8266_pipe, &buf[4]);
bool pipe_read(Pipe_t *pipe, uint8_t * value)
{
    if((*pipe).headPtr != (*pipe).tailPtr)
    {
        *value = *((*pipe).tailPtr);
        (*pipe).tailPtr++;
        if((*pipe).tailPtr == (*pipe).endPtr)
            (*pipe).tailPtr = (*pipe).beginPtr;
        return true;
    }
    else
    {
        *value = 0xFF;//也可以是0x00吧
        return false;
    }
}

//向管道写入数据
//参数1:管道名
//参数2:要写入的数值
//示例:pipe_write(&TLSR8266_pipe,ch);
//一般用于中断服务函数里面读取到的数据,写入;
bool pipe_write(Pipe_t *pipe, uint8_t value)
{
    if((*pipe).headPtr != (*pipe).tailPtr - 1)//判断管道元素首部是否与管道元素尾部相同,相同表示存满
    {
        if(((*pipe).headPtr != (*pipe).endPtr -1) || ((*pipe).tailPtr != (*pipe).beginPtr))//判断管道元素首部是否存放到管道尾地址,或者管道元素尾部是否存放到管道首地址
        {
            *((*pipe).headPtr) = value; //数据存放到管道元素首部
            (*pipe).headPtr++;          //管道元素首部向后移一位
            if((*pipe).headPtr == (*pipe).endPtr)//如果管道元素首部等于管道尾地址,即存满管道了
            {
                (*pipe).headPtr = (*pipe).beginPtr;//管道元素首部指向管道首地址(环形内存)
            }
            return true;

        }
        else
        {
            return false;
        }

    }
    else
    {
        return false;
    }
}

下面以TLRS 8266的蓝牙模块为例,使用管道存储和读取蓝牙数据;

//初始化蓝牙模块的时候,应该一起初始化管道,也是申请一个管道;
pipe_init(&TLSR8266_pipe, (uint8_t *)Usart3_buff,USART3_BUFF_SIZE);//主要用途是使用管道存储和读取蓝牙数据

//封装“pipe_read”函数
/**********************************************************
**函数功能:读取AT指令发送后返回的值
**buf数组大小固定为6个元素
***********************************************************/
static void TLSR8266_ReadReturn(unsigned char* buf)
{
    pipe_read(&TLSR8266_pipe, &buf[0]);
    pipe_read(&TLSR8266_pipe, &buf[1]);
    pipe_read(&TLSR8266_pipe, &buf[2]);
    pipe_read(&TLSR8266_pipe, &buf[3]);
    pipe_read(&TLSR8266_pipe, &buf[4]);
    pipe_read(&TLSR8266_pipe, &buf[5]);
}
uint8_t buf[6] = {0};
TLSR8266_ReadReturn(buf);
printf("buf : %s\r\n",buf);//打印出从管道读取的数据

//蓝牙模块接收手机发送来的数据,存放到管道里面
void USART3_IRQHandler(void)
{
    if(USART_GetFlagStatus(USART3, USART_FLAG_IDLE) != RESET)
    {
    }
    if(USART_GetFlagStatus(USART3, USART_FLAG_ORE) != RESET)
    {
        USART_ReceiveData(USART3);//接收到数据
    }
    //接收完的一批数据,还没有被处理,则不再接收其他数据
    if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)
    {
        uint8_t ch = USART3->DR;

        USART_ClearITPendingBit (USART3, USART_IT_RXNE);

        if(TLSR8266_pipe_enable)
                pipe_write(&TLSR8266_pipe,ch);//向管道写入数据

        usart1_putc(ch);//把蓝牙接收的数据显示在串口上
//      printf("%x ",ch);//十六进制显示

    }
}

至此,基本完成对管道的使用;
代码链接:https://pan.baidu.com/s/1DUtrQLRgiwj7_tOsszDL-g 密码:a3xy

猜你喜欢

转载自blog.csdn.net/weixin_37787043/article/details/81476928
今日推荐