【动手学STM32G4】(1)STM32G431之导入和创建项目
【动手学STM32G4】(2)STM32G431之外部中断
【动手学STM32G4】(3)STM32G431之PWM
【动手学STM32G4】(4)STM32G431之ADC/DAC
【动手学STM32G4】(5)STM32G431之UART 串口通信
【动手学STM32G4】(6)STM32G431之USB 虚拟串口通信
【动手学STM32G4】(7)STM32G431之上位机波形显示
【动手学STM32G4】(4)STM32G431之ADC/DAC
-
- [1. 项目简介](#1. 项目简介)
- [2. 工作原理](#2. 工作原理)
-
- [2.1 ADC:模拟量采样](#2.1 ADC:模拟量采样)
- [2.2 DAC:模拟电压输出](#2.2 DAC:模拟电压输出)
- [2.3 ADC 与 DAC 的闭环测试](#2.3 ADC 与 DAC 的闭环测试)
- [3. 软硬件准备](#3. 软硬件准备)
- [4. CubeMX 工程创建与配置](#4. CubeMX 工程创建与配置)
-
- [4.1 新建工程与基础设置](#4.1 新建工程与基础设置)
- [4.2 ADC配置](#4.2 ADC配置)
- [4.3 DAC 配置:单通道模拟输出](#4.3 DAC 配置:单通道模拟输出)
- [4.4 GPIO 与串口(可选)配置](#4.4 GPIO 与串口(可选)配置)
- [4.5 DMA(可选,用于后续扩展)](#4.5 DMA(可选,用于后续扩展))
- [4.6 时钟配置](#4.6 时钟配置)
- [4.7 工程配置](#4.7 工程配置)
- [4.8 生成工程代码](#4.8 生成工程代码)
- [5. 使用 STM32CubeIDE 编写和调试 DAC→ ADC 程序](#5. 使用 STM32CubeIDE 编写和调试 DAC→ ADC 程序)
- [6. 输出正弦波 ADC + DAC 波形](#6. 输出正弦波 ADC + DAC 波形)
1. 项目简介
在嵌入式系统中,模拟信号的采集与输出是连接物理世界与数字处理系统的关键环节。无论是电机控制、信号调理、数据采集卡,还是音频处理与闭环控制系统,均离不开"ADC 采样 → 数字处理 → DAC 输出"的基本流程。
本项目基于 NUCLEO-G431RB 开发板,利用其片上高速 12 位 ADC 和 12 位 DAC,构建一个简单而完整的模拟信号闭环实验:
- 使用 ADC 采样外部输入电压,并将采样结果转化为数字量;
- 在 MCU 内对该数字量进行转换或数学处理(例如比例变换、限幅或函数运算);
- 将处理后的数值通过 DAC 转换回模拟电压;
- 再使用 ADC 对 DAC 输出的电压进行采样验证,从而构成一个"采样---处理---重构---验证"的闭环流程。
这种 ADC→DAC→ADC 的实验结构不仅可帮助读者直观理解 STM32 模拟外设的工作方式,也为进一步实现数字滤波、电压调节、信号变换算法测试等应用奠定基础。
本文将介绍如何在 CubeMX 中配置 ADC 与 DAC 的关键参数,如何正确进行数值映射与转换,并最终通过上位机观察输入与输出电压的变化,实现一个可视化的模拟信号闭环实验。
2. 工作原理
2.1 ADC:模拟量采样
ADC(Analog-to-Digital Converter,模数转换器)用于将连续的模拟电压转换为离散的数字量,是 MCU 采集外部信号的核心外设。
ADC 的工作流程可以分为三个阶段:
- 采样(Sample):捕获输入电压瞬时值
- 量化(Quantize):12 位数字化
- 转换(Convert):将采样结果送入数据寄存器
STM32G431 片上集成多路 12 位高速 ADC,具有高转换速率、灵活的采样配置和多种触发方式。
STM32G4 ADC 支持多种触发源:
- 软件启动(Software Trigger)
- 定时器触发(TIMx TRGO)→ 实现固定采样频率
- 外部 GPIO 上升沿触发
STM32G431 ADC 提供多个模拟输入通道(如 IN1、IN2、IN3...),用户可依需求选择:
- 单通道采样(Single Channel)
- 多通道扫描模式(Scan Mode)
ADC 的核心作用是把外部模拟电压转换为 MCU 能处理的数字量,并保证采样精度与时间一致性。掌握 ADC 的采样时间、分辨率、触发模式和读取方式,是实现采集链路的基础。
2.2 DAC:模拟电压输出
DAC(Digital-to-Analog Converter,数模转换器)用于将 MCU 内部处理得到的数字量重新转换为模拟电压,是实现信号重构、波形输出、控制量生成等场景的重要外设。其基本作用与 ADC 相反,即 把离散数值变为连续电压。
DAC 的工作流程可以分为三个阶段:
- 装载(Load):将数字数值写入 DAC 数据寄存器
- 转换(Convert):根据输入数字量生成对应的模拟电压
- 输出(Output):通过 DAC 通道输出到引脚,供外部电路使用
STM32G431 片上集成 12 位 DAC,可提供稳定的模拟信号输出,支持缓冲器模式、触发模式以及多种更新方式。
STM32G4 DAC 支持多种触发源:
- 软件更新(Software Trigger)
- 定时器触发(TIMx TRGO)→ 实现固定频率的波形输出
- 外部触发输入(EXTI)
STM32G431 DAC 提供若干输出通道(如 DAC1_CH1、DAC1_CH2),用户可根据需要选择:
- 单通道输出(Single Output)
- 多通道独立控制(Dual Output)
DAC 的核心作用是把 MCU 内部的数字计算结果转换为可测量、可驱动的模拟电压,为信号重构、闭环控制与测试验证提供基础。理解 DAC 的输出范围、分辨率、触发模式与数据更新方式,有助于在实验中实现稳定的模拟信号输出。
2.3 ADC 与 DAC 的闭环测试
在本实验中,ADC 和 DAC 并不是独立使用,而是构成一个完整的"采样---处理---重构---验证"的闭环流程,实现了一个最基本的模拟信号链路。闭环的核心思想是:
- ADC 负责采样外部模拟电压并转换为数字量;
- MCU 根据需要对采样值进行数值变换或算法处理;
- DAC 将处理后的数值重新转换为模拟电压输出;
- ADC 再次对 DAC 输出的电压进行采样验证结果。
通过这样的闭环结构,可以验证算法处理前后电压变化是否符合预期,测试 DAC 输出的准确度和稳定性,在上位机中观察输入与输出波形的差异,为后续的滤波器测试、信号调理、控制系统原型验证奠定基础。
3. 软硬件准备
硬件资源:
-
NUCLEO-G431RB 开发板
内置 STM32G431 具有高速 12 位 ADC、12 位 DAC 以及丰富的模拟外设资源,是本实验的核心平台。
-
USB 数据线(Micro USB → USB-A)
用于开发板供电、程序下载和串口通信。
-
杜邦线
用于建立 DAC 输出与 ADC 输入之间的闭环连接。
-
示波器(可选)
用于观察 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 线就能做串口实验。
-
用杜邦线将 PA0 与 PA4 相连 ,建立 DAC 输出与 ADC 输入之间的闭环连接。
4. CubeMX 工程创建与配置
4.1 新建工程与基础设置
- 新建工程
启动 STM32CubeMX,点击 "Start New Project" (或Ctrl-N快捷键)新建工程,进入 New Project 界面。
- 选择MCU为 STM32G431RBT6(参考开发板的 MCU 型号选择)。
- 选择开发板为 NUCLEO-G431RB 开发板。
- 点击右上角 "Start Project" 创建项目。

- 基础设置:
选择"引脚配置(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"。

4.2 ADC配置
- 选择"引脚配置(Pinout & Configuration)",
从左侧下拉列表中选择 "Analog -- ADC1" ,使用 IN1(PA0) 作为模拟输入通道,将 IN1 设置为 "IN1 Singel-ended"。Pinout view 视图中的 PA0 引脚 就自动配置为 "ADC1_IN1"。
工作模式和参数选择默认值即可。通常地,分辨率:保持 12-bit; 数据对齐:Right alignment(右对齐)。

4.3 DAC 配置:单通道模拟输出
- 选择"引脚配置(Pinout & Configuration)",
从左侧下拉列表中选择 "Analog -- DAC1" ,使用 OUT1(PA4) 作为模拟输入通道,将 OUT1 设置为 "Connected to external pin only"。Pinout view 视图中的 PA4 引脚 就自动配置为 "DAC1_OUT1"。
工作模式和参数选择默认值即可。

4.4 GPIO 与串口(可选)配置
1 GPIO(可选)
- CubeMX 默认会为 ADC、DAC、调试接口(SWD)分配相应引脚;
- 如有需要,可额外配置一些 GPIO 用于 LED 指示或按键触发。例如,将 PA5 配置为 GPIO_OUT(LD2),将 PC13 配置为 GPIO_EXTI13(UserBTN)

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

4.5 DMA(可选,用于后续扩展)
虽然本章的基础实验可以先使用 查询(Polling)方式 读写 ADC/DAC,但考虑到后续有可能进行连续采样或实时波形输出,可以提前预留 DMA 资源:
1 为 ADC 分配 DMA(可选)
- 在 ADC1 的 DMA Settings 中添加一个 DMA 通道;
- Direction:Peripheral to Memory;
- Mode:Normal 或 Circular,根据后续采样需求选择。
2 为串口或 DAC 分配 DMA(可选) - 用于高频率发送数据到上位机或更新波形时,可以考虑为 LPUART1_TX 或 DAC 分配 DMA 通道。

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

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

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

4.8 生成工程代码
点击右上角 "GENERATE CODE" ,将自动生成带 .ioc 的工程文件 "STM32G431_ADC01.ioc"
加载完毕后,弹出代码生成提示窗口,点击" OPEN PROJECT",进入 STM32CubeIDE。

可以在 main.c 中看到 CubeMX 自动生成的初始化函数调用:
c
MX_GPIO_Init();
MX_ADC1_Init();
MX_DAC1_Init();
MX_LPUART1_UART_Init();
后续我们将在这些初始化的基础上,编写 ADC 采样、数值变换与 DAC 输出的用户代码。
5. 使用 STM32CubeIDE 编写和调试 DAC→ ADC 程序
-
在 STM32CubeIDE 打开代码文件 main.c。
代码生成后,已经自动进入 STM32CubeIDE,并打开创建的 STM32G431_ADC01 项目。在 "Core\Src" 目录中,已经生成了 adc.c, dac.c 和 main.c 等基础程序。
-
从 "Core\Src" 目录打开程序文件 main.c,如下图所示。

-
修改 main.c 代码。
(1)在程序开头的用户代码引用区包含需要的头文件。
c
/* USER CODE BEGIN Includes */
#include "string.h"
#include "stdio.h"
#include "stdlib.h"
(2)在 main.c 顶部的 "用户变量区" 添加用户变量。
c
/* USER CODE BEGIN PV */
// 方波参数
#define SQUARE_PERIOD 1000 // 方波周期 1000ms
#define SQUARE_AMP_VOLT 1.65f // 方波幅值 1.65V
#define SQUARE_DUTY_CYCLE 0.4f // 方波占空比 30%(0.0-1.0之间)
#define WAVE_HIGH 128 // 高电平 1.65V
#define WAVE_LOW 0 // 低电平:0V
// 控制变量
uint32_t time_counter = 0; // 时间计数器(ms)
uint8_t dac_output = 0; // DAC输出值
float adc_voltage = 0.0f; // ADC测量电压
uint16_t adc_raw_value = 0; // ADC原始值
uint16_t high_duration = 0; // 高电平持续时间(ms)
// 串口发送缓冲区(固定不变)
static uint8_t serialData[8] = {0, 0, 0, 0, 0, 0, 0x80, 0x7F}; // 初始化时设置帧尾
(3)轮询程序 while(1) 的代码如下,生成方波,并使用 LPUART1 重定向 printf 打印数据。
c
/* Infinite loop */
while (1)
{
time_counter += 10; // 更新时间计数器(每循环增加10ms)
// 生成方波:根据占空比判断状态
uint32_t phase = time_counter % SQUARE_PERIOD;
dac_output = (phase < high_duration) ? WAVE_HIGH : WAVE_LOW;
// 设置 DAC 输出
HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_1, DAC_ALIGN_8B_R, dac_output);
HAL_Delay(1); // 延时,让 DAC 稳定
// ADC 采样
HAL_ADC_Start(&hadc1); // 启动ADC单次转换
HAL_ADC_PollForConversion(&hadc1, 10); // 轮询等待ADC转换完成
adc_raw_value = HAL_ADC_GetValue(&hadc1); // 读取ADC转换结果
// 使用 DMA 向 VOFA+ 发送数据
adc_voltage = adc_raw_value * 3.3f / 4095.0f; // 计算ADC测量电压(0-3.3V)
memcpy(&serialData[0], &adc_voltage, 4); // 更新数据的前4字节(ADC电压)
HAL_UART_Transmit_DMA(&hlpuart1, serialData, 8); // DMA发送数据(8字节)
// LED指示:高电平时亮,低电平时灭
if (dac_output == 128)
HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET);
else
HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);
// 延时控制采样速度(总循环周期约10ms)
HAL_Delay(9); // 前面已延时1ms
}

-
启用 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" 确认设置。

-
程序编辑、编译与调试
- 硬件连接
- 用杜邦线将 PA0 与 PA4 相连 ,建立 DAC 输出与 ADC 输入之间的闭环连接。
用杜邦线直接连接,建立硬件闭环 - 用 USB连接线,连接 PC 与 NUCLEO-G431RB 开发板。
- 用杜邦线将 PA0 与 PA4 相连 ,建立 DAC 输出与 ADC 输入之间的闭环连接。
- 软件调试
- 点击工具栏中 "Build Debug" 按键对程序代码进行编译。
- 点击工具栏中 "Debug" 按键,将程序下载烧录到目标板 NUCLEO-G431RB 。
- 点击工具栏中 "Resume" 按键 或 F8 快捷键,运行程序。
- 打开 VOFA+ 软件:
(1)点击 "数据引擎" 下拉菜单,选择 "JustFloat" 协议。
(2)点击 "数据接口" 下拉菜单,选择 "串口"。
(3)点击 "端口号" 下拉菜单,选中 STM STLink Virtual COM Port。
(4)将配置参数设为与 STM32CubeMX 中 "Connectivity -- LPUART1" 的配置一致:
波特率:115200
数据位:8 Bits
校验位:None
数据流控:None
停止位:1
- 点击 VOFA+ 左上角的 "连接" 按钮,在数据显示区就将显示 HEX 格式的数据,并在上方图形区域显示 ADC 采样的波形。

6. 输出正弦波 ADC + DAC 波形
我们进一步尝试让 STM32 通过 DAC 生成 正弦波波形,并用 ADC 采集输出波形,使用 VOFA+ 同时显示 ADC波形和DAC波形。
STM32CubeMX 的配置不变,可以另存为 STM32G431_ADC02.ioc。生成代码并在 STM32CubeIDE中打开 main.c 程序。
- 修改 main.c 如下:
(1)在程序开头的用户代码引用区包含需要的头文件。
c
/* USER CODE BEGIN Includes */
#include "string.h"
#include "stdio.h"
#include "stdlib.h"
#include "math.h"
(2)在 main.c 顶部的 "用户变量区" 添加用户变量。
c
/* USER CODE BEGIN PV */
// 正弦波参数
#define PI_F 3.1415926f
#define SINE_PERIOD_MS 1000 // 正弦波周期 2000ms
#define SINE_FREQ_HZ 0.5f // 正弦波频率 0.5Hz
#define SINE_AMPLITUDE_V 1.65f // 正弦波幅值 1.65V(峰峰值3.3V)
#define SINE_OFFSET_V 1.65f // 偏移量 = 幅值(确保最小值=0V)
// 范围:0V ~ 3.3V(峰峰值3.3V)
#define SAMPLE_INTERVAL 10 // 采样间隔 10ms
// 控制变量
uint32_t time_counter = 0; // 时间计数器(ms)
uint8_t dac_output = 0; // DAC输出值(0-255)
float dac_set_voltage = 0.0f; // DAC设定电压(V)
float adc_measure_voltage = 0.0f; // ADC测量电压(V)
uint16_t adc_raw_value = 0; // ADC原始值(0-4095)
float phase_angle = 0.0f; // 正弦波相位角(弧度)
// 串口发送缓冲区:2个float数据 + 帧尾 = 3个float = 12字节
typedef union {
float f;
uint8_t b[4];
} FloatBytes;
FloatBytes serialData[3]; // [0]=DAC电压, [1]=ADC电压, [2]=帧尾
(3)初始化
c
/* MCU Configuration--------------------------------------------------------*/
HAL_Init(); // Reset of all peripherals
SystemClock_Config(); // Configure the system clock
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_LPUART1_UART_Init();
MX_ADC1_Init();
MX_DAC1_Init();
/* USER CODE BEGIN 2 */
HAL_DAC_Start(&hdac1, DAC_CHANNEL_1); // 启动DAC
// 初始化串口数据帧尾 (0x00 0x00 0x80 0x7F = NaN,小端序)
memcpy(serialData[2].b, (uint8_t[]){0x00, 0x00, 0x80, 0x7F}, 4);```
(4)轮询程序 while(1) 的代码如下,生成正弦波,并使用 LPUART1 重定向串口输出数据。
```c
/* Infinite loop */
while (1)
{
// 1. 更新相位
phase_angle += 2.0f * PI_F * SINE_FREQ_HZ * (SAMPLE_INTERVAL / 1000.0f);
if (phase_angle > 2.0f * PI_F) {
phase_angle -= 2.0f * PI_F;
HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin); // 过零点翻转LED
}
// 2. 计算正弦波电压:(1 + sin(θ)) × 幅值 / 2 + 偏移量
// 确保:最小值=0V,最大值=3.3V,中心值=1.65V
dac_set_voltage = SINE_OFFSET_V * (1.0f + sinf(phase_angle)) / 2.0f;
if (dac_set_voltage < 0.0f) dac_set_voltage = 0.0f;
if (dac_set_voltage > 3.3f) dac_set_voltage = 3.3f;
// 3. 转换为DAC值DAC输出值 (8位,0-255对应0-3.3V)
dac_output = (uint8_t)(dac_set_voltage * 255.0f / 3.3f);
// 4. 设置DAC输出
HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_1, DAC_ALIGN_8B_R, dac_output);
HAL_Delay(1); // 短暂延时让DAC稳定
// 5. ADC采样
HAL_ADC_Start(&hadc1); // 启动ADC转换
HAL_ADC_PollForConversion(&hadc1, 10); // 等待转换完成
adc_raw_value = HAL_ADC_GetValue(&hadc1); // 读取ADC值
// 6. 计算ADC测量电压
adc_measure_voltage = adc_raw_value * 3.3f / 4095.0f;
// 7. 准备VOFA+数据 (2个通道:DAC设定电压和ADC测量电压)
serialData[0].f = dac_set_voltage; // 通道1:DAC设定波形
serialData[1].f = adc_measure_voltage; // 通道2:ADC测量波形
// serialData[2] 已包含帧尾
// 8. 通过DMA发送数据到VOFA+ (3个float = 12字节)
HAL_UART_Transmit_DMA(&hlpuart1, (uint8_t *)serialData, 12);
// 9. 控制采样率 (总循环约10ms)
HAL_Delay(SAMPLE_INTERVAL - 1); // 前面已延时1ms
}
-
启用 printf 的浮点输出--非常重要!
-
程序编辑、编译与调试
- 硬件连接
- 用杜邦线将 PA0 与 PA4 相连 ,建立 DAC 输出与 ADC 输入之间的闭环连接。
用杜邦线直接连接,建立硬件闭环 - 用 USB连接线,连接 PC 与 NUCLEO-G431RB 开发板。
- 用杜邦线将 PA0 与 PA4 相连 ,建立 DAC 输出与 ADC 输入之间的闭环连接。
- 软件调试
- 点击工具栏中 "Build Debug" 按键对程序代码进行编译。
- 点击工具栏中 "Debug" 按键,将程序下载烧录到目标板 NUCLEO-G431RB 。
- 点击工具栏中 "Resume" 按键 或 F8 快捷键,运行程序。
- 打开 VOFA+ 软件:
(1)点击 "数据引擎" 下拉菜单,选择 "JustFloat" 协议。
(2)点击 "数据接口" 下拉菜单,选择 "串口"。
(3)点击 "端口号" 下拉菜单,选中 STM STLink Virtual COM Port。
(4)将配置参数设为与 STM32CubeMX 中 "Connectivity -- LPUART1" 的配置一致:
波特率:115200
数据位:8 Bits
校验位:None
数据流控:None
停止位:1
- 点击 VOFA+ 左上角的 "连接" 按钮,在数据显示区就将显示 HEX 格式的数据,并在上方图形区域显示波形。
鼠标移到上方波形区域,点击鼠标右键唤出设置菜单。
(1)点击 "X轴",选择"使用时间轴";
(2)点击 "Y轴",选择"All" 绘制所有曲线的波形;
于是在VOFA+中,我们可以同时观察到:
(1) 绿色曲线(DAC):完美的数字正弦波
(2)红色曲线(ADC):实际采集的模拟信号

本项目基于STM32G431RB开发板,构建了一个完整的模拟信号闭环系统。通过片上12位DAC生成正弦波信号,再由12位ADC实时采集,最终通过VOFA+数据可视化工具实时显示DAC设定波形与ADC实测波形的对比。这个实验完美展示了嵌入式系统中模拟信号处理的全流程。
版权声明:
【动手学电机驱动】是 youcans@qq 原创作品,转载必须标注原文链接:(https://blog.csdn.net/youcans/article/details/155774119)
Copyright@youcans 2025
Crated:2025-12