STM32的串口是否具有硬件缓存的功能?
本帖最后由 ChenXC1121 于 2022-8-21 16:03 编辑程序如下,STM32跑UCOS II系统,在串口中断中收取数据(串口数据来的时间不定的,有时间隔很短)并缓存到全局数组usart_rxbuf中,另外在主程序中判断到rec_flag标志被置2了,就关闭串口中断,之后把全局数组usart_rxbuf中的数据拷贝到主程序中定义的一个局部数组中,拷贝时间应该很快,之后又马上开启串口中断,如果刚刚好在主程序关闭串口中断拷贝数据的时候串口数据来了,请问STM32内部有硬件缓存功能来缓存这段时间来的数据吗?还是这时候的数据一定会丢,请大神帮忙分析下,谢谢!
/********************串口中断处理函数*******************************/
volatile u8 usart_rxbuf;
volatile u8 rec_flag=0;
volatile u8 USART2_RX_BUF; //接收缓冲
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=res;
rev_num++;
if(rev_num>63)
{
if(USART2_RX_BUF==0x55)
{
if(USART2_RX_BUF==0x5C) //采集模块数据上报
{
crc_check=cal_crc(&USART2_RX_BUF,63);
temp=crc_check&0x00ff;
if(temp==USART2_RX_BUF) //必须校验和正确才会执行写入动作
{
rec_flag=2;
for(j=0;j<4;j++)
{
temp=j*50;
if(usart_rxbuf==0xff) //0xff代表本段没数据可以存入
{
for(i=5;i<45;i++)
usart_rxbuf=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!=0xff) //代表该位置存在数据
{
for(j=0;j<50;j++)
{
//usart_rxbuffer数组是while循环内部定义的局部数组变量
usart_rxbuffer=usart_rxbuf;
}
usart_rxbuf=0xff; //该条数据处理完成后第一个BYTE置FF代表数据已处理过了
USART_INT_ENABLE(); //开启串口中断
//后面是对usart_rxbuffer数组进行分析处理
}
}
}
}
stm32的串口没有缓存或者某种意义上是1Byte的缓存,简单讲就是在关闭串口中断时间这段时间内串口若发生“接收中断”则数据就会丢失,也就是说你最大只有1一个字节的传输时间去拷贝数据,和你关闭中断的时刻有关。这样的设计是很容丢数据的。比较好的实现方式:开辟环形缓冲区,中断只负责将接收的串口数据塞入环形缓冲区中,数据处理在其它地方进行。 本帖最后由 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;
}
} akey3000 发表于 2022-8-21 16:14
fifo,是硬件缓存
(引用自3楼)
请问STM32能通过代码设置开启这个功能吗? ChenXC1121 发表于 2022-8-21 16:16
请问STM32能通过代码设置开启这个功能吗?
(引用自4楼)
stm32串口接收硬件FIFO的实现 akey3000 发表于 2022-8-21 16:17
stm32串口接收硬件FIFO的实现
(引用自5楼)
这个FIFO是不是就相当于环形缓冲区啦? ChenXC1121 发表于 2022-8-21 16:24
这个FIFO是不是就相当于环形缓冲区啦?
(引用自6楼)
串口通信速率不高,就在中断中把数据放到软件fifo,速率高,可以参考楼上文章 每隔一段时间就有人问类似的问题,这个问题的根源是在串口中断里有做数据处理,耗费太多时间。
正常的处理流程是串口中断程序只负责把数据从RX寄存器中读出(没用DMA的情况),然后压入环形缓冲。
主程序中不断判断缓冲里是否有数据,有则取出、判断、处理。 全双工的吗增加fifo就有啦 好像有2个,调试时接收一个进中断,发送方已发送完,出中断,还会进入一次,avr好像有3个,进入后中断,还会进入2次 dma怎么不利用起来? 有的,一般8或16字节缓冲。 stm32H7 有16字节缓冲,开了以后,可以减少16倍中断的频率。但是16字节才能处理一次数据。正确的方案是DMA加串口空闲中断。 DMA加持下不需要经常进入中断的 这样处理数据明摆着增加硬件成本!中断里只负责读数据,然后放进环形缓冲就出来了,不会丢数据。
页:
[1]