TIM 输入捕获与 PWMI:从边沿到频率、占空比

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

这里最关键的关联是:同一个有效边沿产生两条并行硬件动作

  1. 捕获通道把旧的 CNT 锁存到 CCR1,保留刚刚结束的周期长度。
  2. 触发控制器让从模式控制器复位 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 页 CCMR1IC1F[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。有效边沿到来后:

  1. CNT → CCR1
  2. SR.CC1IF 置 1,表示出现新捕获;
  3. 若前一次捕获还未处理又发生新捕获,SR.CC1OF 可置 1,提示过捕获。

参考手册位置:输入捕获行为见 PDF 第 267 页,SR 见第 287 页,CCMR1 输入模式见第 290 页,CCER 见第 292 页,CCR1 见第 294 页。


5. 主从触发:为什么还要配置 TSSMS

捕获只负责保存 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 选择 TI1FP1SMCR.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 更适合自动测周期

复位模式可直接选择 TI1FP1TI2FP2 作为触发源,因此课堂用 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 标志位/中断接口 新数据有效、是否过捕获 可做有效性判断或中断处理

可以把这些寄存器分成四组来记:

  1. 时钟与时间尺:RCC、PSC、ARR、CNT。
  2. 输入边沿加工:CCMR1、CCER。
  3. 自动联动:SMCR。
  4. 结果与状态: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-1PSC=720-1CCR1=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 用已知信号和示波器校验

动手前回答下面十个问题,代码就不会只剩"背函数":

  1. 被测信号的频率、占空比、电压范围是什么?
  2. 数据手册中哪个引脚是目标 TIMx_CH1/CH2?是否重映射?
  3. 选择测频法还是测周法?为什么?
  4. fTIM 到底是多少?APB 分频是否使定时器时钟倍频?
  5. 希望一个 CNT 代表多长时间?据此 PSC 是多少?
  6. 一个最慢周期是否小于 (ARR+1)/fCNT
  7. 捕获上升沿还是下降沿?每几个边沿捕获一次?
  8. 滤波参数会不会滤掉最窄脉冲?
  9. 哪个边沿作为复位基准?CCR1、CCR2 各表示什么?
  10. 启动未捕获、溢出、过捕获和整数精度怎么处理?

12. 最小验证步骤

  1. 先用 TIM2 在 PA0 输出已知的 1 kHz、50% PWM。
  2. 用导线把 PA0 接到 PA6,并确保共地。
  3. 单通道 IC 先只看频率,预期约 1000 Hz。
  4. 改 PWM 的 PSC,确认显示频率按公式变化。
  5. 换 PWMI,保持频率不变并修改 CCR,确认占空比跟随变化。
  6. 用示波器测 PA0 的真实频率/占空比,与 OLED 比较。
  7. 提高频率或缩短脉宽,分别尝试 ICFilter=0xF 与较小值,观察何时开始漏捕获。
  8. 降低到 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. 课程源码中的 +1 可用于它采用的计数约定,但不是脱离具体定时器时序后仍无条件成立的公式。应统一 N 的定义并实测校准。
  2. GPIO_Speed=50MHz 对 STM32F1 的输入模式不决定输入带宽;输入性能还由 I/O 电气特性、定时器同步与数字滤波决定。
  3. ICFilter=0xF 强调抗毛刺,但会限制可接受的窄脉冲,不能把"滤波越强越好"当作原则。
  4. 课程轮询读取最新 CCR 适合演示;正式测量建议加入有效样本、超时、溢出、过捕获和异常输入处理。
相关推荐
知产xiao_xin40 分钟前
知识产权入门 —— 工业品外观设计
经验分享·笔记·知识产权
2601_949950631 小时前
考研英语资料太散?用小程序把真题、词汇和错题放到一起
人工智能·学习·考研·小程序·刷题·小程序推荐
小猪code1 小时前
frp 80/443 Web 服务两种部署模式实操笔记
前端·笔记
熊猫钓鱼>_>1 小时前
鸿蒙AI Agent新范式:从“对话式辅助”到“工程化代理”的Harness架构实战解析
人工智能·笔记·学习·华为·架构·harmonyos
GGMM7891 小时前
西门子 AAOP 亚洲高级操作面板详解(MM420/MM440 专用)
笔记·变频器·变频器维修
GGMM7891 小时前
西门子 IOP 智能操作面板详细使用教程(G120/G120C)
笔记·变频器·变频器维修
2501_919749031 小时前
华为鸿蒙管理学习生活与工作APP—小羊管理
学习·华为·生活·harmonyos·鸿蒙
单片机仿真设计2 小时前
【proteus仿真】基于 STM32 的久坐提醒与坐姿矫正器设计(仿真图+程序)
stm32·单片机·嵌入式硬件·proteus·毕设
一条破秋裤2 小时前
STM32 学习笔记:PWM 输出比较原理与计算
笔记·stm32·学习