| 一、STM32F103定时器分类及区别共有8个定时器,它们是:TIM1~TIM8。STM32的定时器分为基本定时器、通用定时器和高等定时器。TIM6、TIM7(基本定时器):基本定时器是只能向上计数的16位定时器,基本定时器只能有定时的功能,没有外部IO口,所以没有捕获和比较通道。
 TIM2、TIM3、TIM4、TIM5(通用定时器):通用定时器是可以向上计数,也可以向下计数的16位定时器。通用定时器可以定时、输出比较、输入捕捉,每个通用定时器具有4个外部IO口。
 TIM1、TIM8(高级定时器):高级定时器是是可以向上计数,也可以向下计数的16位定时器。高等定时器可以定时、输出比较、输入捕捉、还可以输出三相电机互补信号,每个高等定时器有8个外部IO口。
 二、通用定时器主要功能通用TIMx (TIM2、TIM3、TIM4和TIM5)定时器功能包括:● 16位向上、向下、向上/向下自动装载计数器
 ● 16位可编程(可以实时修改)预分频器,计数器时钟频率的分频系数为1~65536之间的任意
 数值
 ● 4个独立通道:
 ─ 输入捕获
 ─ 输出比较
 ─ PWM生成(边缘或中间对齐模式)
 ─ 单脉冲模式输出
 ● 使用外部信号控制定时器和定时器互连的同步电路
 ● 如下事件发生时产生中断/DMA:
 ─ 更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
 ─ 触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)
 ─ 输入捕获
 ─ 输出比较
 ● 支持针对定位的增量(正交)编码器和霍尔传感器电路
 通用定时器计数模式向上计数,向下计数,中心对齐 三、通用定时器工作过程 从时钟源产生框可以看到
 定时器时钟有四种来源:
 ● 内部时钟(CK_INT)
 ● 外部时钟模式1:外部输入脚(TIx) (输入捕获的引脚)
 ● 外部时钟模式2:外部触发输入(ETR)
 ● 内部触发输入(ITRx):(定时器级联)使用一个定时器作为另一个定时器的预分频器,如可以配置一个定时器Timer1而作为另一个定时器Timer2的预分频器。
 产生CK_PSC时钟,然后在从模式控制器内设置好计数模式(向上向下),再经过预分频器产生CK_CNT,若为CNT计数器向下计数,则当其计数到0时,自动重装载寄存器会重新为CNT计数器装载新值重新递减计数,并产生一个更新事件。
 时基单元:● 计数器寄存器(TIMx_CNT)
 ● 预分频器寄存器 (TIMx_PSC)
 ● 自动装载寄存器 (TIMx_ARR)
 输入捕获:信号通过捕获通道进入,经滤波,经分频,经,,输入捕获与输出比较的四个通道其实是一个。
 四、时钟源配置(选内部时钟) 
  由以上两张图,我们知道CK_CNT时钟来源于APB1,并且如果APB1预分频系数如果不为1则CK_INT=APB1*2(单位是频率),然后设置好预分频系数CK_PSC为N,得CK_CNT=CK_INT / (N+1)。
 CK_INT到底是多少呢?
 那以STM32F103RBT6为例,打开system_stm32f10x.c文件找到SystemInit函数,其注释如下:
 
  翻译:设置系统时钟(系统时钟源、PLL倍增器因子、AHB/APBx预分频器和闪存设置)
 找到函数,我们为其一一注释:
 void SystemInit (void)
{
  
  RCC->CR |= (uint32_t)0x00000001;
  
#ifndef STM32F10X_CL
  RCC->CFGR &= (uint32_t)0xF8FF0000;
#else
  RCC->CFGR &= (uint32_t)0xF0FF0000;
#endif    
  
  
  RCC->CR &= (uint32_t)0xFEF6FFFF;
  
  RCC->CR &= (uint32_t)0xFFFBFFFF;
  
  RCC->CFGR &= (uint32_t)0xFF80FFFF;
  									
  									
  									
#ifdef STM32F10X_CL 
  
  RCC->CR &= (uint32_t)0xEBFFFFFF;
  
  RCC->CIR = 0x00FF0000;
  
  RCC->CFGR2 = 0x00000000;
#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
  
  RCC->CIR = 0x009F0000;
  
  RCC->CFGR2 = 0x00000000;      
#else
  
  RCC->CIR = 0x009F0000;
#endif 
#if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)
  #ifdef DATA_IN_ExtSRAM
    SystemInit_ExtMemCtl(); 
  #endif 
#endif 
SetSysClock();
  
#ifdef VECT_TAB_SRAM
  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; 
#else
  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; 
#endif 
}
 [注]: 这里STM32F10X_CL宏定义问题,这玩意没有被定义,参考链接1,链接2. 上头函数SystemInit ()的功能主要是复位与时钟相关的寄存器,并执行SetSysClock()。 #if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
 #define SYSCLK_FREQ_24MHz  24000000
#else
 
#define SYSCLK_FREQ_72MHz  72000000
#endif
static void SetSysClock(void)
{
#ifdef SYSCLK_FREQ_HSE
  SetSysClockToHSE();
#elif defined SYSCLK_FREQ_24MHz
  SetSysClockTo24();
#elif defined SYSCLK_FREQ_36MHz
  SetSysClockTo36();
#elif defined SYSCLK_FREQ_48MHz
  SetSysClockTo48();
#elif defined SYSCLK_FREQ_56MHz
  SetSysClockTo56();  
#elif defined SYSCLK_FREQ_72MHz
  SetSysClockTo72();
#endif
 
  
}
 由此部分代码可知(如果宏定义STM3210X_HD),默认状态下,在函数SetSysClock()中将会执行函数SetSysClockTo72()。关于这个函数详细信息参考链接3,主要关注一下 设置HCLK,HCLK = SYSCLK设置PCLK2,PCLK2 = HCLK设置PCLK1,PCLK1 = HCLK / 2(即APB1预分频系数为2,不为1的哟!!!)设置PLL时钟来源及PLL倍频因数选择PLL作为系统时钟源,即PLLCLK = SYSCLK
 到现在终于真相大白:CK_CNT=CK_INT /(N+1)=APB1*2 /(N+1)=72M / (N+1)(这里的N指PSC预分频器的预分频系数)。 五、通用定时器配置步骤void MSTimerInit(void)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	TIM_TimeBaseStructure.TIM_Prescaler = 35999;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseStructure.TIM_Period = 0xFFFF; 
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;      
	
	TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; 
	TIM_DeInit(TIM3);
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);
	TIM_ITConfig(  
		TIM3, 
		TIM_IT_Update ,
		ENABLE  
		);
	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
	NVIC_Init(&NVIC_InitStructure);  
	TIM_Cmd(TIM3, ENABLE);  
 对于上面这段代码,定时器的溢出时间为=(重装载值+1)x(分频系数+1)/72M=(65535+1) x (35999+1) / 72M=65536 x 0.5ms |