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

管道是什么?

管道是先进先出的数据结构,相当于一个缓冲区;
数据长度一般是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

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值