【动手学STM32G4】(13)STM32G431之 TIM+ADC

【动手学STM32G4】(1)STM32G431之导入和创建项目
【动手学STM32G4】(2)STM32G431之外部中断
【动手学STM32G4】(13)STM32G431之 TIM+ADC

【动手学STM32G4】(13)STM32G431之 TIM+ADC

    • [1. 项目简介](#1. 项目简介)
      • [1.1 定时触发采样的重要性](#1.1 定时触发采样的重要性)
      • [1.2 定时器触发ADC的原理](#1.2 定时器触发ADC的原理)
    • [2. CubeMX工程配置](#2. CubeMX工程配置)
      • [2.1 CubeMX 工程配置](#2.1 CubeMX 工程配置)
      • [2.2 ADC 配置](#2.2 ADC 配置)
      • [2.3 TIM 配置](#2.3 TIM 配置)
      • [2.4 工程配置](#2.4 工程配置)
    • [3. CubeIDE 编程与调试](#3. CubeIDE 编程与调试)
      • [2.1 CubeIDE编程](#2.1 CubeIDE编程)
      • [2.2 编译与调试](#2.2 编译与调试)
    • [4. 小结](#4. 小结)

1. 项目简介

在前文【动手学STM32G4】(5)STM32G431之ADC采样 中,我们介绍了STM32G4的ADC采样系统构建,实现了电位器电压的采集。

本文介绍使用定时器触发 ADC 转换,并使用 DMA 进行数据传输。通过设置定时器的触发间隔,就能实现 ADC 定时采样转换功能。

1.1 定时触发采样的重要性

在嵌入式数据采集系统中,时序精度往往决定了整个系统的性能上限。软件触发 ADC 采样方式存在诸多局限:CPU需要频繁响应中断,采样间隔受限于中断延迟,多任务环境下难以保证时间一致性。

定时触发采样通过硬件机制确保了数据采集的时间精度,实现了纳秒级的时间一致性,这对于需要严格时序控制的电机控制、音频处理等应用至关重要;同时,它将CPU从频繁的中断处理中解放出来,配合DMA大幅提升了系统效率;更重要的是,定时器能够精确协调ADC、PWM、DAC等多个外设的协同工作,为复杂嵌入式系统提供了硬件级的同步保障;在抗干扰方面,硬件触发独立于CPU执行,有效避免了软件调度带来的时序抖动,增强了系统的稳定性。

1.2 定时器触发ADC的原理

STM32G431的TIM1作为高级定时器,具备独立的时钟源和可配置的触发输出功能,能够产生精确的时间基准。当TIM1配置为触发ADC时,其工作原理如下:

定时器在计数达到预设定值后产生更新事件(UEV),这个硬件事件通过TIM1的TRGO(Trigger Output)输出,直接连接到ADC的外部触发输入。ADC检测到这个触发信号后,立即启动转换过程,无需CPU干预。这种硬件级联动确保了采样时刻的精确性和可重复性,将时间抖动控制在纳秒级别。

关键时序关系可表示为:

bash 复制代码
定时器配置:
  时钟源 → PSC分频 → 计数器 → ARR重载 → 更新事件
                        ↓
                触发中断 & 触发ADC检测
                        ↓
                  ADC启动转换 → 开始转换

触发延迟主要包括ADC的采样时间和转换时间,这些参数在CubeMX中可配置,为系统设计提供了灵活性和可预测性。

2. CubeMX工程配置

2.1 CubeMX 工程配置

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

  2. 配置系统时钟树。
    (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. 系统配置:在引脚配置(Pinout & Configuration)中,选择 "System Core -- SYS" 。

    (1)设置调试器类型,将 Debug 模式设为 "Serial Wire"。

    (2)设置基础时钟源(Timebase Source),可以选择默认设置 "SysTick"。

    (3)时钟配置:在引脚配置(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.2 ADC 配置

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

  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 引脚颜色变为绿色,表示已配置为模拟输入模式。
    (4)在 NVIC 设置中为 ADC1 启用中断,以便在回调函数中 ADC 转换结束时可以切换 GPIO。

(5)配置 ADC 工作模式和参数,注意触发源配置为 Timer 1 定时器触发。

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: Timer 1 Trigger Out event
   External Trigger Conversion Edge: Trigger detection on the rising edge
Rank 1: 
   Channel: Channel 8
   Smapling Time: 24.5 Cycles
   Offset Number: No offset   
youcans@qq.com

2.3 TIM 配置

配置定时器 TIM1 中断频率为 1kHz。

计算预分频器(PSC)

TIM1 挂载在APB1总线,时钟频率 = 160MHz。

所需中断频率 = 10kHz。考虑ARR通常设为较小值以获得高分辨率,选择 PSC = 159,分频后频率 = 160MHz / (159+1) = 160MHz / 160 = 1000kHz。

计算自动重载值(ARR):

中断频率 = 分频后频率 / (ARR+1)

ARR = (分频后频率 / 中断频率) - 1 = (1000kHz / 1kHz) - 1 = 1000 - 1 = 999

参数 设置值 说明
Clock Source Internal Clock 使用内部时钟源
Prescaler (PSC) 159 预分频值
Counter Mode Up 向上计数模式
Counter Period (ARR) 999 自动重载值
auto-reload preload Disabled 禁用自动重载预装载
Trigger Event Selection Update Event 选择更新事件作为触发输出
  1. 启用并配置TIM1 :
    (1)选择 "引脚配置(Pinout & Configuration)",从左侧下拉列表中选择 "Timers -- TIM1 -- TIM1 Mode and Configuration " ,将通道1 配置为生成但不输出 PWM: "PWM Generation No Output",用于定时器内部触发 ADC。

2.4 工程配置

  1. 工程管理配置。
    (1)点击 "Project Manager"→ "Project",输入项目名称 "STM32G431_ADC02"。。
    (2)点击 "Project Manager"→ "Code Generator",设置如下。
bash 复制代码
Project:
  - Project Name: STM32G431_ADC02
  - 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_ADC02.ioc" 生成初始代码。
    (2)生成初始代码完成后,弹出代码生成提示窗口,点击 "Open Project" 直接进入 STM32CubeIDE 并打开代码。

3. CubeIDE 编程与调试

2.1 CubeIDE编程

  1. 在 STM32CubeIDE 打开代码文件 main.c。

    代码生成后,已经自动进入 STM32CubeIDE,并打开创建的 STM32G431_DAC01 项目。在 "Core\Src" 目录中,已经生成了 dac.c 和 main.c 等基础程序。

  2. 程序 main.c 的架构如下:

c 复制代码
main.c
├── 系统初始化
│   ├── 系统时钟配置(160MHz)
│   ├── GPIO初始化
│   ├── TIM1初始化
│   └── ADC1初始化
├── 主程序
│   ├── ADC校准
│   ├── 启动ADC中断模式
│   ├── 启动TIM1 PWM输出
│   ├── 配置TIM1 主从模式
│   └── 主循环
│       └── 串口输出 ADC 数据(可选)
└── 中断服务
    └── HAL_ADC_ConvCpltCallback()
        ├── 读取ADC转换值
        ├── 更新转换计数器
        └── 每10次转换切换LED(可选)
youcans@qq.com        
  1. 生成代码并添加变量:
c 复制代码
/* USER CODE BEGIN PV */
// 用户变量
volatile uint16_t adc_raw = 0;          // ADC 转换原值
volatile uint16_t adc_count = 0;        // ADC 转换计数/
* USER CODE END PV */
  1. 主函数初始化后添加代码:
c 复制代码
  /* USER CODE BEGIN 2 */
  // 校准ADC(youcans@qq.com)
  if(HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED) != HAL_OK)
                Error_Handler();
  // 使能 ADC 中断
  if(HAL_ADC_Start_IT(&hadc1) != HAL_OK)
                Error_Handler();

  // 启动 TIM1 CH1 的 PWM 输出(用于触发ADC)
  if(HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1) != HAL_OK)
                Error_Handler();
  1. 添加ADC转换完成回调函数:
c 复制代码
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
	if (hadc->Instance == ADC1)
	{
		// 获取ADC转换值(youcans@qq.com)
    	adc_raw = HAL_ADC_GetValue(&hadc1);
    	adc_count++;
    // 每10次转换切换一次LED(便于观察)
    if (adc_count == 10)
    {
        HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
        adc_count = 0;
    }
  }
}
  1. 添加串口调试功能:
c 复制代码
  /* Infinite loop youcans@qq.com*/
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  // Update the transmission
  	  float Vch1 = adc_raw * 3.3f / 4095.0f;
  	  float Vch2 = 0;  // low level
  	  float Vch3 = 3.3;  // high level

  	  // 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(1);  // 1ms
  }

2.2 编译与调试

  1. 程序编辑、编译与调试:

    点击工具栏中 "Build Debug" 按键对程序代码进行编译。

    点击工具栏中 "Debug" 按键,将程序下载烧录到目标板 NUCLEO-G431RB 。

    点击工具栏中 "Resume" 按键 或 F8 快捷键,运行程序。

  2. 频率验证:用示波器测量PA5(LD2)引脚,看到 50Hz方波,如下图所示。

    TIM1 中断频率为 1kHz,LED 每10次转换(10ms)切换一次,因此 LED 的闪烁周期为 50Hz。这说明 采样频率精确控制为1kHz。

  1. 采样结果验证:
    板载电位器连接到PA0(ADC1_IN8),提供0-3.3V模拟电压。旋转板载电位器,通过串口查看 ADC 值变化,如下图所示。
    AD 转换的最小值为 0 ,最大值为 3.3,输出波形随电位器而变化,说明 AD 采样正常。

4. 小结

本实验成功实现了基于STM32G431的定时器触发ADC周期性采样系统。通过配置TIM2定时器产生精确的10kHz触发信号,驱动ADC1对板载电位器电压进行周期性采样,并在每次转换完成后通过中断回调函数处理数据,同时利用LED的50Hz方波输出直观验证系统运行状态。

本实验不仅实现了基本的ADC采样功能,更重要的是构建了一个可扩展、可验证、高可靠性的数据采集框架。通过严格的时序控制和中断管理,为后续更复杂的嵌入式应用开发奠定了坚实基础。

版权声明:

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

Copyright@youcans 2026

Crated:2026-1

相关推荐
兔子,你孩子掉了3 小时前
【gd32vf103 折腾】基于gcc+make的开发环境配置
单片机·硬件工程
小灰灰搞电子3 小时前
STM32、GD32 ppm协议解析源码分享
stm32·ppm协议
项目題供诗5 小时前
51单片机入门(二)
单片机·嵌入式硬件·51单片机
恶魔泡泡糖5 小时前
51单片机步进电机
单片机·嵌入式硬件·51单片机
tobias.b6 小时前
408真题解析-2010-12-计组-程序执行时间
单片机·嵌入式硬件·fpga开发·计算机考研·408真题解析
List<String> error_P6 小时前
独立看门狗IWDG原理详解
stm32·单片机·嵌入式硬件·定时器
王然-HUDDM6 小时前
技术领跑:HUDDM-7D系统L4级功能安全预研验证
人工智能·嵌入式硬件·安全·车载系统·汽车
shansz20206 小时前
CDC虚拟串口与硬件串口传输速度的对比测试
单片机·嵌入式硬件
一个云朵6 小时前
【江协科技】KEIL如何下载离线支持包
单片机·嵌入式硬件