STM32定时器
一、STM32定时/计数器概述
定时器可以对输入的脉冲进行计数,并在计数值达到设定值时触发中断,同时也可以进行计时
时基单元:16位预分频器PSC、16位计数器CNT、16位自动重装载寄存器ARR,在72MHz计数时钟下可以实现最大59.65s的定时
1.1 定时器类型
主要功能 | 高级定时器 | 通用定时器 | 基本定时器 |
更新中断和DMA(直接存储器访问) | √ | √ | √ |
计数方向 | 向下、向上、双向 | 向下、向上、双向 | 向上 |
内外时钟源选择 | √ | √ | |
其他定时器触发或级联 | √ | √ | |
输入捕获、输出比较 | √ | √ | |
单脉冲输出方式 | √ | √ | |
正交编码器输入 | √ | √ | |
霍尔传感器输入 | √ | √ | |
输出比较信号死区生产 | √ | ||
制动信号输入 | √ |
STM32芯片最多包含8个定时/计数器,其中
STM32F103C8T6定时器资源:TIM1、
TIM2
、
TIM3
、
TIM4
基本定时器
:集成了1个16位自动加载递增计数器、1个16位预分频器、1个16位自动重装载寄存器。可以作为定时器提供时间基准,特别的,
为DAC提供时钟,在芯片内部直接连接到DAC并通过触发输出直接驱动DAC
通用定时器
:集成了1个16位自动加载递增/递减计数器、1个16位预分频器、1个16位自动重装载寄存器
和4个独立通道。每个通道都可以用于输入捕获(测量输入信号的脉冲长度)、输出比较(PWM输出)和单脉冲输出
高级定时器
:集成了1个16位自动加载递增/递减计数器、1个16位预分频器、1个16位自动重装载寄存器和4个独立通道。通道的功能与通用定时器相同。高级定时器可以看作分配到6个通道的三相PWM发生器,它具有
带死区插入的PWM输出
,还可以作为通用定时器使用
上述三类定时器均可使用内部时钟源8MHz,均可以产生中断和DMA(直接寄存器访问)请求。除了基本定时器只有向上计数方式,其他两类均有向上、向下和双向3种计数方式
此外,STM2还具有
2个看门狗定时器和1个
系统滴答定时器(24位递减计数器)
1.2 计数模式
(1)向上计数模式:
计数器从0计数到自动加载值(TIMx_ARR),然后从0开始并产生一个上溢事件。每次计数溢出时,可产生一个更新事件,所有寄存器都被更新同时置更新标志位
(2)向下计数模式:
计数器从自动加载值(TIMx_ARR)向下计数到0,然后从ARR开始并产生一个
下溢事件。每次计数溢出时,可产生一个更新事件,所有寄存器都被更新同时置更新标志位
(3)中央对齐模式:
在中央对齐模式,计数器从0
开始计数到
自动加载的值(TIMx_ARR寄存器)
− 1
,产生一个计数器上溢事件,然后向下计数到1
并且产生一个计数器下溢事件;然后再从
0
开始重新计数。
1.3 时钟源
1.3.1 内部时钟(CK_INT)
当使用
内部时钟时,计数器对内部脉冲时钟进行计数,属于
定时功能
1.3.2 外部时钟模式1(外部输入引脚TIx)
计数器对输入通道的
TI1F_ED(上升沿、下降沿均有效)或这
TI1FP1、TI2FP2的每个上升沿下降沿进行计数,属于
计数功能
1.3.3 外部时钟模式2(外部触发输入ETR,External Trigger Input)
计数器对外部触发引脚
(TIMx_ETR)进行计数,属于
计数功能
1.3.4 内部触发输入(ITR,Internal Trigger Input)
使用一个定时器作为另一个定时器的预分频器
二、STM32定时器的结构(以通用定时器为例)
通用定时器主要包括1个外部触发引脚(TIMx_ETR,External Trigger Input),4个输入/输出通道(TIMx_CHx),1个内部时钟,1个触发控制器,一个时钟单元(预分频器PSC、自动重装载寄存器ARR和计数器CNT)
(1)定时/计数中断
预分频器对时钟信号进行分频,之后CNT计数器可以对分频后的时钟信号进行计数,当达到自动重装载寄存器ARR的值(向上计数)后,产生一个更新事件
实际分频系数=预分频器的值+1
计数频率:CK_CNT = CK_PSC / (PSC + 1)
溢出频率:CNT_OV = CK_PSC / (PSC + 1) / ARR
值得注意的是,
预分频器PSC、自动重装载寄存器ARR和4个捕获/比较寄存器都有一个在物理上与其对应的寄存器,称为
影子寄存器(阴影部分)。
预装载寄存器可以用程序读写,但影子寄存器无法被读写,在实际中
真正起作用的是影子寄存器。根据TIMx_CR1寄存器中自动装载预装载使能位(ARPE)的设置,预装载寄存器的内容被立即或每次产生更新事件时传入影子寄存器
(2)输出比较(Output Compare,OC)
输出比较可以通过
比较CNT与CCR
(捕获/比较)
寄存器值的关系,来对 输出电平进行置1、置0或翻转
的操作,用于输出一定频率和占空比的PWM
波形
①PWM频率与定时器的溢出频率相同
Freq = 时钟源频率 / 预分频系数 / 自动给重装载寄存器的值
(时钟源频率 / 预分频系数 = 计数的频率;计数的频率 / 目标值 = 溢出频率
②占空比:Duty = CCR/(ARR + 1)
③分辨率:占空比的变化步距
输出比较:CNT寄存器与CCR寄存器进行比较,当达到某个条件后,按照输出模式进行输出
OC1REF(reference,输出参考信号),可以输出至主模式控制器,还可以通过输出极性配置进行输出
输出比较模式:
(3)输入捕获模式(Input Capture)
频率测量:
①测频法:在既定的时间T内,测量上升沿或下降沿的次数N,每来一个边沿信号则认为是一个周期(
适用高频信号)
Freq = N / T
②测周法:在两个相同且相邻的边沿信号内以标准频率f进行计次N(
适用低频信号)
Freq = f / N
③中界频率:由于上述两种频率都会产生±1的误差,当N的值越大,其误差的影响就越小。当N相同时,则可得到中界频率(小于此频率,选用测周法比较合适;大于此频率,选用测频法比较合适)
※主从触发模式
主模式:
可以将定时器中的内部信号,输出至TRGO引脚,用于触发其他外设
从模式:
接收其他外设或自身的一些信号,用于控制自身定时器的运行
触发源:选择从模式的触发信号源
输入捕获的结构框图:
输入捕获测量波形频率的基本思想:
频率:当遇到输入波形的上升沿时,将
CNT中的值锁存到CCR1中,并
利用从模式实现CNT自动清0,当遇到下一个上升沿时,依然进行锁存,清零。此时已为一个波形的周期。CCR中存放一个完整周期的计数值。因此:标准频率 / (CCR+1)即为输入波形频率(由于CNT是从0开始计数,所以各个CCR的值都需要加1)
PWMI的结构框图:
测量PWM波形的频率和占空比的基本思想:
占空比:当遇到输入波形的上升沿时,将CNT中的值锁存到CCR1中,并利用从模式实现CNT自动清0,当遇到下降沿时,通过通道2,将CNT中的值锁存到CCR2中.当遇到下一个上升沿时,依然进行锁存,清零。此时已为一个波形的周期。CCR2中存放高电平时,计数的个数;CCR1存放一个周期内,计数的个数。当然,整个计数的频率都是相同的,因此:CCR2/CCR1即为占空比,由于CCR1<CCR2,若想使其显示百分比的形式,需要给CCR2✖100,即可(由于CNT是从0开始计数,所以CCR的值都需要加1)
频率:在一个完整的周期内,在标准频率下,CNT计数值锁存在CCR1中。因此:
标准频率 / (CCR1 + 1)即为波形频率(由于CNT是从0开始计数,所以各个CCR的值都需要加1)
(4)编码器接口(Encoder Interface)
正交信号:一个信号相对于另一路信号超前或滞后90°
当电机转的越快,其输出的方波频率就越高。简而言之,
方波频率代表了速度
优点:①精度高,A、B相均可以计次,频率相当于提高了一倍
②
抗噪声,正交信号是交替跳变的,当一个信号因噪声干扰跳变,另一个信号不 变, 使得计次值不会增加
工作流程:
编码器的正交信号,分别通过通道1和通道2输入,之后通过编码器接口,控制计数器的计数时钟和计数方向
在输入通道中会遇到极性选择,而
编码器的上升沿和下降沿均有效(CNT均计次)。此时,
极性选择表示高低电平的选择,
上升沿:高、低电平均不反转;下降沿:高、低电平均反转
编码器接口模式基本上相当于使用了一个
带有方向选择的外部时钟(接管定时器)
。这意味着计数器只在0
到 TIMx_ARR寄存器的自动装载值之间连续计数
(
根据方向,或是
0
到
ARR
计数,或是
ARR
到
0
计数)
。
(5)单脉冲模式
计数器响应一个激励,并在一个程序可控的延时之后,产生一个脉宽可程序控制的脉冲。
计数器
可以通过软件启动,也可以通过从模式触发
。计数器启动后,在下一个更新事件来临之前的时间段内实现固定个数的脉冲输出。当下一个更新事件来临时计数器停止计数。输出的脉冲个数可以一个或几个。如果是
通用计数器就是1个,如果是
高级定时器,
脉冲个数与RCR数值和计数模式有关。
三、定时器相关库函数
3.1 时基单元初始化:TIM_TimeBaseInit()
所谓时钟分频因子,就是数字滤波器的采样频率与定时器时钟之间的关系
3.2 输出比较初始化:TIM_OCInit()
高电平:极性不反转,低电平:极性反转
3.3 输入捕获初始化:TIM_ICInit()
3.4 定时器使能:TIM_Cmd()
3.5 定时器中断配置函数:TIM_ITConfig()
3.6 选择触发源TIM_SelectInputTrigger()
3.7 选择从模式TIM_SlectSlaveMode()
3.8 编码器接口配置:TIM_EncoderInterfaceConfig()
四、定时器配置流程
4.1 定时器中断配置
(1)开启定时器时钟
(2)选择定时器的时钟源
TIM_InternalClockConfig(TIM2); //使用内部时钟
(3)配置时钟单元,完成初始化(清除标志位)
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; //滤波器的采样频率是由内部时钟信号提供的,可以分频
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; //向上计数
TIM_TimeBaseInitStruct.TIM_Period = 10000-1; //自动重装载寄存器的值
TIM_TimeBaseInitStruct.TIM_Prescaler = 7200-1; //预分频器
TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0; //重复次数寄存器的值
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);
TIM_ClearFlag(TIM2,TIM_FLAG_Update); //TIM_TimeBaseInit()会产生一个更新
(4)配置定时器中断控制
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE); //中断配置:更新中断
(5)配置NVIC优先级分组
(6)配置NVIC,完成初始化
(7)使能定时器
4.2 定时器输出比较配置
(1)开启定时器时钟,GPIO(使用对应通道的引脚)
如果选择重映射的方式,先要使能AFIO时钟,并进行重映射配置
如果重映射的方式,还需要将调式的功能关闭
(2)进行GPIO配置,完成初始化(配置为复用推挽输出)
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
(3)选择定时器的时钟源
TIM_InternalClockConfig(TIM2); //使用内部时钟
(4)配置时钟单元,完成初始化
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; //滤波器的采样频率是由内部时钟信号提供的,可以分频
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; //向上计数
TIM_TimeBaseInitStruct.TIM_Period = 100-1; //自动重装载寄存器的值
TIM_TimeBaseInitStruct.TIM_Prescaler = 720-1; //预分频器
TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0; //重复次数寄存器的值
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);
(5)配置输出比较单元,完成初始化
TIM_OCInitTypeDef TIM_OCInitStruct;
TIM_OCStructInit(&TIM_OCInitStruct);
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1; //PWM1模式
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High; //极性不反转
TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_Pulse = 0; //CCR
TIM_OC1Init(TIM2,&TIM_OCInitStruct);
(6)使能定时器
4.3 定时器输入捕获比较配置
(1)开启定时器时钟,GPIO(使用对应通道的引脚)
如果选择重映射的方式,先要使能AFIO时钟,并进行重映射配置
如果重映射的方式,还需要将调式的功能关闭
(2)进行GPIO配置,完成初始化(配置为浮空输入)
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
(3)选择定时器的时钟源
TIM_InternalClockConfig(TIM3); //使用内部时钟
(4)配置时钟单元,完成初始化
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; //滤波器的采样频率是由定时器提供的
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; //向上计数
TIM_TimeBaseInitStruct.TIM_Period = 65535-1; //自动重装载寄存器的值
TIM_TimeBaseInitStruct.TIM_Prescaler = 72-1; //预分频器
TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0; //重复次数寄存器的值,高级定时的功能
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);
(5)配置输入捕获单元,完成初始化
TIM_ICInitTypeDef TIM_ICInitStruct;
TIM_ICInitStruct.TIM_Channel = TIM_Channel_1; //通道1
TIM_ICInitStruct.TIM_ICFilter = 0xF; //数字滤波器
TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿
TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1; //分频系数为1
TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI; //直接通道
TIM_ICInit(TIM3,&TIM_ICInitStruct);
(6)选择从模式的触发源,并选择从模式
TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1); //选择TIM通道1的TI1FP信号作为触发源
TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset); //选择从模式:复位,自动实现CNT清零
(6)使能定时器
4.4 定时器编码器接口配置
(1)开启定时器时钟,GPIO(使用对应通道的引脚)
如果选择重映射的方式,先要使能AFIO时钟,并进行重映射配置
如果重映射的方式,还需要将调式的功能关闭
(2)进行GPIO配置,完成初始化
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; //上拉输入
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
(3)配置时钟单元,完成初始化
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; //滤波器的采样频率是由内部时钟信号提供的,可以分频
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; //计数方式也被编码器托管
TIM_TimeBaseInitStruct.TIM_Period = 65535-1; //自动重装载寄存器的值
TIM_TimeBaseInitStruct.TIM_Prescaler = 1-1; //预分频器
TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0; //重复次数寄存器的值
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);
(4)配置输出比较单元,完成初始化
TIM_ICInitTypeDef TIM_ICInitStruct;
TIM_ICStructInit(&TIM_ICInitStruct); //结构体成员默认值
TIM_ICInitStruct.TIM_Channel = TIM_Channel_1 | TIM_Channel_2;
TIM_ICInitStruct.TIM_ICFilter = 0xF;
TIM_ICInit(TIM3,&TIM_ICInitStruct);
(5)配置编码器接口
TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising); //上升沿:高低电平不反转
(6)使能定时器
作者:℡☞小白☜ღ