TIM 输入捕获与 PWMI:从边沿到频率、占空比
课程:
[6-5] TIM 输入捕获、[6-6] 输入捕获模式测频率、[6-7] PWMI 模式测频率占空比核心目标:不只记住初始化函数,而是能从"要测什么"反推出引脚、计数时钟、捕获通道、触发源、从模式和计算公式。
示例芯片与库:STM32F103、STM32 标准外设库。
1. 本节资料索引
| 资料 | 本节使用位置 |
|---|---|
| 课堂录音转写《2026-09-01 17_21 TIM 输入捕获》 | 00:02~02:36 演示;02:36~05:34 输入捕获定义;05:34~11:28 测频法/测周法;11:28~18:43 输入捕获通道;18:43~20:53 主从触发;20:53~23:41 单通道测频;23:41~25:27 PWMI |
| 教师 PPT《STM32入门教程》 | 第 74~79 页:输入捕获简介、频率测量、输入捕获通道、主从触发、基本结构、PWMI 结构 |
| 师兄笔记《STM32笔记》 | PDF 第 59~63 页:定义与公式、通道结构、主从触发、基本结构、PWMI、初始化源码批注 |
| 《STM32F10xxx参考手册(中文)》 | PDF 第 265~268 页:捕获/比较通道、输入捕获、PWM 输入模式;第 274~276 页:复位等从模式;第 282~294 页:CR1、SMCR、SR、CCMR1、CCER、CNT/PSC/ARR/CCR 寄存器 |
| 《STM32F103x8B数据手册(中文)》 | PDF 第 18 页:PA6 的默认复用功能包含 TIM3_CH1 |
| 示例源码 | 6-6 输入捕获模式测频率、6-7 PWMI模式测频率占空比 |
页码均指 PDF 阅读器显示的文件页码;不同版本手册的书内页码可能略有差异。
2. 先用一句话理解输入捕获
输入捕获就是:外部引脚出现指定边沿时,硬件立即把定时器当前的 CNT 值复制到 CCRx 中。
CNT像一直走动的秒表。- 外部上升沿/下降沿像按下"计次"按钮。
CCRx像秒表的圈速记录,保存按键瞬间的读数。- CPU 不必恰好在边沿到来时读取
CNT,因此比软件轮询 GPIO 更及时、更稳定。

输入捕获本身只完成"在边沿处记下 CNT"。要得到周期,还要让相邻两个同类边沿之间从相同的起点计数。本课程使用 TI1FP1 触发 + 从模式复位 ,让每个上升沿在锁存后自动把 CNT 清零。
#mermaid-svg-pK28OcIX0Lhnx759{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-pK28OcIX0Lhnx759 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-pK28OcIX0Lhnx759 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-pK28OcIX0Lhnx759 .error-icon{fill:#552222;}#mermaid-svg-pK28OcIX0Lhnx759 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-pK28OcIX0Lhnx759 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-pK28OcIX0Lhnx759 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-pK28OcIX0Lhnx759 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-pK28OcIX0Lhnx759 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-pK28OcIX0Lhnx759 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-pK28OcIX0Lhnx759 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-pK28OcIX0Lhnx759 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-pK28OcIX0Lhnx759 .marker.cross{stroke:#333333;}#mermaid-svg-pK28OcIX0Lhnx759 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-pK28OcIX0Lhnx759 p{margin:0;}#mermaid-svg-pK28OcIX0Lhnx759 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-pK28OcIX0Lhnx759 .cluster-label text{fill:#333;}#mermaid-svg-pK28OcIX0Lhnx759 .cluster-label span{color:#333;}#mermaid-svg-pK28OcIX0Lhnx759 .cluster-label span p{background-color:transparent;}#mermaid-svg-pK28OcIX0Lhnx759 .label text,#mermaid-svg-pK28OcIX0Lhnx759 span{fill:#333;color:#333;}#mermaid-svg-pK28OcIX0Lhnx759 .node rect,#mermaid-svg-pK28OcIX0Lhnx759 .node circle,#mermaid-svg-pK28OcIX0Lhnx759 .node ellipse,#mermaid-svg-pK28OcIX0Lhnx759 .node polygon,#mermaid-svg-pK28OcIX0Lhnx759 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-pK28OcIX0Lhnx759 .rough-node .label text,#mermaid-svg-pK28OcIX0Lhnx759 .node .label text,#mermaid-svg-pK28OcIX0Lhnx759 .image-shape .label,#mermaid-svg-pK28OcIX0Lhnx759 .icon-shape .label{text-anchor:middle;}#mermaid-svg-pK28OcIX0Lhnx759 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-pK28OcIX0Lhnx759 .rough-node .label,#mermaid-svg-pK28OcIX0Lhnx759 .node .label,#mermaid-svg-pK28OcIX0Lhnx759 .image-shape .label,#mermaid-svg-pK28OcIX0Lhnx759 .icon-shape .label{text-align:center;}#mermaid-svg-pK28OcIX0Lhnx759 .node.clickable{cursor:pointer;}#mermaid-svg-pK28OcIX0Lhnx759 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-pK28OcIX0Lhnx759 .arrowheadPath{fill:#333333;}#mermaid-svg-pK28OcIX0Lhnx759 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-pK28OcIX0Lhnx759 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-pK28OcIX0Lhnx759 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-pK28OcIX0Lhnx759 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-pK28OcIX0Lhnx759 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-pK28OcIX0Lhnx759 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-pK28OcIX0Lhnx759 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-pK28OcIX0Lhnx759 .cluster text{fill:#333;}#mermaid-svg-pK28OcIX0Lhnx759 .cluster span{color:#333;}#mermaid-svg-pK28OcIX0Lhnx759 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-pK28OcIX0Lhnx759 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-pK28OcIX0Lhnx759 rect.text{fill:none;stroke-width:0;}#mermaid-svg-pK28OcIX0Lhnx759 .icon-shape,#mermaid-svg-pK28OcIX0Lhnx759 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-pK28OcIX0Lhnx759 .icon-shape p,#mermaid-svg-pK28OcIX0Lhnx759 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-pK28OcIX0Lhnx759 .icon-shape .label rect,#mermaid-svg-pK28OcIX0Lhnx759 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-pK28OcIX0Lhnx759 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-pK28OcIX0Lhnx759 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-pK28OcIX0Lhnx759 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 外部方波进入 PA6
输入滤波 IC1F
边沿检测 CC1P
输入映射 CC1S
捕获预分频 IC1PSC
有效上升沿
把 CNT 锁存到 CCR1
TI1FP1 作为 TRGI
从模式 Reset 将 CNT 清零
内部时钟
PSC 分频
CNT 按 fCNT 计数
软件读取 CCR1
频率 f = fCNT / N
这里最关键的关联是:同一个有效边沿产生两条并行硬件动作。
- 捕获通道把旧的
CNT锁存到CCR1,保留刚刚结束的周期长度。 - 触发控制器让从模式控制器复位
CNT,为下一个周期重新计数。
因此,不能把它理解成"先清零再读,所以 CCR1 永远是 0"。锁存与复位属于硬件事件链,捕获值会被保存下来。参考手册的输入捕获模式、PWM 输入模式和复位模式时序见 PDF 第 267~268、274~276 页。
3. 测频法与测周法:为什么输入捕获采用测周法

3.1 测频法:固定时间内数外部边沿
在闸门时间 T 内数到 N 个周期:
fx=NT f_x=\frac{N}{T} fx=TN
例:闸门打开 1 s,数到 1234 个周期:
fx=12341=1234 Hz f_x=\frac{1234}{1}=1234\text{ Hz} fx=11234=1234 Hz
计数可能有约 ±1 个周期的量化误差。测 1234 Hz 时相对误差约为 1/1234≈0.081%;测 2 Hz 时若 1 秒内只数到约 2 个,±1 就可能变成 ±50%,低频下很差。
3.2 测周法:一个周期内数标准时钟
输入捕获使用定时器内部计数时钟作为"尺子"。相邻两个同类边沿之间,CNT 走过 N 个计数:
Tx=N⋅1fCNT,fx=1Tx=fCNTN T_x=N\cdot\frac{1}{f_{CNT}},\qquad f_x=\frac{1}{T_x}=\frac{f_{CNT}}{N} Tx=N⋅fCNT1,fx=Tx1=NfCNT
本工程将 TIM3 配成:
fCNT=fTIMPSC+1=72 MHz71+1=1 MHz f_{CNT}=\frac{f_{TIM}}{PSC+1} =\frac{72\text{ MHz}}{71+1} =1\text{ MHz} fCNT=PSC+1fTIM=71+172 MHz=1 MHz
所以:
CNT每增加 1,经过1 μs;- 若捕获值所代表的周期计数
N=1000,则周期为1000 μs=1 ms; - 频率
f=1 MHz/1000=1 kHz。
测低频时,一个周期内能积累很多计数,分辨率高;测高频时,一个周期可能只有几个计数,误差会明显放大。例如:
| 被测频率 | fCNT=1 MHz 时的 N |
约 ±1 计数对应的相对量化误差 |
|---|---|---|
| 20 Hz | 50 000 | 0.002% |
| 1 kHz | 1 000 | 0.1% |
| 200 kHz | 5 | 20% |
3.3 中界频率怎么来
课堂按两种方法都存在 ±1 次计数误差来比较:
- 测频法的计数值:
N频 = fx·T - 测周法的计数值:
N周 = fc/fx
令两者相等:
fxT=fcfx⇒fx2=fcT⇒fm=fcT f_xT=\frac{f_c}{f_x} \Rightarrow f_x^2=\frac{f_c}{T} \Rightarrow \boxed{f_m=\sqrt{\frac{f_c}{T}}} fxT=fxfc⇒fx2=Tfc⇒fm=Tfc
若标准计数时钟 fc=1 MHz、闸门时间 T=1 s:
fm=106=1 kHz f_m=\sqrt{10^6}=1\text{ kHz} fm=106 =1 kHz
粗略选择是:低于 1 kHz 更适合测周法,高于 1 kHz 更适合测频法。实际边界还会受到滤波、同步延迟、时钟误差、信号质量和允许刷新时间影响。
课堂疑问:「还不是很理解,好好解释一下。」
最直观的判断是看"被数的东西够不够多":高频信号在固定 1 秒里周期很多,适合数周期;低频信号的单个周期很长,内部高速时钟能在这个周期里数很多下,适合测周期。
4. 输入捕获通道内部到底经过了什么

从 PA6 到 CCR1 不是一根直线,而是依次通过以下模块。
4.1 GPIO 与引脚复用:先确认信号能不能到 TIM3
数据手册 PDF 第 18 页的引脚复用表给出:PA6 的默认复用功能包含 TIM3_CH1。因此示例把外部信号接到 PA6,选择 TIM3 通道 1。
c
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_Init(GPIOA, &GPIO_InitStructure);
这里配置的是上拉输入,使引脚未被外部信号驱动时有确定的高电平。对于由 TIM2 的推挽输出直接驱动的测试线,上拉不是测量成立的必要条件。STM32F1 在输入模式下,GPIO_Speed 不决定输入采样速度,代码中的 50MHz 只是结构体成员被赋值。
硬件测试按接线图将 PA0(TIM2_CH1 PWM 输出) 与 PA6(TIM3_CH1 输入) 相连,并保证共地:

4.2 输入滤波器 IC1F:只承认持续足够久的电平
滤波器不是把波形"变平滑"的模拟滤波器,而是数字采样判决器:只有连续采样到规定次数的相同电平,才承认发生了稳定跳变。
c
TIM_ICInitStructure.TIM_ICFilter = 0xF;
IC1F=0xF 是很强的滤波配置。按 STM32F1 的 ICxF 表,它使用较低采样频率并要求连续 8 次一致才确认边沿。优点是抗毛刺,缺点是引入延迟,并可能直接滤掉高频或窄脉冲。
本例 CKD=DIV1、定时器内核时钟约 72 MHz 时,0xF 对应的采样频率约为 fDTS/32=2.25 MHz,8 次稳定采样约需 3.56 μs。因此它不是所有测频场景的通用默认值:信号干净或频率较高时应减小滤波,甚至使用 0x0。具体编码查参考手册 PDF 第 290 页 CCMR1 的 IC1F[3:0] 表。
4.3 边沿极性 CC1P:在什么时刻拍照
c
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
本例选择上升沿,因此相邻两次捕获之间正好是一个完整周期。若改成下降沿,仍可测完整周期;关键是两次捕获必须使用同类边沿。PWMI 则同时需要上升沿和下降沿,分别得到周期与高电平时间。
4.4 输入映射 CC1S:哪个 TI 信号送给哪个捕获单元
c
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
- 直连
DirectTI:IC1 接 TI1,设置CC1S=01。 - 交叉
IndirectTI:IC2 也可以接 TI1,设置对应的CC2S,让同一个引脚同时进入两个捕获单元。
这种"一个引脚,两条捕获路径"正是 PWMI 能同时测周期和高电平时间的基础。
4.5 捕获预分频 IC1PSC:每几个有效边沿捕获一次
c
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
DIV1 表示每个有效边沿都捕获。DIV2/DIV4/DIV8 表示每 2/4/8 个有效边沿才捕获一次,可拉长高频信号的测量区间、增加计数值。若一次捕获跨过 M 个周期,公式必须改成:
fx=M⋅fCNTN f_x=\frac{M\cdot f_{CNT}}{N} fx=NM⋅fCNT
4.6 捕获使能 CC1E、状态标志 CC1IF/CC1OF
TIM_ICInit() 最终还会使能通道,即 CCER.CC1E=1。有效边沿到来后:
CNT → CCR1;SR.CC1IF置 1,表示出现新捕获;- 若前一次捕获还未处理又发生新捕获,
SR.CC1OF可置 1,提示过捕获。
参考手册位置:输入捕获行为见 PDF 第 267 页,SR 见第 287 页,CCMR1 输入模式见第 290 页,CCER 见第 292 页,CCR1 见第 294 页。
5. 主从触发:为什么还要配置 TS 和 SMS

捕获只负责保存 CNT,不会天然把计数器清零。若 CNT 一直从 0 数到 65535 再回绕,后续每次 CCR1 得到的是"从上电开始的绝对时刻",而不是直接的周期长度。可以软件相减,但还要处理回绕;课堂示例选择硬件自动清零。
SMCR.TS:选择谁作为内部触发输入TRGI。TIM_TS_TI1FP1:选择经滤波、极性判断后的通道 1 信号。SMCR.SMS:选择触发到来后从模式控制器做什么。TIM_SlaveMode_Reset:触发到来时复位CNT。
c
TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
寄存器对应关系是 SMCR.TS=101 选择 TI1FP1,SMCR.SMS=100 选择复位模式。详细定义及复位时序见参考手册 PDF 第 284~285、274~276 页。
注意:教师把这部分统称为"主从触发模式",便于从整体结构理解;本例真正使用的是定时器自身的 触发输入选择 + 从模式复位。没有把 TIM3 的 TRGO 输出给另一个定时器,因此不必为了术语去额外配置主模式。
6. 单通道测频:一个周期内硬件发生了什么

6.1 逐步事件时间线
CPU 从模式控制器 TIM3_CCR1 TIM3_CNT 输入捕获 CH1 PA6/TI1 方波 CPU 从模式控制器 TIM3_CCR1 TIM3_CNT 输入捕获 CH1 PA6/TI1 方波 #mermaid-svg-a2NVesXpCzZGW8uu{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-a2NVesXpCzZGW8uu .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-a2NVesXpCzZGW8uu .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-a2NVesXpCzZGW8uu .error-icon{fill:#552222;}#mermaid-svg-a2NVesXpCzZGW8uu .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-a2NVesXpCzZGW8uu .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-a2NVesXpCzZGW8uu .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-a2NVesXpCzZGW8uu .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-a2NVesXpCzZGW8uu .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-a2NVesXpCzZGW8uu .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-a2NVesXpCzZGW8uu .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-a2NVesXpCzZGW8uu .marker{fill:#333333;stroke:#333333;}#mermaid-svg-a2NVesXpCzZGW8uu .marker.cross{stroke:#333333;}#mermaid-svg-a2NVesXpCzZGW8uu svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-a2NVesXpCzZGW8uu p{margin:0;}#mermaid-svg-a2NVesXpCzZGW8uu .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-a2NVesXpCzZGW8uu text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-a2NVesXpCzZGW8uu .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-a2NVesXpCzZGW8uu .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-a2NVesXpCzZGW8uu .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-a2NVesXpCzZGW8uu .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-a2NVesXpCzZGW8uu #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-a2NVesXpCzZGW8uu .sequenceNumber{fill:white;}#mermaid-svg-a2NVesXpCzZGW8uu #sequencenumber{fill:#333;}#mermaid-svg-a2NVesXpCzZGW8uu #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-a2NVesXpCzZGW8uu .messageText{fill:#333;stroke:none;}#mermaid-svg-a2NVesXpCzZGW8uu .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-a2NVesXpCzZGW8uu .labelText,#mermaid-svg-a2NVesXpCzZGW8uu .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-a2NVesXpCzZGW8uu .loopText,#mermaid-svg-a2NVesXpCzZGW8uu .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-a2NVesXpCzZGW8uu .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-a2NVesXpCzZGW8uu .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-a2NVesXpCzZGW8uu .noteText,#mermaid-svg-a2NVesXpCzZGW8uu .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-a2NVesXpCzZGW8uu .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-a2NVesXpCzZGW8uu .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-a2NVesXpCzZGW8uu .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-a2NVesXpCzZGW8uu .actorPopupMenu{position:absolute;}#mermaid-svg-a2NVesXpCzZGW8uu .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-a2NVesXpCzZGW8uu .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-a2NVesXpCzZGW8uu .actor-man circle,#mermaid-svg-a2NVesXpCzZGW8uu line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-a2NVesXpCzZGW8uu :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 以 1 MHz 计数,1 count = 1 us f = fCNT / N 第一个上升沿锁存当前 CNTTI1FP1 产生 TRGIReset,CNT=0对下一个周期持续计数第二个上升沿锁存周期计数 N再次产生 TRGIReset,CNT=0读取最近一次 N
课堂疑问:「把这个思路逻辑好好给我讲解一下,逐步讲解」
可以把配置拆成三条线:① 用
PSC先造出已知刻度的秒表;② 用CCMR1+CCER决定哪个边沿给秒表拍照;③ 用SMCR让同一个边沿在拍照后把秒表归零。最后CCR1保存的才是一个周期所跨过的刻度数。
6.2 为什么通道 1/2 更适合自动测周期
复位模式可直接选择 TI1FP1 或 TI2FP2 作为触发源,因此课堂用 CH1。CH3/CH4 也能做输入捕获,但不能按这套路径直接作为相同的复位触发源;通常需要软件相减、另一触发路径或组合定时器方案。
6.3 量程怎么算
本例 ARR=65535,16 位 CNT 最长能表示约:
Tmax=ARR+1fCNT=655361 MHz=65.536 ms T_{max}=\frac{ARR+1}{f_{CNT}} =\frac{65536}{1\text{ MHz}} =65.536\text{ ms} Tmax=fCNTARR+1=1 MHz65536=65.536 ms
不处理溢出时,最低可测频率约:
fmin≈165.536 ms=15.26 Hz f_{min}\approx\frac{1}{65.536\text{ ms}}=15.26\text{ Hz} fmin≈65.536 ms1=15.26 Hz
若要测更低频率,可增大 PSC 降低 fCNT,或统计溢出次数。降低 fCNT 会牺牲高频分辨率,这就是量程与精度之间的权衡。
7. PWMI:为什么一个引脚能同时得到频率和占空比

PWMI 把同一个 TI1 输入交叉送入两个捕获单元:
| 捕获单元 | 输入路径 | 捕获边沿 | 保存内容 | 是否触发 CNT 复位 |
|---|---|---|---|---|
| CH1 / CCR1 | TI1 直连 | 上升沿 | 完整周期计数 Nperiod |
是 |
| CH2 / CCR2 | TI1 交叉 | 下降沿 | 从上升沿到下降沿的高电平计数 Nhigh |
否 |
#mermaid-svg-bLBQWiHo8CMdtm9A{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-bLBQWiHo8CMdtm9A .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-bLBQWiHo8CMdtm9A .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-bLBQWiHo8CMdtm9A .error-icon{fill:#552222;}#mermaid-svg-bLBQWiHo8CMdtm9A .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-bLBQWiHo8CMdtm9A .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-bLBQWiHo8CMdtm9A .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-bLBQWiHo8CMdtm9A .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-bLBQWiHo8CMdtm9A .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-bLBQWiHo8CMdtm9A .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-bLBQWiHo8CMdtm9A .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-bLBQWiHo8CMdtm9A .marker{fill:#333333;stroke:#333333;}#mermaid-svg-bLBQWiHo8CMdtm9A .marker.cross{stroke:#333333;}#mermaid-svg-bLBQWiHo8CMdtm9A svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-bLBQWiHo8CMdtm9A p{margin:0;}#mermaid-svg-bLBQWiHo8CMdtm9A .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-bLBQWiHo8CMdtm9A .cluster-label text{fill:#333;}#mermaid-svg-bLBQWiHo8CMdtm9A .cluster-label span{color:#333;}#mermaid-svg-bLBQWiHo8CMdtm9A .cluster-label span p{background-color:transparent;}#mermaid-svg-bLBQWiHo8CMdtm9A .label text,#mermaid-svg-bLBQWiHo8CMdtm9A span{fill:#333;color:#333;}#mermaid-svg-bLBQWiHo8CMdtm9A .node rect,#mermaid-svg-bLBQWiHo8CMdtm9A .node circle,#mermaid-svg-bLBQWiHo8CMdtm9A .node ellipse,#mermaid-svg-bLBQWiHo8CMdtm9A .node polygon,#mermaid-svg-bLBQWiHo8CMdtm9A .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-bLBQWiHo8CMdtm9A .rough-node .label text,#mermaid-svg-bLBQWiHo8CMdtm9A .node .label text,#mermaid-svg-bLBQWiHo8CMdtm9A .image-shape .label,#mermaid-svg-bLBQWiHo8CMdtm9A .icon-shape .label{text-anchor:middle;}#mermaid-svg-bLBQWiHo8CMdtm9A .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-bLBQWiHo8CMdtm9A .rough-node .label,#mermaid-svg-bLBQWiHo8CMdtm9A .node .label,#mermaid-svg-bLBQWiHo8CMdtm9A .image-shape .label,#mermaid-svg-bLBQWiHo8CMdtm9A .icon-shape .label{text-align:center;}#mermaid-svg-bLBQWiHo8CMdtm9A .node.clickable{cursor:pointer;}#mermaid-svg-bLBQWiHo8CMdtm9A .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-bLBQWiHo8CMdtm9A .arrowheadPath{fill:#333333;}#mermaid-svg-bLBQWiHo8CMdtm9A .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-bLBQWiHo8CMdtm9A .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-bLBQWiHo8CMdtm9A .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-bLBQWiHo8CMdtm9A .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-bLBQWiHo8CMdtm9A .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-bLBQWiHo8CMdtm9A .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-bLBQWiHo8CMdtm9A .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-bLBQWiHo8CMdtm9A .cluster text{fill:#333;}#mermaid-svg-bLBQWiHo8CMdtm9A .cluster span{color:#333;}#mermaid-svg-bLBQWiHo8CMdtm9A div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-bLBQWiHo8CMdtm9A .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-bLBQWiHo8CMdtm9A rect.text{fill:none;stroke-width:0;}#mermaid-svg-bLBQWiHo8CMdtm9A .icon-shape,#mermaid-svg-bLBQWiHo8CMdtm9A .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-bLBQWiHo8CMdtm9A .icon-shape p,#mermaid-svg-bLBQWiHo8CMdtm9A .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-bLBQWiHo8CMdtm9A .icon-shape .label rect,#mermaid-svg-bLBQWiHo8CMdtm9A .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-bLBQWiHo8CMdtm9A .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-bLBQWiHo8CMdtm9A .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-bLBQWiHo8CMdtm9A :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} PA6 / TI1
滤波与边沿检测
CH1 直连 上升沿
CH2 交叉 下降沿
CCR1 = 周期计数
TRGI 复位 CNT
CCR2 = 高电平计数
频率 = fCNT / CCR1
占空比 = CCR2 / CCR1
为什么下降沿不能复位?因为若下降沿也把 CNT 清零,那么下一次上升沿前只计到了低电平时间,CCR1 就不再代表完整周期。正确做法是只用周期基准边沿(这里是上升沿)清零,下降沿只拍照。
7.1 计算示例:2 kHz、30% 占空比
已知 fCNT=1 MHz:
T=12000=500 μs T=\frac{1}{2000}=500\ \mu s T=20001=500 μs
因此周期捕获约为 Nperiod=500。高电平时间:
tH=30%×500 μs=150 μs t_H=30\%\times500\ \mu s=150\ \mu s tH=30%×500 μs=150 μs
因此 Nhigh=150。反算:
f=1 000 000500=2000 Hz f=\frac{1\,000\,000}{500}=2000\text{ Hz} f=5001000000=2000 Hz
Duty=150500×100%=30% Duty=\frac{150}{500}\times100\%=30\% Duty=500150×100%=30%
TIM_PWMIConfig() 的意义,就是根据主通道的直连、极性等设置,自动把配对通道设置成相反极性和交叉输入。它不是一种新的计数器,而是帮我们一次配好两条输入捕获路径。参考手册 PWM 输入模式见 PDF 第 267~268 页。
8. 每个关键寄存器的作用与前后关联
| 配置目标 | 寄存器/位 | 标准库调用 | 它解决的问题 | 与下一步的联系 |
|---|---|---|---|---|
| 开启 TIM3 时钟 | RCC_APB1ENR.TIM3EN |
RCC_APB1PeriphClockCmd |
外设先获得工作时钟 | TIM3 寄存器配置才能生效 |
| 开启 GPIOA 时钟 | RCC_APB2ENR.IOPAEN |
RCC_APB2PeriphClockCmd |
PA6 端口获得时钟 | 输入信号才能进入片内 |
| 配置 PA6 输入 | GPIOA_CRL 中 CNF/MODE6 |
GPIO_Init |
设置上拉输入 | PA6 对应 TIM3_CH1 |
| 设定计数刻度 | TIM3_PSC |
TIM_TimeBaseInit |
把 72 MHz 分到 1 MHz | 决定公式中的 fCNT |
| 设定最大量程 | TIM3_ARR |
TIM_TimeBaseInit |
决定 CNT 回绕点 | 决定无溢出处理时的最低频率 |
| 设置滤波时钟 | TIM3_CR1.CKD |
TIM_TimeBaseInit |
影响 fDTS |
与 IC1F 一起决定滤波响应 |
| 选择输入和滤波 | TIM3_CCMR1.CC1S/IC1F |
TIM_ICInit |
让 IC1 接 TI1 并过滤毛刺 | 输出 TI1FP1 给边沿/触发链 |
| 捕获预分频 | TIM3_CCMR1.IC1PSC |
TIM_ICInit |
每 1/2/4/8 个边沿捕获 | 决定一次 N 跨几个周期 |
| 极性和通道使能 | TIM3_CCER.CC1P/CC1E |
TIM_ICInit |
选上升沿并开启捕获 | 有效边沿可锁存 CCR1 |
| 选择触发源 | TIM3_SMCR.TS |
TIM_SelectInputTrigger |
让 TI1FP1 成为 TRGI | 触发信号送入从模式控制器 |
| 选择复位动作 | TIM3_SMCR.SMS |
TIM_SelectSlaveMode |
每个基准边沿后清 CNT | 下一周期重新从 0 计数 |
| 开始计数 | TIM3_CR1.CEN |
TIM_Cmd |
启动 CNT | 等待输入边沿并持续捕获 |
| 保存测量结果 | TIM3_CCR1/CCR2 |
TIM_GetCapture1/2 |
保存周期/高电平计数 | 软件代入频率和占空比公式 |
| 通知软件 | TIM3_SR.CC1IF/CC1OF |
标志位/中断接口 | 新数据有效、是否过捕获 | 可做有效性判断或中断处理 |
可以把这些寄存器分成四组来记:
- 时钟与时间尺:RCC、PSC、ARR、CNT。
- 输入边沿加工:CCMR1、CCER。
- 自动联动:SMCR。
- 结果与状态:CCR1/CCR2、SR。
9. 对照源码:为什么按这个顺序配置
9.1 示例 6-6:输入捕获测频率
c
void IC_Init(void)
{
/* 1. 外设和引脚先有时钟 */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/* 2. 信号入口:PA6 = TIM3_CH1 */
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);
/* 3. 建立时间尺:72 MHz / 72 = 1 MHz */
TIM_InternalClockConfig(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;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
/* 4. 定义什么边沿算一次有效捕获 */
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);
/* 5. 让同一个上升沿自动复位 CNT */
TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
/* 6. 所有参数就绪后再启动 */
TIM_Cmd(TIM3, ENABLE);
}
这个顺序的因果链是:先通电 → 接通信号入口 → 做出时间尺 → 定义拍照条件 → 定义拍照后的自动动作 → 最后开跑。仿制其他输入捕获项目时按这六问逐项替换即可。
c
uint32_t IC_GetFreq(void)
{
return 1000000 / (TIM_GetCapture1(TIM3) + 1);
}
1000000来自fCNT=1 MHz,不是固定魔法数。改 PSC 后必须同步改公式。TIM_GetCapture1()读取CCR1。- 课程源码使用
CCR1+1,注释也说明不加通常可以。这里涉及计数从 0 开始及具体事件时序的约定;工程中应明确N是 CCR 还是 CCR+1,并用示波器/已知信号校准,不要把+1当成所有芯片、所有模式都必须套用的规则。 - 大多数周期计数很大时,差 1 影响很小;高频、N 很小时影响会明显。
9.2 测试信号为什么是 1 kHz、50%
TIM2 PWM 参数:ARR=100-1、PSC=720-1、CCR1=50。
fPWM=72 MHz720×100=1000 Hz f_{PWM}=\frac{72\text{ MHz}}{720\times100}=1000\text{ Hz} fPWM=720×10072 MHz=1000 Hz
Duty=50100×100%=50% Duty=\frac{50}{100}\times100\%=50\% Duty=10050×100%=50%
把 PA0 接到 PA6 后,TIM3 理论上读到周期约 1000 个 1 μs 计数,因此显示约 1000 Hz。
9.3 示例 6-7:PWMI 只改了哪里
c
TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);
它代替单通道的 TIM_ICInit(),同时配置 CH1 和配对的 CH2:CH1 捕获上升沿周期,CH2 捕获下降沿高电平时间。触发源仍选 TI1FP1,复位模式仍只由上升沿控制。
c
uint32_t IC_GetDuty(void)
{
return (TIM_GetCapture2(TIM3) + 1) * 100
/ (TIM_GetCapture1(TIM3) + 1);
}
分子是高电平计数,分母是周期计数。若扩展到更大计数范围,乘 100 前可先转为 uint64_t,避免 32 位乘法溢出。
10. 照着写容易忽略的 7 个问题
10.1 刚启动时还没有有效捕获
课程代码直接读取 CCR。上电后 CCR1 可能仍为 0,此时 +1 虽避免除零,却可能暂时显示 1 MHz 这一无效结果。更稳妥的实现应先等待 CC1IF,或在中断中设置"已有有效样本"标志。
10.2 计数器可能溢出
低于约 15.26 Hz 时,本例 1 MHz/16 位配置会在一个周期内回绕。要么降低计数时钟,要么统计更新溢出次数,再组合成更宽的周期计数。
10.3 ICFilter=0xF 可能过强
毛刺多时强滤波有用,高频或窄脉冲时可能测不到。滤波值应根据信号最短高/低电平时间选择,而不是固定复制 0xF。
10.4 高频不等于一定能测准
即使滤波器放行,高频周期只对应几个 CNT 计数,整数分辨率很差。可提高 fCNT、使用捕获预分频跨多个周期测量,或改用固定闸门测频法。
10.5 整数除法会截断
1000000/N 只保留整数 Hz。需要小数时可保留定点小数,例如先算 10000000/N,再把结果解释为 0.1 Hz;同时注意乘法溢出。
10.6 CC1OF 能暴露"软件跟不上"
新捕获覆盖旧捕获而软件尚未处理时会出现过捕获标志。轮询显示的演示程序只关心最新值,因此未处理;需要每个周期数据的正式项目应检查 CC1OF、用中断/DMA,并评估处理吞吐量。
10.7 输入电气条件必须正确
PA6 需要合法的数字电平并与信号源共地。本实验是板内 3.3 V PWM 直连;外部 5 V、负电压、缓慢模拟波形或强干扰信号不能不加判断地直连,应根据数据手册和电路增加限流、分压、电平转换、施密特整形、比较器或隔离。
11. 从需求反推配置:以后复现时的固定思路
#mermaid-svg-elT3BwyPz0OHTuSh{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-elT3BwyPz0OHTuSh .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-elT3BwyPz0OHTuSh .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-elT3BwyPz0OHTuSh .error-icon{fill:#552222;}#mermaid-svg-elT3BwyPz0OHTuSh .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-elT3BwyPz0OHTuSh .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-elT3BwyPz0OHTuSh .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-elT3BwyPz0OHTuSh .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-elT3BwyPz0OHTuSh .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-elT3BwyPz0OHTuSh .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-elT3BwyPz0OHTuSh .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-elT3BwyPz0OHTuSh .marker{fill:#333333;stroke:#333333;}#mermaid-svg-elT3BwyPz0OHTuSh .marker.cross{stroke:#333333;}#mermaid-svg-elT3BwyPz0OHTuSh svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-elT3BwyPz0OHTuSh p{margin:0;}#mermaid-svg-elT3BwyPz0OHTuSh .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-elT3BwyPz0OHTuSh .cluster-label text{fill:#333;}#mermaid-svg-elT3BwyPz0OHTuSh .cluster-label span{color:#333;}#mermaid-svg-elT3BwyPz0OHTuSh .cluster-label span p{background-color:transparent;}#mermaid-svg-elT3BwyPz0OHTuSh .label text,#mermaid-svg-elT3BwyPz0OHTuSh span{fill:#333;color:#333;}#mermaid-svg-elT3BwyPz0OHTuSh .node rect,#mermaid-svg-elT3BwyPz0OHTuSh .node circle,#mermaid-svg-elT3BwyPz0OHTuSh .node ellipse,#mermaid-svg-elT3BwyPz0OHTuSh .node polygon,#mermaid-svg-elT3BwyPz0OHTuSh .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-elT3BwyPz0OHTuSh .rough-node .label text,#mermaid-svg-elT3BwyPz0OHTuSh .node .label text,#mermaid-svg-elT3BwyPz0OHTuSh .image-shape .label,#mermaid-svg-elT3BwyPz0OHTuSh .icon-shape .label{text-anchor:middle;}#mermaid-svg-elT3BwyPz0OHTuSh .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-elT3BwyPz0OHTuSh .rough-node .label,#mermaid-svg-elT3BwyPz0OHTuSh .node .label,#mermaid-svg-elT3BwyPz0OHTuSh .image-shape .label,#mermaid-svg-elT3BwyPz0OHTuSh .icon-shape .label{text-align:center;}#mermaid-svg-elT3BwyPz0OHTuSh .node.clickable{cursor:pointer;}#mermaid-svg-elT3BwyPz0OHTuSh .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-elT3BwyPz0OHTuSh .arrowheadPath{fill:#333333;}#mermaid-svg-elT3BwyPz0OHTuSh .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-elT3BwyPz0OHTuSh .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-elT3BwyPz0OHTuSh .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-elT3BwyPz0OHTuSh .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-elT3BwyPz0OHTuSh .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-elT3BwyPz0OHTuSh .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-elT3BwyPz0OHTuSh .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-elT3BwyPz0OHTuSh .cluster text{fill:#333;}#mermaid-svg-elT3BwyPz0OHTuSh .cluster span{color:#333;}#mermaid-svg-elT3BwyPz0OHTuSh div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-elT3BwyPz0OHTuSh .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-elT3BwyPz0OHTuSh rect.text{fill:none;stroke-width:0;}#mermaid-svg-elT3BwyPz0OHTuSh .icon-shape,#mermaid-svg-elT3BwyPz0OHTuSh .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-elT3BwyPz0OHTuSh .icon-shape p,#mermaid-svg-elT3BwyPz0OHTuSh .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-elT3BwyPz0OHTuSh .icon-shape .label rect,#mermaid-svg-elT3BwyPz0OHTuSh .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-elT3BwyPz0OHTuSh .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-elT3BwyPz0OHTuSh .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-elT3BwyPz0OHTuSh :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 1 明确测频率还是频率+占空比
2 查数据手册选 TIMx_CH1/CH2 引脚
3 估算频率范围与所需分辨率
4 选择 fCNT 并计算 PSC
5 用 ARR 检查最低频率是否溢出
6 选择直连/交叉、极性、滤波、捕获分频
7 选择 TI1FP1/TI2FP2 为 TRGI
8 选择 Reset 从模式
9 读取 CCR 并按统一 N 约定计算
10 用已知信号和示波器校验
动手前回答下面十个问题,代码就不会只剩"背函数":
- 被测信号的频率、占空比、电压范围是什么?
- 数据手册中哪个引脚是目标
TIMx_CH1/CH2?是否重映射? - 选择测频法还是测周法?为什么?
fTIM到底是多少?APB 分频是否使定时器时钟倍频?- 希望一个 CNT 代表多长时间?据此
PSC是多少? - 一个最慢周期是否小于
(ARR+1)/fCNT? - 捕获上升沿还是下降沿?每几个边沿捕获一次?
- 滤波参数会不会滤掉最窄脉冲?
- 哪个边沿作为复位基准?CCR1、CCR2 各表示什么?
- 启动未捕获、溢出、过捕获和整数精度怎么处理?
12. 最小验证步骤
- 先用 TIM2 在 PA0 输出已知的 1 kHz、50% PWM。
- 用导线把 PA0 接到 PA6,并确保共地。
- 单通道 IC 先只看频率,预期约 1000 Hz。
- 改 PWM 的 PSC,确认显示频率按公式变化。
- 换 PWMI,保持频率不变并修改 CCR,确认占空比跟随变化。
- 用示波器测 PA0 的真实频率/占空比,与 OLED 比较。
- 提高频率或缩短脉宽,分别尝试
ICFilter=0xF与较小值,观察何时开始漏捕获。 - 降低到 15 Hz 左右,观察 16 位 CNT 溢出边界,验证量程计算。
13. 本节记忆卡片
- 输入捕获:边沿到来,
CNT → CCRx。 - 测周法:
f = fCNT/N。 - 计数时钟:
fCNT = fTIM/(PSC+1)。 - 最大无溢出周期:
Tmax=(ARR+1)/fCNT。 - 直连通道决定周期边沿;交叉通道可测另一极性的脉宽。
- PWMI:
CCR1≈周期,CCR2≈高电平时间,Duty=CCR2/CCR1。 CCMR1管输入映射、滤波和捕获分频;CCER管极性和使能。SMCR.TS选触发源,SMCR.SMS决定触发后怎样控制 CNT。SR.CCxIF表示新捕获,CCxOF表示可能丢过数据。- 真正复现时先算量程和精度,再写初始化函数。
14. 勘误与补充说明
- 课程源码中的
+1可用于它采用的计数约定,但不是脱离具体定时器时序后仍无条件成立的公式。应统一N的定义并实测校准。 GPIO_Speed=50MHz对 STM32F1 的输入模式不决定输入带宽;输入性能还由 I/O 电气特性、定时器同步与数字滤波决定。ICFilter=0xF强调抗毛刺,但会限制可接受的窄脉冲,不能把"滤波越强越好"当作原则。- 课程轮询读取最新 CCR 适合演示;正式测量建议加入有效样本、超时、溢出、过捕获和异常输入处理。