如果APM32F107串口中断接收丢包现象成立,那么可能的解决方法分析
如果APM32F107串口中断接收丢包现象成立,那么可能的解决方法分析:APM32F107在串口同时发送和接收的情况下串口接收丢字节,具体表现为偶发进入串口接收中断了,但是USART_FLAG_RXBNE标志位没有触发,导致读不到这个字节进而丢字节,通过计数发现进入中断的次数与实际应该收到的字节数一致。1、发送是阻塞式发送的,没有用发送中断,排除进入的是发送中断的可能。2、出现这种情况时打断点看了,其他的溢出及错误标志位并没有置位,也打印检查了,没有置位。3、排查代码了没有在其他地方主动调用USART_RxDatad读取。4、串口中断优先级已调至最高。5、只接收不发送不会丢字节,挂一晚上都不丢,只要一发送接收就会丢。发送代码:void Uart1_Send(char buf){ uint16_t data_9th = buf; dog_feed_count_clean(); // 循环清除喂狗变量,超过DOG_PROTECT_TIME_100MS不清除则认为主循环异常,并停止喂狗。 if (g_rParameters.sPort.ucParity == UART_CHK_MARK) { data_9th |= (1 << (uart1_data_bit - 1)); } else if (g_rParameters.sPort.ucParity == UART_CHK_SPACE) { data_9th &= ~(1 << (uart1_data_bit - 1)); } WAIT_TX_EMPTY; // wait data register empty//等待发送完 USART_TxData(USART1, data_9th);}接收中断:void USART1_IRQHandler(void){ uint8_t data; uint8_t longth = g_sParameters.sPort.ucDataSize; if (USART_ReadStatusFlag(USART1, USART_FLAG_OVRE) == SET) { // 由软件清0,先读取USART_STS寄存器,再读USART_DATA寄存器完成清0。 USART_RxData(USART1); } if (USART_ReadStatusFlag(USART1, USART_FLAG_RXBNE) == SET) { data = (uint8_t)USART_RxData(USART1); // fetch recv data from buffer if (g_sParameters.sPort.ucParity != UART_CHK_NONE) { data = data & (~(1 << longth)); // 去掉校验位 } if (AtCmd_enter_mode(0, data) == 1) { packet_count = 0; } else { packet_count = 0; uart1_rx_ringbuf_push(&uart1_rx_ringbuf, data); // uart_rec_len ++; } usart_recv_total_len++; } timer_pack_reset_func();}解释在APM32F107微控制器上,串口同时进行发送和接收时出现接收丢包的问题,具体表现为偶发进入串口接收中断但`USART_FLAG_RXBNE`标志位未触发,导致无法读取到该字节。以下是对问题的详细解释及可能的解决方案:
问题描述
1. 现象:在串口同时发送和接收数据时,接收端偶尔会丢失字节。具体表现为进入接收中断的次数与实际应接收的字节数一致,但有时`USART_FLAG_RXBNE`标志位未被触发,导致无法读取到该字节。
2. 排查结果:
发送是阻塞式发送,没有使用发送中断,排除了进入发送中断的可能性。
其他溢出及错误标志位(如`USART_FLAG_OVRE`)未被置位。
代码中没有在其他地方主动调用`USART_RxData`读取数据。
串口中断优先级已调至最高。
只接收不发送时不会丢字节,挂一晚上都不丢,只要一发送接收就会丢。
可能的原因
1. 发送和接收冲突:在阻塞式发送过程中,可能会占用串口资源,导致接收中断无法及时响应。
2. 中断处理时间过长:如果接收中断处理函数执行时间过长,可能会导致后续的接收中断被延迟或丢失。
3. 硬件资源竞争:发送和接收操作可能涉及到相同的硬件资源(如DMA通道、缓冲区等),导致资源竞争。
4. 时钟配置问题:串口的时钟配置可能不稳定,导致在高负载下出现异常。
5. 软件逻辑问题**:接收中断处理函数中的逻辑可能存在问题,导致某些情况下无法正确处理接收数据。
解决方案
1. 优化发送方式:
考虑使用非阻塞式发送或发送中断,避免在发送过程中长时间占用串口资源。
确保发送完成后再进行接收操作,避免资源竞争。
2. 缩短中断处理时间:
尽量简化接收中断处理函数中的代码,减少不必要的操作。
如果需要执行复杂操作,可以将数据放入缓冲区,在主循环中处理。
3. 检查硬件资源:
确保发送和接收操作使用不同的DMA通道或缓冲区,避免资源竞争。
检查串口的时钟配置,确保在高负载下稳定运行。
4. 增加错误处理:
在接收中断处理函数中增加对`USART_FLAG_OVRE`等错误标志位的处理,确保在发生错误时能够及时恢复。
定期检查串口状态,确保通信正常。
5. 调试和日志:
在关键位置添加日志输出,记录发送和接收的状态,帮助定位问题。
使用示波器或逻辑分析仪检查串口信号,确保硬件连接正常。
示例代码优化
```c
void Uart1_Send(char buf) {
uint16_t data_9th = buf;
dog_feed_count_clean(); // 循环清除喂狗变量,超过DOG_PROTECT_TIME_100MS不清除则认为主循环异常,并停止喂狗。
if (g_rParameters.sPort.ucParity == UART_CHK_MARK) {
data_9th |= (1 << (uart1_data_bit - 1));
} else if (g_rParameters.sPort.ucParity == UART_CHK_SPACE) {
data_9th &= ~(1 << (uart1_data_bit - 1));
}
WAIT_TX_EMPTY; // wait data register empty//等待发送完
USART_TxData(USART1, data_9th);
}
void USART1_IRQHandler(void) {
uint8_t data;
uint8_t longth = g_sParameters.sPort.ucDataSize;
if (USART_ReadStatusFlag(USART1, USART_FLAG_OVRE) == SET) {
// 由软件清0,先读取USART_STS寄存器,再读USART_DATA寄存器完成清0。
USART_RxData(USART1);
}
if (USART_ReadStatusFlag(USART1, USART_FLAG_RXBNE) == SET) {
data = (uint8_t)USART_RxData(USART1); // fetch recv data from buffer
if (g_sParameters.sPort.ucParity != UART_CHK_NONE) {
data = data & (~(1 << longth)); // 去掉校验位
}
if (AtCmd_enter_mode(0, data) == 1) {
packet_count = 0;
} else {
packet_count = 0;
uart1_rx_ringbuf_push(&uart1_rx_ringbuf, data);
// uart_rec_len ++;
}
usart_recv_total_len++;
}
timer_pack_reset_func();
}
```
总结
通过优化发送方式、缩短中断处理时间、检查硬件资源、增加错误处理以及调试和日志记录,可以有效解决APM32F107在串口同时发送和接收时出现的接收丢包问题。 这个是AI上传上来的解答吗? 如果上流程上面的问题,出现概率应该比较大。
感觉是哪里撞车了,只是没有考虑到 这种情况确实棘手,通常需要检查硬件连接和软件配置。你的排查很全面,可以尝试优化中断服务程序,减少处理时间,看是否有改善。
lemonboard 发表于 2025-4-26 20:03
这个是AI上传上来的解答吗?
哈 心跳回响 发表于 2025-4-27 10:51
如果上流程上面的问题,出现概率应该比较大。
感觉是哪里撞车了,只是没有考虑到 ...
感谢回复。 快乐制造机 发表于 2025-4-27 15:49
这种情况确实棘手,通常需要检查硬件连接和软件配置。你的排查很全面,可以尝试优化中断服务程序,减少处理 ...
感谢回复。 根据AI的结论,一步步排查,总能解决问题,这样的过程我屡试不爽。毕竟AI已经读遍世界上所有的书了。 用DMA和空闲中断可能会好有点
页:
[1]