当我在 STM32F407VET 中使用 UART 中断方法时,我丢失了一些字符
I'm missing some characters when I'm using UART interrupt method in STM32F407VET
我在中断模式下使用STM32F407VE的UART1。波特率为 115200。
我正在使用 docklight serial window 来读取 UART 输出。我一次发送 15 到 20 个字符。
当我检查环回代码时,我缺少字符,如下所示。
我尝试更改波特率。但是当我增加字符数时,同样的问题仍然存在。
这是我的中断处理程序:
void USART1_IRQHandler(void) {
uint8_t data;
HAL_UART_IRQHandler(&huart1);
__HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_RXNE);
data = (uint8_t)(huart1.Instance->DR); //& (uint16_t)0x00FFU);
HAL_UART_Transmit(&huart1, (uint8_t *)&data, 1, 10);
}
您正在接收一个字节并将该字节放入 UART 的 TDR
寄存器中。它可能是 运行 相同的波特率,因此在传输完成之前收到一个新的接收中断。对 HAL_UART_Transmit
的调用正在阻塞,将检查传输是否为 运行。语句 if(huart->gState == HAL_UART_STATE_READY)
将 return false
因此将采用 else
路径。这将导致 return 值为 HAL_BUSY
。这表明没有发生转移,因为转移仍在进行中。
您需要添加一个循环缓冲区来解决这个问题。将接收到的字节存储在中断处理程序中的存储容器中,程序的另一部分需要检查存储容器是否不为空,如果不为空则传输内容。更新存储容器时需要禁用中断,因为可能会出现竞争条件。
您还可以在传输中添加传输结束字符,表明可以安全地将其回显给您,从而避免出现竞争情况。如果您使用 ASCII,0x04
是一个很好的选择,因为它被定义为 EOT
(传输结束)。
另一种选择是使用 HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
在中断模式下接收一定数量的字节。
UART 的库代码可以在里面找到:stm32f4xx_hal_uart.c
。 STM 的 HAL 具有很好的可读性和信息性,请随意查看。它可以帮助将来找到其他错误。 (ST 并不总是在他们的代码中做出明显或合作的选择)
实际上这里几乎什么都错了。不要以这种方式清除 RXNE 标志。当uC从数据寄存器中读取数据时,由硬件清零。不要在中断处理程序中使用阻塞函数。
如果您使用 HAL,请使用回调函数。
我的建议是先阅读 uC 文档和 HAL 手册,然后再开始编程。
此外,您可能超出了 USART。要确认,请以 9600 波特尝试,如果丢失的字符较少,那就是你的问题。在这种情况下,您需要使用 HW 握手,或者添加缓冲区并且不要在 IRQ 处理程序中进行传输,而是在主循环中进行传输。
我在中断模式下使用STM32F407VE的UART1。波特率为 115200。 我正在使用 docklight serial window 来读取 UART 输出。我一次发送 15 到 20 个字符。 当我检查环回代码时,我缺少字符,如下所示。
我尝试更改波特率。但是当我增加字符数时,同样的问题仍然存在。 这是我的中断处理程序:
void USART1_IRQHandler(void) {
uint8_t data;
HAL_UART_IRQHandler(&huart1);
__HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_RXNE);
data = (uint8_t)(huart1.Instance->DR); //& (uint16_t)0x00FFU);
HAL_UART_Transmit(&huart1, (uint8_t *)&data, 1, 10);
}
您正在接收一个字节并将该字节放入 UART 的 TDR
寄存器中。它可能是 运行 相同的波特率,因此在传输完成之前收到一个新的接收中断。对 HAL_UART_Transmit
的调用正在阻塞,将检查传输是否为 运行。语句 if(huart->gState == HAL_UART_STATE_READY)
将 return false
因此将采用 else
路径。这将导致 return 值为 HAL_BUSY
。这表明没有发生转移,因为转移仍在进行中。
您需要添加一个循环缓冲区来解决这个问题。将接收到的字节存储在中断处理程序中的存储容器中,程序的另一部分需要检查存储容器是否不为空,如果不为空则传输内容。更新存储容器时需要禁用中断,因为可能会出现竞争条件。
您还可以在传输中添加传输结束字符,表明可以安全地将其回显给您,从而避免出现竞争情况。如果您使用 ASCII,0x04
是一个很好的选择,因为它被定义为 EOT
(传输结束)。
另一种选择是使用 HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
在中断模式下接收一定数量的字节。
UART 的库代码可以在里面找到:stm32f4xx_hal_uart.c
。 STM 的 HAL 具有很好的可读性和信息性,请随意查看。它可以帮助将来找到其他错误。 (ST 并不总是在他们的代码中做出明显或合作的选择)
实际上这里几乎什么都错了。不要以这种方式清除 RXNE 标志。当uC从数据寄存器中读取数据时,由硬件清零。不要在中断处理程序中使用阻塞函数。
如果您使用 HAL,请使用回调函数。
我的建议是先阅读 uC 文档和 HAL 手册,然后再开始编程。
此外,您可能超出了 USART。要确认,请以 9600 波特尝试,如果丢失的字符较少,那就是你的问题。在这种情况下,您需要使用 HW 握手,或者添加缓冲区并且不要在 IRQ 处理程序中进行传输,而是在主循环中进行传输。