基于STM32的串口数据环形缓冲队列


最近进行STM32开发,在处理大规模串口数据的时候,由于数据处理速度不够及时而出现掉包的问题,为此通过以下方案成功解决。


BTW:在串口循环发送一组数据的时候,应该在发送第一个字节之前也加上判断缓冲区是否为空。
正确形式如下:

//这个函数会循环执行
void stop(void){
	//发送10给上位机,使其进入数据解调
	float_data.d = 10 * 10000;
	while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);
	USART_SendData(USART1,0xff);//发送开始帧标志位
	while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);
	USART_SendData(USART1,float_data.s[3]);
	while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);
	USART_SendData(USART1,float_data.s[2]);
	while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);
	USART_SendData(USART1,float_data.s[1]);
	while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);
	USART_SendData(USART1,float_data.s[0]);
	while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);
	USART_SendData(USART1,0x0e);//发送结束标志位
	while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);
}

参考博客:基于stm32串口环形缓冲队列处理机制—入门级(单字节)


1. 环形缓冲队列

STM32串口在接收数据的时候,数据的处理速度小于数据接收的速度,造成数据丢包现象。
为此,引进串口环形缓冲区对未来得及处理的数据进行缓存,待系统空闲的时候进行处理。
环形缓冲区就是一个带“头指针”和“尾指针”的数组。头指针指向环形缓冲区中可读的数据,尾指针指向环形缓冲区中可写的缓冲空间。
缓冲区建立过程:
当串口接收到新的数组,则将数组保存到环形缓冲区中,同时将“尾指针”加1,以保存下一个数据;应用程序在读取数据时,“头指针”加1,以读取下一个数据。当“尾指针”超过数组大小,则“尾指针”重新指向数组的首元素,从而形成“环形缓冲区”!,有效数据区域在“头指针”和“尾指针”之间。
在这里插入图片描述
环形队列缓冲

缓冲区构造:

#define MAX_SIZE  12//缓冲区大小

typedef struct 

{

  unsigned char head;        //缓冲区头部位置

  unsigned char tail;         //缓冲区尾部位置

  unsigned int ringBuf[MAX_SIZE]; //缓冲区数组

} ringBuffer_t;

ringBuffer_t buffer = {0,0,{0}};                 //定义一个结构体,并初始化

① 空队列:头指针head和尾指针tail都是指向数组的元素0

空队列

② 缓冲区满
缓冲区满
当如果l加入队列,则缓冲队列处于满载状态,如图所示。
如果此时,接收到新的数据并需要保存,则tail需要归零,将接收到的数据存到数组的第一个元素空间,如果尚未读取缓冲数组的一个元素空间的数据,则此数据会被新接收的数据覆盖。同时head需要增加1,修改头节点偏移位置丢弃早期数据。

在这里插入图片描述
③ 缓冲区为空: tail和head相等
缓冲区为空

2. 环形缓冲队列的实现

ringbuffer.h

#ifndef _RINGBUFFER_H
#define _RINGBUFFER_H

#define BUFFER_MAX 6000//定义缓冲区大小

typedef struct{
	unsigned int headPosition;//缓冲区头部位置
	unsigned int tailPosition;
	float ringBuf[BUFFER_MAX];//缓冲区数组
	
}ringBuffer_t;

void RingBuf_Write(float data);//向缓冲区写入一个字节
unsigned char RingBuf_Read(float* pData);//读取缓冲区一个字节的数据
unsigned char VoltageSend(void);
void stop(void);
#endif


ringbuffer.c:

#include "ringbuffer.h"

ringBuffer_t buffer = {0,0,{0}};

void RingBuf_Write(float data){//向缓冲区写入一个字节
	buffer.ringBuf[buffer.tailPosition] = data;//从尾部追加
//	printf("writeok\r\n");
	if(++buffer.tailPosition >= BUFFER_MAX)//尾节点偏移
		buffer.tailPosition = 0;//大于数组,最大长度归零,形成环形数组
	//如果尾部节点追到头部节点,则修改头节点偏移位置丢弃早期数据
	if(buffer.tailPosition == buffer.headPosition)
		if(++buffer.headPosition >= BUFFER_MAX)
			buffer.headPosition=0;
}


unsigned char RingBuf_Read(float* pData){//读取缓冲区一个字节的数据
	if(buffer.headPosition == buffer.tailPosition){//头尾相接表示缓冲区数据为空
		return 0;//读取失败返回0
	}
	else{
		*pData = buffer.ringBuf[buffer.headPosition];//如果缓冲区非空则取头结点值并偏移头结点
		if(++buffer.headPosition>=BUFFER_MAX)
			buffer.headPosition = 0;
		return 1;//读取成功返回1
	}
}



main.c:关注核心代码即可

int main()
{
	unsigned int totalSend = 0;
	unsigned int datacount = 0;
	SysTick_Init();
	LED_Config();
	USART1_Config();
	NVIC_Config();
	ADC1_Config();
	DMA1Config();
	PWM_Config();
//	printf("hello,stop\r\n");
//	printf("%d\r\n",totalSend);
//	printf("hello,stop\r\n");
	while(1){
		//从缓冲区取数据进行发送
		if(datacount < 120){
			if(!VoltageSend())//数据发送成功
			{
				totalSend++;
				
	//			printf("\r\n");
	//			printf("%d\r\n",totalSend);
				if(totalSend == 600){
					delay_ms(100);
					stop();
					totalSend = 0;
					datacount++;
					//延时,等待上位机开启数据解调线程10ms
					delay_s(6);
				}
				delay_ms(50);
			}
		}
	}
}
  • 8
    点赞
  • 127
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32串口接收环形队列是一种常见的串口接收数据的方法,其核心思想是利用环形缓冲区来存储串口接收到的数据,从而实现数据的有效保存和处理。 首先,我们需要定义一个固定大小的环形缓冲区,通常使用数组来实现。数组的大小取决于接收数据的量大小和实际需求。同时,我们还需定义两个指针,一个用于指向缓冲区的头部,一个用于指向缓冲区的尾部。 当串口接收到数据时,将数据依次存储在缓冲区的尾部,并将尾指针向后移动一位。如果尾指针超出了缓冲区的大小,则将其重置为缓冲区的头部。这样,当数据存储到缓冲区尾部时,尾指针将会自动回到缓冲区的头部,形成一个闭环。 同时,我们还需定义一个变量来保存当前接收到的数据个数。当接收到数据时,计数器加一;当读取数据时,计数器减一。通过计数器的值,我们可以确定缓冲区是否为空或已满。 为了方便读取数据,我们可以编写一个读取函数。该函数首先判断缓冲区是否为空,若为空则返回错误信息,否则将读取头指针指向的数据,并将头指针向后移动一位。同样,如果头指针超出了缓冲区的大小,则将其重置为缓冲区的头部。 使用环形队列的好处是,可以很方便地处理串口接收数据的时序问题。不用担心数据的读取和存储的时序问题,只需按照指针指向的位置进行相关操作即可。另外,由于环形队列的特性,可以大大减少数据溢出的风险,提高了数据的可靠性。 总结来说,STM32串口接收环形队列提供了一种高效、稳定的串口接收数据的方法。通过合理的设计和操作,可以实现串口数据的无缝读取与存储,保证数据的准确性和完整性。这种方法在许多嵌入式应用中被广泛使用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值