文章目录
一、定时器基础知识。
定时器概述
stm32系列的cpu,有8个定时器。定时器是完全独立的,没有互相共享的资源。定时器可以与定时器形成级联,组建更大的定时范围。所有定时器的时钟以72M作为标志(若使用默认的库配置方式配置时钟为72M)。具体有
- 2个基本定时器(TIM6、TIM7)
- 4个通用定时器(TIM2-TIM5)
- 2个高级定时器(TIM1、TIM8)
-
基本定时器类似51单片机的定时器,具有定时/计数的功能。 它是一个通过可编程预分频器驱动的16bit的自带装载计数器构成。
-
通用定时器是 基本定时器拓展而来,增加了输入捕获与输出比较等功能。
-
高级定时器是由 通用定时器 拓展而来,增加了可编程死去互补输出、重复计数器、带刹车功能。(高级定时器很少使用)
功能简介
输入捕获:可以用来捕获外部事件,并为其赋予时间标记以说明此事件的发生时刻。主要是用来测量外部信号的频率,测量输入信号的脉冲长度
输出比较:产生输出波形。
PWM生成:略
单脉冲模式输出:略
互补输出:用于三相点击的驱动,防死机。
计数模式介绍
- 向上计数模式 ↑↑
向上计数模式中,计数器从 0 计数到 自动装入的值 (TIMx ARR计数器内容),然后重新从0开始计数并且产生一个计数器溢出事件。当TIMx_CR1寄存器中的DIR位为低的时候执行向上计数。 - 向下计数模式 ↓↓
在向下模式中,计数器从 自动装入的值 (TIMx_ ARR)开始向下计数到 0 ,然后从自动装入的值重新开始,并产生一个计数器向下溢出事件。当TIMx_ _CR1寄存器的DIR位为高时执行向下计数。 - 向上/向下计数模式(中央对齐模式)↑↓↑↓
向上/向下计数模式(中央对齐模式)是计数器从 0 开始计数到 自动装入的值 ,产生一个计数器溢出事件,然后 向下计数 到 1 并且产生一个计数器溢出事件;然后再从 0 开始重新计数。当TIMx_ CR1 寄存器中的CMS位不为0时为中央对齐模式。形象点就是来回往复计数。
时基单元
时基单元有三个主要部分:计数器(Counter)、预分频器(Prescaler)、和自动重载寄存器(Auto-Reload Register)。 我们可以在任何时间任何状态下对这三个主要部分进行读写操作。还有个程序员无法读写的,用作缓冲的影子寄存器。
-
PSC预分频器:
其工作就是对其输入时钟CK_PSC进行分频,以得到自己想要的计数器时钟CK_CNT用于驱动计时器计数。(CK_CNT=CK_PSC/(PSC+1), 其中PSC+1的+1 是为了防止PSC=0时出现除以0的错误) -
CNT计数器:
有16位,即计数范围是(0~65535),在CK_CNT的驱动下 向上计数/向下计数/中央对齐计数。 -
自动重载寄存器:
定义了计数器只能在0与该寄存器的值ARR之间计数。
每当计数器向上计数到达ARR,或者向下计数到达0时,就会产生一次UEV事件,如果开启了中断,将产生相应的中断信号。 -
影子寄存器:
仔细观察,功能框图上,PSC预分频寄存器、ARR自动重新装载寄存器都有一个影子。影子寄存器起到一个缓冲的作用。
根据TIMx_ CR1 寄存器中APRE位的设置:
APRE=0时,预装载寄存器的内容可以随时传送到影子寄存器,此时2者是连通的;
而APRE=1时,在每一次更新事件(UEV)时,才把预装在寄存器的内容传送到影子寄存器。
即我们定义的值不会立马产生作用,而是在溢出中断来临后再产生作用。、
计数器时序图
- 向上计数模式
这里的分频因子的值就是预分频器的值。预分频器可以将计数器的时钟频率按1到65536之间的任意值分频
- 向下计数模式
- 中央对齐模式
定时时间的计算
一般根据计数器时钟频率,预分频器,自动重装载寄存器,来计算定时时间。
关于STM32定时器,在库设置默认的情况下,TIMx(1-8)的时钟频率都是72M的时钟;
我们一般只用设置 预分频器 和 自动重装载寄存器 来设置定时时间。
//这里的定时器计数模式是 向上计数模式
TIM_TimeBaseInitStructure.TIM_Period = 60000-1; //设置自动重装载值
TIM_TimeBaseInitStructure.TIM_Prescaler=36000-1; //设置定时器预分频数
TIM_Prescaler 预分频系数为35999,表示定时器的时钟频率CK_CNT 为72M/(35999+1) = 2000Hz
,那么就是周期就是1/2000 s = 0.5 ms
,表示每0.5ms 根据设定的计数模式把计数寄存器的值 +1 或 -1。
TIM_Period 自动重装载系数是59999,当计数值寄存器到达59999+1时,产生事件出现中断,即定时器在 0.5 * (59999+1) ms = 30 s
产生一个事件(如中断事件)。
计算公式如下:
Tout= ((arr+1)*(psc+1))/Tclk;
Tout: 一次计时的时间
Tclk: 输入的时钟频率(单位为 Mhz)。
arr : 自动重装载系数
psc : 预分频系数
二、基本定时器(TIM6,TIM7)简介。
主要特性
- 计数器16bit(0~65535),计数模式只有向上计数.
- 时钟来自PCLK1,为72M,可实现1~65535分频。
- 没有GPIO,属于内部资源,只能用来定时。
基本定时器框图
-
时钟源:只有一个时钟来源,是CK_INT内部时钟,从APB1总线通过倍频器得来。
-
控制器:包括触发控制器,控制器。
触发控制器,可以触发DAC。
控制器,可以控制定时器的时钟来源,复位,使能,计数。 -
时基单元:包括PSC预分频寄存器,CNT计数器寄存器,自动重装载寄存器, ARR影子寄存器。
PSC预分频寄存器:可以对得到的CK_PSC时钟频率再次分频,以得到自己想要的计数器时钟CK_CNT。(CK_CNT=CK_PSC/(PSC+1),除以 PSC+1 使为了防止出现除以0的错误)
CNT计数器寄存器:在计数器时钟的驱动下开始计数,在脉冲到来后+1或者-1。
ARR自动重装载寄存器:在计数器寄存器溢出之后,对其进行重新装载计数的值。
影子寄存器:仔细观察,功能框图上,PSC预分频寄存器、ARR自动重新装载寄存器都有一个影子。影子寄存器起到一个缓冲的作用。用户定义值->寄存器->影子寄存器->产生作用。即我们定义的值不会立马产生作用,而是在溢出中断来临后再产生作用。其控制位在TIMx_CR1:APRE。一般我们很少使用这个寄存器。
三、通用定时器(TIM2~TIM5)简介。
主要特性
- 计数器16bit(0~65535),计数模式有向上计数,向上计数,向上/向下计数。
- 时钟来自PCLK1,为72M,可实现1~65535分频。
- 有4个独立通道(TIMx_CH1~TIMx_CH4),这些通道可以用来作为输入捕获,输出比较,PWM生成,单脉冲模式输出。
通用定时器框图
-
时钟源:
·内部时钟(CK_ INT)
·外部时钟模式1:外部输入脚(TIx)
·外部时钟模式2:外部触发输入(ETR)
·内部触发输入(ITRx):使用一-个定时器作为另–个定时器的预分频器,如可以配置–个定时器Timer1而作为另一个定时器Timer2的预分频器。 -
控制器
·触发控制器:用来片内外设输出一个触发信号,如作为其他定时器的时钟,触发DAC/ADC的转换
·从模式控制器:控制计数器的复位,使能,向上/向下,计数。
·编码器接口:不清楚 -
时基单元:
同基本定时器,略 -
输入捕获
其功能大概有:捕获输入信号的上升沿,下降沿,双边沿。获取输入信号的频率,占空比。
有4个输入通道,分别对应到不同的GPIOI口。(可以通过映射,把通道映射到不同的GPIO口)
-
输出比较
有4个输出通道,略。
四、高级定时器(TIM1,TIM8)简介 略。
略
五、相关的配置寄存器
具体参考中文手册。
六、定时器中断编程
通过配置定时器2的相关配置寄存器,实现1s产生一次中断,改变led1的状态。通过开发板上的led灯观察效果。
思路:
- 使能定时器时钟
- 配置定时器的相关参数:预分频系数,计数方式,计数值。
- 配置定时器中断优先级,并使能定时器中断
- 使能定时器,开始计数
- 编写中断服务函数
对应使用的库函数如下:
-
RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState)
使能定时器时钟,定时器默认时钟为系统内部时钟。 -
TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)
配置定时器的相关参数 -
TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState)
用来使能所需的定时器中断 -
NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)
配置定时器中断优先级 -
TIM_Cmd()
定时器使能 -
ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT)
获取中断标志位 -
TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT)
清除中断标志位
//TIMx参数是 指定配置的定时器,
//TIM_TimeBaseInitStruct参数 是 配置参数结构体
void TIM_TimeBaseInit(TIM_TypeDef*TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
typedef struct
{
uint16_t TIM_Prescaler; //预分频系数,0-35999
uint16_t TIM_CounterMode; //设置计数方式,向上、向下、向下向上
uint16_t TIM_Period; //设置自动重载计数周期值,定义cnt为多少时产生中断,
uint16_t TIM_ClockDivision; //设置时钟分频因子,用于输入捕获的滤波
uint8_t TIM_RepetitionCounter; //高级时钟用的
} TIM_TimeBaseInitTypeDef;
timer.h
#ifndef TIMER_H
#define TIMER_H
#include "stm32f10x.h"
#include "Tool.h"//这个文件位绑定了led1
void TIM2_Init(u16 arr,u16 psc);
#endif
timer.c
#include "timer.h"
void TIM2_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //时钟使能,定时器
TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim,因为不用到输入捕获这句可以省略
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断
//中断优先级NVIC设置
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //TIM2中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //初始化NVIC寄存器
TIM_Cmd(TIM2, ENABLE); //使能TIMx
}
//定时器2中断服务程序
void TIM2_IRQHandler(void) //TIM2中断
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) //检查TIM2更新中断发生与否
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update ); //清除TIM2更新中断标志
led1 = !led1;
}
}
main.c
#include "led.h"
#include "Tool.h"
#include "timer.h"
int main(void)
{
led_init();
TIM2_Init(1999,35999);
led1 = 0;
led2 = 0;
printf("system start!\n");
while(1)
{
}
}