【江科大STM32学习笔记-06】TIM 定时器 - 6.3 定时器输入捕获功能
前言
第六章 TIM 定时器主要包含以下四个部分:
- 第一部分:定时器基本定时功能(已学习)
- 第二部分:定时器输出比较功能(已学习)
- 第三部分:定时器输入捕获功能(本篇内容)
- 第四部分:定时器编码器接口功能
在前两部分中,我们掌握了时基单元的定时逻辑与输出比较(OC)的波形产生技术。本章将深入探讨输入捕获功能。该功能不仅是测量外部信号频率与占空比的核心手段,更是理解定时器主从触发自动化机制的关键。
目录
1 频率测量理论基础
针对数字信号(高低电平方波信号)的频率测量,工程中通常采用测频法(Direct Frequency Measurement)与 测周法(Period Measurement)两种算法。在讲解 STM32 输入捕获功能前建立这些理论储备,是因为STM32 的输入捕获本质上就是“测周法”在硬件层面的自动化实现,因此它在测量中低频信号时具有天然的精度优势。理解了算法底层逻辑,便能更透彻地掌握输入捕获的硬件配置与参数计算。
在 STM32 的通用定时器架构中,标准输入捕获功能正是基于测周法来设计的。下图展示了这两种方法涉及到的关键参数:

1.1 测频法 (适合高频信号)
测量原理:开启一个固定时长的时间窗口(即闸门时间 ),在此窗口内利用计数器对输入信号的有效边沿(如上升沿)进行计次,最终得到计数值 N。
计算公式:频率的物理本质是单位时间(1s)内信号周期的个数。若在 秒内监测到 N 个完整周期,则 1 秒内的周期数(频率)即为:
工程特性:
- 自带均值滤波效果,输出数值较为平滑,但测量结果的更新率受限于设定的闸门时间(更新较慢)。
- 误差分析:计数器在闸门开闭瞬间会产生不可避免的
量化误差。待测信号频率越高,在相同
内累积的计数值 N 越大,
误差对整体结果的相对误差(1/N)就越小。因此,该方法极度适合高频信号测量。
1.2 测周法 (适合低频信号)
测量原理:利用一个已知且极高频率的标准时钟(频率为 fc)来驱动定时器计数。通过捕获待测信号两个相邻有效边沿(如连续两个上升沿),测量出一个完整信号周期内标准时钟的计步总数 N。
计算公式: 频率与周期互为倒数(f = 1/T)。已知标准时钟计一步的时间为 1/fc,若待测信号一个周期内标准时钟计了 N 步,则待测信号的周期 Tx 为:
则待测信号频率 fx 为:
工程特性:
- 高实时性。每经历一个完整的待测信号周期,即可输出一次测量结果,更新速度动态跟随待测信号。
- 误差分析:此时的
量化误差来源于内部标准时钟 fc 的计数跳变。待测信号频率越低,其单周期时间越长,所能容纳的标准时钟计数值 N 就越大,相对误差也就越小。因此,该方法极度适合低频信号测量。
1.3 中界频率
中界频率(fm)是指测频法与测周法相对测量误差绝对相等时的临界频率点。从数学本质上看。
计算公式:当这两种方法在同等条件下产生的的相对误差相等时,意味着它们的计数值 N 相同。
由测频法得:
由测周法得:
令两者相等:
解得中界频率:
注:fc 为测周法标准频率,为测频法闸门时间)
架构选型指南:
- 当待测信号频率 fx < fm 时,测周法的相对误差更小,应选用测周法。
- 当待测信号频率 fx > fm 时,测频法的相对误差更小,应选用测频法。
2 输入捕获原理概述
输入捕获(Input Capture, IC)是 STM32 定时器的核心功能之一。与输出比较(OC)通过主动比对计数器 CNT 与捕获/比较寄存器 CCR 的值来驱动引脚电平逻辑不同,输入捕获的核心任务是:在外部信号发生预设的电平跳变时,通过硬件瞬间记录该时刻定时器的计数值。
具体而言,当输入捕获通道对应的 GPIO 引脚(TIMx_CHx)检测到指定的有效边沿(上升沿、下降沿或双边沿,可通过软件寄存器配置)时,定时器内部的捕获电路会立即触发锁存动作,将 CNT 的当前数值自动转运并保存至对应的 CCR 中,完成一次捕获。同时还可以配置捕获时是否触发中断/DMA 等。
以定时器通道 1(TIMx_CH1)为例,展示外部信号从引脚输入到最终触发捕获的完整硬件路径。下图展示了信号经过滤波、边沿检测、交叉映射到最终触发捕获的完整底层逻辑:

该机制由硬件底层全自动执行,具备以下显著的技术特性:
- 高度自动化:捕获触发动作由硬件逻辑直接完成,无需 CPU 实时参与运算。
- 时序严谨性:计数值的锁存时刻与输入信号的边沿跳变保持严格同步。
- 测量高精度:捕获精度直接取决于定时器的计数频率,即系统时钟的分辨率。
正因为输入捕获能够精确记录物理时间节点,所以通过对连续两次或多次捕获值进行差值计算,可以精准提取信号的关键时域参数,包括:信号周期、信号频率、PWM 占空比、高电平持续时间以及低电平持续时间。
补充:输入捕获 vs. 外部中断(EXTI)
虽然两者均具备检测电平跳变的能力,但在底层执行逻辑上存在本质差异。EXTI 的执行动作是触发 CPU 挂起当前任务并执行中断服务程序(ISR);而输入捕获的动作是将 CNT 的计数值原子性地存入 CCR。这种纯硬件级的时间记录方式,彻底消除了中断响应延迟对时间测量的影响,使得测量高频信号时精度更高,系统开销更小
在明确了输入捕获的底层触发机制与应用场景后,需要进一步剖析其在 STM32 定时器内部的硬件架构与数据流向。
3 输入捕获硬件电路分析
在硬件资源配置上,STM32 的通用定时器和高级定时器通常配备 4 个独立的输入捕获通道(CC1 ~ CC4)。为了直观理解其在定时器系统中的物理定位,可以参考下图所示的定时器结构框图:

从上述框图中可以清晰观察到,输入捕获模块与输出比较模块在底层共用了同一通道的硬件资源(即同一个 CCR 寄存器与物理引脚)。
基于上述硬件共享机制,在工程配置中必须遵守以下约束:同一物理通道在同一时刻无法同时启用输入捕获与输出比较功能;但不同通道之间(例如 CH1 与 CH2)具备完全的独立性,可并行执行不同的工作模式。
3.1 信号链路与核心处理模块
明确了模块间的宏观资源分配后,需要深入通道内部,剖析外部信号是如何一步步转化为寄存器中的数值的。
以下就以定时器通道 1(TIMx_CH1)为例,展示其输入部分的底层硬件逻辑结构:

为了确保测量结果的准确与自动化,输入捕获电路在信号触发捕获前,必须经过以下四个核心处理单元的逐级处理:
3.1.1 输入滤波器
信号从 TIMx_CH1—>TI1 引脚进入定时器后,首先经过输入滤波器。该模块以特定的采样频率()对输入信号连续采样 N 次,只有当连续 N 次采样电平均相同时,输出逻辑才发生跳变。此机制可有效滤除外部信号的高频噪声与物理毛刺。
滤波器的参数(采样频率和 N 值)由寄存器 TIMx_CCMR1 中的 IC1F[3:0] 位配置,用户可根据外部信号质量灵活调整。数字滤波后的干净信号记为 TI1F,送往下一级处理。
3.1.2 边缘检测器与极性选择
TI1F 随后进入边沿检测器。极性选择由寄存器 TIMx_CCER 中的 CC1P 位控制:
- 当 CC1P = 0 时,选择上升沿作为有效触发边沿;
- 当 CC1P = 1 时,选择下降沿。
该选择的结果产生最终的触发信号 TI1FP1,用于后续捕获或触发。同时,边沿检测器还会输出一个 TI1F_ED 信号(任意双边沿触发),直接送往从模式控制器,用于特殊的双边沿触发场景。
3.1.3 通道交叉映射
STM32 定时器的硬件架构提供了灵活的信号路由机制。经过滤波及极性选择后的 TI1FP1 信号,将与另外两路参考信号共同输入至多路选择器(Data Selector)。该选择器的输出信号 IC1 将作为通道 1 捕获单元的最终触发源。
参与多路选择的信号源主要包括:
- TI2FP1(交叉映射信号):源自通道 2(CH2)的输入信号。通过内部硬件链路跨越至通道 1,使通道 1 能够获取相邻通道的频率或占空比特征。
- TRC(Trigger Controller):内部触发总线信号。该信号源于从模式控制器的触发输入,通常用于定时器级联同步或与芯片内部其他外设(如 ADC 触发、DMA 请求)进行硬件级联动。
最终的路由路径由寄存器 TIMx_CCMR1 中的 CC1S[1:0] 位进行配置:
- CC1S[1:0] = 00:直连模式 (DirectTI)。选择 TI1FP1 作为输入源,即通道 1 捕获其自身引脚的输入信号。
- CC1S[1:0] = 01:交叉模式 (IndirectTI)。选择 TI2FP1 作为输入源,即通道 1 捕获来自通道 2 引脚的信号。
- CC1S[1:0] = 10:TRC 映射模式。选择内部触发信号 TRC 作为输入源,用于实现定时器间的复杂同步逻辑。
这种硬件路由机制是实现 PWM 输入模式 (PWMI) 的底层物理基础。通过将单一物理引脚(如 TI1)的信号同时路由至直连通道(IC1)与交叉通道(IC2),系统可以在不增加额外外部连线的前提下,利用两个独立的捕获/比较寄存器(CCR1 和 CCR2)并行锁存信号的周期与脉宽数据。这种设计显著降低了 CPU 的运算开销,并确保了测量参数在时域上的严格同步。
名词解释:硬件路由(Signal Routing)
在 STM32 的定时器架构中,“路由”特指信号的路径选择与定向输送。
这一过程本质上是通过配置寄存器(如 TIMx_CCMR1 中的 CC1S[1:0] 位)来控制内部多路选择器的导通状态。它决定了外部引脚采集到的信号(如 TI1)在芯片内部的流向——是定向输送至本通道的捕获单元(直连路径),还是跨越至相邻通道的捕获单元(交叉路径)。这种灵活的路由机制允许开发者在不改动外部硬件电路的前提下,通过软件协议栈自由重组信号链路。
3.1.4 主从触发模式(硬件自动化)
为了解决测周法要求每次测量必须“从零开始计时”的需求,必须引入从模式控制器以实现“零 CPU 干预”的全自动化测量。
在此机制中,信号在处理链路上被分流为两个并行的动作分支:
- 捕获动作:信号 IC1 先送入输入捕获分频器(由
ICPS[1:0]控制),分频后的信号最终触发捕获事件,将当前 CNT 值锁存至 CCR1 中。 - 触发动作:与此同时,信号 TI1FP1 作为 触发输入信号(Trigger Input, TRGI)被路由至从模式控制器。

作为从模式控制器的标准输入源,TRGI 在硬件链路上起到了同步触发源的作用。其本质是一个与捕获边沿严格同步的逻辑脉冲。当从模式被配置为 复位模式(Reset Mode)时,该脉冲信号会直接驱动从模式控制器的硬件组合逻辑,瞬间完成计数器 CNT 的清零操作。
配置为复位模式后的具体执行逻辑如下:
- 捕获:有效边沿到达瞬间,硬件电路首先执行锁存操作,将 CNT 的值原子性地转运至 CCR。
- 复位:在完成捕获的同时,TRGI 信号驱动从模式控制器将 CNT 清零,为下一个周期的计数重置基准。
由于底层硬件逻辑在设计上确保了捕获动作早于清零动作(或采用原子级同步逻辑),从而规避了由于先清零而导致捕获值为 0 的逻辑冲突。这种由 TRGI 驱动的硬件同步机制,确保了 CCR 中存储的值永远是上一个周期的完整计数值 N,为后续频率与占空比的精确计算提供了可靠的数据支撑。
将上述的“通道交叉映射”与“主从自动复位”机制有机结合,便构成了 STM32 用于同时测量信号频率与占空比的最强应用架构——PWM 输入模式。
4 PWM 输入模式(PWMI)原理
PWM 输入模式(PWM Input Mode, PWMI)是 STM32 定时器输入捕获功能的一种特殊硬件工作模式。该模式利用定时器内部的通道交叉映射机制与从模式控制器(Slave Mode Controller)的硬件同步复位功能,实现了仅需占用一个物理输入引脚,即可同步测量外部 PWM 信号的周期(Period)与脉宽(Pulse Width)。
4.1 核心设计特性
在信号链路结构上,PWMI 模式建立在标准输入捕获单元的基础之上,但通过特定的寄存器组合配置,实现了测量过程的完全硬件自动化。其核心特性包括:
- 同源映射(Signal Multiplexing):两个独立的捕获通道(如 IC1 与 IC2)在内部同时映射至同一个物理输入信号源。例如,输入引脚 TI1 的信号被分为两路:一路直连映射(TI1 —> IC1),另一路交叉映射(TI1 —> IC2)。因此,单一外部信号可同时驱动两个捕获单元。
- 互补极性检测(Complementary Edge Detection):两个捕获通道被配置为相反的有效触发边沿。一个通道检测信号周期的起始边沿(如上升沿),另一个通道检测高/低电平的结束边沿(如下降沿),从而在时域上截取周期长度与脉冲宽度。
- 硬件同步复位(Hardware Synchronized Reset):选定的输入触发信号(TI1FP1 或 TI2FP2)被路由至从模式控制器的触发输入端(TRGI)。当有效边沿到达时,从模式控制器自动执行计数器(CNT)清零操作,以此实现周期测量的无缝自动同步。
注:捕获锁存与计数器复位由不同的硬件单元执行,但由同一外部事件同步触发,硬件设计保证了先捕获、后复位此时序逻辑。
4.2 硬件配置与执行逻辑(以引脚 TI1 为例)
当待测 PWM 信号接入 TI1 引脚时,定时器通过内部两个捕获通道的协同工作,完成周期与脉宽的提取。
4.2.1 通道 1(直连映射:测量周期)
通道 1 负责捕获信号的完整周期,同时充当从模式控制器的复位触发源。
- 输入源选择:设置 TIMx_CCMR1 寄存器中的 CC1S[1:0] = 01,将 IC_1 通道配置为直连输入模式,即物理引脚 TI_1 的信号直接作为 IC_1 的输入源。
- 极性配置:设置 TIMx_CCER 寄存器中的 CC1P = 0,设定为上升沿检测。当检测到上升沿时,输入级生成内部触发信号 TI1FP1。
- 从模式配置:设置 TIMx_SMCR 寄存器中的 TS[2:0] = 101(选择 TI1FP1 为TRGI触发源),并设置 SMS[2:0] = 100(配置从模式为复位模式)。
- 底层执行逻辑:当 TI1 出现上升沿并触发 TI1FP1 时,硬件产生原子性同步动作:首先将当前 CNT 的值锁存至 CCR1 寄存器中,随后瞬间触发从模式控制器将 CNT 寄存器复位清零,开启新一轮周期的计数。
4.2.2 通道 2(交叉映射:测量脉宽)
通道 2 负责捕获电平翻转点(如高电平结束时刻),记录与占空比相关的计数值。
-
输入源选择:设置 TIMx_CCMR1 寄存器中的 CC2S[1:0] = 10,将 IC_2 通道设定为交叉输入模式。此时,TI1 引脚的信号经过经过滤波与极性选择后,生成的 TI1FP2 信号被路由至通道 2 的数据选择器,最终映射至 IC_2。如图所示:

-
极性配置:设置 TIMx_CCER 寄存器中的 CC2P = 1,设定为下降沿检测。当检测到下降沿时,生成内部信号 TI1FP2。
- 底层执行逻辑:当输入信号出现下降沿时,触发通道 2 的捕获电路,将当前 CNT 的值锁存至 CCR2 寄存器中。由于 CNT 已经在上一个上升沿被硬件清零,因此此时 CCR2 中锁存的值,即为精确的 PWM 高电平持续时间。注:TI1FP2 并未被配置为 TRGI 触发源,因此该边沿不会引发 CNT 复位。
通过上述配置,定时器内部形成了基于同一输入信号的双通道协同测量结构。下图展示了 TI1 输入信号如何同时驱动捕获单元与从模式控制器,实现周期测量与脉宽测量的时序同步:

说明:图中首个上升沿出现 IC2 捕获的底层原因
在 PWMI 模式的初始阶段,当第一个上升沿到来触发 TRGI 复位动作时,由于 IC2 通道已被使能(CC2E = 1),根据 STM32 的内部硬件逻辑,触发控制器会同步向所有已使能的捕获通道发送采样脉冲。这意味着在 CNT 被清零前的瞬间,硬件会强制 IC2 执行一次捕获锁存操作。因此,IC2 在此处的捕获是由主从复位动作连带触发的硬件级同步行为,而非单纯的下降沿触发。
4.3 频率与占空比的量化计算
得益于由 TI1FP1 驱动的“先捕获、后复位”硬件机制,CCR1 寄存器始终存储着上一个完整周期的计数值,而 CCR2 寄存器则存储着高电平阶段的计数值。基于此,可通过以下公式直接量化物理参数:
- 周期测量:外部信号的周期 T 由 CCR1 决定。
其中 为定时器驱动时钟频率;+1 用于补偿计数器从 0 开始计数的硬件偏移量)。
- 频率计算:外部信号的频率
为周期T的倒数。
-
占空比测量:外部信号的占空比 Duty 由两个寄存器的比值决定:
这种基于纯硬件寄存器的数据获取方式,彻底避免了高频中断对 CPU 资源的挤占,确保了系统在面对高频信号时依然具备极高的测量精度与实时性。
4.4 硬件资源约束与选型规范
依据 STM32 定时器的内部布线架构,在物理层面上,仅有 TI1FP1 与 TI2FP2 这两路信号被直接硬连线至从模式控制器的触发输入总线(TRGI)。如图所示:

因此,在使用硬件级 PWMI 自动复位机制时,必须严格遵循以下硬件通道分配约束:
- TI1 输入源限制:若待测信号接入 TI1 引脚,必须由通道 1(利用 TI1FP1)触发从模式复位。
- TI2 输入源限制:若待测信号接入 TI2 引脚,必须由通道 2(利用 TI2FP2)触发从模式复位。
- CH3/CH4 不适用:定时器的通道 3(CH3)与通道 4(CH4)在硬件设计上不具备指向从模式控制器 TRGI 的直连触发链路,故无法原生支持标准的 PWMI 自动复位功能。若项目强行需要使用 CH3 或 CH4 测量 PWM,则必须退而求其次,依赖软件中断进行清零,或通过复杂的内部触发(ITR)级联来实现等效功能。
5 输入捕获配置步骤(基于标准外设库)
前面几章我们彻底剖析了输入捕获与 PWMI 模式的底层硬件路由和主从触发机制。接下来,我们将这些纯硬件的理论映射到具体的软件代码中。
在实际工程中,利用 STM32 标准库配置输入捕获(IC)与 PWM 输入模式(PWMI)的流程高度一致。结合硬件的主从触发复位机制,我们可以彻底免去传统的中断繁琐操作。具体配置步骤如下:
5.1 使能时钟与 GPIO 初始化
输入捕获信号必须通过特定的物理引脚进入定时器。以本实验使用 TIM3 的通道 1(对应引脚为 PA6) 为例,首先需要开启定时器与对应 GPIO 的时钟,并将引脚配置为合适的输入模式。
通常,为了防止外部信号悬空导致的误触发,建议将其配置为上拉输入(IPU)或下拉输入(IPD)。
/* 1. 开启 TIM3 与 GPIOA 时钟 */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/* 2. 配置 PA6 为上拉输入模式 */
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入,提升抗干扰能力
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
5.2 初始化定时器时基单元(TimeBase)
时基单元决定了测周法的“标尺精度”和“测量量程”,因此必须配置合理的预分频器(PSC)和自动重装载值(ARR):
- 预分频系数(PSC):决定了标准频率 fc。如 PSC = 72-1,则 fc = 72MHz / 72 = 1MHz。这意味着计数器每 1us 计一个数。
- 自动重装值(ARR):在测周法中,ARR 应设为最大值(65535)。这是为了保证在待测信号的一个周期内,计数器不会因为溢出而提前归零,从而导致周期测量错误。
TIM_InternalClockConfig(TIM3); // 选择内部时钟驱动 TIM3
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 滤波器采样时钟不分频
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数
TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1; // 设为最大值,防止提前溢出
TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; // 预分频为72,标准时钟频率 Fc = 1MHz
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
5.3 初始化输入捕获通道(核心区分点)
这一步是配置信号的极性、滤波器、分频与路由映射。标准库提供了一个结构体 TIM_ICInitTypeDef 来完成这些参数的集合配置:
- TIM_Channel:指定要配置的通道(如 TIM_Channel_1)。
- TIM_ICPolarity:定义以何种电平跳变形式触发捕获(上升沿 Rising 或下降沿 Falling)。
- TIM_ICSelection:配置映射关系:
- 直连(DirectTI):TI1 —> IC1,信号从通道 1 入,交给通道 1 处理。
- 交叉(IndirectTI):TI1 —> IC2,信号从通道 1 入,跨界交给通道 2 处理,PWMI 模式的关键。
- TIM_ICPrescaler:捕获预分频。设为 TIM_ICPSC_DIV1 即不分频,每次边沿均触发。
- TIM_ICFilter:硬件数字滤波器。设为 0xF 可最大程度滤除高频噪声毛刺。
【模式分支配置】:根据需求选择不同的初始化函数
- 普通输入捕获模式(仅测频率):调用 TIM_ICInit(),仅初始化单一目标通道。
- PWMI 模式(测频率与占空比):调用 TIM_PWMIConfig()。这是一个强大的宏观库函数,传入通道 1 的参数后,它会在底层自动将通道 2 配置为相反的极性与交叉映射,一步到位完成 PWMI 的底层路由构建。
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICFilter = 0xF;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; // 周期起点:上升沿
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
/* 模式选择:二选一 */
// 仅测频率使用:
// TIM_ICInit(TIM3, &TIM_ICInitStructure);
// PWMI 测频率与占空比使用:
TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);
5.4 配置从模式与硬件复位触发
为了让计数器在捕获发生的瞬间自动清零,必须配置主从同步触发。
- 触发源选择:TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1),将通道 1 信号(TI1FP1)指定为触发输入(TRGI)。
- 从模式选择:TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset),设定触发后的动作为“复位计数器”。
如此,当上升沿到来触发从模式复位时,硬件会先执行锁存操作,将当前计数器 CNT 的实时值复制到捕获寄存器 CCR1 中。在捕获动作完成后(极短的硬件时钟周期延迟内,通常仅 1~2 个时钟周期),从模式控制器的复位信号生效,将 CNT 清零为,使定时器立即开始下一周期的计数,这一过程完全由硬件自动完成。
TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1); // 选择 TI1FP1 为触发源 TRGI
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset); // 从模式配置为复位动作
5.5 使能定时器
所有参数就绪后,启动定时器,硬件闭环机制即刻开始自动化运作。
TIM_Cmd(TIM3, ENABLE); // 使能 TIM3,计数与捕获逻辑开始运行
5.6 数据读取与参数计算
配置完成后,CPU 无需再干预捕获过程,随时在主循环中读取捕获寄存器(CCR)的值即可获取结果:
- 读取周期计数值(N):调用 TIM_GetCapture1(TIM3)。
- 读取脉宽计数值(W):调用 TIM_GetCapture2(TIM3)(仅 PWMI 模式有效)。
最终计算逻辑封装:
/* 获取频率 (Fc = 1000000Hz) */
uint32_t IC_GetFreq(void)
{
// 测周法公式:fx = fc / N
// 注意:这里的 1000000 (1MHz) 是由时基单元配置中的 PSC 决定的 (72MHz / 72 = 1MHz)
// 若修改了预分频值,此常数需同步调整
return 1000000 / (TIM_GetCapture1(TIM3) + 1);
}
/* 获取占空比 (PWMI模式) */
uint32_t IC_GetDuty(void)
{
// 公式:Duty = (W / N) * 100%
return (TIM_GetCapture2(TIM3) + 1) * 100 / (TIM_GetCapture1(TIM3) + 1);
}
提示:
在工程中,代码里的 1000000 是测周法的“标准频率” fc。它严格取决于你在 TIM_TimeBaseInit 中设置的预分频系数(PSC)。
例如,若你将 PSC 改为 720-1,则 fc 变为 100kHz,此时代码中的常数也必须同步修改为 100000,否则计算结果将出现数量级偏差。
6. 本章节实验
6.1 输入捕获模式测频率
6.1.1 实验目标
- 掌握外设协同与系统闭环设计:利用芯片内部的两个独立定时器资源,实现“信号发生”与“信号测量”的硬件级闭环测试系统。
- 掌握测试信号源的构建:学习配置定时器(TIM2)的输出比较(PWM)功能,生成频率与占空比可软件动态调节的待测方波信号。
- 深化输入捕获与主从触发应用:掌握将定时器(TIM3)配置为输入捕获模式,并结合硬件触发源(TRGI)与从模式控制器,实现无需 CPU 干预的计数器(CNT)自动复位。
- 验证测周法理论:将测周法理论的数学公式转化为实际代码,完成物理信号向频率参数的量化计算。
6.1.2 硬件设计

6.1.3 软件设计
本实验在软件架构上脱离了单向的测量模式,而是将系统划分为信号发生、信号测量 和 结果展示三大核心模块。
1. 信号发生模块(基于 TIM2)
- 引脚配置:将指定的 GPIO 引脚配置为复用推挽输出模式,将其控制权交接给 TIM2 外设。
- 波形生成:利用 TIM2 的时基单元与输出比较通道(PWM 模式 1),持续输出高低电平交替的方波信号 。
- 动态调节接口:封装底层的寄存器操作,提供独立的函数用于动态修改预分频器(PSC,决定频率)与捕获比较寄存器(CCR,决定占空比),模拟真实多变的外部被测信号。
2. 信号测量模块(基于 TIM3)
- 信号接入:配置另一组 GPIO 引脚为上拉输入模式,用于物理接收 TIM2 产生的方波信号。
- 配置时基单元:为 TIM3 设定合理的预分频系数,确立内部测周法的标准时钟频率(fc)。同时将自动重装载值(ARR)设定为最大值,以提供最大的单周期测量量程,防止低频测量时发生溢出。
- 捕获配置:将输入通道配置为直连映射(Direct TI),设定为上升沿触发,并开启硬件数字滤波器以消除潜在的物理抖动。
- 主从复位自动化:指定通道的有效跳变沿(TI1FP1)为硬件触发输入源(TRGI),并将从模式控制器配置为“复位模式”。这使得定时器在每次捕获到上升沿时,不仅会锁存计数值,还会通过纯硬件逻辑瞬间清零计数器。
3. 运行与数据处理逻辑(主程序)
- 硬件自治:系统启动后,TIM2 持续发送脉冲,TIM3 在后台通过纯硬件机制连续执行:“捕获 —> 清零 —> 重新计数” 的死循环,全程无需触发任何软件中断 。
- 数据换算与显示:在 while(1) 主循环中,主控只需按需调用读取函数,获取 TIM3 捕获寄存器(CCR1)中存储的上一个完整周期计数值 N。随后,利用测周法公式:fx = fc / (N+1) 换算出待测信号的频率,并将其刷新至 OLED 屏幕。
具体代码如下:
main.c文件:
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
#include "IC.h"
int main(void)
{
/*模块初始化*/
OLED_Init(); //OLED初始化
PWM_Init(); //PWM初始化
IC_Init(); //输入捕获初始化
/*显示静态字符串*/
OLED_ShowString(1, 1, "Freq:00000Hz"); //1行1列显示字符串Freq:00000Hz
/*使用PWM模块提供输入捕获的测试信号*/
PWM_SetPrescaler(720 - 1); //PWM频率Freq = 72M / (PSC + 1) / 100
PWM_SetCompare1(50); //PWM占空比Duty = CCR / 100
while (1)
{
OLED_ShowNum(1, 6, IC_GetFreq(), 5); //不断刷新显示输入捕获测得的频率
}
}
IC.c文件:
#include "stm32f10x.h" // Device header
/**
* 函 数:输入捕获初始化
* 参 数:无
* 返 回 值:无
*/
void IC_Init(void)
{
/*开启时钟*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //开启TIM3的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟
/*GPIO初始化*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA6引脚初始化为上拉输入
/*配置时钟源*/
TIM_InternalClockConfig(TIM3); //选择TIM3为内部时钟,若不调用此函数,TIM默认也为内部时钟
/*时基单元初始化*/
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //定义结构体变量
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数
TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1; //计数周期,即ARR的值
TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; //预分频器,即PSC的值
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重复计数器,高级定时器才会用到
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure); //将结构体变量交给TIM_TimeBaseInit,配置TIM3的时基单元
/*输入捕获初始化*/
TIM_ICInitTypeDef TIM_ICInitStructure; //定义结构体变量
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; //选择配置定时器通道1
TIM_ICInitStructure.TIM_ICFilter = 0xF; //输入滤波器参数,可以过滤信号抖动
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //极性,选择为上升沿触发捕获
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //捕获预分频,选择不分频,每次信号都触发捕获
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //输入信号交叉,选择直通,不交叉
TIM_ICInit(TIM3, &TIM_ICInitStructure); //将结构体变量交给TIM_ICInit,配置TIM3的输入捕获通道
/*选择触发源及从模式*/
TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1); //触发源选择TI1FP1
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset); //从模式选择复位
//即TI1产生上升沿时,会触发CNT归零
/*TIM使能*/
TIM_Cmd(TIM3, ENABLE); //使能TIM3,定时器开始运行
}
/**
* 函 数:获取输入捕获的频率
* 参 数:无
* 返 回 值:捕获得到的频率
*/
uint32_t IC_GetFreq(void)
{
return 1000000 / (TIM_GetCapture1(TIM3) + 1); //测周法得到频率fx = fc / N,这里不执行+1的操作也可
}
PWM.c文件:
#include "stm32f10x.h" // Device header
/**
* 函 数:PWM初始化
* 参 数:无
* 返 回 值:无
*/
void PWM_Init(void)
{
/*开启时钟*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //开启TIM2的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟
/*GPIO重映射*/
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //开启AFIO的时钟,重映射必须先开启AFIO的时钟
// GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE); //将TIM2的引脚部分重映射,具体的映射方案需查看参考手册
// GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); //将JTAG引脚失能,作为普通GPIO引脚使用
/*GPIO初始化*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA0引脚初始化为复用推挽输出
//受外设控制的引脚,均需要配置为复用模式
/*配置时钟源*/
TIM_InternalClockConfig(TIM2); //选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟
/*时基单元初始化*/
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //定义结构体变量
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数
TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; //计数周期,即ARR的值
TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1; //预分频器,即PSC的值
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重复计数器,高级定时器才会用到
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); //将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元
/*输出比较初始化*/
TIM_OCInitTypeDef TIM_OCInitStructure; //定义结构体变量
TIM_OCStructInit(&TIM_OCInitStructure); //结构体初始化,若结构体没有完整赋值
//则最好执行此函数,给结构体所有成员都赋一个默认值
//避免结构体初值不确定的问题
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //输出比较模式,选择PWM模式1
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性,选择为高,若选择极性为低,则输出高低电平取反
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //输出使能
TIM_OCInitStructure.TIM_Pulse = 0; //初始的CCR值
TIM_OC1Init(TIM2, &TIM_OCInitStructure); //将结构体变量交给TIM_OC1Init,配置TIM2的输出比较通道1
/*TIM使能*/
TIM_Cmd(TIM2, ENABLE); //使能TIM2,定时器开始运行
}
/**
* 函 数:PWM设置CCR
* 参 数:Compare 要写入的CCR的值,范围:0~100
* 返 回 值:无
* 注意事项:CCR和ARR共同决定占空比,此函数仅设置CCR的值,并不直接是占空比
* 占空比Duty = CCR / (ARR + 1)
*/
void PWM_SetCompare1(uint16_t Compare)
{
TIM_SetCompare1(TIM2, Compare); //设置CCR1的值
}
/**
* 函 数:PWM设置PSC
* 参 数:Prescaler 要写入的PSC的值,范围:0~65535
* 返 回 值:无
* 注意事项:PSC和ARR共同决定频率,此函数仅设置PSC的值,并不直接是频率
* 频率Freq = CK_PSC / (PSC + 1) / (ARR + 1)
*/
void PWM_SetPrescaler(uint16_t Prescaler)
{
TIM_PrescalerConfig(TIM2, Prescaler, TIM_PSCReloadMode_Immediate); //设置PSC的值
}
6.1.4 实验现象
使用板载 TIM2 输出的 1000Hz PWM 信号接入 PA6 进行自我测试,OLED 屏幕上实时显示当前测量得出的频率数值稳定为 1000Hz。

6.2 PWM 输入模式测频率与占空比
6.2.1 实验目标
- 深入理解通道交叉映射机制:掌握 STM32 定时器内部输入通道的硬件路由分配原理,理解单根物理引脚如何同时驱动两个独立的捕获寄存器。
- 掌握 PWMI 专属配置接口:学习使用标准库提供的高效宏观函数(TIM_PWMIConfig),快速搭建互补极性的双通道协同捕获架构,替代繁琐的单通道独立配置。
- 实现多维信号参数同步测量:在上一节闭环测试系统的基础上进一步升级,实现对高频 PWM 信号的**频率(周期)与占空比(脉宽)**两个维度的全硬件、无干预同步解析。
6.2.2 硬件设计

6.2.3 软件设计
本实验的软件架构在上一节频率测量的基础上进行了维度扩展,核心在于利用 PWMI 模式的硬件自动化特性,在同一输入信号上提取双重特征参数。
1. 信号发生模块(基于 TIM2)
-
全参数可调信号源:继续沿用 TIM2 作为测试信号发生器。除了通过调节预分频器(PSC)来改变信号频率外,本实验中输出比较寄存器(CCR)的数值也作为关键变量,用于动态改变信号的高电平持续时间,从而生成频率与占空比均可独立控制的标准 PWM 测试波形。
2. PWMI 捕获架构(基于 TIM3)
- 单线双路信号接入:外部 PWM 信号仅接入单一物理引脚(PA6)。在芯片内部,该信号被硬件级一分为二,同时送往通道 1(直连)与通道 2(交叉映射)。
- 自动互补配置(TIM_PWMIConfig):在软件层面抛弃了对两个通道分别初始化的繁琐流程。主程序仅需向库函数传入基准通道(如通道 1:直连映射、上升沿捕获)的配置结构体,底层硬件会自动推导并配置关联通道(通道 2:交叉映射、下降沿捕获),从而形成严密的互补检测逻辑。
- 从模式联动:保留上一个实验的主从复位机制,利用基准通道的有效边沿(上升沿)触发从模式控制器,实现定时器计数器(CNT)的周期性自动清零。
3. 运行逻辑与双维参数提取(主程序)
-
硬件级测量时序:系统运行时,纯硬件电路将按以下时序自动流转 :
-
阶段一(周期起点):信号产生上升沿 —> 通道 1 触发,CCR1 锁存上一个周期的总计数值 —> 从模式触发,瞬间清零 CNT。
-
阶段二(脉宽终点):信号产生下降沿 —> 通道 2 触发,CCR2 独立锁存当前 CNT 的值(此时的值即为高电平持续时间)。
-
阶段三(周期终点):下一个上升沿到来,重复阶段一,CNT 重新开始计数。如下图所示:
-

-
数据换算展示:主程序彻底摆脱了时序追踪的负担,只需从两个专职寄存器中直接提取结果:
-
频率计算:沿用
获取频率。
-
占空比计算:利用公式
直接求得占空比百分比,并将其格式化后与频率同步刷新至 OLED 屏幕。
-
具体代码如下:
main.c文件:
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
#include "IC.h"
int main(void)
{
/*模块初始化*/
OLED_Init(); //OLED初始化
PWM_Init(); //PWM初始化
IC_Init(); //输入捕获初始化
/*显示静态字符串*/
OLED_ShowString(1, 1, "Freq:00000Hz"); //1行1列显示字符串Freq:00000Hz
OLED_ShowString(2, 1, "Duty:00%"); //2行1列显示字符串Duty:00%
/*使用PWM模块提供输入捕获的测试信号*/
PWM_SetPrescaler(720 - 1); //PWM频率Freq = 72M / (PSC + 1) / 100
PWM_SetCompare1(50); //PWM占空比Duty = CCR / 100
while (1)
{
OLED_ShowNum(1, 6, IC_GetFreq(), 5); //不断刷新显示输入捕获测得的频率
OLED_ShowNum(2, 6, IC_GetDuty(), 2); //不断刷新显示输入捕获测得的占空比
}
}
IC.c文件:
#include "stm32f10x.h" // Device header
/**
* 函 数:输入捕获初始化
* 参 数:无
* 返 回 值:无
*/
void IC_Init(void)
{
/*开启时钟*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //开启TIM3的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟
/*GPIO初始化*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA6引脚初始化为上拉输入
/*配置时钟源*/
TIM_InternalClockConfig(TIM3); //选择TIM3为内部时钟,若不调用此函数,TIM默认也为内部时钟
/*时基单元初始化*/
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //定义结构体变量
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数
TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1; //计数周期,即ARR的值
TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; //预分频器,即PSC的值
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重复计数器,高级定时器才会用到
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure); //将结构体变量交给TIM_TimeBaseInit,配置TIM3的时基单元
/*PWMI模式初始化*/
TIM_ICInitTypeDef TIM_ICInitStructure; //定义结构体变量
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; //选择配置定时器通道1
TIM_ICInitStructure.TIM_ICFilter = 0xF; //输入滤波器参数,可以过滤信号抖动
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //极性,选择为上升沿触发捕获
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //捕获预分频,选择不分频,每次信号都触发捕获
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //输入信号交叉,选择直通,不交叉
TIM_PWMIConfig(TIM3, &TIM_ICInitStructure); //将结构体变量交给TIM_PWMIConfig,配置TIM3的输入捕获通道
//此函数同时会把另一个通道配置为相反的配置,实现PWMI模式
/*选择触发源及从模式*/
TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1); //触发源选择TI1FP1
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset); //从模式选择复位
//即TI1产生上升沿时,会触发CNT归零
/*TIM使能*/
TIM_Cmd(TIM3, ENABLE); //使能TIM3,定时器开始运行
}
/**
* 函 数:获取输入捕获的频率
* 参 数:无
* 返 回 值:捕获得到的频率
*/
uint32_t IC_GetFreq(void)
{
return 1000000 / (TIM_GetCapture1(TIM3) + 1); //测周法得到频率fx = fc / N,这里不执行+1的操作也可
}
/**
* 函 数:获取输入捕获的占空比
* 参 数:无
* 返 回 值:捕获得到的占空比
*/
uint32_t IC_GetDuty(void)
{
return (TIM_GetCapture2(TIM3) + 1) * 100 / (TIM_GetCapture1(TIM3) + 1); //占空比Duty = CCR2 / CCR1 * 100,这里不执行+1的操作也可
}
PWM.c文件:
#include "stm32f10x.h" // Device header
/**
* 函 数:PWM初始化
* 参 数:无
* 返 回 值:无
*/
void PWM_Init(void)
{
/*开启时钟*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //开启TIM2的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟
/*GPIO重映射*/
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //开启AFIO的时钟,重映射必须先开启AFIO的时钟
// GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE); //将TIM2的引脚部分重映射,具体的映射方案需查看参考手册
// GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); //将JTAG引脚失能,作为普通GPIO引脚使用
/*GPIO初始化*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA0引脚初始化为复用推挽输出
//受外设控制的引脚,均需要配置为复用模式
/*配置时钟源*/
TIM_InternalClockConfig(TIM2); //选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟
/*时基单元初始化*/
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //定义结构体变量
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数
TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; //计数周期,即ARR的值
TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1; //预分频器,即PSC的值
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重复计数器,高级定时器才会用到
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); //将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元
/*输出比较初始化*/
TIM_OCInitTypeDef TIM_OCInitStructure; //定义结构体变量
TIM_OCStructInit(&TIM_OCInitStructure); //结构体初始化,若结构体没有完整赋值
//则最好执行此函数,给结构体所有成员都赋一个默认值
//避免结构体初值不确定的问题
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //输出比较模式,选择PWM模式1
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性,选择为高,若选择极性为低,则输出高低电平取反
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //输出使能
TIM_OCInitStructure.TIM_Pulse = 0; //初始的CCR值
TIM_OC1Init(TIM2, &TIM_OCInitStructure); //将结构体变量交给TIM_OC1Init,配置TIM2的输出比较通道1
/*TIM使能*/
TIM_Cmd(TIM2, ENABLE); //使能TIM2,定时器开始运行
}
/**
* 函 数:PWM设置CCR
* 参 数:Compare 要写入的CCR的值,范围:0~100
* 返 回 值:无
* 注意事项:CCR和ARR共同决定占空比,此函数仅设置CCR的值,并不直接是占空比
* 占空比Duty = CCR / (ARR + 1)
*/
void PWM_SetCompare1(uint16_t Compare)
{
TIM_SetCompare1(TIM2, Compare); //设置CCR1的值
}
/**
* 函 数:PWM设置PSC
* 参 数:Prescaler 要写入的PSC的值,范围:0~65535
* 返 回 值:无
* 注意事项:PSC和ARR共同决定频率,此函数仅设置PSC的值,并不直接是频率
* 频率Freq = CK_PSC / (PSC + 1) / (ARR + 1)
*/
void PWM_SetPrescaler(uint16_t Prescaler)
{
TIM_PrescalerConfig(TIM2, Prescaler, TIM_PSCReloadMode_Immediate); //设置PSC的值
}
6.2.4 实验现象
OLED 屏幕同步显示两行数据:第一行为测得的信号频率(如 10000Hz),第二行为测得的信号占空比(如 50%)。动态修改发生器(或 TIM2)的预分频或捕获比较寄存器值,屏幕显示的测量参数会即刻跟随发生线性变化。

更多推荐



所有评论(0)