首页 文章

**带有DMA的STM32f427 UART **从控制台接收数据时,最高位有时为1

提问于
浏览
2

使用STM32f427 UART和DMA(使用stm cube HAL库)时遇到问题 .

我想制作一个控制台回显函数,所以我在uart空闲中断处理函数中立即回复接收到的数据 .

但有时,当我在键盘输入任何键时,接收数据的最高位将为1 . 如下

0x31 -> 0xB1
0x32 -> 0xB2
0x40 -> 0xC0

有人有任何想法吗?代码段如下 .

非常感谢你 .

My uart configuration as following

uart_handler.Instance          = USARTx;
uart_handler.Init.BaudRate     = baudrate;
uart_handler.Init.WordLength   = UART_WORDLENGTH_8B;
uart_handler.Init.StopBits     = UART_STOPBITS_1;
uart_handler.Init.Parity       = UART_PARITY_NONE;
uart_handler.Init.HwFlowCtl    = UART_HWCONTROL_NONE;
uart_handler.Init.Mode         = UART_MODE_TX_RX;
uart_handler.Init.OverSampling = UART_OVERSAMPLING_8;

My PIN and DMA channels configuration as following

GPIO_InitStruct.Pin       = USARTx_TX_PIN;
GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull      = GPIO_PULLUP;
GPIO_InitStruct.Speed     = GPIO_SPEED_HIGH;
GPIO_InitStruct.Alternate = USARTx_TX_AF;
HAL_GPIO_Init(USARTx_TX_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = USARTx_RX_PIN;
GPIO_InitStruct.Mode      = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull      = GPIO_NOPULL;
GPIO_InitStruct.Alternate = USARTx_RX_AF;
HAL_GPIO_Init(USARTx_RX_GPIO_PORT, &GPIO_InitStruct);
hdma_tx.Instance                 = USARTx_TX_DMA_STREAM;
hdma_tx.Init.Channel             = USARTx_TX_DMA_CHANNEL;
hdma_tx.Init.Direction           = DMA_MEMORY_TO_PERIPH;
hdma_tx.Init.PeriphInc           = DMA_PINC_DISABLE;
hdma_tx.Init.MemInc              = DMA_MINC_ENABLE;
hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_tx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;
hdma_tx.Init.Mode                = DMA_NORMAL;
hdma_tx.Init.Priority            = DMA_PRIORITY_LOW;
hdma_tx.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;
hdma_tx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
hdma_tx.Init.MemBurst            = DMA_MBURST_INC16;
hdma_tx.Init.PeriphBurst         = DMA_MBURST_INC16;
HAL_DMA_Init(&hdma_tx);

/ 将初始化的DMA句柄与UART句柄相关联 /

__HAL_LINKDMA(huart, hdmatx, hdma_tx);

/ 为接收过程配置DMA处理程序 /

hdma_rx.Instance                 = USARTx_RX_DMA_STREAM;
hdma_rx.Init.Channel             = USARTx_RX_DMA_CHANNEL;
hdma_rx.Init.Direction           = DMA_PERIPH_TO_MEMORY;
hdma_rx.Init.PeriphInc           = DMA_PINC_DISABLE;
hdma_rx.Init.MemInc              = DMA_MINC_ENABLE;
hdma_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_rx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;
hdma_rx.Init.Mode                = DMA_NORMAL;
hdma_rx.Init.Priority            = DMA_PRIORITY_HIGH;
hdma_rx.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;
hdma_rx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
hdma_rx.Init.MemBurst            = DMA_MBURST_INC16;
hdma_rx.Init.PeriphBurst         = DMA_MBURST_INC16;

并使用uart空闲中断来接收数据 .

uint32_t temp;
if((__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE) != RESET))
{
__HAL_UART_CLEAR_IDLEFLAG(huart);
HAL_UART_DMAStop(&uart_handler);
temp = uart_handler.hdmarx->Instance->NDTR;
g_usart_info.rx_len =  USART_DMA_RECV_LEN - temp;
g_usart_info.receive_flag = 1;
g_usart_info.usart_dma_tx_buff = g_usart_info.usart_dma_rx_buff[0] ;
memset(g_usart_info.usart_dma_rx_buff, 0,                
sizeof(g_usart_info.usart_dma_rx_buff));
__HAL_UART_CLEAR_FLAG(&uart_handler, UART_FLAG_RXNE);
g_usart_info.usart_dma_rx_buff[0] = 0;
HAL_UART_Receive_DMA(&uart_handler, g_usart_info.usart_dma_rx_buff, 
USART_DMA_RECV_LEN);
}

谢谢 .

我追踪了UART_Receive_IT的功能并添加了调试代码 . 并为int a = *插入断点(huart-> pRxBuffPtr - 1);

我发现huart-> Instance-> DR是0x31但int a是0xB1 .

我试图禁用其他中断但它仍然无法解决 .

if(huart->Init.Parity == UART_PARITY_NONE)
      {
        *huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
                if(*(huart->pRxBuffPtr - 1) != 0x31)
                {
                    int a = *(huart->pRxBuffPtr - 1);
                    a = a;
                }
      }
      else
      {
        *huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x007F);
      }

================================================== ======================

I found the problem point

RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 /*| RCC_CLOCKTYPE_PCLK2*/);

如果我评论 RCC_CLOCKTYPE_PCLK2 ,这个问题可以解决 . 但我不知道为什么,这是官方的示例代码 . 我认为应该是对的 .

2 回答

  • 0

    好吧,那听起来像时钟问题 .

    • 你有示波器吗?您可以直接从STM32发送已知字节,而不是进行回声测试 . 我通常发送 0xAA0x55 . 然后,您可以测量STM32的UART的时序并验证它是否正确 .

    • 有时在更高的时钟速度下,外设时钟的精度会降低 . 您还可以尝试提高系统时钟的速度 .

    Thought: 再次查看您的代码我想我可能已经找到了问题 . 在您的UART配置更改中

    uart_handler.Init.OverSampling = UART_OVERSAMPLING_8;
    

    uart_handler.Init.OverSampling = UART_OVERSAMPLING_16;
    

    这将强制STM32更精细地查看传入的字节,并可以解决您的问题 . 根据我的理解, 16x 过采样是使用的典型配置,即使在较低的UART速度下也是如此 .

  • 0

    最后,我找到了这个问题的根本原因 . 我在我的电路板上使用官方示例代码,但这些示例代码用于官方开发板,电路板带有嵌入式stlink / v2电路,它将通过STM32F4芯片传输8M hz用于HSE时钟 .

    但我的电路板没有电路,所以我必须使用外部stlink / v2模块来开发我的电路板 .

    所以,我需要做以下改变 .

    WAS:RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS;

    IS:RCC_OscInitStruct.HSEState = RCC_LSE_ON;

    改变后,我的问题就解决了 .

    并感谢Hein Wessels观看和帮助:) .

相关问题