STM32TIM基础定时器深度解析:时基原理、核心寄存器、影子寄存器、基础定时器和中断与DMA联动、代码实战及面试考点全解

前言

在STM32嵌入式开发里,定时器是十分核心的外设,LED闪烁、按键消抖、电机控制、实时调度等场景都需要它。基础定时器(Basic Timer)是定时器家族里最简单的一员,也是学习通用、高级定时器的基础。

不少初学者只会调用HAL库做延时,看不懂时基单元、影子寄存器和时钟通路,学到PWM、输入捕获时容易混淆,本质就是基础定时器底层原理没有学透。

本文基于STM32F1,从基础定时器的作用出发,拆解时基单元、时钟链路、影子寄存器,讲解中断、DMA联动原理、配置和适用场景,附带可直接运行的HAL库代码与面试考点。读完可以掌握定时器底层逻辑,为后续学习打下根基。

一、什么是基础定时器?我们为什么需要它?

1.1 基础定时器的硬件定位

下图列出STM32F103系列不同型号内置定时器资源差异,区分高级、通用、基础定时器:

下图为STM32F1系统架构框图,体现定时器、总线矩阵、APB1/APB2总线之间的连接关系:

下图示意Cortex‑M3内核与基础定时器TIM6、TIM7在MCU内部的布局:

在STM32F103系列中,TIM6、TIM7 是两款标准的基础定时器。它们是定时器家族中结构最简、资源最少的型号:

  • 仅包含16位自动重装载计数器,仅支持向上计数一种模式

  • 没有外部IO引脚,不支持输入捕获、输出比较、PWM生成等功能

  • 核心能力:定时计数、产生更新事件、触发中断、触发DMA、触发DAC转换

简单说:基础定时器就是一个"纯硬件计数器",只专注于定时这件事,不做任何和IO相关的工作。

1.2 为什么不直接用SysTick?

很多人会有疑问:Cortex-M内核自带了SysTick滴答定时器,也能实现定时,为什么还要设计基础定时器?核心原因有三点:

  1. 硬件独立性

    SysTick属于内核外设,和CPU强绑定;而基础定时器是独立的片上外设,可完全脱离CPU工作。配合DMA可以实现"零CPU干预"的定时触发,CPU可以休眠或处理其他任务。

  2. 外设联动能力

    基础定时器的更新事件可以直接触发DAC转换、ADC采集、DMA传输,是模拟外设、数据传输的硬件时基,这是SysTick做不到的。

  3. 数量与扩展性

    一颗芯片上可以有多个基础定时器(F103有TIM6、TIM7两个),各自独立工作;而SysTick只有一个,通常被操作系统占用作为系统时基,用户无法随意使用。

1.3 典型应用场景

  • 简单的定时任务:按键扫描、LED闪烁、数据周期采集

  • DAC波形生成:定时触发DAC输出,生成正弦波、方波等模拟信号

  • DMA周期搬运:定时触发DMA,自动完成内存到外设、内存到内存的数据搬运

  • 操作系统辅助:作为独立的硬件时基,辅助任务调度

二、STM32定时器全分类与特点对比

STM32的定时器按功能从简到繁分为三类,基础定时器是整个体系的基石,所有定时器的时基单元原理完全一致。

表格

核心规律:所有定时器的时基单元原理完全相同。搞懂基础定时器的时基,后续学通用、高级定时器只需要额外学习通道功能即可。

三、基础定时器核心原理:时基单元全拆解

基础定时器的核心是时基单元(Time-Base Unit),它是定时器实现计数的硬件核心,由三个关键寄存器+时钟通路组成。

3.1 时基单元的组成

时基单元包含三个核心寄存器,全部为16位:

  1. 预分频寄存器(PSC)

    对输入的定时器时钟进行分频,输出计数器工作时钟CK_CNT。

    写入值范围:0 ~ 65535,实际分频系数 = 写入值 + 1。

    例如写入71,分频系数就是72,72MHz输入时钟会变成1MHz输出。

  2. 计数器寄存器(CNT)

    真正执行计数的寄存器,在CK_CNT时钟驱动下累加。

    基础定时器仅支持向上计数:从0开始,每个时钟加1,计数到目标值后溢出。

  3. 自动重装载寄存器(ARR)

    保存计数的上限值。当CNT的值等于ARR的值时,计数器溢出,产生更新事件(UEV),同时CNT自动清零,开启下一轮计数。

3.2 完整计数工作流程

  1. 总线时钟经过RCC分频后,输入到定时器的预分频器PSC

  2. PSC分频后得到计数器时钟CK_CNT,驱动CNT寄存器从0开始向上累加

  3. 当CNT计数值 == ARR值时,计数器溢出,硬件自动产生更新事件UEV

  4. UEV事件会做三件事:

  • 自动将CNT清零,重新开始计数

  • 将预装载寄存器的值加载到影子寄存器(下一节详解)

  • 可触发更新中断、DMA请求、DAC转换

  1. 重复上述过程,产生周期性的定时信号

3.3 定时时间计算公式

定时周期(秒)= (PSC + 1) × (ARR + 1) / 定时器时钟频率

  • 加1的原因:PSC和ARR都是从0开始计数,写入0代表不分频/计数1个周期

  • 定时器时钟频率:F1系列基础定时器挂载在APB1总线,默认72MHz

举例计算(72MHz时钟)

  • 1ms定时:PSC=71,ARR=999

    周期 = 72 × 1000 / 72000000 = 0.001s = 1ms

  • 1秒定时:PSC=7199,ARR=9999

    周期 = 7200 × 10000 / 72000000 = 1s

3.4 RCC时钟源与时基单元的关系

下图是STM32F103的时钟树框图,图中标注了APB预分频与定时器时钟的倍频逻辑:

下图示意在STM32F103中,由RCC时钟树输出TIMxCLK,驱动基础定时器工作:

这是初学者最容易搞错的知识点:基础定时器的时钟不是直接等于APB1总线时钟。

STM32F1的时钟规则:

  • 如果APB1预分频系数 = 1,定时器时钟 = APB1总线时钟

  • 如果APB1预分频系数 > 1,定时器时钟 = APB1总线时钟 × 2

F1系列默认配置:APB1总线最大36MHz,预分频系数为2,系统主频72MHz。

因此:基础定时器的输入时钟 = 36MHz × 2 = 72MHz

关键结论:不要直接拿APB1总线频率算定时周期,一定要记得定时器有2倍频机制。使用前必须在RCC中开启对应定时器的时钟,否则定时器不会工作。

四、重点难点:影子寄存器(Shadow Register)深度解析

影子寄存器是STM32定时器最经典的设计,也是面试必考知识点,很多人学了很久定时器都没真正搞懂。

4.1 什么是影子寄存器?

以ARR寄存器为例,它在硬件上并不是一个寄存器,而是成对存在:

  • 预装载寄存器(Preload Register):我们通过代码读写的就是它。你写的数值会先存在这里,不会直接影响计数器。

  • 影子寄存器(Shadow Register):真正和CNT做比较的寄存器,它的值才决定计数周期。

简单概括:预装载寄存器是"缓存",影子寄存器是"运行内存"。我们改的是缓存,不会立刻生效,只有特定时机才会同步到运行内存。

4.2 为什么要设计影子寄存器?

核心目的:保证每一个计数周期的完整性,避免中途改参数导致时序混乱。

举个场景:当前ARR=999,周期1ms。当CNT计数到500的时候,你在代码里把ARR改成1999。

  • 如果没有影子寄存器:计数器立刻以新的ARR=1999为上限,当前这个周期会从500数到1999,周期变长,时序被打乱。

  • 如果有影子寄存器:当前周期依然以999为上限,数到999正常溢出;等下一个周期开始时,才会加载新值1999。每个周期都是完整的,时序完全稳定。

对于工业控制、电机驱动等对时序精度要求高的场景,影子寄存器是保障时序稳定的关键设计。

4.3 ARPE位:影子寄存器的开关

下图是TIMx_CR1寄存器,ARPE位控制ARR预装载缓冲:

通过TIMx_CR1寄存器的ARPE位(自动重装载预装载使能) 可以控制影子寄存器是否生效:

  • ARPE = 0 :关闭预装载功能。修改ARR的值后,立即直接写入影子寄存器,立刻生效,无缓冲。

  • ARPE = 1 :开启预装载功能。修改ARR的值仅写入预装载寄存器,等待下一次更新事件UEV发生时,才加载到影子寄存器,下一个周期生效。

4.4 拓展:PSC也有影子寄存器

很多教程只讲ARR有影子寄存器,实际上预分频器PSC同样有影子寄存器,原理完全一致。

修改PSC的值不会立刻改变分频系数,会等到下一次更新事件时才生效,保证当前计数周期的时钟稳定。

4.5 软件触发更新事件(UG位)

下图是TIMx_EGR寄存器,UG位用于软件手动触发更新事件:

TIMx_EGR寄存器的UG位可以软件强制产生一次更新事件。

它的作用就是:初始化定时器后,手动触发一次UEV,把PSC和ARR的预装载值立刻加载到影子寄存器里,让第一个周期就按设定值运行。

HAL库的初始化函数内部默认会置位UG位,完成影子寄存器的初始化。

五、深度详解:基础定时器和中断与DMA联动

基础定时器的核心价值,在于通过更新事件UEV联动中断和DMA,实现定时任务的硬件自动化。这也是基础定时器区别于SysTick的核心优势。

5.1 更新中断(Update Interrupt)机制全解

5.1.1 中断的产生与标志位

下图为TIMx_DIER寄存器,用来开启定时器更新中断与DMA请求:

下图是TIMx_SR寄存器,UIF标记更新事件标志:

当计数器溢出产生更新事件UEV时,如果TIMx_DIER寄存器的UIE位(更新中断使能) 置1,就会向NVIC发起中断请求。

  • 中断标志位:TIMx_SR寄存器的UIF位,中断触发后硬件自动置1

  • 必须在中断服务函数中软件清除UIF标志,否则会反复进入中断

5.1.2 HAL库中断处理完整流程

  1. 初始化阶段:配置定时器参数,开启定时器时钟,配置NVIC中断优先级

  2. 启动阶段:调用 HAL_TIM_Base_Start_IT() ,硬件自动置位UIE位,开启更新中断

  3. 中断触发:计数器溢出,产生中断请求,CPU跳转到TIM6_IRQHandler中断入口

  4. HAL库中断处理:

  • 进入 HAL_TIM_IRQHandler() 通用处理函数

  • 检查UIF标志位,确认是更新中断

  • 硬件清除UIF标志位

  • 调用回调函数 HAL_TIM_PeriodElapsedCallback()

  1. 用户逻辑:在回调函数中编写定时任务代码

5.1.3 中断使用注意事项

  • 中断服务函数快进快出:不要在回调里执行延时、串口打印等耗时操作,避免阻塞其他中断和主程序

  • 优先级配置:根据任务紧急程度配置中断抢占优先级和子优先级,高优先级任务可以打断低优先级

  • 避免重入问题:如果回调中执行时间超过定时周期,会出现中断重入,导致逻辑混乱;必要时可在进入回调后关闭中断,退出前再开启

  • 适用场景:任务逻辑简单、执行时间短、需要CPU参与判断的定时场景,比如按键扫描、标志位翻转、短周期数据采集

5.2 DMA硬件触发联动原理与实战

DMA联动是基础定时器的高阶用法,真正实现"零CPU占用"的定时自动化。

5.2.1 硬件通路与通道对应

基础定时器的更新事件可以直接作为DMA的硬件触发信号,无需CPU干预。

  • STM32F103中,TIM6更新事件对应DMA1的通道3,TIM7更新事件对应DMA1的通道4

  • 触发方向:通常是内存→外设(比如把内存里的波形数据搬到DAC寄存器),也可以外设→内存、内存→内存

  • 硬件自动完成:定时器溢出→触发DMA传输→传输完成可选DMA中断,全程CPU不参与

5.2.2 完整工作流程

  1. 配置DMA:设置源地址、目标地址、传输数据量、数据宽度,开启定时器触发模式

  2. 配置定时器:设置定时周期,开启DMA触发使能(TIMx_DIER寄存器的UDE位)

  3. 启动定时器与DMA:定时器开始计数

  4. 每产生一次更新事件,硬件自动触发DMA完成一次数据传输

  5. 传输完成后,可选择产生DMA传输完成中断,通知CPU处理

5.2.3 典型应用:定时器+DMA+DAC生成任意波形

这是基础定时器最经典的工业应用:

  • 把正弦波/方波的采样点存在数组里(内存)

  • TIM6定时产生更新事件,触发DMA把一个采样点搬到DAC_DATA寄存器

  • DAC输出对应的模拟电压,最终输出连续的波形

  • 整个过程CPU只需要初始化一次,之后完全硬件自动运行,CPU可以休眠

5.2.4 HAL库核心配置代码片段

5.3 中断模式 vs DMA模式:如何选型

表格

六、代码实战:HAL库1ms定时中断(可直接复用)

下面基于STM32F103C8T6,给出完整的1ms定时中断工程代码,包含CubeMX配置步骤和核心逻辑。

6.1 CubeMX配置步骤

  1. 配置系统时钟:外部高速晶振HSE,配置主频72MHz

  2. 进入Timers → TIM6配置:

  • Activated:勾选,激活定时器

  • Prescaler (PSC):71

  • Counter Mode:Up(向上计数)

  • Counter Period (ARR):999

  • auto-reload preload:Enable(开启影子寄存器,ARPE=1)

  1. 进入NVIC Settings:勾选TIM6 global interrupt,开启定时器中断

  2. 生成工程代码

6.2 核心代码解析

6.3 启动定时器与中断回调

在main函数中启动定时器中断:

编写定时回调函数,实现1ms执行一次任务:

6.4 影子寄存器验证实验(选做)

你可以亲手验证影子寄存器的效果:

  1. 开启ARPE,在主循环中延时修改ARR值为1999

  2. 观察LED:会在当前1ms周期结束后,才变成2ms闪烁

  3. 关闭ARPE,重复实验:LED闪烁频率会立刻变化

七、面试高频考点汇总

基础定时器是嵌入式岗位面试的入门必考题,以下是最高频的8个问题及标准答案:

  1. 基础定时器和SysTick有什么区别?
  • SysTick是Cortex-M内核自带的24位递减计数器,通常用作系统时基,功能单一,和CPU绑定。

  • 基础定时器是独立片上外设,16位计数器,可触发中断、DMA、DAC,多个定时器可独立工作,不占用内核资源,外设联动能力强。

  1. 什么是影子寄存器?它的作用是什么?

影子寄存器是定时器中ARR、PSC的缓冲机制。寄存器分为预装载寄存器和影子寄存器两层,我们操作的是预装载寄存器,只有更新事件发生时,值才会加载到影子寄存器中真正生效。

作用:保证每个计数周期的完整性,避免中途修改参数导致计数周期混乱、时序异常,提升定时精度和稳定性。

  1. 定时器的定时周期如何计算?

定时周期 = (PSC预分频值 + 1) × (ARR自动重装载值 + 1) ÷ 定时器输入时钟频率。

加1是因为PSC和ARR都从0开始计数。

  1. 基础定时器可以输出PWM吗?

不可以。基础定时器仅包含时基单元,没有输入输出通道,不能产生PWM波形,只能实现定时计数、触发中断/DMA、触发DAC。

  1. ARPE位的功能是什么?

自动重装载预装载使能位,控制ARR影子寄存器是否生效。

  • 置1:修改ARR的值仅写入预装载寄存器,下一次更新事件时生效;

  • 置0:修改ARR的值立即生效,无缓冲。

  1. STM32F1的定时器时钟和APB1时钟是什么关系?

当APB1预分频系数为1时,定时器时钟等于APB1时钟;

当APB1预分频系数大于1时,定时器时钟为APB1时钟的2倍。

F1默认APB1分频系数为2,36MHz总线频率,因此定时器时钟为72MHz。

  1. 定时器触发DMA和定时器中断有什么区别?
  • 中断需要CPU进入中断服务函数处理数据,占用CPU资源,适合需要逻辑处理的场景;

  • DMA触发由硬件自动完成数据传输,CPU零占用,适合高速、纯数据搬运的场景,精度更高、响应更快。

  1. 基础定时器TIM6、TIM7有什么专属用途?

可以直接触发DAC转换,是DAC输出波形的常用硬件时基;同时可以触发DMA传输,实现无CPU干预的自动数据搬运。

结语

基础定时器虽结构简单,却是整个STM32定时器体系的核心根基。时基单元的计数逻辑、影子寄存器的时序设计、中断与DMA的双模式联动,本质上都是嵌入式硬件时序控制思想的具象体现。吃透这部分内容,不止是掌握了一个外设,更是建立硬件级开发思维的关键一步,后续学习通用定时器、高级定时器都会事半功倍。

如果本文对你有所帮助,欢迎点赞、收藏、转发支持,后续会持续更新STM32外设开发、嵌入式编程、电赛实战相关的技术干货,和大家一起从入门进阶到精通。

相关推荐
Sakura_j_h_1 小时前
STM32 采集 NTC 温度抖动:RC 硬件滤波与软件滑动平均怎么选
stm32·单片机·嵌入式硬件·滑动平均·传感器滤波·rc低通
考研保研资料分享11 小时前
211公共管理保研北航行政管理:五校考核、论文追问与择校复盘
面试
考研保研资料分享11 小时前
985工科跨保上财应用统计:数学笔试、匿名面试与机试复盘
面试·职场和发展
糖糖单片机设计11 小时前
基于 STM32 与中移 OneNet 的智慧电梯监控平台系统
stm32·单片机·嵌入式硬件·51单片机·语音识别
Aurora1114 小时前
Jane Street OA 真题解析:Mastermind 猜密码与候选集筛选
面试
创界工坊工作室14 小时前
55-基于STC89C52宠物智能饲喂控制系统设计
stm32·单片机·嵌入式硬件·51单片机·proteus·宠物
skytier15 小时前
昇思大模型推理:输出 logits
面试
丑陋小蚊子16 小时前
简历电脑上清楚,手机上字太小,先改哪里?
面试·求职招聘·大学生·简历·简历下载
pipixia2003316 小时前
C++继承面试四连问:内存叠加、私有继承、sizeof、权限重映射
c++·面试·嵌入式·继承·面向对象·对象模型