首页
学习
活动
专区
圈层
工具
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

STM32,读取ADC值并使用串口传输(HAL库)

要在 STM32 上使用 HAL 库读取 ADC 值并通过串口传输数据,可以按照以下步骤进行。本文将以 STM32F1 系列为例,详细介绍如何配置 ADC 和 UART,并实现数据的读取与传输。


​1. 硬件准备​

​所需硬件​

  • STM32 开发板(如 STM32F103C8T6 "蓝色小板")
  • USB 转串口模块(如 CH340、CP2102 等)
  • 面包板和杜邦线
  • 可选:外部电压源(用于测试 ADC 输入)

​连接说明​

  1. ​ADC 输入引脚​​:
    • 选择 STM32 的一个 ADC 输入引脚(如 PA0),连接到一个可变电压源或固定电压源(确保电压范围在 ADC 输入范围内,通常为 0V 至 VDDA)。
  2. ​UART 连接​​:
    • STM32 的 TX 引脚(如 PA9)连接到 USB 转串口模块的 RX 引脚。
    • STM32 的 RX 引脚(如 PA10)连接到 USB 转串口模块的 TX 引脚。
    • STM32 的 GND 连接到 USB 转串口模块的 GND。

    ​注意​​:确保电压匹配,STM32 的逻辑电平通常为 3.3V,避免直接连接 5V 设备。


​2. 软件环境设置​

​所需软件​

  • STM32CubeMX:用于生成初始化代码。
  • STM32CubeIDE 或 Keil uVision:用于编写和调试代码。
  • ST-Link 或其他调试器(用于烧录程序)。

​安装步骤​

  1. 下载并安装 STM32CubeMX。
  2. 下载并安装 STM32CubeIDE(集成开发环境,包含编译器和调试工具)。
  3. 安装 ST-Link 驱动程序(如果使用 ST-Link 进行调试)。

​3. ADC 配置​

​使用 STM32CubeMX 配置 ADC​

  1. ​创建新项目​​:
    • 打开 STM32CubeMX,点击 "New Project"。
    • 选择你的 STM32 型号(如 STM32F103C8Tx),点击 "Start Project"。
  2. ​配置时钟​​:
    • 在 "Pinout & Configuration" 标签页,确保系统时钟配置正确(通常使用 HSE 或 HSI)。
    • 切换到 "Clock Configuration" 标签页,配置系统时钟频率(如 72 MHz)。
  3. ​启用 ADC​​:
    • 在 "Pinout & Configuration" 标签页,选择要使用的 ADC 引脚(如 PA0),将其模式设置为 "Analog"。
    • 在 "Middleware" 或 "Configuration" 标签页,找到 "ADC1" 并启用它。
  4. ​配置 ADC 参数​​:
    • 点击 "ADC1",进入其设置页面。
    • 设置分辨率为 12 位(默认)。
    • 配置转换模式为单通道单次转换(Single Conversion)或连续转换(Continuous Conversion),根据需求选择。
    • 设置采样时间(如 239.5 Cycles)以获得更准确的读数。
    • 如果使用外部触发,配置触发源;否则,保持软件触发。
  5. ​生成代码​​:
    • 点击 "Project" -> "Settings",选择工具链为 "STM32CubeIDE" 或其他你使用的 IDE。
    • 点击 "Generate Code",生成初始化代码。

​4. UART 配置​

​使用 STM32CubeMX 配置 UART​

  1. ​启用 UART​​:
    • 在 "Pinout & Configuration" 标签页,找到 "USART1"(或其他可用 UART),将其模式设置为 "Asynchronous"。
    • STM32F103C8T6 的默认 UART 引脚为 PA9 (TX) 和 PA10 (RX)。
  2. ​配置 UART 参数​​:
    • 点击 "USART1",进入其设置页面。
    • 设置波特率为 115200(可根据需要调整)。
    • 数据位:8
    • 停止位:1
    • 校验位:None
    • 硬件流控制:None
  3. ​生成代码​​:
    • 确保所有配置完成后,点击 "Generate Code" 生成 UART 初始化代码。

​5. 主程序实现​

在生成的代码基础上,编写主程序以实现以下功能:

  1. 初始化 ADC 和 UART。
  2. 循环读取 ADC 值。
  3. 将 ADC 值通过 UART 发送。

​示例步骤​

  1. ​初始化​​:
    • main.c 中,确保 HAL 库已正确初始化 ADC 和 UART。
  2. ​读取 ADC 值​​:
    • 使用 HAL_ADC_PollForConversion 读取 ADC 值。
    • 将 ADC 值转换为实际电压(如果需要)。
  3. ​通过 UART 发送数据​​:
    • 使用 HAL_UART_Transmit 将 ADC 值发送到串口。

​6. 完整代码示例​

以下是一个完整的 main.c 示例,展示如何读取 ADC 值并通过 UART 发送:

代码语言:javascript
复制
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include <stdio.h>

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_ADC1_Init(void);
static void MX_USART1_UART_Init(void);

/* Private variables ---------------------------------------------------------*/
ADC_HandleTypeDef hadc1;
UART_HandleTypeDef huart1;

/* Function prototypes -------------------------------------------------------*/
#ifdef __GNUC__
  /* With GCC/RAISONANCE, 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 ---------------------------------------------------------*/
/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* MCU 初始化 */
  HAL_Init();

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

  /* 初始化所有配置的外设 */
  MX_GPIO_Init();
  MX_ADC1_Init();
  MX_USART1_UART_Init();

  /* 配置 printf 通过 UART 输出 */
  __HAL_UART_ENABLE(&huart1);
  
  char msg[50];
  uint32_t adc_value;
  float voltage;

  /* 无限循环 */
  while (1)
  {
    /* 启动 ADC 转换 */
    if (HAL_ADC_Start(&hadc1) == HAL_OK)
    {
      /* 等待转换完成 */
      if (HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY) == HAL_OK)
      {
        /* 获取 ADC 值 */
        adc_value = HAL_ADC_GetValue(&hadc1);
        
        /* 将 ADC 值转换为电压(假设 VREF=3.3V,12位分辨率) */
        voltage = (adc_value * 3.3f) / 4095.0f;
        
        /* 格式化字符串 */
        snprintf(msg, sizeof(msg), "ADC Value: %lu, Voltage: %.2f V\r\n", adc_value, voltage);
        
        /* 通过 UART 发送 */
        HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
      }
    }
    
    /* 延时(例如 500ms) */
    HAL_Delay(500);
  }
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** 初始化 RCC 振荡器 
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  
  /** 初始化 RCC 时钟 
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief ADC1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_ADC1_Init(void)
{

  /* 用户可以在此处调整 ADC 参数 */
  ADC_ChannelConfTypeDef sConfig = {0};

  /** 初始化 ADC 
  */
  hadc1.Instance = ADC1;
  hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
  hadc1.Init.ContinuousConvMode = DISABLE;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.NbrOfConversion = 1;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }
  
  /** 配置 ADC 通道 
  */
  sConfig.Channel = ADC_CHANNEL_0; // PA0
  sConfig.Rank = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief USART1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_USART1_UART_Init(void)
{

  /* 用户可以在此处调整 UART 参数 */
  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();
  }
}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  __HAL_RCC_GPIOA_CLK_ENABLE();
}

/**
  * @brief  Retargets the C library printf function to the UART.
  * @param  None
  * @retval None
  */
PUTCHAR_PROTOTYPE
{
  /* 将字符通过 UART 发送 */
  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
  return ch;
}

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* 用户可以添加自己的错误处理代码,例如 LED 指示 */
  while(1)
  {
  }
}

​代码说明​

  1. ​SystemClock_Config​​:
    • 配置系统时钟,使用 HSE 和 PLL 将时钟设置为 72 MHz。
  2. ​MX_ADC1_Init​​:
    • 初始化 ADC1,配置为单通道单次转换模式,采样时间为 239.5 周期。
  3. ​MX_USART1_UART_Init​​:
    • 初始化 USART1,设置波特率为 115200。
  4. ​MX_GPIO_Init​​:
    • 启用 GPIOA 时钟(用于 ADC 和 UART 引脚)。
  5. ​PUTCHAR_PROTOTYPE​​:
    • 重定向 printf 函数到 UART,以便使用 printf 发送数据。
  6. ​主循环​​:
    • 启动 ADC 转换,读取 ADC 值,并将其转换为电压。
    • 使用 printf 将 ADC 值和电压通过 UART 发送。
    • 延时 500ms 后重复。

​7. 调试与验证​

​步骤 1:编译代码​

  1. 打开 STM32CubeIDE,导入项目。
  2. 确保项目配置正确(如芯片型号、时钟设置等)。
  3. 点击 "Build" 或 "Rebuild" 编译项目。

​步骤 2:烧录程序​

  1. 连接 ST-Link 到开发板和电脑。
  2. 在 STM32CubeIDE 中,点击 "Debug" 按钮,选择 ST-Link 作为调试器。
  3. 烧录程序到 STM32。

​步骤 3:连接串口终端​

  1. 使用 USB 转串口模块将 STM32 连接到电脑。
  2. 打开串口终端软件(如 Tera Term、PuTTY 或 CoolTerm)。
  3. 配置串口参数:
    • 波特率:115200
    • 数据位:8
    • 停止位:1
    • 校验位:None
    • 流控制:None
  4. 打开串口,开始接收数据。

​步骤 4:验证数据​

  1. 如果一切配置正确,串口终端应每 500ms 接收到类似如下的数据: ADC Value: 2048, Voltage: 1.65 V (具体值取决于输入电压)
  2. 如果没有数据接收,检查以下内容:
    • 硬件连接是否正确。
    • 串口终端配置是否正确。
    • 是否选择了正确的串口端口。
    • 是否正确烧录了程序。

​8. 常见问题及解决方法​

​问题 1:串口无数据输出​

​可能原因​​:

  • UART 初始化错误。
  • 波特率设置不匹配。
  • 硬件连接错误。
  • 串口终端配置错误。

​解决方法​​:

  1. 检查 MX_USART1_UART_Init 函数中的波特率是否与串口终端设置一致。
  2. 使用示波器或逻辑分析仪检查 TX 引脚是否有信号。
  3. 确认硬件连接正确,TX 和 RX 是否交叉连接(即 STM32 的 TX 接 PC 的 RX,STM32 的 RX 接 PC 的 TX)。
  4. 确认串口终端选择了正确的端口和波特率。

​问题 2:ADC 值不正确或为 0​

​可能原因​​:

  • ADC 引脚未正确配置为模拟输入。
  • 参考电压不正确。
  • 采样时间不足。
  • 硬件连接错误。

​解决方法​​:

  1. 检查 MX_ADC1_Init 函数中 ADC 通道是否配置为模拟输入(在 STM32CubeMX 中设置引脚为 "Analog")。
  2. 确认 VREF+ 引脚连接正确,通常连接到 3.3V。
  3. 增加采样时间(如 ADC_SAMPLETIME_71CYCLES_5 或更长)。
  4. 使用万用表测量 ADC 输入引脚的电压,确认是否有预期电压。

​问题 3:程序无法烧录​

​可能原因​​:

  • ST-Link 驱动未安装或安装不正确。
  • 调试接口选择错误。
  • 芯片被锁定。

​解决方法​​:

  1. 确保安装了最新的 ST-Link 驱动程序。
  2. 在 STM32CubeIDE 中,确认选择了正确的调试接口(SWD 或 JTAG)。
  3. 如果芯片被锁定,尝试解锁(需要特定工具和操作)。

​补充说明​

​ADC 输入电压范围​

  • STM32 的 ADC 输入电压范围通常为 0V 至 VREF+。
  • 对于大多数 STM32 系列,VREF+ 连接到 3.3V,因此输入电压不应超过 3.3V,否则可能损坏 ADC 或读取错误值。

​提高 ADC 精度​

  • 使用更长的采样时间(如 ADC_SAMPLETIME_239CYCLES_5)以提高精度。
  • 对 ADC 进行校准(调用 HAL_ADCEx_Calibration_Start)。
  • 使用外部参考电压(如果需要更高精度)。

​多通道 ADC 读取​

如果需要读取多个 ADC 通道,可以配置扫描模式或多通道转换,并在代码中处理多个值。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

没有搜到相关的视频

领券