个人技术分享

一、 STM32定时器的组成结构(了解)

1.1 定时器的概述

STM32内部集成了多个定实/计数器,根据型号不同,STM32系列芯片最多包含8个定时/计数器。其中TIM6和TIM7为基本定时器,TIM2·TIM5为通用定时器,TIM1和TIM8为高级控制定时器,功能最强。
三类定时器均可使用8MHz内部时钟作为时钟源,16位计数单元最大计数为65536,均可产生中断和DMA请求。除基本定时器计数方向为向上外,其他两类定时器均有向上、向下和双向3种计数方向。
1. 主要功能介绍
外部事件计数:可计算外部脉冲个数、频率和宽度。
输入捕获:用来计算脉冲频率和宽度。
输出比较:用来控制一个输出波形,或者指示一段给定的事件已经到时。
单脉冲输出:响应一个激励,并在一个程序可控的延时之后,产生一个宽度可程序控制的脉冲。
正交编码器:可计算编码器的运行情况。
霍尔传感器输入:可用来捕获霍尔信号,主要用在马达控制上。
输出比较信号死区产生:高级点十七能够输出两路互补信号,并且能够管理输出的瞬时关断和接通,这段时间通常成为死区。
刹车信号输入功能:用来完成紧急停止。
2. 定时器的类型
基本定时器:基本定时器内部集成了1个16位自动加载递增计数器、1个16位预分频器。两个基本定时器时相互独立的,不共享任何资源。可以作为通用定时器提供事件基准,特别地可以位数模转化器提供时钟,在芯片内部直接连接到DAC并通过触发输出直接驱动DAC。
通用定时器:通用定时器内部集成了1个16位自动加载递增/递减计数器、1个16位预分频器和4个独立通道。每一个通道都可以用于输入捕获、输出比较、PWM输出和单脉冲输出,通用定时器之间是完全独立的,没有互相共享任何资源。
高级控制定时器:高级控制定时器内部集成了1个16位自动加载递增/递减计数器、1个16位预分频器和4个独立通道。每一个通道都可以用于输入捕获、输出比较、PWM输出和单脉冲输出。高级定时器可以被看成分配6个通道的三相PWM发生器,它具有带死区插入的PWM输出,还可以用作完整的通用定时器。
在这里主要介绍通用定时器,实现其基本定实功能。

1.2 通用定时器的结构特性

STM32可编程通用定实/计数器的主要组成部分包括1个外部触发引脚(TIMx_ETR),4个输入输出通道(TIMx_CHy),1个内部时钟,1个触发控制器,1个时钟单元。通用定时器的基本结构如下图所示:
来自STM32F103数据手册
(1)STM32F103的通用定时器有两个外部触发引脚:TIM2_ETR和TIM3_ETR。外部触发引脚经过极性选择、边沿检测、预分频器和输入滤波连接到触发控制器,触发其他定时器、DAC/ADC或经过触发控制器中的从模式控制器连接到PSC预分频实现计数功能。
(2)STM32F103C8T6的有3通用定时器共12个捕获/比较通道。每一个捕获通道/比较通道都围绕着一个捕获/比较寄存器,包括捕获的输入部分和输出部分。输入部分对应TIx(x = 1,2,3,4)输入信号经过信号采用,京输入滤波器和边沿检测器产生一个信号,该信号可以作为从模式控制器的输入触发,并通过预分频进入捕获寄存器作为捕获控制或产生一个中间波形经输出控制后输出。

二、通用定时器相关寄存器(了解)

  1. 计数器——TIMx_CNT
    该寄存器是定时器的计数器,存储了当前定时器的计数值。
    在这里插入图片描述

  2. 预分频器——TIMx_PSC
    该寄存器是定时器的预分频器,粗怒气了当前预分频器的预装载寄存器的值。
    在这里插入图片描述

  3. 自动重装载寄存器——TIMx_ARR
    该寄存器是定时器的自动重装载寄存器,存储了当前自动重装载寄存器的预装载寄存器的值。
    在这里插入图片描述

  4. 状态寄存器——TIMx_SR
    该寄存器是定时器的状态寄存器,标记当前于定时器相关的各种事件/中断是否发生。
    在这里插入图片描述

  5. 控制寄存器1——TIMx_CR1
    该寄存器用来设置时钟分频、计数方向、计数器使能等。
    在这里插入图片描述
    在这里插入图片描述

  6. 控制寄存器2——TIMx_CR2
    该寄存器用来设置输入输出通道。
    在这里插入图片描述

  7. 从模式控制寄存器——TIMx_SMCR
    该寄存器用来设置外部触发。
    在这里插入图片描述

  8. 事件产生寄存器——TIMx_EGR
    该寄存器用来设置产生事件。
    在这里插入图片描述
    在这里插入图片描述

  9. 捕获/比较使能寄存器——TIMx_CCER
    该寄存器用来设置捕获/比较使能。
    在这里插入图片描述

  10. 捕获/比较模式寄存器1——TIMx_CCMR1
    该寄存器用来设置输入输出通道1和输入输出通道2的捕获/比较的模式。
    在这里插入图片描述

  11. 捕获/比较模式寄存器2——TIMx_CCMR2
    该寄存器用来设置输入输出通道3和输入输出通道4的捕获/比较的模式。
    在这里插入图片描述

  12. 捕获/比较寄存器1——TIMx_CCR1
    该寄存器存储了输入输出通道1的捕获/比较寄存器的值。还有3个捕获比较寄存器于TIMx_CCR1类似。
    在这里插入图片描述
    上诉图片来自于STM32F103系列数据手册的截屏,相关寄存器的功能熟悉了解即刻。明白寄存器都是做什么用的就可以了,不需要完全的记忆,也记不住呀!!!

三、功能及工作方式(熟悉)

3.1 时基单元

时基单元是设置定时器/计数器时钟的基本单元,包含计数器寄存器、预分频器、自动重装载寄存器。根据实际需求,由软件设置预分频器寄存器,可以得到定时器/计数器的计数时钟。

  1. 计数器寄存器(TIMx_CNT):由预分频器的时钟输出CK_CNT驱动,当设置了控制寄存器TIMx_CR1中的计数器使能位(CEN)时,CK_CNT才有效。就是通过调用库函数中的TIM_SetCounter()函数。
  2. 预分频器寄存器(TIMx_PSC):可以将计数器的时钟频率按1~65536之间的任意值分频。这个控制寄存器带有缓冲器,它能够在工作时被改变。就是调用库函数中的TIM_Prescalor()函数。
  3. 自动装载寄存器(TIMx_ARR):是预先装载的,写或读自动装载寄存器将访问预装载寄存器。
    下图为当预分频的参数从1变到2时计数器的时许图。
    在这里插入图片描述

四、常用库函数介绍(掌握)

  1. 函数TIM_TimeBaseInit:初始化TIM的事件基数单位。
typedef struct 
{
	uint16_t TIM_Period;  // 自动重装载值
	uint16_t TIM_Prescaler; // 预分频值
	uint8_t TIM_ClockDivision; //时钟分割
	uint8_t TIM_CounterMode;
}TIM_TimeBaseInitTypeDef;
  1. 函数TIM_Cmd:使能或使能TIMx外设。
    该函数的使用方法:
//使能TIM2、
TIM_Cmd(TIM2,ENABLE);
  1. 函数TIM_ITConfig:使能或使能指定的TIM中断。
    该函数的使用方法:
//使能TIM2的捕获/比较中断
TIM_ITConfig(TIM2,TIM_IT_CC1,ENABEL);
  1. 函数TIM_SetCounter:设置TIMx计数器寄存器值。
    该函数的使用方法:
//设置TIM2新的计数值
uint16_t TIMcounter = 0xfff;
TIM_SetCounter(TIM2,TIMcounter );
  1. 函数TIM_GetFlagStatus:检查指定的TIM标志位设置与否。
    该函数的使用方法:
// 检查TIM2捕获/比较标志位是否为1
if(TIM_GetFlagStatus(TIM2,TIM_FLAG_CC1)  == 1)
{}
  1. 函数TIM_ClearFlag:清除TIMx的待处理标志位。
    该函数的使用方法:
//清除TIM2捕获/比较1标志位
TIM_ClearFlag(TIM2,TIM_FLAG_CC1) 
  1. 函数TIM_GetITStatus:
    该函数的使用方法:
//检查TIM2捕获/比较1中断是否发生
if(TIM_GetITStatus(TIM2,TIM_IT_CC1)  == 1)
{}
  1. 函数TIM_ClearITPendingBit:
    该函数的使用方法:
//清除TIM2捕获/比较1中断挂起位
TIM_ClearITPendingBit(TIM2,TIM_IT_CC1)

上诉函数为常用的几种库函数,如果有其他需求可以参考相关库函数资料。

五、定时器案例

  1. 案例介绍:使用定时器实现LED的闪烁。
  2. Timer.c
#include "Timer.h"

#define BoardClkNum 8

void Timer2_Iint(void) 
{
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE);
	//定时时间 time = Period*Prescaler/(SYSCLK) (Unit: s)
  //例:     1s=    10000*7200/72M = 1s 
	TIM_TimeBaseStructure.TIM_ClockDivision  = TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_Period = 29999;   
	TIM_TimeBaseStructure.TIM_Prescaler = 7199;     // 3s
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //正向计数
	TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
  TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);
		
  TIM_ClearFlag(TIM2, TIM_FLAG_Update);
  TIM_ITConfig(TIM2, TIM_IT_Update,ENABLE);
	
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;   // 响应优先级
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;  // 抢占优先级
	NVIC_Init(&NVIC_InitStructure);
	
  TIM_Cmd(TIM2,ENABLE);	
}
  1. stm32f10x_it.h文件
void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2,TIM_IT_Update) != RESET)
	{
		  GPIO_WriteBit(GPIOC,GPIO_Pin13,(BitAction)((1-GPIO_ReadOutputDataBit(GPIOC,GPIO_Pin_13))));
	}
	TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
}
  1. main.c 文件
#include "stm32f10x.h"
#include "LedDriver.h"
#include "Timer.h"


void main()
{
	LedDriver_Init();
	Timer2_Init();
	GPIO_RseetBits(GPIOC,GPIO_Pin_13);
	while(1)
	{}
}