【动手学STM32G4】(5)STM32G431之ADC采样

【动手学STM32G4】(1)STM32G431之创建项目
【动手学STM32G4】(2)STM32G431之外部中断
【动手学STM32G4】(3)STM32G431之定时器
【动手学STM32G4】(4)STM32G431之PWM输出
【动手学STM32G4】(5)STM32G431之ADC采样
【动手学STM32G4】(6)STM32G431之DAC输出
【动手学STM32G4】(7)STM32G431之UART 串口通信
【动手学STM32G4】(8)STM32G431之USB虚拟串口
【动手学STM32G4】(9)STM32G431之上位机波形显示

【动手学STM32G4】(5)STM32G431之ADC采样

    • [1. 项目简介](#1. 项目简介)
      • [1.1 实验目标](#1.1 实验目标)
      • [1.2 ADC 的原理和架构](#1.2 ADC 的原理和架构)
      • [1.3 软硬件准备](#1.3 软硬件准备)
    • [2. CubeMX 工程创建与配置](#2. CubeMX 工程创建与配置)
      • [2.1 新建工程](#2.1 新建工程)
      • [2.2 基础配置](#2.2 基础配置)
      • [2.3 ADC 配置](#2.3 ADC 配置)
      • [2.4 时钟与项目配置](#2.4 时钟与项目配置)
    • [3. STM32CubeIDE 编程和调试](#3. STM32CubeIDE 编程和调试)
      • [3.1 编程和调试](#3.1 编程和调试)
      • [3.2 上位机显示波形](#3.2 上位机显示波形)
    • [4. 小结](#4. 小结)

1. 项目简介

在嵌入式系统中,模拟信号的采集与输出是连接物理世界与数字处理系统的关键环节。ADC(模数转换器) 是连接物理世界与数字系统的入口。无论是电压、电流、温度,还是电位器、传感器信号,最终都需要通过 ADC 转换为可处理的数字量。

ADC 的核心作用是把外部模拟电压转换为 MCU 能处理的数字量,并保证采样精度与时间一致性。掌握 ADC 的采样时间、分辨率、触发模式和读取方式,是实现采集链路的基础。

1.1 实验目标

本次实验旨在掌握STM32G4系列微控制器的ADC(模数转换器)模块的实际应用。我们将以NUCLEO-STM32G431RB开发板为硬件平台,实现模拟电压信号的采集、转换与显示功能。

本文将介绍如何在 CubeMX 中配置 ADC 参数,如何正确进行数值映射与转换,并最终通过上位机观察输入电压的变化。具体目标包括:

  1. 硬件配置:正确配置STM32G431的ADC模块,特别是连接至PC2引脚的ADC1_IN3通道,用于采集板载蓝色电位器的电压信号。
  2. 软件实现:编写ADC初始化、采样控制、数据转换等核心代码,将ADC原始数字值转换为实际的电压值(0-3.3V范围)。
  3. 数据可视化:通过两种方式展示采集结果:一是使用示波器直接观察ADC输出波形,二是通过USART串口通信将电压数据发送到上位机软件进行实时显示。
  4. 性能评估:测试ADC的采样速率、分辨率和精度等关键性能指标,为后续的传感器数据采集、信号监测等应用奠定基础。

通过这个完整的ADC数据采集系统,我们将理解 STM32G431 中模拟信号处理的全过程。

1.2 ADC 的原理和架构

ADC(Analog-to-Digital Converter,模数转换器)用于将连续的模拟电压转换为离散的数字量,是 MCU 采集外部信号的核心外设。

STM32 ADC 基于逐次逼近寄存器(SAR) 架构,基本原理是通过内部数模转换器(DAC) 与比较器的逐次比较,逐步逼近输入模拟电压的数值,最终输出对应的数字编码。

STM32G431 集成多路 12 位高速 ADC模块,支持12位、10位、8位和6位可选分辨率,最高可达4Msps的采样率(在160MHz系统时钟下),最多支持19个外部通道和3个内部通道(温度传感器、内部参考电压等)。

工作原理:

  1. 采样保持
    ADC 通过采样开关对输入的模拟电压进行采样,采样完成后,采样开关断开,采样电容会保持该电压一段时间,供后续比较使用。采样时间可通过寄存器配置,以适配不同输入阻抗的信号源。
  2. 逐次比较
    (1)SAR 寄存器从最高位(MSB)开始,依次设置每一位的数值,并将其送入内部 DAC,DAC 输出对应的参考电压 VDAC。
    (2)比较器将采样保持的模拟电压 VIN 与 VDAC 进行比较:若 VIN≥VDAC,则保留当前位的 "1";若 VIN<VDAC,则将当前位清零。
    (3)从最高位到最低位(LSB)依次完成上述比较,最终 SAR 寄存器中的数值就是模拟电压对应的数字量。
  3. 结果输出
    比较完成后,数字结果会被存入 ADC 的数据寄存器(ADC_DR),同时触发相应的中断或 DMA 请求(若开启),供 MCU 读取。

工作模式:

  1. 单次转换模式(Single Conversion Mode)
    每次触发完成一次转换。ADC在收到触发信号后,仅执行一次完整的转换过程,完成后自动停止,等待下一次触发。工作流程如下。
bash 复制代码
触发信号 → 启动转换 → 完成一次转换 → 产生EOC中断 → 进入停止状态
  1. 连续转换模式(Continuous Conversion Mode)
    自动连续进行转换。ADC启动后连续不断地进行转换,前一次转换完成后立即开始下一次转换,形成连续的数据流。工作流程如下。
bash 复制代码
首次触发 → 转换1 → 转换2 → 转换3 → ... → 持续转换
      ↑           ↑           ↑
    EOC中断    EOC中断    EOC中断
  1. 扫描模式(Scan Mode)
    自动按顺序转换多个通道。ADC按照预设的顺序自动转换多个通道,每个通道可独立配置采样时间。工作流程如下。
bash 复制代码
触发 → 转换通道1 → 转换通道2 → ... → 转换通道N → 完成所有通道 → EOC中断
  1. 不连续转换模式(Discontinuous Conversion Mode)
    在扫描模式下,每次触发只转换指定数量的通道,而不是全部通道。工作流程如下。
bash 复制代码
触发1 → 转换通道1-3 → EOC中断
触发2 → 转换通道4-6 → EOC中断
...
  1. 注入转换模式(Injected Conversion Mode)
    可以打断规则通道转换的紧急通道。注入通道具有比规则通道更高的优先级,可以在规则序列转换过程中打断并执行注入转换,完成后恢复规则序列。

1.3 软硬件准备

硬件资源:

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

Nucleo-G431RB 开发板通过其USB端口(Micro-USB)连接到PC。

Nucleo-G431RB 开发板上没有板载旋钮,堆叠插接 X-NUCLEO-IHM16M1 电机驱动扩展板 后,PC2 引脚连接到 NUCLEO-IHM16M1 驱动板上的板载旋钮电位器。

软件资源:

STM32CubeMX, STM32CubeIDE,VOFA+ 串口调试工具

2. CubeMX 工程创建与配置

2.1 新建工程

  1. 启动 STM 32CubeMX并选择芯片
    (1)打开 STM32CubeMX。
    (2)选择 New Project(或Ctrl-N快捷键)新建工程,进入 New Project 界面。
    (3)选择 MCU 为 STM32G431RBT6(参考开发板的 MCU 型号选择)。
    (4)双击芯片图标或点击"Start Project",创建新工程。

2.2 基础配置

工程创建后,进入主配置界面。

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

    设置高速时钟为外部晶振,将 High Speed Clock (HSE) 设为 "Crystal/Ceramic Resonator"。

    Low Speed Clock (LSE) 设为 "Disable"(本实验不需要)。

  2. GPIO 配置。

    (1)将 LD2(PA5)配置为输出模式 "GPIO_Output"。

    (2)将用户按键(PC13)配置为外部中断 "GPIO_EXTI13"。

  3. 配置设置虚拟串口(LPUART)

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

    用于高频率发送数据到上位机或更新波形时,可以考虑为 LPUART1_TX 分配 DMA 通道。

2.3 ADC 配置

  1. 启用并配置 ADC 通道
    (1)选择 "引脚配置(Pinout & Configuration)",从左侧下拉列表中选择 "Analog -- ADC1" ,使用 IN8(PC2) 作为模拟输入通道,将 IN8 设置为 "IN8 Singel-ended"。
    (2)开启独立通道 IN8,设置为 "IN1 Single-ended"。
    (3)在 Pinout view 视图中,将 PC2 引脚配置为 "ADC1_IN8"。PC2 引脚颜色变为绿色,表示已配置为模拟输入模式。
  1. 配置 ADC 工作模式和参数。
bash 复制代码
ADCs_Common_Settings
   Mode: Independent mode
ADC_Settings
   Clock Prescaler: Asynchronous clock mode divided by 4
   Resolution: ADC 12-bit resolution
   Data Alignment: Right alignment(右对齐)
   Gain Compensation: 0
   Scan Conversion Mode:Disable
   End of Conversion Selection:End of single of conversion
   Continuous Conversion Mode: Disable
   DMA Continuous Requests: Disabled
ADC_Regular_ConversionMode:
   Number of Conversion: 1
   External Trigger Conversion Source: Regular Conversion launched by software
Rank 1: 
   Channel: Channel 8
   Smapling Time: 24.5 Cycles
   Offset Number: No offset   
youcans@qq.com

添加 DMA 通道:

  • 在 ADC1 的 DMA Settings 中添加一个 DMA 通道。
bash 复制代码
Add DMA Request:ADC1
Mode:Circular
Data Width:Half Word(16-bit)

2.4 时钟与项目配置

  1. 配置系统时钟树。
    (1)点击顶部 "Clock Configuration" 选项卡,进入时钟树配置。
    (2)设置输入频率 Input frequency=24 MHz,SysCLK frequency=160 MHz。
    配置完成后,System Clock 显示为160MHz,HCLK、PCLK1、PCLK2 均为160MHz。
bash 复制代码
Input frequency: 24 MHz (HSE)
SysCLK frequency: 160 MHz (HSE)
System Clock Mux: PLLCLK
AHB Prescaler: 1 (不分频)
APB1 Prescaler: 1
APB2 Prescaler: 1
  1. 工程管理配置。
    (1)点击 "Project Manager"→ "Project",输入项目名称 "STM32G431_ADC01"。。
    (2)点击 "Project Manager"→ "Code Generator",设置如下。
bash 复制代码
Project:
  - Project Name: STM32G431_ADC01
  - Toolchain/IDE: STM32CubeIDE

Code Generator:
  √ Generate peripheral initialization as a pair of '.c/.h'
  √ Keep User Code when re-generating
  √ Backup previously generated files
youcans@qq.com
  1. 生成代码。
    (1)点击右上角"GENERATE CODE"按钮,将自动由工程文件 "STM32G431_ADC01.ioc" 生成初始代码。
    (2)生成初始代码完成后,弹出代码生成提示窗口,点击 "Open Project" 直接进入 STM32CubeIDE 并打开代码。

3. STM32CubeIDE 编程和调试

3.1 编程和调试

  1. 在 STM32CubeIDE 打开 "STM32G431_ADC01" 项目。

    代码生成后,打开STM32G431_ADC01 项目。在 "Core\Src" 目录中,已经生成了 adc.c, main.c 等基础程序。

  2. 从 "Core\Src" 目录打开程序文件 adc.c,检查 CubeMX 生成的 ADC 配置。

c 复制代码
/* 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_DISABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc1.Init.LowPowerAutoWait = DISABLE;
  hadc1.Init.ContinuousConvMode = DISABLE;
  hadc1.Init.NbrOfConversion = 1;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.DMAContinuousRequests = DISABLE;
  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;
  if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
  {
    Error_Handler();
  }

  /* Configure Regular Channel */
  sConfig.Channel = ADC_CHANNEL_8;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_24CYCLES_5;
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
}
  1. 修改 main.c 代码。
    (1)从 "Core\Src" 目录打开程序文件 main.c,如下图所示。

(2)在 main.c 程序开头的用户代码引用区包含需要的头文件。

c 复制代码
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "dma.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "string.h"
#include "stdio.h"
#include "stdlib.h"

(3)变量定义。为兼容与上位机进行多通道数据传输,按 3 通道定义串口发送的数据结构。

c 复制代码
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
// 用户变量 youcans@qq.com
uint16_t adc_raw = 0;          // ADC原始值
//float Vknob = 0.0f;           // ADC测量电压

// 串口发送缓冲区
// DMA Transmission Buffer: 3 Channels of float = 12 Bytes
typedef union {
    float f;
    uint8_t b[4];
} FloatBytes;
// One frame of data: 3 channels of float + 4-byte frame tail = 4*4 = 16 bytes
FloatBytes frame[4];          // frame[0]~[2] = 3 waveform channels; frame[3] = frame tail
volatile uint8_t txReady = 1; // 1 = New DMA transmission can be initiated; 0 = Transmission in progress
/* USER CODE END PV */

(4)轮询程序 while(1) 代码如下。

c 复制代码
/* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
      // ADC 采样
      HAL_ADC_Start(&hadc1);  // 启动ADC单次转换
      HAL_ADC_PollForConversion(&hadc1, 10);  // 轮询等待ADC转换完成
      adc_raw = HAL_ADC_GetValue(&hadc1);  // 读取ADC转换结果
//      Vknob = adc_raw * 3.3f / 4095.0f;  // 计算ADC测量电压(0-3.3V)

	  // Update the transmission
	  float Vch1 = adc_raw * 3.3f / 4095.0f;
	  float Vch2 = 0.0f;
	  float Vch3 = 3.3f;

	  // New DMA transmission can only be initiated after the previous one is completed
	  if (txReady)
	  {
		  txReady = 0;
		  frame[0].f = Vch1;      // VOFA+CH1
		  frame[1].f = Vch2;      // VOFA+CH2
		  frame[2].f = Vch3;      // VOFA+CH3
		  // The frame tail at frame[3] is a fixed value
		  // A total of 4 floats (3 channels of data + 1 frame tail), 16 bytes in total.
		  HAL_UART_Transmit_DMA(&hlpuart1, (uint8_t *)frame, 4 * sizeof(float));
	  }

	  HAL_Delay(10);  // 1ms
	  HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin); // LD2_Pin
  }
  1. 程序编辑、编译与调试
    (1)硬件连接
    用 USB连接线,连接 PC 与 NUCLEO-G431RB 开发板。
    (2)软件调试
    • 点击工具栏中 "Build Debug" 按键对程序代码进行编译。
    • 点击工具栏中 "Debug" 按键,将程序下载烧录到目标板 NUCLEO-G431RB 。
    • 点击工具栏中 "Resume" 按键 或 F8 快捷键,运行程序。
bash 复制代码
09:41:52 **** Incremental Build of configuration Debug for project STM32G431_ADC01 ****
make -j20 all 
arm-none-eabi-size  STM32G431_ADC01.elf 
   text	   data	    bss	    dec	    hex	filename
  37004	    472	   2472	  39948	   9c0c	STM32G431_ADC01.elf
youcans Finished building: default.size.stdout
09:41:52 Build Finished. 0 errors, 0 warnings. (took 188ms)
  1. 打开 VOFA+ 软件:
    (1)点击 "数据引擎" 下拉菜单,选择 "JustFloat" 协议。
    (2)点击 "数据接口" 下拉菜单,选择 "串口"。
    (3)点击 "端口号" 下拉菜单,选中 STM STLink Virtual COM Port。
    (4)将配置参数设为与 STM32CubeMX 中 "Connectivity -- LPUART1" 的配置一致:
bash 复制代码
波特率:115200
数据位:8 Bits
校验位:None
数据流控:None
停止位:1

3.2 上位机显示波形

  1. 点击 VOFA+ 左上角的 "连接" 按钮,在数据显示区就将显示 HEX 格式的数据,并在上方图形区域显示 ADC 采样的波形。
    调节 IHM16M1 驱动板上的板载旋钮电位器,采样波形跟随变化如下图所示。

4. 小结

通过本章实验,我们成功完成了STM32G4的ADC采样系统构建。掌握了从CubeMX工程配置到代码实现的完整流程,实现了电位器电压的精确采集与串口数据传输。

版权声明:

【动手学电机驱动】是 youcans@qq 原创作品,转载必须标注原文链接:(https://blog.csdn.net/youcans/article/details/157101980)

Copyright@youcans 2026

Crated:2026-1

相关推荐
一丁_3 小时前
瞬态抑制二极管和稳压二极管在电路中的应用
单片机·嵌入式硬件
代码游侠3 小时前
嵌入式开发——ARM Cortex-A7内核和i.MX6处理器相关的底层头文件
arm开发·笔记·嵌入式硬件·学习·架构
VekiSon3 小时前
ARM架构——用汇编语言点亮 LED
汇编·arm开发·嵌入式硬件
炸膛坦客4 小时前
FreeRTOS 学习:(二十四)任务状态与信息查询 API 函数
stm32·操作系统·freertos
流浪_彩虹4 小时前
Bluejay电调固件电机参数分析
单片机
Y1rong5 小时前
STM32之GPIO
stm32·单片机·嵌入式硬件
宵时待雨5 小时前
STM32笔记归纳2:GPIO
笔记·stm32·嵌入式硬件
小码过河.5 小时前
设计模式——建造者模式
单片机·设计模式·建造者模式
9稳5 小时前
基于单片机的家庭安全系统设计
开发语言·网络·数据库·单片机·嵌入式硬件