历史上的今天
今天是:2024年08月26日(星期一)
2019年08月26日 | 基于STM32的串口数据环形缓冲队列
2019-08-26 来源:eefocus
最近进行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("writeokrn");
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,stoprn");
// printf("%drn",totalSend);
// printf("hello,stoprn");
while(1){
//从缓冲区取数据进行发送
if(datacount < 120){
if(!VoltageSend())//数据发送成功
{
totalSend++;
// printf("rn");
// printf("%drn",totalSend);
if(totalSend == 600){
delay_ms(100);
stop();
totalSend = 0;
datacount++;
//延时,等待上位机开启数据解调线程10ms
delay_s(6);
}
delay_ms(50);
}
}
}
}
史海拾趣
|
数字、英文 1/4比特数 quarter bit number AGC恢复时间 AGC recovery time AGC启动时间 AGC attack time ATM技术 asynchronous transfer technics, 异步转移模式,为多种速率信 息的情况下研究的一种合适的传输与交换方式。 GSM 泛欧数字蜂窝 ...… 查看全部问答> |
|
第一次接触到单片机这块,前几天老师给了我一块带ATMAGE16L的开发板,上面只有一个JTAG接口,一个flash存储块,还有一个8兆的晶振元件(上面标有8.000,我对硬件不熟悉,不知道是不是这么称呼),要求我用8兆的晶振 ...… 查看全部问答> |
|
evc4开发环境 我自己写了一个类。 CRulers::CRulers() { CRect rect; GetClientRect(rect); m_X = 20; m_DownY =(m_rec ...… 查看全部问答> |
|
从网上下载了一个mp3播放器的代码应该是wince5.0自带的媒体播放器,在EVC4.0下能够编译,但连接后启动模拟器时就弹出一个对话框,出现下面的错误提示!(SDK是自己导出的,不是标准的SDK,CPU没选是在模拟器下运行的) The specified& ...… 查看全部问答> |
|
CCS编译错误error:symbol referencing errors-`f14.out` not built 如题目。我编译的时候只有这一个错误,请问谁能帮我指点一下到底错在哪里了??… 查看全部问答> |
|
s3c6410_iic.dll 文件可以被加载,也生成了IIC0设备,但是IIC_Init()函数里的打印信息没有输出来: DEBUGMSG(1,(TEXT(\"+IIC_Init\\r\\n\"))); 打开IIC0设备进行操作也没有信号丛SCL与SDA输出。 为什么驱动被加载了,但没有跑IIC_Init()函数 ...… 查看全部问答> |
|
Linear公司于1981年9月26日建立,今天刚好是其30岁生日,公司由Bob Widlar、Bob Swanson以及Bob Dobkin创办。作为从美国国家半导体分拆出的业务部门,Linear一直扎根于模拟IC业,而其“导师”NS(美国国家半导体)最近十余年一直在迷失着方向。从收 ...… 查看全部问答> |
|
我用的是msp430f149型,想要用A5通道测外部电压,并在1602上显示出来,但程序烧进去后A5通道还未连接任何待测器件时1602上就显示了1.87V的电压。当我依次测十二个电阻串联时的电压时 前两个还是准的可约到后面测的越不准了,电压变化越来越小。这是 ...… 查看全部问答> |




