STM32f091rc UART 接收函数只返回数据包的最后一个字节而不是完整的数据包

STM32f091rc UART Receive function returning only the last byte of the packet instead of the full data packet

我一直在研究 STM32f091rc 板,试图让 UART1 和 UART2 工作。我尝试从控制器向 STM 板发送 8 个字节的数据包。由于某些原因,我的功能只是显示数据包的最后一个字节。我的接收函数如下:-

uint8_t rxd[10];
void getChar (void) {

while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET) { // Check RXNE to 
//see if there is data
    for(j=0; j<8; j++) { 
        rxd[i] = (0xFF & (USART1->RDR));
    }

我做错了什么?谁能指出我正确的方向?谢谢你的时间。

这里:

for(j=0; j<8; j++) { 
  rxd[i] = (0xFF & (USART1->RDR));
}

您使用 j 作为循环计数器,但您写入索引 i 下的 rxd,而不是 j。您覆盖了同一个字节 8 次。

另一件事是你等待 USART_FLAG_RXNE 标志被设置,然后你从 RDR 寄存器读取 8 次。当接收到第一个字节时设置此标志,然后您读取它 8 次 - 您的读取速度很可能比发送数据的速度快得多。如果你想通过轮询来完成——这似乎是你的意图——你应该在分别读取每个字节后等待 USART_FLAG_RXNE 标志被设置,因为这个 MCU 中的 USART 外设没有 FIFO,只能容纳一个收到字节供您阅读(提到 RDR 寄存器)。

UART->RDR 寄存器没有缓冲区,它只保存最后一个完全接收的字节。如果接收到另一个字节,它将被覆盖。

你应该确保每次一个字节到达后,下一个字节被接收之前,RDR中的值被读出。有 3 种基本方法。

  • 轮询

定期检查 RXNE 标志,并在设置时读取 RDR 一次 。重复直到您拥有整个数据包。从 RDR 读取一个字节会清除 RXNE 标志,等到它再次设置后再读取下一个字节。

  • 中断

设置CR1中的RXNEIE位,使能NVIC中UART对应的中断。每次接收到一个字节时都会调用中断处理程序。处理程序一开始可以非常简单,只需读取 RDR 并将其存储在缓冲区中。稍后您可以添加错误检查和恢复。不要忘记将中断处理程序接触的每个变量声明为 volatile.

  • DMA

先设置DMA通道(USART1默认映射到DMA1_Channel3,可以重新映射,其他的请查看参考手册):

DMA1_Channel3->CPAR = (uint32_t)&USART1->RDR;
DMA1_Channel3->CMAR = (uint32_t)rxd;            // start of receive array
DMA1_Channel3->CNDTR = 8;                       // 8 bytes to receive
DMA1_Channel3->CCR = DMA_CCR_MINC | DMA_CCR_EN; // Memory increment, enable

然后设置串口,使能DMA接收USART1->CR3。传输结束在 DMA1->ISR 寄存器中发出信号,您可以在主程序中定期检查它,或者在 DMA1_Channel3->CCR(和 NVIC)中启用中断。你应该通过DMA1->IFCR清除中断标志,否则你会在启用时得到无限的中断。要开始另一次传输,请再次设置 CNDTR 寄存器。将 DMA 或中断处理程序接触的所有变量声明为 volatile.

你的逻辑完全错误。

for(j=0; j<8; j++) 
{
    while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) != SET); // wait for the data
    rxd[i] = (0xFF & (USART1->RDR));
}