【STM32F4教程】第五节:通用定时器之精准延时

A strong man will struggle with the storms of fate.(Thomas Addison)

强者能同命运的风暴抗争。(爱迪生)

通用定时器之精准延时

通用定时器概述

STM32定时器分类

TIM2  到 TIM5  主要特性

 

TIM9 到 TIM14 通用定时器具有以下特性:

通用定时器的应用:

通用定时器的计数模式:

定时器的时钟来源有 4 个:

定时器中断的配置

定时器时钟实现例程

tim.c

main.c


通用定时器概述

定时器:芯片内通过计数得到定时时长的外设。

定时器时长短与什么有关:定时器的频率及设置计数大小有关

STM32定时器分类

定时器分类:高级定时器 通用定时器 基本定时器

       高级定时器:TIM1 TIM8

       通用定时器:TIM2 TIM3 TIM4 TIM5 TIM9 TIM10 TIM11 TIM12 TIM13 TIM14

       基本定时器:TIM6 TIM7

定时器都挂在APB1及APB2下

       挂在APB1定时器: TIM2、TIM3、TIM4、TIM5、TIM6、TIM7、TIM12、TIM13、TIM14

       挂在APB2定时器:  TIM1、TIM8、TIM9、TIM10、TIM11

如果APB预分频器为1,定时器时钟频率等APB域的频率。否则,等于APB域的频率的两倍(×2)

       挂在APB1定时器频率:APB1X2 = 42MHZ X2 = 84MHZ

       挂在APB2定时器频率:APB2X2 = 84MHZ X2 = 168MHZ

        STM32F4 的定时器有14个,其中TIM2~TIM5,TIM9~TIM14属于通用定时器,TIM1 和TIM8 则属于高级控制定时器,TIM6和TIM7是基本定时器。

 

TIM2 到 TIM5  主要特性

16 位(TIM3 和 TIM4)或 32 位(TIM2 和 TIM5) 递增、递减和递增/递减自动重载计数器。

16 位可编程预分频器,用于对计数器时钟频率进行分频(即运行时修改) ,分频系数介于 1 到 65536 之间。

多达 4 个独立通道,可用于:

  1. 输入捕获
  2. 输出比较
  3. PWM 生成(边沿和中心对齐模式)
  4. 单脉冲模式输出

 使用外部信号控制定时器且可实现多个定时器互连的同步电路。

发生如下事件时生成中断/DMA 请求(6个独立的IRQ/DMA请求生成器):

  1. 更新:计数器上溢/下溢、计数器初始化(通过软件或内部/外部触发)
  2. 触发事件(计数器启动、停止、初始化或通过内部/外部触发计数)
  3. 输入捕获
  4. 输出比较

支持定位用增量(正交)编码器和霍尔传感器电路

外部时钟触发输入或逐周期电流管理

TIM9到 TIM14 通用定时器具有以下特性

16 位自动重载递增计数器(属于中等容量器件)

16 位可编程预分频器,用于对计数器时钟频率进行分频(即运行时修改),分频系数介于 1 和 65536 之间

多达 2 个独立通道,可用于:

  1. 输入捕获
  2. 输出比较
  3. PWM 生成(边沿对齐模式)
  4. 单脉冲模式输出

使用外部信号控制定时器且可实现多个定时器互连的同步电路

发生如下事件时生成中断:

  1. 更新:计数器上溢、计数器初始化(通过软件或内部触发)
  2. 触发事件(计数器启动、停止、初始化或者由内部触发计数)
  3. 输入捕获
  4. 输出比较

通用定时器的应用:

       STM32 的通用定时器可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和 PWM)等。   

使用定时器预分频器和 RCC 时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个毫秒间调整。STM32 的每个通用定时器都是完全独立的,没有互相共享的任何资源。

通用定时器的计数模式:

通用定时器可以向上计数、向下计数、向上向下双向计数模式。

  1. 向上计数模式:计数器从0计数到自动加载值(TIMx_ARR),然后重新从0开始计数并且产生一个计数器溢出事件。
  2. 向下计数模式:计数器从自动装入的值(TIMx_ARR)开始向下计数到0,然后从自动装入的值重新开始,并产生一个计数器向下溢出事件。
  3. 中央对齐模式(向上/向下计数):计数器从0开始计数到自动装入的值-1,产生一个计数器溢出事件,然后向下计数到1并且产生一个计数器溢出事件;然后再从0开始重新计数。

定时器的时钟来源有 4 个:

  1. 内部时钟(CK_INT)
  2. 外部时钟模式 1:外部输入脚(TIx)
  3. 外部时钟模式 2:外部触发输入(ETR) ,仅适用于 TIM2、TIM3、TIM4
  4. 内部触发输入(ITRx) :使用 A 定时器作为 B 定时器的预分频器(A 为 B 提供时钟) 。

        这些时钟,具体选择哪个可以通过 TIMx_SMCR 寄存器的相关位来设置。这里的 CK_INT时钟是从 APB1 倍频的来的,除非 APB1 的时钟分频数设置为 1(一般都不会是 1) ,否则通用定时器 TIMx 的时钟是 APB1 时钟的 2 倍,当 APB1 的时钟不分频的时候,通用定时器 TIMx的时钟就等于 APB1 的时钟。这里还要注意的就是高级定时器以及 TIM9~TIM11 的时钟不是来自 APB1,而是来自 APB2 的。

定时器中断的配置

定时器相关的库函数主要集中在固件库文件 stm32f4xx_tim.h 和 stm32f4xx_tim.c 文件中。定时器配置步骤如下:

1、能定时器时钟。根据定时器挂在APB1及APB2还是下

void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState)//定时器挂在APB1 
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState)//定时器挂在APB2

2、初始化定时器,配置ARR,PSC。

void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)

3、启定时器中断,配置NVIC。

void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)

4、设置 TIM3_DIER  允许更新中断

void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState)

5、使能定时器。

void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState)

6、编写中断服务函数。

TIMx_IRQHandler();

定时器时钟实现例程

以TIM3通用定时器为例

tim.c

#include "tim.h"

static __IO uint32_t TimingDelay;

//延迟函数
void Delay(__IO uint32_t nTime)
{ 
   TimingDelay = nTime;
   while(TimingDelay != 0);
}

/*
定时器说明
TIM3 -- APB1
定时器TIM3:84MHZ

16位定时器:值范围:0~65535
*/
void Tim3_Init(void)
{
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseInitStruct;        //初始化定时器结构体
	NVIC_InitTypeDef  NVIC_InitStruct;			//配置NVIC结构体
	
	//1、能定时器时钟。
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	
	TIM_TimeBaseInitStruct.TIM_Prescaler    = 84-1;    		//84分频 84MHZ/84 = 1MHZ
	TIM_TimeBaseInitStruct.TIM_Period		= 1000-1;  		//计1000个数 在1MHZ下,用时1ms
	TIM_TimeBaseInitStruct.TIM_CounterMode  = TIM_CounterMode_Up; 	//向上计数
	TIM_TimeBaseInitStruct.TIM_ClockDivision= TIM_CKD_DIV1; 	//分频因子
	//2、初始化定时器,配置ARR,PSC。
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);
	
	
	NVIC_InitStruct.NVIC_IRQChannel					 = TIM3_IRQn;//NVIC通道,在stm32f4xx.h可查看通道 (可变)
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority= 0x01;	    //抢占优先级
	NVIC_InitStruct.NVIC_IRQChannelSubPriority		 = 0x01;	    //响应优先级
	NVIC_InitStruct.NVIC_IRQChannelCmd				 = ENABLE;   //使能
    //3、启用定时器中断,配置NVIC。
	NVIC_Init(&NVIC_InitStruct);		
	
	//4、设置 TIM3_DIER  允许更新中断
	TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
	
	//5、使能定时器。
	TIM_Cmd(TIM3, ENABLE);
}

//编写中断服务函数。这个函数不需要程序员在主函数调用,满足条件CPU自行调用的函数
//每来一次中断就TimingDelay的值就减一
void TIM3_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET) //溢出中断
	{
		if (TimingDelay != 0x00) 
		{ 
			TimingDelay--;
		}
	}
	TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //清除中断标志位
}

main.c

#include "stm32f4xx.h"
#include "led.h"
#include "key.h"
#include "exti.h"
#include "delay.h"
#include "tim.h"

int main(void)
{
	//NVIC分组(一个工程当中只能配置一次分组)抢占优先级2位,值范围:0~3;响应优先级2位,值范围:0~3;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	//LED灯初始化
	Led_Init();
	//定时器3初始化
	Tim3_Init();
	

	while(1)
	{
		GPIO_ToggleBits(GPIOE, GPIO_Pin_14);
		Delay(1000);
	}
	return 0;
}

 


版权声明:本文为qq_44796935原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。