【动手学STM32G4】(1)STM32G431之创建项目
【动手学STM32G4】(2)STM32G431之外部中断
【动手学STM32G4】(3)STM32G431之定时器
【动手学STM32G4】(11)STM32G431之 ADC 温度检测


1. 项目简介

在嵌入式系统中,模拟信号的采集与输出是连接物理世界与数字处理系统的关键环节。

本项目基于 NUCLEO-G431RB 开发板,对片上温度传感器(VTS)和内部电压基准(VREFINT)进行 ADC1 转换,计算实际温度;再通过虚拟串口在 VOFA+ 中绘制实时温度曲线。

通过本实验,学生将掌握 STM32 微控制器 ADC 内部通道(Internal Channel)的使用方法,理解片上温度传感器的工作机理,并完成从数据采集到上位机可视化的完整工程流程。具体目标包括:

  1. 理解 STM32 ADC 内部通道(Temperature Sensor、VREFINT)的原理与特点;
  2. 掌握 STM32CubeMX 中 ADC 多通道扫描与 DMA 的配置方法;
  3. 熟悉 LPUART + DMA 的数据发送方式;
  4. 使用 VOFA+ 软件实现实时波形显示。

1.1 工作原理

STM32G431 片内往往都集成了一个内部温度传感器用于测量芯片的结温(Tj),并给出了出厂时基于特定温度及参考电压下的校准值以供使用。

STM32G4 系列 ADC 除了支持外部模拟输入引脚,还提供多个内部通道:

  • 温度传感器(TS):产生的电压 VTS 随温度线性变化,温度传感器内部连接到 ADC1 的输入通道 ADC1_IN16,用于将传感器的输出电压转换为数字量。
  • 内部电压基准(VREFINT):EFINT 为 ADC 和比较器提供一个稳定的带隙基准电压,内部连接到 ADC1 的输入通道
    ADC1_IN18。
  • 校准值地址:在生产测试时单独测量每颗芯片的 VREFINT 精确值,并将其存入系统存储区,用户只能以只读方式访问。
    • TS_CAL1:0x1FFF75A8(30°C,VDDA=3.0V)
    • TS_CAL2:0x1FFF75CA(130°C,VDDA=3.0V)
    • VREFINT_CAL:0x1FFF75AA(30°C,VDDA=3.0V)

本例程主要示例 ADC 的应用,为简化程序不使用 TS_CAL1/TS_CAL2 校准,而采用 ST 常见的典型参数 V30=0.76V、Avg_Slope=2.5mV/°C 来估算温度。代码简单、无需读校准常量。

片上温度传感器本质上是一个与温度相关的模拟电压源,其输出电压 V T S V_{TS} VTS 随温度变化,近似满足线性关系:

T = V T S − V 30 A v g S l o p e + 30 T = \frac{V_{TS}-V_{30}}{A_{vg}Slope} + 30 T=AvgSlopeVTSV30+30

其中:
V30:30℃ 时的传感器电压(典型值 ≈ 0.76V)
AvgSlope:平均斜率(典型值 ≈ 2.5mV/℃)

Vts = ADC_TS * VDDA / 4096
Temp = (Vts - V30) / Avg_Slope + 30

1.2 实验任务

  1. 配置 ADC1,扫描两个内部通道:
    Rank1:温度传感器
    Rank2:VREFINT
  2. 使用 DMA 连续采样 ADC 数据
  3. 计算:温度值(℃),温度传感器电压
  4. 通过 LPUART1(ST-LINK 虚拟串口)发送数据
  5. 在 VOFA+ 中实时显示两通道曲线:CH1:温度(℃),CH2:Vts(V)

1.3 软硬件准备

硬件资源:

  1. NUCLEO-G431RB 开发板
    内置 STM32G431 具有高速 12 位 ADC、12 位 DAC 以及丰富的模拟外设资源,是本实验的核心平台。

  2. USB 数据线(Micro USB → USB-A)
    用于开发板供电、程序下载和串口通信。

  3. 示波器(可选)
    用于观察 DAC 输出的实际模拟波形,便于与采样数据进行对比。

软件资源:
STM32CubeMX, STM32CubeIDE,VOFA+ 串口调试工具

硬件连接:

  • Nucleo-G431RB 开发板通过其USB端口(Micro-USB)连接到PC。
    安装 ST-LINK 驱动后,在设备管理器里能看到一个 “ST-LINK Virtual COM Port (COMx)”。

  • 在 Nucleo-G431RB开发板上,默认 LPUART1(PA2/PA3)接到 ST-LINK 的虚拟串口。
    这种方式不需要再接 USB-TTL,只要一根 USB 线就能做串口实验。


2. CubeMX 工程创建与配置

2.1 新建工程与基础设置

  1. 新建工程
    启动 STM32CubeMX,点击 “Start New Project” (或Ctrl-N快捷键)新建工程,进入 New Project 界面。
  • 选择MCU为 STM32G431RBT6(参考开发板的 MCU 型号选择)。
  • 选择开发板为 NUCLEO-G431RB 开发板。
  • 点击右上角 “Start Project” 创建项目。

在这里插入图片描述


  1. 基础设置:
    选择“引脚配置(Pinout & Configuration)”,
    (1)选择 “System Core – SYS” 设置调试器类型,将 Debug 模式设为 “Serial Wire”。
    (2)选择 “System Core – SYS” 设置基础时钟源(Timebase Source),可以选择默认设置 “SysTick”。

在这里插入图片描述

(3)选择 “System Core – RCC” 配置时钟模式,设置高速、低速时钟为外部晶振,将 High Speed Clock (HSE) 、Low Speed Clock (LSE) 都设为 “Crystal/Ceramic Resonator”。

在这里插入图片描述


2.2 ADC配置

  1. 选择 PA0 为 ADC1-IN1 的采样通道引脚,配置为模拟模式。
    (1)选择 “引脚配置(Pinout & Configuration)”,从左侧下拉列表中选择 “Analog – ADC1” ,使用 IN1(PA0) 作为模拟输入通道,将 IN1 设置为 “IN1 Singel-ended”。在 Pinout view 视图中,将 PA0 引脚配置为 “ADC1_IN1”(通常会自动配置)。
    (2)开启独立通道 IN1,设置为 “IN1 Single-ended”。
    (3)开启温度传感器通道 和 内部电压基准(Vrefint)通道。

在这里插入图片描述

  1. 配置 ADC 工作模式和参数。
ADCs_Common_Settings
   Mode: Independent mode
ADC_Settings   
   Resolution: ADC 12-bit resolution
   Data Alignment: Right alignment(右对齐)
   Gain Compensation: 默认为 0
   Continuous Conversion Mode: Enabled(持续扫描,配合 DMA 使用)
   DMA Continuous Requests: Enabled
Scan Conversion Mode:Enable
Number of Conversion: 2
Rank 1: 
   Channel: Channel Temperature Sensor
   Smapling Time: 92.5 Cycles
   Offset Number: No offset
Rank 2: 
   Channel: Channel Vrefint
   Smapling Time: 92.5 Cycles
   Offset Number: No offset

在这里插入图片描述
在这里插入图片描述

  1. 添加 DMA 通道:
    在 ADC1 的 DMA Settings 中添加一个 DMA 通道;
Add DMA Request:ADC1
Mode:Circular
Data Width:Half Word(16-bit)

在这里插入图片描述


2.3 GPIO 与串口(可选)配置

  1. GPIO(可选)
    可选地,配置一些 GPIO 用于 LED 显示或按键触发。
    例如,将 PA5 配置为 GPIO_OUT(LD2),将 PC13 配置为 GPIO_EXTI13(UserBTN)

在这里插入图片描述

  1. 串口 / LPUART(用于上位机调试,可选)
    如需要使用串口发送 ADC/DAC 数据到 PC 来显示波形:启用 LPUART1,模式设为 Asynchronous;波特率设置为 115200;引脚使用默认的 PA2(TX)/PA3(RX),连接到 Nucleo 板上的 ST-LINK 虚拟串口。

在这里插入图片描述


2.4 时钟配置

在 Clock Configuration 视图进行时钟配置,如下图所示。

在这里插入图片描述


2.5 工程配置

点击工具栏 “Project Manager” 进入工程配置界面,如下图所示。
(1)在 Project Name 输入项目名称 “STM32G431_ADC03”。
(2)在 Toolchain/IDE 选择 IDE 工具为 “STM32CubeIDE”(也可以根据需要选择其它 IDE 工具 )。

在这里插入图片描述

(3)在 “Project Manager” 继续向下拉,“在 MCU and Firmware Package” 栏中,取消选中 “Use latest available version”,根据所安装的 G4 固件版本,选择 “STM32Cube FW_G4 V1.6.0”;
(4)如果固件包不是安装在默认路径,则要取消选中 “Use Default Firmware Location”,通过 Browse 选择固件包的安装路径。

在这里插入图片描述


2.6 生成工程代码

点击右上角 “GENERATE CODE” ,将自动生成带 .ioc 的工程文件 “STM32G431_ADC03.ioc”
加载完毕后,弹出代码生成提示窗口,点击“ OPEN PROJECT”,进入 STM32CubeIDE。
可以在 main.c 中看到 CubeMX 自动生成的初始化函数调用:

MX_GPIO_Init();
MX_ADC1_Init();
MX_DAC1_Init();
MX_LPUART1_UART_Init();

3. 使用 STM32CubeIDE 编写和调试

  1. 在 STM32CubeIDE 打开代码文件 main.c。
    代码生成后,已经自动进入 STM32CubeIDE,并打开创建的 STM32G431_ADC03 项目。在 “Core\Src” 目录中,已经生成了 adc.c 和 main.c 等基础程序。

  2. 从 “Core\Src” 目录打开程序文件 adc.c,检查 CubeMX 生成的 ADC 配置是否是 “2 rank + DMA 循环”。

/* ADC1 init function */
void MX_ADC1_Init(void)
{
  ADC_MultiModeTypeDef multimode = {0};
  ADC_ChannelConfTypeDef sConfig = {0};

  /** Common config */
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.GainCompensation = 0;
  hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc1.Init.LowPowerAutoWait = DISABLE;
  hadc1.Init.ContinuousConvMode = ENABLE;
  hadc1.Init.NbrOfConversion = 2;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.DMAContinuousRequests = ENABLE;
  hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  hadc1.Init.OversamplingMode = DISABLE;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure the ADC multi-mode */
  multimode.Mode = ADC_MODE_INDEPENDENT;

  /** Configure Regular Channel */
  sConfig.Channel = ADC_CHANNEL_TEMPSENSOR_ADC1;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  ...

  /** Configure Regular Channel */
  sConfig.Channel = ADC_CHANNEL_VREFINT;
  sConfig.Rank = ADC_REGULAR_RANK_2;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
}
  1. 从 “Core\Src” 目录打开程序文件 main.c,如下图所示。

在这里插入图片描述


  1. 修改 main.c 代码。

(1)在 main.c 开头的 USER CODE 区 加入头文件与宏:

/* USER CODE BEGIN Includes */
#include <string.h>
/* USER CODE END Includes */

(2)在 main.c 开头的Private variables 区 加入“校准地址 + DMA 缓冲 + VOFA 尾帧”:

/* USER CODE BEGIN PV */
/* ADC DMA 缓冲:Rank1=TempSensor, Rank2=VREFINT */
volatile uint16_t adc_buf[2] = {0};

/* USER CODE BEGIN PV */
typedef union {
    float f;
    uint8_t b[4];
} FloatBytes;

/* 串口发送缓冲:2通道 + 帧尾 = 3个float = 12字节 */
static FloatBytes serialData[3];   // [0]=CH1, [1]=CH2, [2]=Tail(NaN)
/* USER CODE END PV */

(3)在 USER CODE BEGIN 0 区 添加 2 个函数 Calc_VDDA_mV(), Calc_TempC_Typical():

/* USER CODE BEGIN 0 */
/* 典型参数(ST 常用示例值) */
#define TS_V30        (0.76f)     // 30°C时 VTS 典型值 (V)
#define TS_AVG_SLOPE  (0.0025f)   // 平均斜率 2.5mV/°C (V/°C)

/* VREFINT_CAL_ADDR 在 stm32g4xx_ll_adc.h 已定义,无需重复 define */
static float Calc_VDDA_mV(uint16_t vref_raw)
{
    if (vref_raw == 0) return 0.0f;
    return 3000.0f * ((float)(*VREFINT_CAL_ADDR)) / (float)vref_raw;
}

static float Calc_TempC_Typical(uint16_t ts_raw, float vdda_mV)
{
    if (vdda_mV <= 0.0f) return 0.0f;

    float vdda_v = vdda_mV / 1000.0f;                 // mV -> V
    float vts    = (float)ts_raw * (vdda_v / 4096.0f); // ADC->V

    return (vts - TS_V30) / TS_AVG_SLOPE + 30.0f;
}
/* USER CODE END 0 */

(4)在 main() 里启动 ADC 校准 + 启动 ADC DMA(放到 USER CODE BEGIN 2):

  /* USER CODE BEGIN 2 */
  /* 1) 初始化 VOFA+ 帧尾:00 00 80 7F (NaN,小端) */
  memcpy(serialData[2].b, (uint8_t[]){0x00, 0x00, 0x80, 0x7F}, 4);

  /* 2) ADC 校准(建议) */
  HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);

  /* 3) 启动 ADC DMA(2个转换:TS + VREFINT) */
  if (HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buf, 2) != HAL_OK)
  {
      Error_Handler();
  }
  /* USER CODE END 2 */

(5)轮询程序 while(1) 的代码修改如下。

  /* Infinite loop */
  while (1)
  {
    /* USER CODE BEGIN 3 */
    /* adc_buf[0]=TS raw (Rank1), adc_buf[1]=VREFINT raw (Rank2) */
    uint16_t ts_raw   = adc_buf[0];  // Rank1: TS
    uint16_t vref_raw = adc_buf[1];  // Rank2: VREFINT

    float vdda_mV = Calc_VDDA_mV(vref_raw);
    float temp_c  = Calc_TempC_Typical(ts_raw, vdda_mV);

    /* 方案1:CH1=温度(℃),CH2=VDDA(mV)  */
    float vdda_v = vdda_mV / 1000.0f;
    float vts = (float)ts_raw * (vdda_v / 4096.0f);
    serialData[0].f = temp_c;
    serialData[1].f = vts;

    /* 通过 DMA 发给 VOFA+:3个float=12字节 */
    if (HAL_UART_GetState(&hlpuart1) == HAL_UART_STATE_READY)
    {
        HAL_UART_Transmit_DMA(&hlpuart1, (uint8_t*)serialData, 12);
    }

    HAL_Delay(100);
  }

在这里插入图片描述


  1. 启用 printf 的浮点输出–非常重要!
    在 STM32CubeIDE 中:
    (1)在菜单点击 “Project → Properties”,弹出 Properties 窗口。
    (2)选择 “C/C++ Build → Settings → Tool Settings → MCU Settings”
    (3)勾选:Use float with printf from newlib-nano (-u _printf_float)
    (4)点击右下角 “Apply and Close” 确认设置。
    在这里插入图片描述

  2. 程序编辑、编译与调试

    • 点击工具栏中 “Build Debug” 按键对程序代码进行编译。
    • 点击工具栏中 “Debug” 按键,将程序下载烧录到目标板 NUCLEO-G431RB 。
    • 点击工具栏中 “Resume” 按键 或 F8 快捷键,运行程序。

  1. 打开 VOFA+ 软件:
    (1)点击 “数据引擎” 下拉菜单,选择 “JustFloat” 协议。
    (2)点击 “数据接口” 下拉菜单,选择 “串口”。
    (3)点击 “端口号” 下拉菜单,选中 STM STLink Virtual COM Port。
    (4)将配置参数设为与 STM32CubeMX 中 “Connectivity – LPUART1” 的配置一致:

波特率:115200
数据位:8 Bits
校验位:None
数据流控:None
停止位:1

  1. 点击 VOFA+ 左上角的 “连接” 按钮,在数据显示区就将显示 HEX 格式的数据,并在上方图形区域显示波形。
    鼠标移到上方波形区域,点击鼠标右键唤出设置菜单。
    (1)点击 “X轴”,选择“使用时间轴”;
    (2)点击 “Y轴”,选择“All” 绘制所有曲线的波形;

于是在VOFA+中,我们可以同时观察到:(1)红色曲线,温度(℃);(2)绿色曲线,Vts(V)。
典型观察结果:

  • 温度 CH1:20~35℃(室温附近)
  • Vts CH2:约 0.70~0.80V

用手指按住 MCU 芯片区域 10~20 秒,红色曲线上升至 30℃ 左右;松开手指后 温度缓慢下降并恢复到正常值。

在这里插入图片描述


总结

通过本实验,完成了一个完整的嵌入式模拟采集与可视化系统,深入理解了:

  • ADC 内部通道的工程价值
  • 模拟量与数字量之间的转换关系
  • “测量 ≠ 直接读数,而是建模 + 校正”的工程思想

版权声明:
【动手学STM32G4】是 youcans@qq 原创作品,转载必须标注原文链接:(https://blog.csdn.net/youcans/article/details/156111840)
Copyright@youcans 2025
Crated:2025-12

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐