stm32学习笔记-定时器

一、定时器基础知识。

定时器概述

stm32系列的cpu,有8个定时器。定时器是完全独立的,没有互相共享的资源。定时器可以与定时器形成级联,组建更大的定时范围。所有定时器的时钟以72M作为标志(若使用默认的库配置方式配置时钟为72M)。具体有

  • 2个基本定时器(TIM6、TIM7)
  • 4个通用定时器(TIM2-TIM5)
  • 2个高级定时器(TIM1、TIM8)
  1. 基本定时器类似51单片机的定时器,具有定时/计数的功能。 它是一个通过可编程预分频器驱动的16bit的自带装载计数器构成。

  2. 通用定时器是 基本定时器拓展而来,增加了输入捕获输出比较等功能。

  3. 高级定时器是由 通用定时器 拓展而来,增加了可编程死去互补输出重复计数器带刹车功能。(高级定时器很少使用)

在这里插入图片描述
功能简介
输入捕获:可以用来捕获外部事件,并为其赋予时间标记以说明此事件的发生时刻。主要是用来测量外部信号的频率,测量输入信号的脉冲长度
输出比较:产生输出波形。
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. 向上计数模式
    这里的分频因子的值就是预分频器的值。预分频器可以将计数器的时钟频率按1到65536之间的任意值分频
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  2. 向下计数模式
    在这里插入图片描述
  3. 中央对齐模式
    在这里插入图片描述

定时时间的计算

一般根据计数器时钟频率预分频器自动重装载寄存器,来计算定时时间。

在这里插入图片描述
关于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)简介。

主要特性

  1. 计数器16bit(0~65535),计数模式只有向上计数.
  2. 时钟来自PCLK1,为72M,可实现1~65535分频。
  3. 没有GPIO,属于内部资源,只能用来定时。

基本定时器框图

在这里插入图片描述

  1. 时钟源:只有一个时钟来源,是CK_INT内部时钟,从APB1总线通过倍频器得来。
    在这里插入图片描述

  2. 控制器:包括触发控制器,控制器。
    触发控制器,可以触发DAC。
    控制器,可以控制定时器的时钟来源,复位,使能,计数。

  3. 时基单元:包括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)简介。

主要特性

  1. 计数器16bit(0~65535),计数模式有向上计数向上计数向上/向下计数
  2. 时钟来自PCLK1,为72M,可实现1~65535分频。
  3. 有4个独立通道(TIMx_CH1~TIMx_CH4),这些通道可以用来作为输入捕获输出比较PWM生成,单脉冲模式输出。

通用定时器框图

在这里插入图片描述

  1. 时钟源:
    ·内部时钟(CK_ INT)
    ·外部时钟模式1:外部输入脚(TIx)
    ·外部时钟模式2:外部触发输入(ETR)
    ·内部触发输入(ITRx):使用一-个定时器作为另–个定时器的预分频器,如可以配置–个定时器Timer1而作为另一个定时器Timer2的预分频器。

  2. 控制器
    ·触发控制器:用来片内外设输出一个触发信号,如作为其他定时器的时钟,触发DAC/ADC的转换
    ·从模式控制器:控制计数器的复位,使能,向上/向下,计数。
    ·编码器接口:不清楚

  3. 时基单元:
    同基本定时器,略

  4. 输入捕获
    其功能大概有:捕获输入信号的上升沿,下降沿,双边沿。获取输入信号的频率,占空比。
    有4个输入通道,分别对应到不同的GPIOI口。(可以通过映射,把通道映射到不同的GPIO口)
    在这里插入图片描述

  5. 输出比较
    有4个输出通道,略。

四、高级定时器(TIM1,TIM8)简介 略。

五、相关的配置寄存器

具体参考中文手册。
在这里插入图片描述
在这里插入图片描述

六、定时器中断编程

通过配置定时器2的相关配置寄存器,实现1s产生一次中断,改变led1的状态。通过开发板上的led灯观察效果。
思路:

  1. 使能定时器时钟
  2. 配置定时器的相关参数:预分频系数,计数方式,计数值。
  3. 配置定时器中断优先级,并使能定时器中断
  4. 使能定时器,开始计数
  5. 编写中断服务函数

对应使用的库函数如下:

  1. RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState)
    使能定时器时钟,定时器默认时钟为系统内部时钟。

  2. TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)
    配置定时器的相关参数

  3. TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState)
    用来使能所需的定时器中断

  4. NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)
    配置定时器中断优先级

  5. TIM_Cmd()
    定时器使能

  6. ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT)
    获取中断标志位

  7. 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)
	{	
	}
}

  • 5
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值