目录
一、 外部时钟模式1 (External Clock Mode 1)
二、 外部时钟模式2 (External Clock Mode 2)
#TIM输入捕获#
输入捕获简介
- IC(Input Capture)输入捕获
- 输入捕获模式下,当通道输入引脚出现指定电平跳变(上升沿/下降沿)时,当前CNT的值将被锁存到CCR中(将当前CNT的值读出来写道CCR中),可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数
- 每个高级定时器和通用定时器都拥有4个输入捕获通道
- 可配置为PWMI模式(PWM输入模式,专门测量PWM频率和占空比),同时测量频率和占空比
- 可配合主从触发模式,实现硬件全自动测量
- 结合PWMI模式和主从触发模式,测量频率占空比就是硬件全自动执行,需要测量时,直接读取CCR寄存器即可
- 由于输入捕获的CH1~CH4四个通道引脚和CCR寄存器与输出比较通道共用,同一个定时器只能使用其中一个
输入捕获IC电路(四个通道)原理图中的位置👇
工作流程:
四个通道引脚(CH1~CH4)→三输入异或门(执行逻辑是当三个输入引脚的任何一个有电平翻转时,输出引脚就产生一次电平翻转),输入接在输入引脚123端口→数据选择器(往①走TIx为三个引脚异或值,往②走TIx为各个引脚的值)→输入滤波器(俩套)(对信号进行滤波,避免一些高频毛刺信号误触发)和边沿检测器(与外部中断一样,选择高/低电平触发,出现指定电平,边沿检测电路就会触发后续电路执行工作)(①一个滤波和极性选择得到TIxFP1-TIx Filter Polarity 1输入给通道1(IC1)的后续电路②另一个滤波和极性选择得到TIxFP2-Tix Filter Polarity 2输入给通道2(IC2)的后续电路)(TRC引脚也可作为捕获部分的输入,来源于外部时钟1)→(俩个通道的信号可以交叉-CH1引脚输入给通道2(IC2),CH2引脚输入给通道1(IC1)(目的:①灵活切换后续捕获电路的输入②一个引脚的输入同时映射到俩个捕获单元)TI1FP1上升沿触发,用来捕获周期;TI1FP1下降沿触发,用来捕获占空比,俩个通道同时对一个引脚进行捕获,就可以同时测量占空比和周期——PWMI模式)预分频器(对前面信号进行分频,触发捕获电路进行工作)→捕获/比较寄存器(来一个触发信号,CNT值向CCR转运一次,同时发生一个捕获事件,并在状态寄存器ICxPS置标志位和产生中断,如果需要在捕获的瞬间处理一些事情的话,就可以开启这个捕获中断。)
频率测量
图上是只有高低电平的数字信号,STM32只能测高电平3.3v,低电平0v的数字信号的频
若需要测量一个正弦波,加一个信号预处理电路(eg.运放搭一个比较器),将正弦波转换为数字信号,再输入给STM32;若测量信号的电压非常高,考虑用隔离放大器、电压互感器等元件,隔离高电压和低压端,保证电路安全
- 测频法(高频信号):在闸门时间T内,对上升沿计次,得到N(越大误差越小),则频率
测量这一块信号的频率,就可以制定一个闸门时间T,通常设置为一秒。
在一秒时间内对信号上升沿计次,从零开始计,每来一个上升沿计次加一,每来一个上升沿,其实就是来了一个周期的信号。所以在一秒时间内来了多少个周期,它的频率就是多少Hz,这符合频率的基本定义。频率的定义就是一秒内出现了多少个重复的周期。频率就是多少Hz。
测量结果更新慢,结果是一段时间的平均值,值比较平滑,会出现正负1误差(一个T内,测量的N不完整)
- 测周法(低频信号):两个上升沿内,以标准频率fc计次,得到N ,则频率
测量时间的方法,实际上也是定时器计次,我们使用一个已知的标准频率fc的计次时钟来驱动计数器,从一个上升沿开始,从零开始一直计到下一个上升沿停止,计一个数的时间是1/fc,计N个数时间就是N/fc,N/fc就是周期,频率就是再取个倒数就得到了公式fx等于fc除以N。
测量结果更新快,只测量一个周期,就能出结果,但结果值会受噪声影响,波动比较大,会出现正负1误差(fc计次记到一半停止)
- 中界频率(判断高低电频信号):测频法与测周法误差相等的频率点(N相同时误差相同,N越大,正负1误差越小)
当待测信号频率小于中界频率时,测周法误差更小,选用测周法更合适。
当待测信号频率大于中界频率时,测频法误差更小,选用测频法更合适。
用STM实现俩种测频率方法:
①测频法:对射式红外传感器计次(每来一个上升沿计次+1)+定时器外部时钟(定一个1s的定时中断,在中断里,每隔1s取一下计次值,同时清0计次,为下一次做准备)=计数器读取的计次值为频率
②测周法:配置上升沿触发捕获,每来一个上升沿,CNT转运到CCR一次,由于CNT计数器由内部标准时钟驱动,即CNT的数值可以用来记录俩个上升沿之间的时间间隔(周期),取倒数为频率
(上升沿用于触发输入捕获,CNT用于计数计时,每来一个上升沿取下CNT的值自动存在CCR里,CCR捕获到的值就是计数值N。CNT的驱动时钟就是fc,fc/N就得到了待测信号的频率)
(每次捕获之后,CNT清零,下一次上升沿触发就是俩个上升沿之间的时间间隔;再一次捕获将CNT清零的步骤——主从触发模式自动完成)
测频法:定时器中断,并记录捕获次数;
测周法:捕获中断,并记录定时器次数。
输入捕获通道
TIMx_CCMR1中CC1E位:输入/捕获1输出使能 (Capture/Compare 1 output enable)
CC1通道配置为输出:
0: 关闭- OC1禁止输出。
1: 开启- OC1信号输出到对应的输出引脚。
CC1通道配置为输入:
该位决定了计数器的值是否能捕获入TIMx_CCR1寄存器。
0:捕获禁止;
1:捕获使能。
更详细的电路流程图:
1.输入信号源选择 (TI1, TI2):
TI1F (Filtered Timer Input 1): 这是通道1的主输入信号,通常直接连接到芯片的某个GPIO引脚(例如PA0对应TIM2_CH1, TIM5_CH1等)。这个信号直接来自外部世界(如PWM信号、编码器信号)。
TI2F (Filtered Timer Input 2): 这是通道2的主输入信号。它也能被路由到通道1的捕获路径上。
通过配置寄存器TIMx_CCMR1捕获模式寄存器1的位CC1S[1:0](Capture/Compare 1 Selection),可以选择通道1的捕获信号源(TI1或者TI2):
- 00: 禁止捕获(通道配置为输出)
- 01: 映射到TI1 (即TI1FP1或TI1FP2路径)
- 10: 映射到TI2 (即TI2FP1或TI2FP2路径)
- 11: 保留
2.边沿极性选择与检测器:
CC1P, CC1NP (Capture/Compare 1 Output Polarity, 输入捕获模式下实际控制输入极性): 这两个位位于控制寄存TIMx_CCER捕获使能寄存器 (Capture/Compare Enable Register) 中。在输入捕获模式下:
CC1P: 控制TI1FP1和TI2FP1的有效边沿极性。(CC1通道配置输入)
- 0: 不反相,上升沿有效。
- 1: 反相,下降沿有效。
CC1NP: 控制TI1FP2和TI2FP2的有效边沿极性(主要用于PWM输入模式或双边沿捕获的特殊配置)。
- 通俗讲: 这个选择器决定“通道1的耳朵”是听自己专用的引脚(TI1),还是去听隔壁通道2的引脚(TI2)。
边沿检测器 (Edge Detector): 这个硬件模块根据CC1P和CC1NP的设置,检测输入信号上发生的有效边沿。
当检测到TI1FP1上的有效边沿(由CC1P决定是上升沿还是下降沿)时,它会输出一个内部捕获触发信号 (TRC - Trigger for Capture)。
图中标注了TI1FP1_Rising和TI1FP1_Falling,表示检测器能识别这两种边沿,但哪个有效由CC1P控制。
- 作用: 告诉系统“什么类型的信号跳变才算数”。你想在信号变高时捕获?还是变低时捕获?还是两者都要(双边沿)?就是这里配置。
- 通俗讲: CC1P/CC1NP是“开关”,决定检测器是响应“上台阶”(上升沿)还是“下台阶”(下降沿)。检测器就是“眼睛”,盯着信号看有没有发生指定的跳变。
3.输入滤波器 (Input Filter):
IC1F[3:0]输入捕获1滤波器 (Input Capture 1 Filter): 这些位位于配置寄存器TIMx_CCMR1中。它控制滤波器的采样频率和次数。
滤波器 (Filter) / 向下计数器 (Down Counter): 这是一个数字滤波器,用于消除信号上的噪声(毛刺)。在实际应用中,如果波形噪声大,参数设置大一些,可以过滤噪声。
它的工作方式:
- 系统时钟(f_CK_INT)经过一个预分频器(图中未明确标出,通常由TIMx_CR1的CKD[1:0]控制)得到采样时钟f_DTS。
- 滤波器配置N个采样点(N由IC1F[3:0]的值决定,可以是1, 2, 4, 8...)。
- 当输入信号发生变化时,滤波器会用f_DTS频率连续采样N次。
- 只有连续N次采样到的电平都一致,滤波器才认为这是一个有效的电平变化,并输出这个新的稳定电平给后面的边沿检测器。否则,输出保持原电平不变。
- 作用: 抗抖动! 比如按钮按下时会产生多次快速跳变的毛刺信号,滤波器能确保只有稳定、持续一段时间的电平变化才被认为是真正的边沿事件,避免误触发捕获。
- 通俗讲: 滤波器就像一个“防抖小卫士”。信号跳一下它不立刻相信,要连续看好几眼(N次),确认信号真的稳定在新状态了,才报告给后面的“眼睛”(边沿检测器)。
4.预分频器 (Prescaler) / 捕获分频器:
IC1PSC[1:0] (Input Capture 1 Prescaler): 这些位位于配置寄存器TIMx_CCMR1中。
分频器 (Divider): 这个硬件模块位于边沿检测器之后、捕获动作之前。它对有效的捕获触发信号(TRC) 进行分频。可配置的分频比:
- 00: 不分频。每个有效边沿都触发捕获。
- 01: 2分频。每2个有效边沿触发一次捕获。
- 10: 4分频。每4个有效边沿触发一次捕获。
- 11: 8分频。每8个有效边沿触发一次捕获。
- 作用: 降低捕获事件的频率。当你只关心信号的周期(需要连续2个上升沿)或者频率很高导致CPU处理不过来中断时,这个分频器非常有用。例如,配置为2分频(01)时,第一个上升沿到来它忽略,第二个上升沿到来它才真正发出捕获命令,这样捕获到的时间差就是信号的一个完整周期。
- 通俗讲: 这个分频器是“事件选择器”。它可以让捕获通道“偷点懒”,比如设定“每隔两次有效跳变我才记录一次时间”。
5.最终捕获路径与寄存器:
IC1 (Input Capture 1 to Register): 这是经过滤波器、边沿检测器、预分频器处理后的最终捕获信号。当这个信号有效(一个被允许的、有效的边沿事件)时,就会触发核心的捕获动作。
捕获动作: 在IC1信号有效的瞬间,硬件会自动将当前定时器计数器TIMx_CNT的值复制(锁存) 到捕获/比较寄存器TIMx_CCR1中。这个动作是硬件完成的,速度极快,保证了时间的精确性。
TIMx_CCR1 (Capture/Compare Register 1): 这就是存放捕获结果的“宝箱”!捕获发生后,你需要读取这个寄存器来获取事件发生时的精确时间点(TIMx_CNT的值)。
6.其他重要连接:
- TRC (Trigger for Capture): 如前所述,这是边沿检测器输出的内部触发信号。它不仅通向通道1的预分频器,还会被送到从模式控制器 (Slave Mode Controller)。
- 从模式控制器 (Slave Mode Controller): 这个强大的模块可以接收各种触发源(包括TRC),并根据配置控制定时器的工作模式(如复位计数器、启动/停止计数器、启动注入通道转换等)。例如,在PWM输入模式下,就利用TRC(来自第一个通道的边沿)复位计数器,然后捕获第二个通道的边沿来测量周期和占空比。
- TI1F_ED (TI1 Filtered Edge Detection): 这是TI1F信号经过滤波器后,直接进行双边沿检测的输出。它不受CC1P/CC1NP控制,只要TI1F上发生任何有效的边沿(上升或下降),它都会输出一个脉冲。这个信号主要用作从模式控制器的触发源(TRGI),尤其是在需要双边沿触发的应用(如某些编码器模式)中。
每捕获一次CNT的值,都要把CNT清零一下,以便于下一次的捕获。在这里硬件电路就可以在捕获之后自动完成CNT的清零工作。
自动清零CNT方式:
TI1FP1信号和TI1的边沿信号TI1F_ED都可以通向从模式控制器。
比如TI1FP1信号的上升沿触发捕获,同时TI1FP1还可以触发从模式。这个从模式里面就有电路,可以自动完成CNT的清零。
主从触发模式
主从触发模式就是主模式,从模式和触发源选择这三个功能的简称。
主模式:将定时器内部的信号映射到TRGO引脚,触发别的外设
从模式:接收其他外设或者自身外设的一些信号,控制自身定时器的运行(被别的信号控制)
触发源选择:选择从模式的触发信号源(可认为从模式的一部分),选择指定的一个信号,得到TRGI,去触发从模式。
若想完成TI1FP1信号自动触发CNT清零,触发源选择就可以选中TI1FP1,从模式执行操作Reset。
1.主模式选择:
若想完成定时器的级联,可选择定时器主模式,输出更新信号到TRGO,另一个定时器选择上一个定时器触发从模式,从模式选择执行外部时钟模式1的操作,可实现定时器级联。
主模式还可以选择复位、使能、比较脉冲和四个OCREF信号作为TRGO的输出。
2.从模式触发源可选择信号
3.触发从模式后执行的操作
4.补充外部时钟模式知识点:
一、 外部时钟模式1 (External Clock Mode 1)
原理:
模式1主要利用定时器的输入捕获通道1 (TI1) 或 输入捕获通道2 (TI2) 来获取外部时钟信号。
外部信号连接到配置为输入的 TIMx_CH1 或 TIMx_CH2 引脚。
信号首先经过输入滤波器和边沿检测器。
然后,信号被送到一个触发控制器(Trigger Controller)。
触发控制器的输出 (TRGI) 被用作从模式控制器 (Slave Mode Controller) 的触发输入。
在模式1中,从模式控制器被配置为 “外部时钟模式1” (External Clock Mode 1)。
最终,这个处理后的信号就成为了定时器计数器 (CNT) 的时钟源 (CK_CNT)。计数器会在选定边沿(上升沿、下降沿或双边沿)到来时递增或递减。
信号路径:
外部信号 -> TIMx_CH1/TIMx_CH2 引脚 -> 输入滤波器 -> 边沿检测器 -> 触发控制器 (TRGI) -> 从模式控制器 (配置为 ECE=1, SMS=111) -> CK_PSC -> CK_CNT (计数器时钟)
特征:
信号源: 只能来自 TIMx_CH1 或 TIMx_CH2 引脚。
边沿选择: 可以配置为上升沿、下降沿或双边沿计数。这通过捕获/比较模式寄存器
TIMx_CCMR1
中对应通道的CCxS
(选择输入源) 和ICxP
/ICxNP
(选择极性) 位,以及从模式控制寄存器TIMx_SMCR
中的ETF
(滤波器) 和ETP
(极性) 位间接影响。滤波: 可以配置输入滤波器 (
TIMx_CCMR1
中的ICxF
位) 来消除信号抖动。分频: 外部时钟信号在进入计数器之前,仍然会经过定时器的预分频器 (PSC)。预分频器设置 (
TIMx_PSC
) 决定了多少个外部时钟边沿才使计数器增加1。应用: 非常适合用于频率测量、脉冲计数等场景,因为它直接利用捕获通道,便于后续的捕获功能配合使用。
二、 外部时钟模式2 (External Clock Mode 2)
原理:
模式2使用一个专门的输入引脚:外部触发输入 (ETR)。
外部信号连接到 TIMx_ETR 引脚。
信号首先经过一个可配置的外部触发极性控制器 (ETP) 和 外部触发预分频器 (ETPS) 以及 外部触发滤波器 (ETF)。
经过这些处理后的信号 (ETRP) 直接作为定时器计数器 (CNT) 的时钟源 (CK_CNT)。它不经过从模式控制器。
同时,模式2需要使能外部时钟模式2功能。这通过设置
TIMx_SMCR
寄存器中的ECE
(External Clock Enable) 位为1
来实现。
信号路径:
外部信号 -> TIMx_ETR 引脚 -> 极性控制器 (ETP) -> 预分频器 (ETPS) -> 滤波器 (ETF) -> ETRP -> CK_PSC -> CK_CNT (计数器时钟) ↑ (需要 TIMx_SMCR.ECE = 1)
特征:
专用引脚: 必须使用 TIMx_ETR 引脚。每个定时器通常只有一个ETR引脚。
独立路径: 时钟信号处理路径独立于输入捕获通道和从模式控制器。
内置预分频器: 模式2有一个专属于ETR信号的预分频器 (
ETPS[1:0]
inTIMx_SMCR
),可以在信号进入定时器核心之前进行分频 (1, 2, 4, 8 分频)。然后信号还会经过主预分频器 (PSC)。极性控制: 可以直接反转输入信号的极性 (
ETP
bit inTIMx_SMCR
)。滤波: 有专用的滤波器 (
ETF[3:0]
inTIMx_SMCR
)。简单直接: 配置相对模式1更简单直接,因为它不涉及触发输入的选择和从模式控制器的复杂配置(除了使能ECE位)。
应用: 非常适合需要独立、专用外部时钟输入的场景,特别是当信号频率较高或需要ETR引脚独有的预分频/滤波时。也常用于精确的外部时钟同步。
三、 核心区别总结
特性 | 外部时钟模式 1 | 外部时钟模式 2 |
---|---|---|
信号源引脚 | TIMx_CH1 或 TIMx_CH2 | 专用 TIMx_ETR |
配置核心 | 通过从模式控制器 (Slave Mode Controller),选择 SMS=111 (外部时钟模式1) 和触发源 TS=TI1FP1/TI2FP2 |
独立路径,只需启用外部时钟模式2 (ECE=1 ) 并配置ETR参数 |
信号路径 | 经过输入通道滤波器/边沿 -> 触发控制器 -> 从模式控制器 -> CK_CNT | 经过ETR极性/预分频/滤波 -> 直接 -> CK_CNT |
专用预分频 | 无。信号仅受主预分频器 (PSC) 影响。 | 有。ETR有自己独立的预分频器 (ETPS: 1,2,4,8分频) 之后再经过主PSC。 |
极性控制 | 主要通过捕获通道配置 (ICxP/ICxNP ) 和从模式触发极性 (TriggerPolarity ) |
有直接的ETR极性控制位 (ETP ) |
滤波 | 使用对应输入捕获通道的滤波器 (ICxF ) |
使用ETR专用滤波器 (ETF ) |
是否依赖捕获通道 | 是,必须配置对应的TI1/TI2通道输入 | 否,完全独立于输入捕获通道 |
配置复杂度 | 相对复杂,需要配置捕获通道(可选但推荐)和从模式控制器 | 相对简单直接,主要配置ETR参数和使能ECE |
典型应用 | 脉冲计数、频率测量 (常结合捕获功能) | 专用外部时钟输入、高频信号计数、需要独立ETR预分频/滤波的场景 |
输入捕获基本结构
结构图只使用一个通道,目前只能测量频率
输入捕获过程:
配置时基单元,启动定时器,CNT会在预分频之后的时钟驱动(驱动CNT的标准频率fc=72M/预分频系数)下,不断自增(CNT为测周法用来计数计时)
输入捕获通道1的GPIO口,输入一个方波信号,经过滤波器和边沿检测,选择TI1FP1为上升沿触发,之后输入选择直连的通道,分频器选择不分频。当TI1FP1出现上升沿之后,CNT的当前计数值转运到CCR1。
同时,触发源选择,选中TI1FP1为触发信号,从模式选择复位操作。这样TI1FP1的上升沿也会触发CNT清零。
TI1FP1的执行顺序:先转运CNT的值到CCR,再触发从模式给CNT清零。或者是非阻塞的同时转移,CNT的值转移到CCR,同时0转移到CNT里面去。
当信号出现一个上升沿,CCR1=CNT(把CNT的值转运到CCR1)这是输入捕获自动执行的。然后CNT=0,清零计数器,这是从模式自动执行的。
之后在一个周期之内,CNT在标准时钟的驱动下不断自增。由于已经将CNT清零,所以CNT就是从上升沿开始,从0开始计数一直加直到下一次上升沿来临,后执行相同操作(CCR=CNT,CNT=0)。
此过程中,CCR1始终保持最新一个周期的计数值N,后fc/N=信号频率
注意:
①CNT值有上限,ARR一般设置为最大65535,CNT最大计数65535,若信号频率太低,CNT值可能溢出
②从模式触发源选择,只有TI1FP1和TI2FP2,因此,使用从模式自动清零CNT只能选择通道1或者2
PWMI基本结构
使用俩个通道同时捕获一个引脚,可以同时测量周期和占空比。
增加一个过程:TI1FP1配置上升沿触发,触发捕获和清零CNT,正常捕获周期。
再加上一个TI1FP2,配置下降沿触发,通过交叉通道,触发通道2捕获单元。
当信号出现一个上升沿,CCR1捕获CNT值,同时清零CNT,后CNT++,在下降沿时触发CCR2捕获CNT值,即CNT为一个周期内高电平的计数值,CCR2不触发CNT清零,CNT++,下一次上升沿,CCR1捕获CNT,CNT清零……
CCR1为一整个周期的计数值,CCR2为高电平期间的计数值
占空比=CCR2/CCR1
输入捕获模式测频率
(库函数引用STM32_stm32 tim16s-CSDN博客)
1.输入捕获初始化
步骤:
①RCC开启时钟,把GPIO和TIM时钟打开
②GPIO初始化,把GPIO配置成输入模式(上拉输入/浮空输入)
③配置时基单元,CNT计数器在内部时钟驱动下自增运行
④配置输入捕获单元,包括滤波器,极性,直连通道还是价差通道,分频器参数
⑤选择从模式触发源TI1FP1
⑥选择从触发模式的操作
⑦开启定时器
2.初始化输入捕获单元
1.用结构体配置输入捕获单元函数
单一配置一个通道
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);2.输入捕获初始化的函数
快速配置俩个通道,把外设电路结构配置成PWMI模式
void TIM_PWMIConfig(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);3.给输入捕获结构体赋一个初始值
void TIM_ICStructInit(TIM_ICInitTypeDef* TIM_ICInitStruct);4.选择输入触发源TRGI(从模式触发源)
void TIM_SelectInputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);5.选择输出触发源TRGO(主模式输出的触发源)
void TIM_SelectOutputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_TRGOSource);6.选择从模式
void TIM_SelectSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_SlaveMode);7.单独配置通道1234分频器
void TIM_SetIC1Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);
void TIM_SetIC2Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);
void TIM_SetIC3Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);
void TIM_SetIC4Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);8.读取4个通道的CCR
uint16_t TIM_GetCapture1(TIM_TypeDef* TIMx);
uint16_t TIM_GetCapture2(TIM_TypeDef* TIMx);
uint16_t TIM_GetCapture3(TIM_TypeDef* TIMx);
uint16_t TIM_GetCapture4(TIM_TypeDef* TIMx);输出比较模式:CCR只写,用SetCompare写入
输入捕获模式,CCR只读,用GetCapture读出
1.IC.c
明确指出:
STM32的定时器可以同时进行输入捕获和输出比较,因为定时器的不同通道是独立的。每个通道可以独立配置为输入捕获或输出比较模式;但是,同一个通道不能同时用于输入捕获和输出比较,因为每个通道只有一个捕获/比较寄存器(CCRx)和相应的模式配置位.
通道独立性:
每个定时器有4个独立通道(TIM1/TIM8有更多)
每个通道可单独配置为:
输入捕获(测量外部信号)
输出比较(生成PWM/波形)
✅ 关键:不同通道可同时使用不同功能
资源分配:
共享资源:计数器(CNT)、预分频器(PSC)、自动重载寄存器(ARR)
独立资源:各通道的捕获/比较寄存器(CCRx)、捕获/比较模式寄存器
通道冲突避免:
TIM3: CH1(PA6) -> 输入捕获 CH2(PA7) -> 输出比较
同一通道不能同时用于输入和输出
解决方案:使用不同物理通道
中断优先级管理:
// 设置捕获中断优先级 HAL_NVIC_SetPriority(TIM3_IRQn, 5, 0); HAL_NVIC_EnableIRQ(TIM3_IRQn);
计数器模式选择:
推荐使用
TIM_COUNTERMODE_UP
(向上计数)避免使用中心对齐模式(可能引起捕获时间计算错误)
时钟频率考虑:
输入信号频率 < 定时器时钟频率/(2×滤波器)
输出PWM频率 = 定时器时钟/((PSC+1)×(ARR+1))
- 注意事项:
1. 定时器的工作模式(如向上计数、向下计数等)是全局的,所以输入捕获和输出比较共享同一个计数器(CNT)。
2. 输入捕获和输出比较的功能是独立的,不会互相干扰,只要使用不同的通道。
3. 需要正确配置每个通道的相应寄存器。
8. 举例说明(以TIM2为例,因为TIM2有4个通道):
- 通道1(PA0):输入捕获,用于捕获外部信号的上升沿。
- 通道2(PA1):输出比较,用于产生PWM信号。
- 通道3(PA2):输出比较,用于产生另一个PWM信号。
- 通道4(PA3):输出比较,用于产生第三个PWM信号。
void IC_init(void)
{
//①开启时钟RCC,将TIM外设和GPIO外设时钟打开
//APB1开启时钟
//由于TIM2输出PWM,换TIM3输入捕获
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//开启TIM3时钟(APB1)
//②GPIO初始化,把GPIO配置成输入模式(上拉输入/浮空输入)
//TIM3的通道1和通道2对应PA6和PA7
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
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);
//③配置时基单元,CNT计数器在内部时钟驱动下自增运行
//选择内部时钟
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;//ARR自动重装器的值,设计最大,以防CNT溢出
TIM_TimeBaseInitStructure.TIM_Prescaler=72-1;//PSC预分频器的值
TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//高级定时器的重复计数器的值,初级没有
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
//④配置输入捕获单元,包括滤波器,极性,直连通道还是交叉通道,分频器参数
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);
//⑤选择从模式触发源TI1FP1
TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);//选择哪一个触发源
//⑥选择从触发模式的操作
TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);
//⑦开启定时器
TIM_Cmd(TIM3,ENABLE);
}
//返回最新一个周期的频率值 Hz
uint32_t IC_GetFreqent(void)
{
return 1000000/TIM_GetCapture1(TIM3);//Fre=72M/(PSC+1)/(ARR+1) ARR+1=100
}//此刻PSC=72-1 N为CCR的值
2.IC.h
#ifndef __IC_H_
#define __IC_H_
uint32_t IC_GetFreqent(void);
void IC_init(void);
#endif
3.pwm.c(修改)
#include "stm32f10x.h" // Device header
void PWM_init(void)
{
/*
①开启时钟RCC,将TIM外设和GPIO外设时钟打开
②配置时基单元和时钟源选择
③配置输出比较单元,包括CCR值,输出比较模式,极性选择,输出使能参数
④配置GPIO口,初始化为复用推挽输出配置
⑤运行控制,启动计数器,输出PWM
*/
//①开启时钟RCC,将TIM外设和GPIO外设时钟打开
//APB1开启时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//开启TIM2时钟(APB1)
//使用TIM2的OC1/CH1通道,输出PWM
//②配置时基单元和时钟源选择
//选择内部时钟
TIM_InternalClockConfig(TIM2);
//配置时基单元
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);
//③配置输出比较单元,包括CCR值,输出比较模式,极性选择,输出使能参数
//选择PA0口→第一个输出通道
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure);//给结构体所有成员赋初始值
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;//输出比较模式
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);
//通过引脚图,是PA0输出,重映射列表中查找PA15引脚也可以
//④配置GPIO口,初始化为复用推挽输出配置
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//推挽复用输出
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
//⑤运行控制,启动计数器,输出PWM
TIM_Cmd(TIM2,ENABLE);
}
/*
调节PWM频率
f=72M(PSC+1)/(ARR+1)
占空比=1/(ARR+1)
俩个公式可知,单独控制PWM频率可以调节PSC
ARR固定100-1
*/
void PWM_set_PSC(uint16_t psc)
{
//单独写入PSC函数
TIM_PrescalerConfig(TIM2,psc,TIM_PSCReloadMode_Update);//重装模式(更新事件重装/立即重装)
}
4.main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "buzzer.h"
#include "pwm.h"
#include "IC.h"
void display(void)
{
PWM_set_PSC(720-1);//Fre=72M/(PSC+1)/(ARR+1) ARR+1=100
TIM_SetCompare1(TIM2,50);//Duty=CCR/(ARR+1) ARR+1=100
//PWM模块已经将待测信号输出到PA0
//PA0通过导线,输入到PA6(TIM3通道1)
//通道1通过输入捕获模块测量得到频率
OLED_ShowNum(1,6,IC_GetFreqent(),6);
}
int main(void)
{
OLED_Init();
PWM_init();
IC_init();
OLED_ShowString(1,1,"Freq:000000Hz");
while(1)
{
display();
}
}
PWMI测量频率和占空比
1.IC.c代码改编
//④配置输入捕获单元,包括滤波器,极性,直连通道还是价差通道,分频器参数
//俩个通道同时捕获一个引脚模式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);
TIM_ICInitStructure.TIM_Channel=TIM_Channel_2;//输入捕获通道
TIM_ICInitStructure.TIM_ICFilter=0xF;//滤波器,若有噪声,可增加滤波器参数,有效避免干扰
TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Falling;//边沿检测极性选择,下降沿触发
TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;//触发信号分频器,不分频就是每次触发都有效
TIM_ICInitStructure.TIM_ICSelection= TIM_ICSelection_IndirectTI ;//配置输入选择器(直连通道/交叉通道)选择触发信号从哪一个引脚输入
TIM_ICInit(TIM3,&TIM_ICInitStructure);
将输入捕获单元复制,配置IC2通道2(有点麻烦)
使用一个库函数:
TIM_PWMIConfig(TIM3,&TIM_ICInitStructure);
自动将剩下的通道初始化成相反的配置
函数仅支持通道1和通道2配置
//返回最新一个周期的频率值 Hz
uint32_t IC_GetFreqent(void)
{
return 1000000/TIM_GetCapture1(TIM3);//Fre=72M/(PSC+1)/(ARR+1) ARR+1=100
}//此刻PSC=72-1 N为CCR的值
//获取占空比的函数
uint32_t IC_GetGuty(void)
{
return TIM_GetCapture2(TIM3)*100/TIM_GetCapture1(TIM3);
}
2.main.c
void display(void)
{
PWM_set_PSC(720-1);//Fre=72M/(PSC+1)/(ARR+1) ARR+1=100
TIM_SetCompare1(TIM2,50);//Duty=CCR/(ARR+1) ARR+1=100
//PWM模块已经将待测信号输出到PA0
//PA0通过导线,输入到PA6(TIM3通道1)
//通道1通过输入捕获模块测量得到频率
OLED_ShowNum(1,6,IC_GetFreqent(),6);
OLED_ShowNum(2,6,IC_GetGuty(),3);
}
int main(void)
{
OLED_Init();
PWM_init();
IC_init();
OLED_ShowString(1,1,"Freq:000000Hz");
OLED_ShowString(2,1,"Duty:000%");
while(1)
{
display();
}
}
测评率的性能:
①测频率的范围:
测量频率下限:
标准频率1MHz,计数器最大只能计数65535,最低频率1M/65535≈15Hz
若想标准频率更低,加大预分频系数
测量频率上限:1MHz,根据误差承受范围决定
提高频率上限,降低PSC,提高标准频率,上限提高
误差分析:
①正负1误差
②晶振误差
输入捕获预输出比较区别
特性 | 输入捕获 | 输出比较 |
---|---|---|
方向 | 输入 (监测外部信号) | 输出 (驱动引脚动作) |
主要目的 | 测量外部事件发生的时间点 | 在预设时间点 控制引脚电平 |
触发源 | 外部信号边沿 (引脚) | 内部计数器达到预设值 (比较匹配) |
核心动作 | 捕获/锁存当前计数器值 (记录时刻) | 改变引脚状态 (驱动动作) |
寄存器操作 | 硬件自动读取计数器值存入捕获寄存器 | 用户写入目标值到比较寄存器 |
典型应用 | 脉冲宽度测量、频率测量、周期测量、编码器 | PWM 生成、方波生成、精确时间触发、单脉冲 |
简单类比:
输入捕获 像一个秒表:当外部事件(比如运动员冲过终点线)发生时,你按下按钮(硬件自动完成),秒表记录下那一刻的时间。
输出比较 像一个闹钟:你预先设定好一个时间(写入比较寄存器),当钟表走到那个时间(计数器匹配),闹钟就会响(引脚电平改变/动作发生)。