硬汉嵌入式论坛

 找回密码
 立即注册
查看: 1173|回复: 7
收起左侧

[有问必答] STM32F405使用UART DMA空闲中断接受不定长数据头包数据乱码问题

[复制链接]

4

主题

7

回帖

19

积分

新手上路

积分
19
发表于 2022-6-29 16:44:57 | 显示全部楼层 |阅读模式
本帖最后由 meng3983 于 2022-6-29 16:49 编辑

代码如下
static void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */

  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */

  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */

  /* USER CODE END USART1_Init 2 */
}

void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(huart->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspInit 0 */

  /* USER CODE END USART1_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_USART1_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**USART1 GPIO Configuration
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* USART1 DMA Init */
    /* USART1_RX Init */
    hdma_usart1_rx.Instance = DMA2_Stream2;
    hdma_usart1_rx.Init.Channel = DMA_CHANNEL_4;
    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;
    hdma_usart1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(huart,hdmarx,hdma_usart1_rx);

    /* USART1 interrupt Init */
               
    HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(USART1_IRQn);
  /* USER CODE BEGIN USART1_MspInit 1 */
    HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 5, 0);
   HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
  /* USER CODE BEGIN USART1_MspInit 1 */

                __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
               
                HAL_UART_Receive_DMA(&huart1,rxbuffer,1);    //接收下一次DMA        
  /* USER CODE END USART1_MspInit 1 */
  }
}

void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */

  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */
        uint32_t temp;
  if((__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE) != RESET) )
        {
     __HAL_UART_CLEAR_IDLEFLAG(&huart1);

                HAL_UART_DMAStop(&huart1);
               
                // 获取DMA当前还有多少未填充 判断接收数据帧长度
    uart1_rx_len = 4096 -__HAL_DMA_GET_COUNTER(&hdma_usart1_rx);//((DMA_Stream_TypeDef *)huart1.hdmarx->Instance)->NDTR;//// (hdma_usart1_rx.Instance->CNDTR);//

                uart1_recv_flag = 1;           //接受标志
                                
                HAL_UART_Receive_DMA(&huart1,rxbuffer,4096);    //接收下一次DMA        

    HAL_UART_Transmit(&huart1, (uint8_t *)&rxbuffer, uart1_rx_len, 0xffff);
        }
  /* USER CODE END USART1_IRQn 1 */
}

为什么重启后第一次接收中断产生长度是4096的乱码数据,之后都能正常,哪里导致__HAL_DMA_GET_COUNTER(&hdma_usart1_rx);获取长度无效
回复

使用道具 举报

2

主题

269

回帖

275

积分

高级会员

积分
275
发表于 2022-6-30 00:01:33 | 显示全部楼层
都用空闲了怎么不把循环接收DMA_CIRCULAR Mode打开,不是更香么?
翻了下以前写的代码主要相关的是下面两,我发过H7的程序。
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
HAL_UARTEx_ReceiveToIdle_DMA(&huart1, s_rx_buf1, UART1_RX_BUF_SIZE); /* 启动DMA */
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107128
QQ
发表于 2022-6-30 01:31:31 | 显示全部楼层
你的DMA时钟配置在哪里。务必要在DMA之前优先配置。
回复

使用道具 举报

4

主题

7

回帖

19

积分

新手上路

积分
19
 楼主| 发表于 2022-6-30 08:57:05 | 显示全部楼层
eric2013 发表于 2022-6-30 01:31
你的DMA时钟配置在哪里。务必要在DMA之前优先配置。

DMA时钟放在了UART初始化最前面也一样现象,我用标准库没问题,但是用HAL库就这样
回复

使用道具 举报

4

主题

7

回帖

19

积分

新手上路

积分
19
 楼主| 发表于 2022-6-30 09:03:24 | 显示全部楼层
cctv180 发表于 2022-6-30 00:01
都用空闲了怎么不把循环接收DMA_CIRCULAR Mode打开,不是更香么?
翻了下以前写的代码主要相关的是下面两 ...

这样也没啥用
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107128
QQ
发表于 2022-6-30 09:46:18 | 显示全部楼层
meng3983 发表于 2022-6-30 08:57
DMA时钟放在了UART初始化最前面也一样现象,我用标准库没问题,但是用HAL库就这样

不行直接参考我们论坛分享的得了。

基于V6的CMSIS-Driver串口应用,支持8串口DMA不定长收发,比CubeMX还要省事
https://www.armbbs.cn/forum.php?mod=viewthread&tid=93714

STM32V6之串口HAL库串口空闲中断接收不定长字节代码实现
https://www.armbbs.cn/forum.php?mod=viewthread&tid=101377
回复

使用道具 举报

3

主题

1233

回帖

1242

积分

至尊会员

积分
1242
发表于 2022-6-30 12:44:09 | 显示全部楼层
[C] 纯文本查看 复制代码
    uint32_t remainBytes_InDmaRx = 0;
    
    if ((__HAL_UART_GET_FLAG(&huart6, UART_FLAG_IDLE) != RESET))
    {
        __HAL_UART_CLEAR_IDLEFLAG(&huart6);
        
        /* Get remain bytes in DMA rx counts. */
        remainBytes_InDmaRx = __HAL_DMA_GET_COUNTER(huart6.hdmarx);
        HAL_UART_AbortReceive(&huart6);
        RxRing_Write(&dmaRxBuffer[0], (RECV_BUFF_SIZE - remainBytes_InDmaRx));
        HAL_UART_Receive_DMA(&huart6, dmaRxBuffer, RECV_BUFF_SIZE);
    }

    HAL_UART_IRQHandler(&huart6);

回复

使用道具 举报

4

主题

7

回帖

19

积分

新手上路

积分
19
 楼主| 发表于 2022-7-22 13:53:12 | 显示全部楼层
找到了解决第一笔数据无法收发问题方法,就是  __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);必须前面加延时放在串口初始化后面才行。代码如下

void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */

  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */

  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */
        HAL_Delay(100);
   __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);

        HAL_UART_Receive_DMA(&huart1, rxbuffer, 100);
  /* USER CODE END USART1_Init 2 */

}
image.png
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-19 17:01 , Processed in 0.185460 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表