第6章 基本定时器介绍及应用

第六章 基本定时器介绍及应用

1. 基本定时器简介(TIM6 和 TIM7)

TIM6 和 TIM7 是 STM32H750VBT6 中的基本定时器(Basic Timers),结构简单但功能关键。它们仅具备16 位向上计数自动重载能力,无输入捕获/输出比较通道,专为精确时基生成外设同步触发而设计。在系统中充当“心脏起搏器”,为 FreeRTOS 滴答时钟、DAC 波形生成、ADC 采样等场景提供高精度时间基准。

🔍 核心定位

  • TIM6:专属 DAC 触发(DAC1_TRIG
  • TIM7:专属 ADC 触发(ADC1_2
    两者均位于 APB1_D3 域(低功耗区域),最高时钟 100 MHz

1.1 基本定时器核心特性(STM32H750VBT6)

特性 参数 说明 典型应用场景
计数器 16-bit 向上计数 仅支持 0→ARR 递增 系统时基生成
时钟源 APB1_D3 (最高 100 MHz) 时钟频率 = APB1 × 2(当 APB1 预分频 ≠ 1) 精确延时控制
预分频器 16-bit (1–65536) T<sub>tick</sub> = (PSC+1)/f<sub>clk</sub> 微秒级分辨率
自动重载 16-bit (ARR) 溢出时重载计数器并触发更新事件 周期性中断
中断能力 仅更新中断(UEV) ARR 溢出时触发 FreeRTOS 滴答时钟
特殊功能 TIM6:DAC 触发
TIM7:ADC 触发
无 GPIO 引脚连接 DAC 波形生成、ADC 同步采样
DMA 请求 支持更新事件 DMA TIMx_DIER.UDE=1 零 CPU 开销的数据流

📌 STM32H750VBT6 专属优势

  • 超低延迟:更新事件延迟 < 5 个时钟周期(比通用定时器快 40%)
  • 低功耗优化:在 Stop 模式下仍可工作(需配置 CR1.OPM
  • 独立时钟域:APB1_D3 域支持独立关闭,不影响系统主时钟

1.2 工作原理详解

1.2.1 时钟与计数逻辑

  • 定时周期公式
    Tperiod = (ARR + 1) × (PSC + 1) / fclk`
    示例:fclk=100MHz, PSC=99, ARR=999 → Tperiod = 1000 × 100 / 100,000,000 = 1 ms

  • 关键限制

    • 计数器仅向上计数(无中央对齐/向下计数模式)
    • 无死区控制(与高级定时器的本质区别)
    • 溢出后自动重载(无需软件干预)

1.2.2 与外设协同机制

定时器 触发信号 外设功能 配置寄存器
TIM6 TRGO DAC1 启动转换 DAC_CR.TEN1=1 + TIM6_CR2.MMS=010
TIM7 TRGO ADC1/2 启动采样 ADC_CFGR.DMACFG=1 + TIM7_CR2.MMS=010

协同优势

  • 硬件级同步:消除软件触发延迟(精度达 ns 级
  • 零 CPU 开销:CPU 无需参与触发过程
  • 抗干扰:避免中断延迟导致的时序偏差

1.3 关键寄存器操作

1.3.1 核心寄存器与配置流程

寄存器 关键位域 功能 配置示例
CR1 CEN, UDIS, URS, OPM, DIR 计数使能、更新控制 TIM6->CR1 = TIM_CR1_CEN; // 启动计数
PSC PSC[15:0] 预分频值 (16-bit) TIM6->PSC = 99; // 100 分频
ARR ARR[15:0] 自动重载值 (16-bit) TIM6->ARR = 999; // 1ms 周期
DIER UDE, UIE DMA/中断使能 TIM6->DIER = TIM_DIER_UIE; // 使能更新中断
SR UIF 更新中断标志 if (TIM6->SR & TIM_SR_UIF) { ... }
EGR UG 软件更新事件 TIM6->EGR = TIM_EGR_UG; // 强制初始化

1.3.2 配置步骤(寄存器级)

// 1. 使能 TIM6 时钟 (RCC)
RCC->APB1LENR |= RCC_APB1LENR_TIM6EN;

// 2. 配置预分频器和重载值
TIM6->PSC = 99;      // 100 分频 → 1MHz 时钟
TIM6->ARR = 999;     // 1000 计数 → 1ms 周期
TIM6->EGR = 1;       // 生成更新事件 (初始化寄存器)

// 3. 使能更新中断
TIM6->DIER = TIM_DIER_UIE;

// 4. 启动定时器
TIM6->CR1 = TIM_CR1_CEN;

// 5. 配置 NVIC (在外部)
NVIC_EnableIRQ(TIM6_DAC_IRQn); 
NVIC_SetPriority(TIM6_DAC_IRQn, 0);

1.3.3 HAL 库简化操作

TIM_HandleTypeDef htim;
htim.Instance = TIM6;
htim.Init.Prescaler = 99;
htim.Init.CounterMode = TIM_COUNTERMODE_UP;
htim.Init.Period = 999;
htim.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&htim);
HAL_TIM_Base_Start_IT(&htim); // 启动中断

// TIM6 触发 DAC 示例
__HAL_TIM_ENABLE_DMA(&htim, TIM_DMA_UPDATE); // 使能 DMA
HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, buffer, size, DAC_ALIGN_12B_R);

2. 基本定时器使用示例-STM32IDE

2.1 STM32Cube配置

2.1.1 RCC配置

只在第一章中展示,因为后续内容一样

2.1.2 TIM6工作模式配置

屏幕截图 20250825 141935png

2.1.3 NVIC配置

屏幕截图 20250825 141940png

2.2 用户代码

2.2.1 TIM6初始化

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    tim.c
  * @brief   This file provides code for the configuration
  *          of the TIM instances.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "tim.h"

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

TIM_HandleTypeDef htim6;

/* TIM6 init function */
void MX_TIM6_Init(void)
{

  /* USER CODE BEGIN TIM6_Init 0 */

  /* USER CODE END TIM6_Init 0 */

  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM6_Init 1 */

  /* USER CODE END TIM6_Init 1 */
  htim6.Instance = TIM6;
  htim6.Init.Prescaler = 9999;
  htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim6.Init.Period = 11999;
  htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim6) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM6_Init 2 */
  HAL_TIM_Base_Start_IT(&htim6); // 启动定时器6及其中断
  /* USER CODE END TIM6_Init 2 */

}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{

  if(tim_baseHandle->Instance==TIM6)
  {
  /* USER CODE BEGIN TIM6_MspInit 0 */

  /* USER CODE END TIM6_MspInit 0 */
    /* TIM6 clock enable */
    __HAL_RCC_TIM6_CLK_ENABLE();

    /* TIM6 interrupt Init */
    HAL_NVIC_SetPriority(TIM6_DAC_IRQn, 1, 3);
    HAL_NVIC_EnableIRQ(TIM6_DAC_IRQn);
  /* USER CODE BEGIN TIM6_MspInit 1 */

  /* USER CODE END TIM6_MspInit 1 */
  }
}

void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
{

  if(tim_baseHandle->Instance==TIM6)
  {
  /* USER CODE BEGIN TIM6_MspDeInit 0 */

  /* USER CODE END TIM6_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_TIM6_CLK_DISABLE();

    /* TIM6 interrupt Deinit */
    HAL_NVIC_DisableIRQ(TIM6_DAC_IRQn);
  /* USER CODE BEGIN TIM6_MspDeInit 1 */

  /* USER CODE END TIM6_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

2.2.2 中断函数

/**
  * @brief This function handles TIM6 global interrupt, DAC1_CH1 and DAC1_CH2 underrun error interrupts.
  */
void TIM6_DAC_IRQHandler(void)
{
  /* USER CODE BEGIN TIM6_DAC_IRQn 0 */

  /* USER CODE END TIM6_DAC_IRQn 0 */
  HAL_TIM_IRQHandler(&htim6);
  /* USER CODE BEGIN TIM6_DAC_IRQn 1 */
  HAL_GPIO_TogglePin(LED_RED_Port, LED_RED_Pin);
  printf("TIM6 Interrupt Triggered!\n");
  /* USER CODE END TIM6_DAC_IRQn 1 */
}

2.2.3 主函数测试

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "tim.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "bsp_init.h"
#include "stdio.h" // For printf function
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MPU_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MPU Configuration--------------------------------------------------------*/
  MPU_Config();

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  /* USER CODE BEGIN 2 */
  bsp_init();
  MX_TIM6_Init(); // 溢出时间约500ms
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

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

  /** Supply configuration update enable
  */
  HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);

  /** Configure the main internal regulator output voltage
  */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0);

  while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.LSIState = RCC_LSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 2;
  RCC_OscInitStruct.PLL.PLLN = 240;
  RCC_OscInitStruct.PLL.PLLP = 2;
  RCC_OscInitStruct.PLL.PLLQ = 2;
  RCC_OscInitStruct.PLL.PLLR = 2;
  RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;
  RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
  RCC_OscInitStruct.PLL.PLLFRACN = 0;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
                              |RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
  RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;

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

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

 /* MPU Configuration */

void MPU_Config(void)
{
  MPU_Region_InitTypeDef MPU_InitStruct = {0};

  /* Disables the MPU */
  HAL_MPU_Disable();

  /** Initializes and configures the Region and the memory to be protected
  */
  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.Number = MPU_REGION_NUMBER0;
  MPU_InitStruct.BaseAddress = 0x0;
  MPU_InitStruct.Size = MPU_REGION_SIZE_4GB;
  MPU_InitStruct.SubRegionDisable = 0x87;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
  MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS;
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
  MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);
  /* Enables the MPU */
  HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);

}

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

3. 基本定时器相关函数(HAL库)

3.1 初始化与配置

  • HAL_TIM_Base_Init(TIM_HandleTypeDef *htim)
    初始化基本定时器(TIM6/TIM7),关键前提

    • 必须使能时钟(TIM6挂载APB1L, TIM7挂载APB1H)

    • 基础配置流程

      __HAL_RCC_TIM6_CLK_ENABLE();  // 使能时钟
      __HAL_RCC_DAC12_CLK_ENABLE(); // 若用于DAC同步需额外使能
      HAL_TIM_Base_Init(&htim6);    // 初始化
      HAL_TIM_Base_Start(&htim6);   // 启动定时器
      
  • TIM_Base_InitTypeDef 结构体成员说明

    成员 说明 有效范围 典型配置
    Prescaler 时钟预分频系数 0-65535 8399 (84MHz→10kHz)
    CounterMode 计数模式 TIM_COUNTERMODE_UP (唯一选项) 固定向上计数
    Period 自动重装载值 0-65535 999 (10ms定时)
    ClockDivision 时钟分频 TIM_CLOCKDIVISION_DIV1 基本定时器无分频
    AutoReloadPreload 自动重载预装载 TIM_AUTORELOAD_PRELOAD_ENABLE 推荐启用
  • 定时周期计算公式(核心!):

    定时周期(μs) = ((Prescaler + 1) × (Period + 1)) / (TIMx_CLK / 1000000)
    

    H750典型配置(TIM6 @ 84MHz):

    htim6.Instance = TIM6;
    htim6.Init.Prescaler = 8399;    // 84MHz/(8399+1)=10kHz
    htim6.Init.Period = 999;        // 10kHz/(999+1)=10Hz (100ms周期)
    htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
    HAL_TIM_Base_Init(&htim6);
    
  • 时钟源选择

    定时器 挂载总线 最大时钟 H750时钟树路径
    TIM6 APB1L 84MHz D2PPRE1 → APB1_DIV2 → TIMx_CLK
    TIM7 APB1H 84MHz D2PPRE1 → APB1_DIV2 → TIMx_CLK

    关键提示

    • 若APB1预分频≠1,HAL库自动将时钟×2(TIMx_CLK = APB1_CLK × 2
    • 实际时钟可通过HAL_RCC_GetPCLK1Freq()验证

3.2 定时器操作核心函数

  • 基础启停控制

    函数 原型 特点 应用场景
    HAL_TIM_Base_Start() (htim) 启动计数 通用定时
    HAL_TIM_Base_Stop() (htim) 停止计数 暂停定时
    HAL_TIM_Base_Start_IT() (htim) 启动+中断 周期性任务
    HAL_TIM_Base_Start_DMA() (htim, Channel, *pData, Length) 启动+DMA DAC同步触发
    HAL_TIM_Base_GetTick() void 系统滴答替代 无SysTick时
  • 计数器操作

    __HAL_TIM_SET_COUNTER(&htim6, 0);      // 设置当前计数值
    uint32_t cnt = __HAL_TIM_GET_COUNTER(&htim6); // 读取计数值
    __HAL_TIM_SET_AUTORELOAD(&htim6, 499); // 动态修改周期
    
  • DAC同步功能(TIM6特有):

    // 配置TIM6触发DAC
    htim6.Instance->CR2 |= TIM_CR2_MMS_1;  // TRGO = 更新事件
    HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, 
                      (uint32_t*)sin_table, TABLE_SIZE,
                      DAC_ALIGN_12B_R);
    

3.3 中断处理机制

  • 中断触发条件

    • 仅支持更新中断(计数器溢出/初始化)
    • 通过TIM_DIER_UIE位使能
  • 中断服务函数

    void TIM6_DAC_IRQHandler(void)  // TIM6与DAC共享中断
    {
        HAL_TIM_IRQHandler(&htim6); // 处理定时器中断
    }
    
    void TIM7_IRQHandler(void)
    {
        HAL_TIM_IRQHandler(&htim7); // 处理定时器中断
    }
    
  • 中断回调函数

    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
    {
        if(htim->Instance == TIM6) {
            // 100ms周期任务
            HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); 
        }
        else if(htim->Instance == TIM7) {
            // 10ms周期任务
            sensor_data_ready = 1;
        }
    }
    
  • 中断标志操作

    __HAL_TIM_GET_FLAG(&htim6, TIM_FLAG_UPDATE);   // 检查更新标志
    __HAL_TIM_CLEAR_FLAG(&htim6, TIM_FLAG_UPDATE); // 手动清除标志
    

3.4 高级功能与特性

  • DMA触发控制

    // 配置更新事件触发DMA
    __HAL_TIM_ENABLE_DMA(&htim6, TIM_DMA_UPDATE);
    
    // 启动DMA传输(用于DAC波形生成)
    HAL_TIM_Base_Start_DMA(&htim6, TIM_DMA_UPDATE, 
                          (uint32_t*)wave_buffer, BUFFER_SIZE);
    
  • 低功耗模式行为

    模式 TIM6/7状态 H750特殊处理
    RUN 正常计数
    SLEEP 继续计数
    STOP0 暂停计数 需配置DBGMCU_APB1LFZ1
    STOP1/STOP2 停止计数 无法用于唤醒
    STANDBY 关闭 复位后需重新配置
  • 多定时器同步

    // TIM7同步启动TIM6
    TIM7->SMCR |= TIM_SMCR_SMS_2;       // 从模式:触发模式
    TIM7->SMCR |= TIM_SMCR_TS_0;        // 触发源:ITR1 (TIM6)
    TIM7->CR2 |= TIM_CR2_MMS_2;         // 主模式:更新事件
    HAL_TIM_Base_Start(&htim7);         // 启动TIM7将同步启动TIM6
    
  • 精确延时实现

void TIM6_Delay_us(uint16_t us)
{
    __HAL_TIM_SET_COUNTER(&htim6, 0);
    __HAL_TIM_SET_AUTORELOAD(&htim6, us - 1);
    HAL_TIM_Base_Start(&htim6);
    while(!__HAL_TIM_GET_FLAG(&htim6, TIM_FLAG_UPDATE));
    HAL_TIM_Base_Stop(&htim6);
}

3.5 使用示例(完整流程)

3.5.1 示例1:100ms周期LED闪烁

TIM_HandleTypeDef htim6 = {0};

// 1. 使能时钟 (TIM6挂载APB1L)
__HAL_RCC_TIM6_CLK_ENABLE();

// 2. 配置定时器参数
htim6.Instance = TIM6;
htim6.Init.Prescaler = 8399;        // 84MHz/(8399+1)=10kHz
htim6.Init.Period = 999;            // 10kHz/1000=10Hz (100ms)
htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;

// 3. 初始化定时器
if (HAL_TIM_Base_Init(&htim6) != HAL_OK) {
    Error_Handler();
}

// 4. 启动定时中断
HAL_TIM_Base_Start_IT(&htim6);

// 5. 配置NVIC优先级
HAL_NVIC_SetPriority(TIM6_DAC_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(TIM6_DAC_IRQn);

// 6. 中断回调处理
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == TIM6) {
        HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); // 翻转LED
    }
}

3.5.2 示例2:TIM6驱动DAC输出正弦波

DAC_HandleTypeDef hdac = {0};
uint16_t sin_table[256] = { /* 正弦波数据 */ };

// 1. 使能TIM6和DAC时钟
__HAL_RCC_TIM6_CLK_ENABLE();
__HAL_RCC_DAC12_CLK_ENABLE();

// 2. 配置TIM6 (100kHz触发频率)
htim6.Instance = TIM6;
htim6.Init.Prescaler = 839;     // 84MHz/840=100kHz
htim6.Init.Period = 99;         // 100kHz/100=1kHz (波形频率)
HAL_TIM_Base_Init(&htim6);

// 3. 配置TIM6触发DAC
TIM6->CR2 |= TIM_CR2_MMS_1;     // TRGO = 更新事件

// 4. 配置DAC通道
hdac.Instance = DAC1;
hdac.Init.Reference = DAC_REF_3V3;
HAL_DAC_Init(&hdac);

// 5. 启动DAC DMA传输
HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1,
                 (uint32_t*)sin_table, 256,
                 DAC_ALIGN_12B_R);

// 6. 启动TIM6 (触发DAC)
HAL_TIM_Base_Start(&htim6);

4. 关键注意事项

  1. 时钟树陷阱
  • H750的APB1分频器可能使定时器时钟翻倍:

    // 实际时钟计算
    uint32_t apb1_clk = HAL_RCC_GetPCLK1Freq();
    uint32_t tim_clk = (RCC->D2PPRE1 & RCC_D2PPRE1_D2PPRE1) ? apb1_clk * 2 : apb1_clk;
    

    验证方法:在CubeMX中勾选"TIMxCLK = 2×APBx"选项

  1. 中断优先级设计
应用场景 推荐优先级 原因
系统滴答替代 0 (最高) 必须高于所有任务
100ms LED闪烁 3 避免阻塞关键中断
DAC同步触发 1 确保波形时序精确
  1. 自动重载预装载
  • TIM_AUTORELOAD_PRELOAD_ENABLE 时:

    • 修改ARR值不会立即生效
    • 需等待更新事件(UEV)后生效
  • 特殊场景

    __HAL_TIM_SET_AUTORELOAD(&htim6, new_period);
    __HAL_TIM_SET_COUNTER(&htim6, 0);      // 清零计数器
    __HAL_TIM_GENERATE_EVENT(&htim6, TIM_EVENTSOURCE_UPDATE); // 强制更新
    
  1. 低功耗模式影响
  • STOP0模式

    • 定时器计数暂停

    • 唤醒后需重置计数器:

      HAL_PWREx_EnableInternalWakeUpLine();
      HAL_SuspendTick();
      HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
      
      // 唤醒后恢复
      SystemClock_Config();
      __HAL_TIM_SET_COUNTER(&htim6, 0);  // 防止虚假中断
      HAL_ResumeTick();
      
  1. 与SysTick协同工作
// 在FreeRTOS中替代SysTick
void vPortSetupTimerInterrupt(void) {
    htim7.Instance = TIM7;
    htim7.Init.Prescaler = (uint32_t)(SystemCoreClock / 10000) - 1;
    htim7.Init.Period = 10 - 1;        // 1ms周期
    HAL_TIM_Base_Init(&htim7);
    HAL_TIM_Base_Start_IT(&htim7);
}

4.1 H750特有优化技巧

场景 解决方案 性能提升 实现要点
超高精度延时 TIM6直接控制 1μs级精度 Prescaler=83, Period=us-1 (84MHz→1MHz)
多路DAC同步 TIM6触发多个DAC 相位一致性 配置`TIM6->CR2
STOP模式滴答 STOP0 + LSE 低功耗持续计时 需切换时钟源至LSE (32.768kHz)
DMA无CPU干预 TIM6+DMA+DAC CPU负载↓90% HAL_DAC_Start_DMA() + TIM_DCR_DBL=15

避坑指南

  1. TIM6与DAC中断共享
  • TIM6_DAC_IRQHandler()必须同时处理TIM6和DAC中断

  • 检查标志位:

    if(__HAL_TIM_GET_FLAG(&htim6, TIM_FLAG_UPDATE)) {
        HAL_TIM_IRQHandler(&htim6);
    }
    if(__HAL_DAC_GET_FLAG(&hdac, DAC_FLAG_DMAUDR1)) {
        HAL_DAC_IRQHandler(&hdac);
    }
    
  1. 重载值计算陷阱
  • 周期 = (Prescaler+1) × (Period+1) / TIMx_CLK
  • 必须+1:0值表示1个时钟周期
  • 错误示例:Period=1000 → 实际1001周期
  1. H750时钟树特殊性
  • D2域APB1总线频率可能≠系统主频
  • 通过HAL_RCC_GetHCLKFreq()RCC->CFGR验证
  1. 调试模式冻结
__HAL_DBGMCU_FREEZE_TIM6();   // 调试时暂停TIM6
__HAL_DBGMCU_FREEZE_TIM7();   // 调试时暂停TIM7

4.2 基本定时器工作模式对比

┌───────────────┬───────────────┬───────────────┬───────────────────┐
│    功能        │   TIM6        │    TIM7       │     H750优势      │
├───────────────┼───────────────┼───────────────┼───────────────────┤
│ 时钟源         │ APB1L (84MHz) │ APB1H (84MHz) │ 时钟独立可分频      │
├───────────────┼───────────────┼───────────────┼───────────────────┤
│ DAC同步        │ 支持 (CH1/2)  │ 不支持         │ 双通道波形生成       │
├───────────────┼───────────────┼───────────────┼───────────────────┤
│ 中断优先级     │ 与DAC共享      │ 独立中断        │ TIM7更适合作系统    │
│               │               │               │ 滴答替代           │
├───────────────┼───────────────┼───────────────┼───────────────────┤
│ 低功耗支持     │ STOP0可冻结    │ STOP0可冻结    │ 需配置DBGMCU寄存器   │
└───────────────┴───────────────┴───────────────┴───────────────────┘

posted @ 2025-08-25 14:59  hazy1k  阅读(22)  评论(0)    收藏  举报