搜索
bottom↓
回复: 14

STM32的串口是否具有硬件缓存的功能?

[复制链接]

出55入4汤圆

发表于 2022-8-21 15:48:15 | 显示全部楼层 |阅读模式
100汤圆
本帖最后由 ChenXC1121 于 2022-8-21 16:03 编辑

程序如下,STM32跑UCOS II系统,在串口中断中收取数据(串口数据来的时间不定的,有时间隔很短)并缓存到全局数组usart_rxbuf中,另外在主程序中判断到rec_flag标志被置2了,就关闭串口中断,之后把全局数组usart_rxbuf中的数据拷贝到主程序中定义的一个局部数组中,拷贝时间应该很快,之后又马上开启串口中断,如果刚刚好在主程序关闭串口中断拷贝数据的时候串口数据来了,请问STM32内部有硬件缓存功能来缓存这段时间来的数据吗?还是这时候的数据一定会丢,请大神帮忙分析下,谢谢!


/********************串口中断处理函数*******************************/
volatile u8 usart_rxbuf[200];
volatile u8 rec_flag=0;
volatile u8 USART2_RX_BUF[100];                                 //接收缓冲

void USART2_IRQHandler(void)
{
        u8 res;
        u8 i=0,j=0;
        u8 temp=0;
        u16 crc_check=0;        
        OSIntEnter();   
        if(USART2->SR&(1<<5))//接收到数据
        {         
                res=USART2->DR;         
                if((res==0xAA)&&(start_rev==0))
                {
                        rev_num=0;
                        start_rev=1;
                }
                if(start_rev==1)
                {
                        USART2_RX_BUF[rev_num]=res;
                        rev_num++;
                        if(rev_num>63)
                        {
                                if(USART2_RX_BUF[1]==0x55)
                                {
                                        if(USART2_RX_BUF[3]==0x5C)        //采集模块数据上报
                                        {
                                                crc_check=cal_crc(&USART2_RX_BUF[0],63);
                                                temp=crc_check&0x00ff;
                                                if(temp==USART2_RX_BUF[63])        //必须校验和正确  才会执行写入动作
                                                {               
                                                        rec_flag=2;                                 
                                                        for(j=0;j<4;j++)
                                                        {
                                                                temp=j*50;
                                                                if(usart_rxbuf[temp]==0xff)        //0xff代表本段没数据  可以存入
                                                                {
                                                                        for(i=5;i<45;i++)
                                                                                usart_rxbuf[4+i+temp]=USART2_RX_BUF;                  
                                                                        break;
                                                                }
                                                        }
                                                }
                                        }                                       
                                        start_rev=0;
                                        rev_num=0;                                       
                                }                                
                                else
                                {
                                        start_rev=0;
                                        rev_num=0;
                                }
                        }
                }
        }                                 
        OSIntExit();  
}



/************主任务程序*****************/
while(1)
{
        if(rec_flag==2)
        {
                rec_flag=0;
               
                for(i=0;i<4;i++)
                {
                        temp=i*50;
                        USART_INT_DISABLE();                                //关闭串口中断
                        if(usart_rxbuf[temp]!=0xff)                //代表该位置存在数据
                        {
                                for(j=0;j<50;j++)        
                                {
                                        //usart_rxbuffer数组是while循环内部定义的局部数组变量
                                        usart_rxbuffer[j]=usart_rxbuf[temp+j];                                       
                                }
                                usart_rxbuf[temp]=0xff;                //该条数据处理完成后第一个BYTE置FF  代表数据已处理过了
                                USART_INT_ENABLE();                        //开启串口中断

                               //后面是对usart_rxbuffer数组进行分析处理

                        }
                }
        }
}


阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入31汤圆

发表于 2022-8-21 16:13:46 | 显示全部楼层
stm32的串口没有缓存或者某种意义上是1Byte的缓存,简单讲就是在关闭串口中断时间这段时间内串口若发生“接收中断”则数据就会丢失,也就是说你最大只有1一个字节的传输时间去拷贝数据,和你关闭中断的时刻有关。这样的设计是很容丢数据的。比较好的实现方式:开辟环形缓冲区,中断只负责将接收的串口数据塞入环形缓冲区中,数据处理在其它地方进行。

出100入312汤圆

发表于 2022-8-21 16:14:15 来自手机 | 显示全部楼层
本帖最后由 akey3000 于 2022-8-21 16:16 编辑

网上转的:

众所周知,STM32串口通讯,接收及发送都没有设计硬件FIFO,这对大部分程序员来说,算是一个硬伤。但实际上,由于STM32串口可以利用DMA收发,这样比固定16字节的FIFO更灵活。


在编写串口接收的bsp层代码时,同时启动DMA接收和空闲中断,就可以实现一个硬件接收缓冲,在空闲中断中,
实现数据从硬件接收缓冲的读取。

串口接收bsp层接收缓冲两层结构
--第一层FIFO硬件接收缓冲 (第一层硬件FIFO接收缓冲,利用DMA自动传输,不占用CPU时间,一般大小可设置为16-1024字节)
--第二层FIFO软件接收缓冲 (第二层软件FIFO接收缓冲,在DMA传输完毕中断中处理,缓冲可设置的比较大,一般是1024~8192字节)

但实际上,由于STM32串口可以利用DMA收发,这样比固定16字节的FIFO更灵活。

同时启动DMA接收和空闲中断,就可以实现一个硬件接收缓冲,空闲中断中,实现数据从硬件接收缓冲的读取。

在3至10Mbps串口通讯的情况下,只有这一个办法。逐个字符中断式接收来不及。

发送一般没有问题,这里主要说接收。波特率低的话,中断可以。波特率高的话,如果是5Mbps,2.2微秒需要接收一个11位串口字符,中断方式显然不现实。

HAL库的串口中断函数,并没有认真考虑DMA和空闲中断,非常不专业。

中断函数应该展开(高速收发仅打开发送完成中断和空闲中断),DMA中断应该跟根据用户定义存在别名。

没有空闲中断,应该算是HAL库不完善。
另外,接收完数据,不应该自以为是的关闭串口,应该由用户决定是否关闭。

HAL库串口空闲中断处理代码:

  /* UART in mode Transmitter end --------------------------------------------*/
  if(((isrflag & USART_SR_TC) != RESET) && ((crlits & USART_CR1_TCIE) != RESET))
  {
    UART_EndTransmit_IT(huart);
    return;
  }
  /* UART in mode Receiver end -----------------------------------------------*/
  if(((isrflags & USART_SR_IDLE) != RESET) && ((crlits & USART_CR1_IDLEIE) != RESET))
  {
    /* Clear the UART IDLE pending flag */
    __HAL_UART_CLEAR_IDLEFLAG(huart);
    return;
  }
}

出55入4汤圆

 楼主| 发表于 2022-8-21 16:16:27 | 显示全部楼层
akey3000 发表于 2022-8-21 16:14
fifo,是硬件缓存
(引用自3楼)


请问STM32能通过代码设置开启这个功能吗?

出100入312汤圆

发表于 2022-8-21 16:17:36 来自手机 | 显示全部楼层
ChenXC1121 发表于 2022-8-21 16:16
请问STM32能通过代码设置开启这个功能吗?
(引用自4楼)

stm32串口接收硬件FIFO的实现

出55入4汤圆

 楼主| 发表于 2022-8-21 16:24:02 | 显示全部楼层
akey3000 发表于 2022-8-21 16:17
stm32串口接收硬件FIFO的实现
(引用自5楼)


这个FIFO是不是就相当于环形缓冲区啦?

出100入312汤圆

发表于 2022-8-21 16:34:45 来自手机 | 显示全部楼层
ChenXC1121 发表于 2022-8-21 16:24
这个FIFO是不是就相当于环形缓冲区啦?
(引用自6楼)

串口通信速率不高,就在中断中把数据放到软件fifo,速率高,可以参考楼上文章

出0入42汤圆

发表于 2022-8-21 16:38:06 | 显示全部楼层
每隔一段时间就有人问类似的问题,这个问题的根源是在串口中断里有做数据处理,耗费太多时间。

正常的处理流程是串口中断程序只负责把数据从RX寄存器中读出(没用DMA的情况),然后压入环形缓冲。

主程序中不断判断缓冲里是否有数据,有则取出、判断、处理。

出1310入193汤圆

发表于 2022-8-21 17:21:55 | 显示全部楼层
全双工的吗  增加fifo就有啦

出0入0汤圆

发表于 2022-8-21 18:25:45 | 显示全部楼层
好像有2个,调试时接收一个进中断,发送方已发送完,出中断,还会进入一次,avr好像有3个,进入后中断,还会进入2次

出0入8汤圆

发表于 2022-8-22 08:57:31 | 显示全部楼层
dma怎么不利用起来?

出15入178汤圆

发表于 2022-8-22 23:08:57 | 显示全部楼层
有的,一般8或16字节缓冲。

出105入79汤圆

发表于 2022-8-22 23:38:59 | 显示全部楼层
stm32H7 有16字节缓冲,开了以后,可以减少16倍中断的频率。但是16字节才能处理一次数据。正确的方案是DMA加串口空闲中断。

出0入0汤圆

发表于 2023-6-29 12:09:16 | 显示全部楼层
DMA加持下不需要经常进入中断的

出0入55汤圆

发表于 2023-6-29 12:32:50 来自手机 | 显示全部楼层
这样处理数据明摆着增加硬件成本!中断里只负责读数据,然后放进环形缓冲就出来了,不会丢数据。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-25 21:44

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表