场景:I有一个STM32单片机,它在DMA模式下使用UART和空闲中断进行RS485数据传输。UART的波特率在CubeMX中设置为115200。我的代码工作正常,当主机使用正确的波特率时,它也是“长时间”稳定的,没有问题或担心。
但是:当我在主机上设置错误的波特率(例如56700而不是115200 )时,UART停止接收数据,即使后来我将主机的波特率设置为与单片机使用的波特率相同的波特率,它也无法工作。到目前为止,解决这个问题的唯一方法是:重新设置MCU并重新连接到正确的波特率。
给你一些(伪)代码:
uint8_t UART_Buf[128];
HAL_UART_Receive_DMA(&huart2, UART_Buf, 128);
__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);或者用简单的话说:有一个用于DMA (UART_Buf128)的UART缓冲区,UART是用HAL_UART_Receive_DMA(.)启动的,DMA Rx在CubeMX中被设置为循环模式,并且使用HAL:__HAL_UART_ENABLE_IT(.)激活了空闲中断;到目前为止,这段代码运行良好。
工作的好方法:当我把数据从我的个人电脑传送到微控制器时,(1)空闲中断由单片机触发(正确)。在ISR中,我设置了一个标志,以便随后开始数据解析。我收到的字节数正好是我发送的,一切都很好。
但是:当我在我的终端程序中设置错误,而不是(正确的)波特率为115200,波特率选择菜单被设置为例如57600,故障开始:
空闲中断在每次传输后仍将触发。但是它在一个快速的“突发”(取决于波特率)中触发2-4次,接收到的字节数是0。我希望至少有一些bs数据,但是缓冲区中正好有0个数据--我可以用调试器检查这些数据。显然什么也没收到。当我改变终端程序中的波特率并重新启动它时,单片机上仍然没有接收到任何信息。
如果主机的波特率不正确,我可以使用0个接收字节,但是,在硬件重置完成之前,一个错误波特率的主机的传入传输将禁用UART,这是非常不酷的。
到目前为止,我试图解决这个问题:计数“空闲中断突发”和0接收字节一起触发一个“自重置”例程,该例程使用MX_USART2_UART_Init();例程停止并重新启动UART。没有效果。我可以看到,Idle中断仍然被正确触发,但是缓冲区仍然是空的,没有数据被传输到缓冲区。UART仍处于未接收状态.
问题有没有人遇到过类似的问题,如果是的话:你是如何解决的?
附加信息:这发生在STM32F030和STM32G03x上
发布于 2022-02-27 21:55:30
当您以错误的波特率发送到UART时,在接收方看来,它将显示为帧错误和/或噪声错误。它也可以显示为随机字符被正确地接收,但这是不太可能的,所以不要惊讶于没有在您的缓冲区。
当您使用DMA接收时,打开错误中断或轮询错误位是正常的。当检测到错误时,您将重新初始化所有内容并重新启动DMA。这听起来像是你试图通过计算空闲的中断来做的事情,但是你只是没有检查正确的部分。
如果你不想这样做,就不难想象你在驱动程序级别上没有什么可做的,并且想要在更高的层次上重新同步(例如:重新开始阅读,直到换行符为止),但是你必须记住至少两件事:
首先,确保清除USART_CR3寄存器中的DDRE位。名称"DMA禁用接收错误“本身就说明了这一点。
第二,只要字节之间存在空闲间隔,UART外围设备就能够自我重新同步。如果您将发射机切换到正确的波特率,但不断地输出数据,则接收器可能永远无法正确识别哪个位是起始位。
发布于 2022-02-28 15:17:14
在进一步研究这个问题之后,我找到了一个解决方案。
摘要:当主机以比UART更高的波特率连接到单片机上时,将进入错误状态并停止向RX缓冲区的DMA传输。您可以检查HAL_UART_GetError(.)是否有错误。函数。如果出现错误,请停止UART/DMA并重新启动它。
的详细信息:首先,它不是USART_CR2寄存器中的DDRE位。CubeMX将其设置为0。但是汤姆五世的暗示把我引向了正确的方向。
我试图通过播放寄存器位来恢复UART。我多次阅读参考手册的UART部分,并试图找出要设置哪些位的顺序,以手动解决错误情况。
我发现:当UART接收到错误波特率的传输时,UART寄存器中发生以下更改(在STM32F030上):控制寄存器1 (USART_CR1) -位8 (PEIE)从1到0。PEIE是奇偶中断启用位。控制寄存器2 (USART_CR2) -保持不变的控制寄存器3 (USART_CR3) -从0d16449更改为0d16384,这意味着位0 (EIE错误中断启用)从1到0位6 (DMAR - DMA启用接收器)从1到0位14 (DMA驱动程序启用模式)保持不变。
USART_CR3.DEM说得通。我使用的by 485功能的F030,所以UART处理驱动程序启用GPIO本身。在USART_CR3.EIE和USART_CR3.DMAR中,从1到0的转换很可能是没有更多数据被传输到DMA缓冲区的原因。
此外,还在ORE和FE的中断和状态寄存器(USART_ISR)中设置了误差标志。矿石代表超限误差,有限元代表框架误差。虽然可以通过将1写入中断标志清除寄存器(USART_ICR)的相应位来清除这些比特,但hUART结构中的ErrorCode仍保持在初始错误值。
在我的尝试和错误过程结束时,我设法使所有寄存器在有效传输过程中具有相同的值,但仍然没有接收到字节。不管我做了什么,我都没有效果。UART仍处于未接收状态。因此,我决定使用“蛮力”方法,并使用HAL函数,我知道这是可行的。
最后,解决方案非常简单:如果检测到一个空闲中断,但接收到的字节数为0 =>,则用HAL_UART_GetError(.)检查UART的错误状态如果有错误,使用HAL_UART_DMAStop(.)停止UART然后用HAL_UART_Receive_DMA(.)重新启动它
代码:
if(RxLen) {
// normal execution, number of received bytes > 0
if(UA_RXCallback[i]) (*UA_RXCallback[i])(hUA); // exec RX callback function
} else {
if(HAL_UART_GetError(&huart2)) {
HAL_UART_DMAStop(&huart2); // STOP Uart
MX_USART2_UART_Init(); // INIT Uart
HAL_UART_Receive_DMA(&huart2, UA2_Buf, UA2_BufSz); // START Uart DMA
__HAL_UART_CLEAR_IDLEFLAG(&huart2); // Clear Idle IT-Flag
__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE); // Enable Idle Interrupt
}
}发布于 2022-08-23 12:57:26
我也有过类似的问题。我使用DMA接收数据,然后定期检查接收的字节数。经过一点错误后,它将无法恢复。对我来说,解决方案是首先在UART_HandleTypeDef上订阅UART_HandleTypeDef。
在错误处理程序中,我再次调用UART_Start_Receive_DMA(...)。这似乎重新启动了UART和DMA,没有问题。
https://stackoverflow.com/questions/71287996
复制相似问题