定时器
定时器分类:
全是自动重装载计数器。
在数据手册中查看:


定时器时钟来源及应用场景:
定时器主从模式:
主模式:定时器主动输出:比较输出、产生更新中断等
从模式:定时器被动接收输入,输入捕获,其它定时器输入等
计数模式

向上计数:
向下计数:
中心对齐:
事件和中断
在高级定时器中,有重复计数器,于一个分频器,原来溢出一次就触发一次,配置为 N 后,N 次溢出才触发一次。
一、定时中断

定时器本质是计数器。
首先,输入的时钟 CK_INT 决定了计数的快慢,
可以看到,图中的寄存器后面有个黑影,叫做影子寄存器,影子寄存器是实际上起作用的寄存器,但是无法直接操作。。
当修改了自动重载寄存器的值时,
设置了直接生效:
没设置直接生效:当计数周期结束时,避免在参数更新过程中产生干扰。
当自动重装载寄存器的值等于计数寄存器的值的时候,便会产生中断和其它事件。
定时参数计算

公式推导过程:
(1)计算定时时间
a. 根据频率得到周期:
p 为分频值
b. 定时时间 = n 个周期:
(2)代入 p 和 n
p = PSC + 1:PSC 是分频系数,为预分频寄存器的值,实际分频比是 PSC + 1。因为硬件是从 0 开始的,计数到 PSC 才会输出一个时钟,也就是 PSC+1 个时钟才会给定时器输入一个时钟,实现 p 倍分频。
n = ARR + 1:ARR 为重装载寄存器的值。定时器在 CNT== ARR 时会产生中断事件,从 0 到 n 共计 n+1 个数,它在 n+1 的时候会产生中断,也就是会多计一个数,因此如果想计 n 个数就中断,需要将寄存器的值设置为 n-1。感觉不对
-1 的关键原因:硬件计数从 0 到 ARR,共 ARR+1 次
定时器不是在“数次数”,而是在“遍历状态”,而状态编号从 0 到 ARR

百分比和比较值转换
已知占空比:
周期 = Period +1 ,是整数,不是 999 这样的,是1000
所以:
八种主模式:

F0标准库:
void Timer3_Initializes(void)
{
TIM_TimeBaseInitTypeDef timer_struct = {0};
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
timer_struct.TIM_RepetitionCounter = 0; // 重复计数值
timer_struct.TIM_Period = 1000;
timer_struct.TIM_Prescaler =48;
timer_struct.TIM_ClockDivision = TIM_CKD_DIV1;
timer_struct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &timer_struct);
TIM_ITConfig(TIM3,TIM_IT_Update, ENABLE); // 开中断
TIM_Cmd(TIM3,ENABLE); // 开启定时器
}
void TIM3_IRQHandler(void)
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
{
// 处理逻辑......
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}
}
二、从模式
从模式:
外部时钟模式
复位模式
门模式
触发模式
触发源:
定时器4个输入通道
外部时钟模式
共 7 个源

复位模式
此时定时器的时钟可以选择为:
内部时钟
ETR 外部时钟
触发源还是 7 个:
ITR0~4、TI1F_ED、TI1FP1、ETR(时钟源为内部时钟时可选择)
触发源触发一下,定时器复位:
CNT 计数器清零
产生定时器更新事件
影子寄存器更新到主寄存器
判断更新中断产生的原因:
门模式
就是控制定时器是否工作
比如上升沿开启定时器,下降沿暂停定时器。
触发模式
仅用于启动定时器计数。
配合“单脉冲模式”使用,这个模式就是计数到自动重装载后就停止运行了。
三、输入捕获

输入捕获可用于测量外部信号频率、脉宽、占空比,高级定时器有4个输入通道,4个输出通道。
输入捕获只有一个中断事件(捕获N次时触发)。
信号处理流程:
信号进来后,首先进入滤波器去除干扰
接着边沿检测器检测是上升沿还是下降沿
根据上面的流程图,信号会进入特定的预分频器处理,会产生中断
最后“捕获/比较寄存器”会计数,当这个值达到了“自动重装载寄存器”的值,便会产生中断
信号选择:


直接信号 :信号来自自己的通道为直接。
间接信号:信号来自其它通道为间接。通道1和2为一对,通道3和4为一对,可组合使用。
TRC信号:
其他定时器信号输入
TI1F_ED:捕获通道1的上升沿和下降沿信号,直接可产生中断事件,不用经过分频器再产生
信号的选择丰富多样,根据实际使用场景选择。


电机中的三相霍尔传感器可以用到,信号输出给通道1。

TRGI 是定时器的触发输入信号,它连接到了定时器内部的 从模式控制器(Slave Mode Controller),可以用来:
作为计数器的时钟源
触发定时器启动、复位
同时产生 TGI 中断信号,这个是写代码的中断处理函数。
TRGO 信号:由触发控制器产生的硬件触发信号,
可触发DAC/ADC外设
可触发其它定时器,就是其它定时器的ITR输入信号
八种从模式:

(1)输入捕获用于测量频率
(1)输入捕获用于测量占空比
(1)输入捕获用于测量脉宽
脉宽是一个周期内高电平的持续时间。
测量脉宽:一个通道捕获上升沿,一个捕获下降沿
脉宽 = (大值 - 小值)*
计数
PWM 测量
定时器同时启动

定时器级联
一个定时器的 TRGO 接另一个定时器的 TRGI,这样串联起来。
例如:
举个例子,实际上不会这么用。

编码器接口
定时器支持增量型旋转编码器功能,免去了手写中断捕获逻辑,节省 CPU 资源。

编码器有两个接口,称为通道 A 和通道 B,分别输出占空比为 50% 的 PWM 方波,旋转时通道 A 和 B 相位差为90°
空闲:统一输出低电平或高电平
顺时针(CW)旋转:A 相领先 B 相 90°,或者相反。
逆时针(CCW)旋转:B 相领先 A 相 90°,或者相反。
不同的编码器,它的输出行为不一样,例如:

该编码器的行为:
空闲时:输出低电平
24° (15Detent):每 24° 有一个点位,共 15 个点位,也就是旋转一圈输出 15 个上升沿(如果默认是高电平那就是下降沿)。
Detent 表示有机械卡位,不能连续旋转。
顺时针旋转:A 相领先 B 相90°
逆时针旋转:B 相领先 A 相90°
判断旋转方向:
顺时针:A 上升沿时 B 为低电平
逆时针:A 上升沿时 B 为高电平
定时器自带编码器功能,正转时数值+1,反转时数值-1,数值保存在定时器的计数寄存器中,定时器中的编码器对上下边沿都处理。

如何理解这个图?
【TI1FP1 信号】在【上升】沿的时候,如果【TI2FP2 信号】为【高】电平,则【向下计数】
【TI1FP1 信号】在【上升】沿的时候,如果【TI2FP2 信号】为【低】电平,则【向上计数】
【仅在TI1计数】时,此时检测的是 TI1FP1 的信号,如果在上升沿的时候 T21FP2 的电平为高电平,则向下计数;反之则向上计数。
对于这个编码器,将A通道接TI1,B接TI2,则数值增加表示顺时针旋转,数值减小表示逆时针旋转。
编码器的数值保存在 CNT 计数器中,所以每个定时器只能处理一个编码器。
怎么在代码里知道是正转还是反转呢?
输入异或功能
霍尔传感器
三、PWM 输出
用到定时器的输出比较功能。

和定时中断一样,先计算设置PWM的频率。
然后设置【捕获/比较寄存器】的值,。
每计一个数,比较计数器和捕获/比较寄存器的值,
计数的
PWM 模式
互补输出
死区插入
刹车功能
其它应用
定时器作为时基
定时器触发ADC
定时器用于消抖
例如,在分布式 IO 的数字量输入模块中,有16个通道,每个通道都需要做消抖处理,如果用一般的做法 delay_ms 阻塞等待,那16个通道的延时是不可接受的,造成系统响应不及时,会错过一些信号的输入。
比如在给第2个通道消抖,但此时第8个通道输入了,等第2个通道消抖结束,第8个通道的信号也结束了,那就错过了第8个通道,这个系统就是不可用的了。
定时器设置为 1 ms,然后在