一、文章目的
记录自己从学习了定时器理论->代码实现使用定时->查询数据手册,加深了对定时器的理解以及该过程遇到了的一些不清楚的知识。
-
上图为参考手册里通用定时器框图,关于定时器各种情况的工作都在上面了,在理论学习和实际应用后再来看这张图会觉得豁然开朗。
-
定时器基本的单元为16位自动装载寄存器ARR,16位预分频器PSC,计数器CNT,另外有4个独立通道,在我看来只有两种大功能:
–输入捕获
(如测输入信号频率、占空比、编码器)
–输出比较
(如输出PWM波控制电机、舵机)
根据这两种功能可以将定时器配置为不同模式
,比如输出pwm的PWM模式、读取编码器的Encoder模式。
二、定时器时钟来源选择(极为重要)
● 内部时钟(CK_INT)
● 内部触发输入(ITRx)
:使用一个定时器作为另一个定时器的预分频器
● 外部时钟模式1
:外部输入脚(TIx) ,4个独立通道的输入
● 外部时钟模式2
:外部触发输入(ETR) ,模式1和模式2看上去非常相似
清楚定时器的时钟来源,后续才能理解定时器的各种模式
三、 理解最基本的定时
在时钟的驱动下,计数器CNT
递增+1(默认向上计数),当到达自动重装载寄存器ARR
中的目标值时,溢出清零,产生中断,循环这个过程。
HAL库实现基本定时
- 1、打开并设置基本定时器
-
- 选择为内部时钟,即内部时钟模式
-
- 设置以下参数:定时器的时钟频率
fc=f /(PSC+1)/(ARR+1)
,f为单片机时钟来源。
- 设置以下参数:定时器的时钟频率
-
预分频器Prescaler PSC
-
自动重装寄存器CouterPeriod ARR
-
输入滤波器的频率分频InternalClockDivision(一般不需要)
-
- 2、打开中断
- 3、main函数中初始化TIM2
HAL_TIM_Base_Start_IT(&htim2);
4、驱动函数中找回调函数然后在main.c中重写
__weak void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim); //原型
//重写
uint16_t hhRetCount=0;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
if(htim==&htim2){
hhRetCount+=1;
}
}
四 、输出比较
此项功能是用来控制一个输出波形,或者指示一段给定的的时间已经到时。
定时器的每个输出通道能够独立的产生一路PWM
信号(由ARR
寄存器确定频率、由CCR
寄存器确定占空比的信号。)
HAL库实现生成PWM(驱动舵机、电机、呼吸灯)
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1);
__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_3,Speed); //设置CCR值控制占空比
五 、输入捕获
输入捕获模式下,当通道输入引脚出现指定电平跳变时(类似于中断),当前CNT
的值将被锁存到CCR
中,可用于测量PWM
波形的频率、占空比、脉冲间隔、电平持续时间等参数。
可配置为PWMI
模式(不清楚没关系),同时测量频率和占空比;也可配合主从触发模式`(下文中从模式的复位模式),实现硬件全自动测量(触发输入实现定时器的自动清零)。
对于同一个定时器,输入捕获和输出比较只能同时用一个。
输入捕获
:将CNT的
值写到CCR
输出比较
:根据CNT
和CCR
的比较后输出
输入捕获测频率、测占空比
从模式-复位模式下,上升沿触发,因此上升沿来临时,计数器CNT
的值存进了CCR1
中然后自动清零;下降沿来临时,CNT
的值存进了CCR2
中,并未清零。然后可以计算频率(用CCR1
)和占空比(用CCR1和CCR2
)。
HAL库实现输入测频率、占空比
- 1、TIM2生成PWM待测信号、启动
- 2、设置TIM3定时器相关参数
通道1
用于测频率-
- 设置
TI1FP1
为ResetMode
,即清空计数
- 设置
-
- 使用内部时钟
-
- 通道1设置为输入捕获模式
-
- 设置预分频器为72
-
- 自动重装寄存器为65535
-
- 输入捕获上升沿
通道2
用于测占空比-
- 打开通道2为
交叉模式
、设置下降沿触发
- 打开通道2为
通道1
通道2
- 3、打开TIM3的全局中断、main中开启TIM3
HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_1);
3、找到输入捕获回调函数并重写
uint32_t capture;
int32_t freq;
uint32_t DutyResult;
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM3) {
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) {
// 上升沿触发的中断
capture =HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1)+1;
uint32_t aa=HAL_RCC_GetPCLK1Freq();
uint32_t bb=(htim->Instance->PSC+1);
uint32_t cc=HAL_RCC_GetPCLK1Freq()/(htim->Instance->PSC+1);
freq=1000000/capture;
} else if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2) {
// 下降沿触发的中断
uint32_t capture2 =HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2)+1;
DutyResult=capture2 *100 / capture;
}
}
}
可动态修改TIM2的频率和占空比
__HAL_TIM_SET_PRESCALER(&htim2,72-1);//10000HZ
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, 83);//83%
HAL库实现读取旋转编码器
每个高级定时器和通用定时器都拥有一个编码器接口,借用输入捕获IC的通道1和通道2。
当定时器设置为编码器接口时,定时器的计数器就不会由内外部时钟控制,而是由两个正交编码器信
号控制。另外,还可以根据选择的计数方式(TI1、TI2计数还是都计数)以及信号上下沿、电平高低的判断确定方向。
利用CUBMX配置编码器模式非常简单:
- 1、设置相关参数
-
- 打开编码器模式(使用
CH1、CH2
两个通道)
- 打开编码器模式(使用
-
- 设置定时器的相关参数。由于是检测速度,所以这里就不分频,尽可能让定时器快点。计数器 设置最大,防止输入信号频率太高溢出。
-
- 设置计数模式,
TI1
计数和TI2
计数
- 设置计数模式,
-
- 设置信号不反向
- 设置信号不反向
-
- 2、main函数中打开定时器编码器模式
HAL_TIM_Encoder_Start(&htim3, TIM_CHANNEL_ALL);
- 3、显示计数值
计数器CNT
返回的是一个无符号的uint32_t
数,因此如果希望反转能够显示负数,还需要将CNT
值转换为有符号的int16_t
数。
//得到计数值
int16_t CNT=__HAL_TIM_GET_COUNTER(&htim3);
- 4、计算速度
如果还希望计算编码器速度,那就秒钟读取一次定时器的计数值(编码器的脉冲)并清空,得到的数字就是当前的速度,单位是Plus/S
int16_t hhGetEncoderSpeedCountAndReset(){
int16_t Speed;
Speed=__HAL_TIM_GET_COUNTER(&htim3);
__HAL_TIM_SET_COUNTER(&htim3,0);
return Speed;
}
六、主从模式
根据定时器的时钟来源
(或者说是否受到从模式控制器的控制),可以将定时器的工作状态分为主模式和从模式。
首先,触发信号分两大类:触发输入信号TRGI
,简单地讲就是从外部引入到本定时器的信号;另一类就是触发输出信号,即TRGO
信号,它是定时器输出给其它定时器或外设的触发信号。
从数目上有讲一般可以多达8个,大致分为三类:
第一类
:来自定时器自身输入通道1或通道2的输入信号,经过极性选择和滤波以后生成的触发信号,连接到从模式控制器,进而控制计数器的工作。 (TI1FP1 、 TI2FP2、TI1F_ED
)
第二类
,来自于外部触发脚ETR脚
经过极性选择、分频、滤波以后的信号,经过触发输入选择器,连接到从模式控制器 (ETRF
)
第三类
,来自其它定时器的触发输出信号TRGO
,通过内部线路连接到本定时器的触发输入控制器而连接到从模式控制器。(ITR0、ITR1、ITR2、ITR3
)
这3类信号有个共同特点:都要经过触发输入选择器而连接到从模式控制器,从而使得计数器的工作受到从模式控制器的控制或影响,基于这一点,定时器工作在从模式
。而主模式
:定时器内部信号映射到TRGO引脚用于触发别的外设。
七、定时器的4种从模式
- 复位模式
- 门控模式
- 触发模式
- 外部时钟模式2+触发模式
在我看来从模式其实就是在正常使用定时器外再添加一个控制功能,根据实际的需要再配置即可。
复位模式
在发生一个触发输入
事件时,计数器和它的预分频器能够重新被初始化;同时,如果TIMx_CR1寄存器的URS位为低,还会产生一个更新事件UEV;然后所有的预装载寄存器(TIMx_ARR,TIMx_CCRx)都会被更新。
例如
TI1输入端的上升沿导致向上计数器被清零:计数器开始依据内部时钟计数,然后正常运转直到TI1出现一个上升沿;此时,计数器被清零然后从0重新开始计数。同时,触发标志(TIMx_SR寄存器中的TIF位)被设置,根据TIMx_DIER寄存器中TIE(中断使能)位和TDE(DMA使能)位的设置,产生一个中断请求或一个DMA请求。
门控模式
按照选中的输入端电平
使能计数器。
例如
下图,计数器只在TI1输入电平为低时计数+1
触发模式
按照输入端上选中的事件
使能计数器。
例如
下图,计数器在TI2输入的上升沿开始向上计数
外部时钟模式2+触发模式
外部时钟模式2可以与另一种从模式(外部时钟模式1和编码器模式除外)一起使用。
外部时钟模式2,ETR
信号被用作外部时钟的输入,在复位模式、门控模式或触发模式时可以选择另一个输入作为触发输入。
例如下图,TI1输入上升沿使能计数器,然后在ETR
信号每次的上升沿计数
八、其他
遇到查询数据手册即可