STM32
直播中

lique

13年用户 884经验值
擅长:模拟与电源
私信 关注
[问答]

如何解决STM32开发数据处理速度不够及时而出现掉包的问题?

如何解决STM32开发数据处理速度不够及时而出现掉包的问题?

回帖(1)

黄飞高

2021-12-7 14:19:29
最近进行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);
}

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);
                        }
                }
        }
}


举报

更多回帖

发帖
×
20
完善资料,
赚取积分