You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

HAL_UART_Transmit_DMA无法正常传输ADC缓冲区的问题排查与解决

问题与解决:STM32F7 ADC-DMA与USART3协同传输乱码问题

使用环境

  • STM32CubeMX版本:6.10.0
  • STM32CubeIDE版本:1.13.1
  • 开发板:Nucleo-F767ZI

问题描述

开发DIY示波器项目时,尝试最大化STM32F7系列ADC的速度与精度。DMA流水线可在不占用CPU的情况下高效传输数据,调试确认adc_buf缓冲区已被准确填充12位ADC值,但调用HAL_UART_Transmit_DMA向板载USART3传输该缓冲区时输出乱码。

已验证USART3可正常传输字符数组,例如通过HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), 0xFFFF);发送测试消息完全正常。外设初始化顺序为MX_GPIO_Init()→MX_DMA_Init()→MX_USART3_UART_Init()→MX_ADC1_Init(),排除了初始化顺序问题。

原简化工作流程代码

/* USER CODE BEGIN PD */
#define ADC_BUF_LEN 8
/* USER CODE END PD */

/* USER CODE BEGIN PV */
uint16_t adc_buf[ADC_BUF_LEN];
/* USER CODE END PV */

int main(void)
{
    /* USER CODE BEGIN 1 */
    char msg[] = "\n\rThe cow jumped over the moon\r\n";
    char buffer[50];
    /* USER CODE END 1 */
    //...初始化操作
    /* USER CODE BEGIN 2 */
    HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), 0xFFFF); // 测试消息传输正常
    HAL_ADC_Start_DMA(&hadc1, (uint32_t *) &adc_buf, ADC_BUF_LEN);
    /* USER CODE END 2 */

    /* 无限循环 */
    /* USER CODE BEGIN WHILE */
    while (1) {
        // 等待USART3传输完成
        while (READ_BIT(huart3.Instance->ISR, USART_ISR_TC)==0){asm("nop");}
        HAL_UART_Transmit_DMA(&huart3, (uint8_t*)adc_buf, ADC_BUF_LEN * sizeof(uint8_t));
        // 需重新启动ADC-DMA以持续读取数据
        HAL_ADC_Start_DMA(&hadc1, (uint32_t *) &adc_buf, ADC_BUF_LEN);
    }
    /* USER CODE END WHILE */
}

预期输出为ADC数值的文本形式,但实际输出乱码。ADC的半完成和完成中断可正常触发,DMA与USART单独工作正常,但协同传输时异常。

解决方法与修改后代码

问题根源在于直接传输uint16_t类型的原始ADC数值,USART无法识别非ASCII编码的二进制数据,同时USART3的数据宽度配置不匹配。解决方式为:将ADC缓冲区的uint16_t值转换为ASCII字符串后再通过DMA传输,同时将USART3的数据宽度从半字改为字节。

修改后的主函数代码:

int main(void)
{
  /* USER CODE BEGIN 1 */
  char msg[] = "\n\rThe cow jumped\r\n";
  char buffer[ADC_BUF_LEN * 6]; // 假设每个值最多占6个字符(含终止符)
  memset(buffer, 0, sizeof(buffer));
  /* USER CODE END 1 */

  /* MCU配置--------------------------------------------------------*/

  /* 复位所有外设,初始化Flash接口和SysTick */
  HAL_Init();

  /* USER CODE BEGIN Init */
  HAL_NVIC_SetPriority(USART3_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(USART3_IRQn);

  /* USER CODE END Init */

  /* 配置系统时钟 */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* 初始化所有配置的外设 */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART3_UART_Init();
  MX_ADC1_Init();
  MX_ETH_Init();
  MX_USB_OTG_FS_PCD_Init();
  /* USER CODE BEGIN 2 */
  HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), 0xFFFF); // 传输正常
  HAL_ADC_Start_DMA(&hadc1, (uint32_t *) &adc_buf, ADC_BUF_LEN);
    //HAL_DMA_RegisterCallback(&hdma_usart3_tx, HAL_DMA_XFER_CPLT_CB_ID, &DMATransferComplete);

  /* USER CODE END 2 */

  /* 无限循环 */
  /* USER CODE BEGIN WHILE */
  while (1) {
      // 等待USART3传输完成
      while (READ_BIT(huart3.Instance->ISR, USART_ISR_TC)==0) {asm("nop");}
      // 等待上一次DMA传输完成
      if (__HAL_DMA_GET_FLAG(&hdma_usart3_tx, DMA_FLAG_TCIF0_4) == RESET) {
          // 将adc_buf转换为字符串后传输
          uint16_t len = 0;
          for (uint8_t i = 0; i < ADC_BUF_LEN; i++) {
              len += sprintf(buffer + len, "%d\r\n", adc_buf[i]); // 将uint16_t值转为ASCII字符串
              }
          HAL_UART_Transmit_DMA(&huart3, (uint8_t*)buffer, len);
      }
      // 等待传输完成
      if (__HAL_DMA_GET_FLAG(&hdma_usart3_tx, DMA_FLAG_TCIF0_4) == RESET) {}
      // 需重新启动ADC-DMA以持续读取数据
      HAL_ADC_Start_DMA(&hadc1, (uint32_t *) &adc_buf, ADC_BUF_LEN);

  }
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  /* USER CODE END 3 */
}

正常输出示例

现在输出正常,可显示正确的ADC数值:

3839
4095
3899
3831
3845

内容的提问来源于stack exchange,提问作者Mark

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 08:07:51