狐尔摩斯 2024-04-10 19:33 采纳率: 0%
浏览 11
已结题

HAL库串口启用硬件流控,数据错乱问题

使用一款国产MCU芯片,使用的是HAL库,在使用串口DMA编写例程,与串口板通信遇到数据错乱和丢失问题。

例程做的事情就是接收数据指定接收6个字节数据,并把数据发送回去,以下是例程代码:

#include "main.h"
#include "string.h"
/* Private define ------------------------------------------------------------*/
#ifdef __GNUC__
  /* With GCC, small printf (option LD Linker->Libraries->Small printf
  set to 'Yes') calls __io_putchar() */
  #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
  #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */

/* Private user code ---------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
static void APP_SystemClockConfig(void);

/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef UartHandle;
uint8_t aTxBuffer[64] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
uint8_t aRxBuffer[64] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};

static void app_uart_init(void)
{
    /* Initialize USART2 */
  UartHandle.Instance          = USART1;
  UartHandle.Init.BaudRate     = 115200;
  UartHandle.Init.WordLength   = UART_WORDLENGTH_8B;
  UartHandle.Init.StopBits     = UART_STOPBITS_1;
  UartHandle.Init.Parity       = UART_PARITY_NONE;
  UartHandle.Init.HwFlowCtl    = UART_HWCONTROL_RTS_CTS;
  UartHandle.Init.Mode         = UART_MODE_TX_RX;
  HAL_UART_Init(&UartHandle);
  
}


int main(void)
{
  /* Reset of all peripherals, Initializes the Systick */
  HAL_Init();
  
  /* System clock configuration */
  APP_SystemClockConfig(); 

    app_uart_init();
    HAL_UART_Transmit_DMA(&UartHandle, (uint8_t *)aTxBuffer, 12);
  while (1)
  {
            
        //UartHandle.hdmarx->Instance->CNDTR = 1024;
    /* Receive data using DMA */
    if (HAL_UART_Receive_DMA(&UartHandle, (uint8_t *)aRxBuffer, 6) != HAL_OK)
    {
      APP_ErrorHandler();
    }
    /* Wait for receiving data to complete */
    while(HAL_UART_GetState(&UartHandle) != HAL_UART_STATE_READY)
    {
    }

        
    /* Send data using DMA */
    if (HAL_UART_Transmit_DMA(&UartHandle, (uint8_t *)aRxBuffer, 6) != HAL_OK)
    {
      APP_ErrorHandler();
    }
    /* Wait for sending data to complete */
    while(HAL_UART_GetState(&UartHandle) != HAL_UART_STATE_READY)
    {
    }
        

  }
}

/**
  * @brief  System clock configuration function
  * @param  None
  * @retval None
  */
static void APP_SystemClockConfig(void)
{
  RCC_OscInitTypeDef  OscInitstruct = {0};
  RCC_ClkInitTypeDef  ClkInitstruct = {0};
  
  OscInitstruct.OscillatorType  = RCC_OSCILLATORTYPE_HSE | RCC_OSCILLATORTYPE_HSI | RCC_OSCILLATORTYPE_LSE | 
                                  RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_HSI48M;
  OscInitstruct.HSEState        = RCC_HSE_OFF;                              /* Disable HSE */
/* OscInitstruct.HSEFreq         = RCC_HSE_16_32MHz; */                     /* HSE working frequency range: 16M~32M */
  OscInitstruct.HSI48MState     = RCC_HSI48M_OFF;                           /* Disable HSI48M */
  OscInitstruct.HSIState        = RCC_HSI_ON;                               /* Enable HSI */
  OscInitstruct.LSEState        = RCC_LSE_OFF;                              /* Disable LSE */
/* OscInitstruct.LSEDriver       = RCC_LSEDRIVE_HIGH; */                    /* Drive capability level: High */
  OscInitstruct.LSIState        = RCC_LSI_OFF;                              /* Disable LSI */
  OscInitstruct.PLL.PLLState    = RCC_PLL_OFF;                              /* Disable PLL */
/*  OscInitstruct.PLL.PLLSource   = RCC_PLLSOURCE_HSE; */                   /* PLL clock source: HSE */
/*  OscInitstruct.PLL.PLLMUL      = RCC_PLL_MUL6; */                        /* PLL multiplication factor: 6 */
  /* Configure Oscillators */
  if(HAL_RCC_OscConfig(&OscInitstruct) != HAL_OK)
  {
    APP_ErrorHandler();
  }
  
  ClkInitstruct.ClockType       = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
  ClkInitstruct.SYSCLKSource    = RCC_SYSCLKSOURCE_HSI;                 /* System clock source: HSI */
  ClkInitstruct.AHBCLKDivider   = RCC_SYSCLK_DIV1;                      /* AHB clock not divided */
  ClkInitstruct.APB1CLKDivider  = RCC_HCLK_DIV1;                        /* APB1 clock not divided */
  ClkInitstruct.APB2CLKDivider  = RCC_HCLK_DIV2;                        /* APB1 clock divided by 2 */
  /* Configure Clocks */
  if(HAL_RCC_ClockConfig(&ClkInitstruct, FLASH_LATENCY_0) != HAL_OK)
  {
    APP_ErrorHandler();
  }
}

/**
  * @brief  This function is executed in case of error occurrence.
  * @param  None
  * @retval None
  */
void APP_ErrorHandler(void)
{
  /* Infinite loop */
  while (1)
  {
  }
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file:pointer to the source file name
  * @param  line:assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* User can add his own implementation to report the file name and line number,
     for example: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* Infinite loop */
  while (1)
  {
  }
}
#endif /* USE_FULL_ASSERT */

IO口配置的代码:

void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
  GPIO_InitTypeDef  GPIO_InitStruct;
    if (huart->Instance == USART1)
  {
    /* Enable clock */
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_USART1_CLK_ENABLE();

    __HAL_RCC_SYSCFG_CLK_ENABLE();
    __HAL_RCC_DMA1_CLK_ENABLE();

    /* GPIO Initialization
    PA2     ------> USART1_TX
    PA3     ------> USART1_RX
    */
    GPIO_InitStruct.Pin       = GPIO_PIN_9;
    GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull      = GPIO_PULLUP;
    GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF2_USART1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_10;
    GPIO_InitStruct.Alternate = GPIO_AF2_USART1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    if(huart->Init.HwFlowCtl == UART_HWCONTROL_RTS_CTS)
    {
        GPIO_InitStruct.Pin = GPIO_PIN_11;//cts
        GPIO_InitStruct.Alternate = GPIO_AF2_USART1;
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

        GPIO_InitStruct.Pin = GPIO_PIN_12;//rts
        GPIO_InitStruct.Alternate = GPIO_AF2_USART1;
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    }


    /* USART1 DMA configuration */
    /* USART1_TX initialization */
    hdma_usart1_tx.Instance = DMA1_Channel1;
    hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_usart1_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_usart1_tx.Init.Mode = DMA_NORMAL;//DMA_CIRCULAR;
    hdma_usart1_tx.Init.Priority = DMA_PRIORITY_LOW;
    if (HAL_DMA_Init(&hdma_usart1_tx) != HAL_OK)
    {
      APP_ErrorHandler();
    }

    __HAL_LINKDMA(huart, hdmatx, hdma_usart1_tx);
    /* USART1_RX initialization */
    hdma_usart1_rx.Instance = DMA1_Channel2;
    hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_usart1_rx.Init.Mode = DMA_NORMAL;
    hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW;
    if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK)
    {
      APP_ErrorHandler();
    }
    __HAL_LINKDMA(huart, hdmarx, hdma_usart1_rx);
    
    /* Set DMA request mapping */
    HAL_DMA_ChannelMap(&hdma_usart1_tx, DMA_CHANNEL_MAP_USART1_WR);
    HAL_DMA_ChannelMap(&hdma_usart1_rx, DMA_CHANNEL_MAP_USART1_RD);
    
    /* Enable NVIC */
    HAL_NVIC_SetPriority(USART1_IRQn, 0, 1);
    HAL_NVIC_EnableIRQ(USART1_IRQn);
    
    HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 1);
    HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);

    HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 1, 1);
    HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);

  }
  else if (huart->Instance == USART2)
  {
    /* Enable clock */
    __HAL_RCC_GPIOD_CLK_ENABLE();
    __HAL_RCC_USART2_CLK_ENABLE();
    __HAL_RCC_SYSCFG_CLK_ENABLE();
    __HAL_RCC_DMA1_CLK_ENABLE();
    
    /* GPIO Initialization
    PA2     ------> USART1_TX
    PA3     ------> USART1_RX
    */
    GPIO_InitStruct.Pin       = GPIO_PIN_5;
    GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull      = GPIO_PULLUP;
    GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF2_USART2;
    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_6;
    GPIO_InitStruct.Alternate = GPIO_AF2_USART2;
    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
    
    /* USART2 DMA configuration */
    /* USART2_TX initialization */
    hdma_usart2_tx.Instance = DMA1_Channel1;
    hdma_usart2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_usart2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_usart2_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_usart2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_usart2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_usart2_tx.Init.Mode = DMA_NORMAL;
    hdma_usart2_tx.Init.Priority = DMA_PRIORITY_LOW;
    if (HAL_DMA_Init(&hdma_usart2_tx) != HAL_OK)
    {
      APP_ErrorHandler();
    }

    __HAL_LINKDMA(&UartHandle, hdmatx, hdma_usart2_tx);
    /* USART2_RX initialization */
    hdma_usart2_rx.Instance = DMA1_Channel2;
    hdma_usart2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_usart2_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_usart2_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_usart2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_usart2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_usart2_rx.Init.Mode = DMA_NORMAL;
    hdma_usart2_rx.Init.Priority = DMA_PRIORITY_LOW;
    if (HAL_DMA_Init(&hdma_usart2_rx) != HAL_OK)
    {
      APP_ErrorHandler();
    }
    __HAL_LINKDMA(&UartHandle, hdmarx, hdma_usart2_rx);
    
    /* Set DMA request mapping */
    HAL_DMA_ChannelMap(&hdma_usart2_tx, DMA_CHANNEL_MAP_USART2_WR);
    HAL_DMA_ChannelMap(&hdma_usart2_rx, DMA_CHANNEL_MAP_USART2_RD);
    
    /* Enable NVIC */
    HAL_NVIC_SetPriority(USART2_IRQn, 0, 1);
    HAL_NVIC_EnableIRQ(USART2_IRQn);
    
    HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 1);
    HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);

    HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 1, 1);
    HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
  }
}



我使用的串口板支持CTS RTS功能,也正确连接了,如果把杜邦线断开,串口调试工具就收不到任何数据,说明引脚连接应该没问题。

实验串口调试助手一次发送12个字节,但是MCU没有分两次把数据完整接收。

实验结果的打印如下:

img


[2024-04-10 19:27:21.880]# RECV HEX>
FF FF FF FF FF FF FF FF FF FF FF FF 
[2024-04-10 19:27:25.525]# SEND HEX>
01 02 03 04 05 06 07 08 09 0A 0B 0C 
[2024-04-10 19:27:25.575]# RECV HEX>
01 02 03 04 05 06 
[2024-04-10 19:27:26.784]# SEND HEX>
01 02 03 04 05 06 07 08 09 0A 0B 0C 
[2024-04-10 19:27:26.847]# RECV HEX>
07 0A 0B 0C 01 02 03 06 07 08 09 0A 
[2024-04-10 19:27:27.470]# SEND HEX>
01 02 03 04 05 06 07 08 09 0A 0B 0C 
[2024-04-10 19:27:27.517]# RECV HEX>
0B 01 02 03 04 05 
[2024-04-10 19:27:29.546]# SEND HEX>
01 02 03 04 05 06 07 08 09 0A 0B 0C 
[2024-04-10 19:27:29.603]# RECV HEX>
06 09 0A 0B 0C 01 02 05 06 07 08 09 
[2024-04-10 19:27:30.186]# SEND HEX>
01 02 03 04 05 06 07 08 09 0A 0B 0C 
[2024-04-10 19:27:30.234]# RECV HEX>
0A 01 02 03 04 05 
[2024-04-10 19:27:30.762]# SEND HEX>
01 02 03 04 05 06 07 08 09 0A 0B 0C 
[2024-04-10 19:27:30.809]# RECV HEX>
06 09 0A 0B 0C 01 02 05 06 07 08 09 
[2024-04-10 19:27:31.551]# SEND HEX>
01 02 03 04 05 06 07 08 09 0A 0B 0C 
[2024-04-10 19:27:31.612]# RECV HEX>
0A 01 02 03 04 05 

并没有按照预期的收到:
01 02 03 04 05 06
07 08 09 0A 0B 0C
01 02 03 04 05 06
07 08 09 0A 0B 0C
这样的数据,是配置的不对,还是硬件流控只能做到这样?请指点。

  • 写回答

18条回答 默认 最新

  • 码农阿豪 Java领域优质创作者 2024-04-10 19:39
    关注
    让阿豪来帮你解答,本回答参考chatgpt3.5编写提供,如果还有疑问可以评论或留言
    问题:使用一款国产MCU芯片,使用的是HAL库,在使用串口DMA编写例程,与串口板通信遇到数据错乱和丢失问题。例程做的事情就是接收数据指定接收6个字节数据,并把数据发送回去。 解答:数据错乱和丢失问题可能有以下几个原因:
    1. 码率不匹配:串口通信需要保证发送端和接收端的波特率一致,如果不一致就可能会出现数据错乱和丢失问题。可以检查是否设置了正确的波特率。
    2. 缓冲区溢出:在DMA传输数据时,需要保证接收缓冲区大小足够。如果接收缓冲区大小不够,数据就会被覆盖,从而出现数据错乱和丢失的问题。
    3. DMA传输未结束:在DMA传输数据时,需要等待传输结束,否则可能会出现数据错乱和丢失的问题。可以通过检查DMA的状态来确认传输是否结束。
    4. 中断优先级设置不正确:如果中断优先级设置不正确,可能会导致数据丢失。可以检查中断优先级设置是否正确。 以下是可能导致数据错乱和丢失问题的例程代码,并给出了解决方案:
    #include "main.h"
    #include "string.h"
    /* Private define ------------------------------------------------------------*/
    #ifdef __GNUC__  
    /* With GCC, small printf (option LD Linker->Libraries->Small printf set to 'Yes') calls __io_putchar() */
    #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
    #else  
    #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
    #endif /* __GNUC__ */
    /* Private user code ---------------------------------------------------------*/
    /* Private macro -------------------------------------------------------------*/
    /* Private function prototypes -----------------------------------------------*/
    static void APP_SystemClockConfig(void);
    /* Private variables ---------------------------------------------------------*/
    UART_HandleTypeDef UartHandle;
    uint8_t aTxBuffer[64] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
    uint8_t aRxBuffer[64] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
    static void app_uart_init(void){
      /* Initialize USART2 */
      UartHandle.Instance          = USART1;
      UartHandle.Init.BaudRate     = 115200;
      UartHandle.Init.WordLength   = UART_WORDLENGTH_8B;
      UartHandle.Init.StopBits     = UART_STOPBITS_1;
      UartHandle.Init.Parity       = UART_PARITY_NONE;
      UartHandle.Init.HwFlowCtl    = UART_HWCONTROL_RTS_CTS;
      UartHandle.Init.Mode         = UART_MODE_TX_RX;
      HAL_UART_Init(&UartHandle);
    }
    int main(void){
      /* Reset of all peripherals, Initializes the Systick */
      HAL_Init();
      
      /* System clock configuration */
      APP_SystemClockConfig();
      
      app_uart_init();
      
      HAL_UART_Transmit_DMA(&UartHandle, (uint8_t *)aTxBuffer, 12);
      
      while (1){
        //UartHandle.hdmarx->Instance->CNDTR = 1024;
        
        /* Receive data using DMA */
        if (HAL_UART_Receive_DMA(&UartHandle, (uint8_t *)aRxBuffer, 6) != HAL_OK){
          APP_ErrorHandler();
        }
        
        /* Wait for receiving data to complete */
        while(HAL_UART_GetState(&UartHandle) != HAL_UART_STATE_READY){
        }
        
        /* Send data using DMA */
        if (HAL_UART_Transmit_DMA(&UartHandle, (uint8_t *)aRxBuffer, 6) != HAL_OK){
          APP_ErrorHandler();
        }
        
        /* Wait for sending data to complete */
        while(HAL_UART_GetState(&UartHandle) != HAL_UART_STATE_READY){
        }
        
      }
    }
    /**
     * @brief  System clock configuration function
     * @param  None
     * @retval None
     */
    static void APP_SystemClockConfig(void){
      RCC_OscInitTypeDef  OscInitstruct = {0};
      RCC_ClkInitTypeDef  ClkInitstruct = {0};
      
      OscInitstruct.OscillatorType  = RCC_OSCILLATORTYPE_HSE | RCC_OSCILLATORTYPE_HSI | RCC_OSCILLATORTYPE_LSE | RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_HSI48M;
      OscInitstruct.HSEState        = RCC_HSE_OFF;                            
      /* Disable HSE */
      /* OscInitstruct.HSEFreq         = RCC_HSE_16_32MHz; */                     
      /* HSE working frequency range: 16M~32M */
      OscInitstruct.HSI48MState     = RCC_HSI48M_OFF;                           
      /* Disable HSI48M */
      OscInitstruct.HSIState        = RCC_HSI_ON;                             
    }
    

    解决方案: 1. 确认串口通信的波特率一致,可以通过以下的代码设置波特率:

    UartHandle.Init.BaudRate = 115200;
    
    1. 确认接收缓冲区大小足够,可以通过以下代码设置接收缓冲区大小:
    uint8_t aRxBuffer[64] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
    if (HAL_UART_Receive_DMA(&UartHandle, (uint8_t *)aRxBuffer, 6) != HAL_OK){
        APP_ErrorHandler();
    }
    
    1. 等待DMA传输结束,可以通过以下代码等待传输结束:
    /* Wait for receiving data to complete */
    while(HAL_UART_GetState(&UartHandle) != HAL_UART_STATE_READY){
    }
    
    1. 确认中断优先级设置正确,可以通过以下代码设置中断优先级:
    HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn);
    
    评论

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 4月15日
  • 创建了问题 4月10日

悬赏问题

  • ¥100 set_link_state
  • ¥15 虚幻5 UE美术毛发渲染
  • ¥15 CVRP 图论 物流运输优化
  • ¥15 Tableau online 嵌入ppt失败
  • ¥100 支付宝网页转账系统不识别账号
  • ¥15 基于单片机的靶位控制系统
  • ¥15 真我手机蓝牙传输进度消息被关闭了,怎么打开?(关键词-消息通知)
  • ¥15 装 pytorch 的时候出了好多问题,遇到这种情况怎么处理?
  • ¥20 IOS游览器某宝手机网页版自动立即购买JavaScript脚本
  • ¥15 手机接入宽带网线,如何释放宽带全部速度