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

时间:2018-03-29 12:41:13

标签: arm stm32 uart cmsis stm32f0

我一直在研究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));
    }

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

3 个答案:

答案 0 :(得分:1)

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

您应该确保在每个字节到达之后以及在接收到下一个字节之前读出RDR中的值。有3种基本方法可以做到。

  • <强>轮询

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

  • 中断

设置RXNEIE中的CR1位,并在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

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

答案 1 :(得分:0)

下面:

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

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

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

答案 2 :(得分:0)

你的逻辑是完全错误的。

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