STM32入门笔记04_TIM定时器+案例:TIM定时器定时中断、定时器外部时钟

TIM定时器

TIM简介

  • TIM(Timer) 定时器

  • 定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断

  • 16位计数器、预分频器、自动重装寄存器的时基单元,在72MHz(系统主频)计数时钟下可以实现最大59.65s的定时(72M/65536/65536取倒数)

  • 不仅具备基本的定时中断功能,而且还包含内外时钟源选择输入捕获输出比较编码器接口主从触发模式等多种功能

  • 根据复杂度和应用场景分为了高级定时器通用定时器基本定时器三种类型

定时器类型

类型

编号

总线

功能

高级定时器

TIM1、TIM8

APB2

拥有通用定时器全部功能,并额外具有重复计数器、死区生成、互补输出、刹车输入等功能

通用定时器

TIM2、TIM3、TIM4、TIM5

APB1

拥有基本定时器全部功能,并额外具有内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等功能

基本定时器

TIM6、TIM7

APB1

拥有定时中断、主模式触发DAC的功能

定时器结构框图

基本定时器

STM32入门笔记04_TIM定时器+案例:TIM定时器定时中断、定时器外部时钟_第1张图片
时基单元寄存器功能介绍
  • 计数器寄存器(TIMx_CNT) 由预分频器的时钟输出CK_CNT驱动, 当设置了控制寄存器TIMx_CR1中的计数器使能位(CEN)时, CK_CNT才有效, 16位寄存器, 可计数范围为0~65535

  • 预分频器(TIMx_PSC) 16位寄存器(可设置0~65535), 可以将计数器的时钟频率按1~65536之间的任意值分频。这个控制寄存器带有缓冲器, 它不能够在工作时被改变。新的预分频器参数再下一次更新事件到来时被采用

  • 自动重装载寄存器(TIMx_ARR) 是预先装载的, 写或读自动重装载寄存器将访问预装载寄存器。根据在TIMx_CR1中的自动重装载预装载使能位(ARPE)的设置, 预装载寄存器的内容被立即或在每次更新事件(UEV)时传送到其影子寄存器。也是一个16位寄存器, 可设置范围为0~65535,当计数值等于自动重装值时, 产生中断并清零计数器

Note: 由计数器寄存器的计数范围、预分频器的分频范围和自动重装载寄存器的可设置范围, 可以计算:最大定时为59.65s

主模式触发DAC功能(硬件自动化设计)
  • 使用DAC时, 可能会用DAC输出一段波形

  • 把定时器的更新事件映射到TRGO(Trigger Out)的位置, TRGO直接接到DAC的触发转换引脚上, 这样定时器的更新就不需要再通过中断来触发DAC转换了

  • 好处避免了主程序处于频繁被中断的状态(该状态会影响到其他中断的运行)

计数模式: 基本定时器的计数模式只有向上计数的方式

通用定时器

STM32入门笔记04_TIM定时器+案例:TIM定时器定时中断、定时器外部时钟_第2张图片
通用定时器的结构

STM32通用定时器主要包括1个外部触发引脚(TIMx_ETR), 4个输入/输出通道(TIMx_CH1, TIMx_CH2, TIMx_CH3, TIMx_CH4), 一个内部时钟(CK_INT), 一个触发控制器、1个时基单元(由预分频器PSC、自动重装载寄存器ARR和计数器CNT组成) ..( 预分频器 Prescaler)

时钟源

定时器时钟可由下列时钟源提供:

  • 内部时钟(CK_INT)

  • 外部时钟模式1(外部输入引脚TIx), 图中为从TIMx_CHx往右边看, 具体位置参考引脚定义表

  • 外部时钟模式2(外部触发输入ETR), 信号来源TIMx_ETR外部触发引脚, 具体位置参考引脚定义表

  • 内部触发输入(ITR, 使用一个定时器作为另一个定时器的预分频器, 也叫级联的方式) 比如: 先初始化TIM3,然后使用主模式把它的更新事件映射到TRGO上,再初始化TIM2, 选择ITR2(对应TIM3的TRGO), 选择时钟为内部触发输入,这样TIM3的更新事件就可以驱动TIM2的时基单元,也就实现了定时器的级联

计数模式:
  • 向上计数(最常用)

  • 向下计数

  • 中央对齐模式(向上/向下计数)

高级定时器

STM32入门笔记04_TIM定时器+案例:TIM定时器定时中断、定时器外部时钟_第3张图片
重复次数计数器

可以实现每隔几个计数周期,才发生一次更新事件和更新中断, 相当于对输出的更新信号又做了一次分频 最大定时时间59.65*65536

DTG(Dead Time Generate)

死区生成电路: 产生一定时长的死区, 让桥臂的上下管全部关断, 防止直通现象。

直通现象: 电子管是利用阴极和阳极之间产生束流来实现电流控制,而所谓直通现象就是阳极与阴极直接连通了

目的: 为了避免开关切换瞬间, 由于器件的不理想, 造成短暂的直通现象

输出

前三路输出引脚由原来的一个, 变为了两个互补输出, 可以输出一对互补的PWM波,(目的是为了驱动三相无刷电机)

刹车输入功能

目的: 给电机驱动提供安全保障, 如果外部引脚BKIN(Break IN) 产生了刹车信号, 或者内部时钟失效, 产生了故障, 控制电路就会自动切断电机的输出, 防止意外发生

定时中断基本结构

STM32入门笔记04_TIM定时器+案例:TIM定时器定时中断、定时器外部时钟_第4张图片

运行控制: 一些寄存器可以控制时基单元的运行

左边部分为时基单元提供时钟,也可通过配置相应寄存器选择时钟源和模式

时基单元产生的中断信号会先在状态寄存器里配置一个中断标志位, 标志位会通过中断输出控制(中断输出的允许位), 到NVIC申请中断

预分频器时序(后面的图差不多, 就不详细说明了)

STM32入门笔记04_TIM定时器+案例:TIM定时器定时中断、定时器外部时钟_第5张图片
  • CK_PSC:一般为72MHz

STM32入门笔记04_TIM定时器+案例:TIM定时器定时中断、定时器外部时钟_第6张图片
  • CNT_EN:计数器使能,高电平正常允许,低电平停止

  • CK_CNT:计数器时钟

  • 计数器寄存器:跟随时钟的上升沿不断自增

  • 预分频寄存器缓冲机制:

  • 预分频缓冲器(影子寄存器):

真正起作用的寄存器

  • 机制过程:

假设在某时刻,把预分频寄存器由0改成1,若计数到一半,则前半部分和后半部分的计数频率就不一致了。而在STM32中,定时器比较严谨,当计数计一半时改变了分频值,这个变化不会立刻生效,而是等本次计数周期结束时,产生了更新事件,预分频寄存器的值才会被传递到缓冲寄存器里,才会生效,所以真正起作用的寄存器是影子寄存器

  • 预分频计数器

预分频器内部实际上也是靠计数分频,当预分频值为0时,计数器就一直为0,直接输出原频率; 当预分频值为1时,计数器就0、1、0、1这样计数,在回到0时输出一个脉冲, 这样输出频率就是输入频率的2分频

  • 计数器计数频率: CK_CNT = CK_PSC / (PSC + 1)

计数器时序

STM32入门笔记04_TIM定时器+案例:TIM定时器定时中断、定时器外部时钟_第7张图片
  • 计数器溢出频率: CK_CNT_OV = CK_CNT / (ARR +1) = CK_PSC / (PSC + 1) / (ARR + 1)

计数器无预装时序

STM32入门笔记04_TIM定时器+案例:TIM定时器定时中断、定时器外部时钟_第8张图片

计数器有预装时序

STM32入门笔记04_TIM定时器+案例:TIM定时器定时中断、定时器外部时钟_第9张图片

RCC时钟树

STM32入门笔记04_TIM定时器+案例:TIM定时器定时中断、定时器外部时钟_第10张图片

Note: 程序中主函数之前还会执行SystemInit函数,这个函数就是用来配置时钟树的

Attention: 主频经过2分频后到APB1为36MHz, 到TIM2~7前频率又×2,因此TIM2~7的频率还是72MHz,而APB2的频率为72MHz

案例: 定时器定时中断&定时器外部时钟

定时器定时中断

1. 配置定时器
STM32入门笔记04_TIM定时器+案例:TIM定时器定时中断、定时器外部时钟_第11张图片
RCC开启时钟
	// RCC开启时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
选择时钟源, 即黄色区域部分
	// 选择时钟源
	TIM_InternalClockConfig(TIM2);  // 内部时钟

可供选择的时钟源在stm32f10x_tim.h中有定义, 感兴趣可以参考STM32技术手册

void TIM_InternalClockConfig(TIM_TypeDef* TIMx);  // 内部时钟
void TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);
void TIM_TIxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_TIxExternalCLKSource,
                                uint16_t TIM_ICPolarity, uint16_t ICFilter);
void TIM_ETRClockMode1Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,
                             uint16_t ExtTRGFilter);	// 外部时钟模式1
void TIM_ETRClockMode2Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, 
                             uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter);  // 外部时钟模式2
配置时基单元
	// 配置时基单元
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;  // 内部时钟分频
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;  // 计数模式
	TIM_TimeBaseInitStructure.TIM_Period=50000-1;  // 加载到自动重装寄存器的值
	TIM_TimeBaseInitStructure.TIM_Prescaler=7200-1;  // 预分频的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;  // 重复计数器的值 
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);  // 调用初始化函数
	TIM_ClearFlag(TIM2, TIM_FLAG_Update);  // 清除标志

最后一步清除标志,解决了复位上电后Num不从0开始而从1开始的问题

原因是TIM_TimeBaseInit() 时基初始化函数在最后面, 手动触发了一次更新事件, 导致标志位也被设置, 因此上电后Num已经加了一次,在该函数外面将标志位清除即可解决问题。

void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)
{
  uint16_t tmpcr1 = 0;

  /* Check the parameters */
  assert_param(IS_TIM_ALL_PERIPH(TIMx)); 
  assert_param(IS_TIM_COUNTER_MODE(TIM_TimeBaseInitStruct->TIM_CounterMode));
  assert_param(IS_TIM_CKD_DIV(TIM_TimeBaseInitStruct->TIM_ClockDivision));

  tmpcr1 = TIMx->CR1;  

  if((TIMx == TIM1) || (TIMx == TIM8)|| (TIMx == TIM2) || (TIMx == TIM3)||
     (TIMx == TIM4) || (TIMx == TIM5)) 
  {
    /* Select the Counter Mode */
    tmpcr1 &= (uint16_t)(~((uint16_t)(TIM_CR1_DIR | TIM_CR1_CMS)));
    tmpcr1 |= (uint32_t)TIM_TimeBaseInitStruct->TIM_CounterMode;
  }
 
  if((TIMx != TIM6) && (TIMx != TIM7))
  {
    /* Set the clock division */
    tmpcr1 &= (uint16_t)(~((uint16_t)TIM_CR1_CKD));
    tmpcr1 |= (uint32_t)TIM_TimeBaseInitStruct->TIM_ClockDivision;
  }

  TIMx->CR1 = tmpcr1;

  /* Set the Autoreload value */
  TIMx->ARR = TIM_TimeBaseInitStruct->TIM_Period ;
 
  /* Set the Prescaler value */
  TIMx->PSC = TIM_TimeBaseInitStruct->TIM_Prescaler;
    
  if ((TIMx == TIM1) || (TIMx == TIM8)|| (TIMx == TIM15)|| (TIMx == TIM16) || (TIMx == TIM17))  
  {
    /* Set the Repetition Counter value */
    TIMx->RCR = TIM_TimeBaseInitStruct->TIM_RepetitionCounter;
  }

  /* Generate an update event to reload the Prescaler and the Repetition counter
     values immediately */
  TIMx->EGR = TIM_PSCReloadMode_Immediate; // 问题在这里           
}
使能更新中断
	// 使能更新中断
	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
// 以下为TIM_ITConfig函数的注释
/**
  * @brief  Enables or disables the specified TIM interrupts.
  * @param  TIMx: where x can be 1 to 17 to select the TIMx peripheral.
  * @param  TIM_IT: specifies the TIM interrupts sources to be enabled or disabled.
  *   This parameter can be any combination of the following values:
  *     @arg TIM_IT_Update: TIM update Interrupt source
  *     @arg TIM_IT_CC1: TIM Capture Compare 1 Interrupt source
  *     @arg TIM_IT_CC2: TIM Capture Compare 2 Interrupt source
  *     @arg TIM_IT_CC3: TIM Capture Compare 3 Interrupt source
  *     @arg TIM_IT_CC4: TIM Capture Compare 4 Interrupt source
  *     @arg TIM_IT_COM: TIM Commutation Interrupt source
  *     @arg TIM_IT_Trigger: TIM Trigger Interrupt source
  *     @arg TIM_IT_Break: TIM Break Interrupt source
  * @note 
  *   - TIM6 and TIM7 can only generate an update interrupt.
  *   - TIM9, TIM12 and TIM15 can have only TIM_IT_Update, TIM_IT_CC1,
  *      TIM_IT_CC2 or TIM_IT_Trigger. 
  *   - TIM10, TIM11, TIM13, TIM14, TIM16 and TIM17 can have TIM_IT_Update or TIM_IT_CC1.   
  *   - TIM_IT_Break is used only with TIM1, TIM8 and TIM15. 
  *   - TIM_IT_COM is used only with TIM1, TIM8, TIM15, TIM16 and TIM17.    
  * @param  NewState: new state of the TIM interrupts.
  *   This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
配置NVIC
	// 配置NVIC
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  // 设置NVIC优先级分组
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;  // 中断通道
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;  
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;  // 抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;  // 响应优先级
	NVIC_Init(&NVIC_InitStructure);

这里和之前一样, 就不详细解释了

启动定时器
	// 启动定时器
	TIM_Cmd(TIM2, ENABLE);

操作的是上图的运行控制部分, 控制定时器的运行

整体初始化代码
void Timer_Init(void)
{
	// RCC开启时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	
	// 选择时钟源
	TIM_InternalClockConfig(TIM2);  // 内部时钟
	
	// 配置时基单元
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;  // 内部时钟分频
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;  // 计数模式
	TIM_TimeBaseInitStructure.TIM_Period=50000-1;  // 加载到自动重装寄存器的值
	TIM_TimeBaseInitStructure.TIM_Prescaler=7200-1;  // 预分频的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;  // 重复计数器的值 
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);  //
	TIM_ClearFlag(TIM2, TIM_FLAG_Update);  // 清除标志
	// 使能更新中断
	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
	
	// 配置NVIC
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  // 设置NVIC优先级分组
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;  // 中断通道
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;  
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;  // 抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;  // 响应优先级
	NVIC_Init(&NVIC_InitStructure);
	
	// 启动定时器
	TIM_Cmd(TIM2, ENABLE);
	return;
}
2.编写中断事件
void TIM2_IRQHandler(void)
{
	// 判断标志位
	if (TIM_GetITStatus(TIM2, TIM_IT_Update)==SET)
	{
		Num++;
		// 清除标志位
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}

这里我们将中断函数放到main.c下, 方便操作Num变量

也可在Timer.c 用extern指令引入Num变量

3.整体代码
main.c
#include "stm32f10x.h" 
#include "OLED.h"
#include "Timer.h"
// 定时器定时中断
// 2023年3月16日12:21:33
uint16_t Num;

int main(void)
{
	OLED_Init();
	Timer_Init();
	
	OLED_ShowString(1, 1, "Num:");
	OLED_ShowString(2, 1, "CNT:");
	while(1)
	{
		OLED_ShowNum(1, 5, Num, 5);
		OLED_ShowNum(2, 5, TIM_GetCounter(TIM2), 5);
	}
}

void TIM2_IRQHandler(void)
{
	// 判断标志位
	if (TIM_GetITStatus(TIM2, TIM_IT_Update)==SET)
	{
		Num++;
		// 清除标志位
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}
Timer.c
#include "stm32f10x.h"

// extern uint16_t Num;

void Timer_Init(void)
{
	// RCC开启时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	
	// 选择时钟源
	TIM_InternalClockConfig(TIM2);  // 内部时钟
	
	// 配置时基单元
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;  // 内部时钟分频
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;  // 计数模式
	TIM_TimeBaseInitStructure.TIM_Period=50000-1;  // 加载到自动重装寄存器的值
	TIM_TimeBaseInitStructure.TIM_Prescaler=7200-1;  // 预分频的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;  // 重复计数器的值 
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);  //
	TIM_ClearFlag(TIM2, TIM_FLAG_Update);  // 清除标志
	// 使能更新中断
	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
	
	// 配置NVIC
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  // 设置NVIC优先级分组
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;  // 中断通道
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;  
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;  // 抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;  // 响应优先级
	NVIC_Init(&NVIC_InitStructure);
	
	// 启动定时器
	TIM_Cmd(TIM2, ENABLE);
	return;
}

/*
void TIM2_IRQHandler(void)
{
	// 判断标志位
	if (TIM_GetITStatus(TIM2, TIM_IT_Update)==SET)
	{
		Num++;
		// 清除标志位
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}
*/

定时器外部中断

硬件接线
STM32入门笔记04_TIM定时器+案例:TIM定时器定时中断、定时器外部时钟_第12张图片
整体代码
main.c
#include "stm32f10x.h" 
#include "OLED.h"
#include "Timer.h"
// 定时器外部中断
// 2023年3月16日14:26:54
uint16_t Num;

int main(void)
{
	OLED_Init();
	Timer_Init();
	
	OLED_ShowString(1, 1, "Num:");
	OLED_ShowString(2, 1, "CNT:");
	while(1)
	{
		OLED_ShowNum(1, 5, Num, 5);
		OLED_ShowNum(2, 5, TIM_GetCounter(TIM2), 5);
	}
}

void TIM2_IRQHandler(void)
{
	// 判断标志位
	if (TIM_GetITStatus(TIM2, TIM_IT_Update)==SET)
	{
		Num++;
		// 清除标志位
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}
Timer.c
#include "stm32f10x.h"

// extern uint16_t Num;

void Timer_Init(void)
{
	// RCC开启时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	// 配置GPIO
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	// 选择时钟 外部时钟模式1
	TIM_ETRClockMode1Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x00);
	
	// 配置时基单元
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;  // 内部时钟分频
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;  // 计数模式
	TIM_TimeBaseInitStructure.TIM_Period=10-1;  // 加载到自动重装寄存器的值
	TIM_TimeBaseInitStructure.TIM_Prescaler=1-1;  //
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;  // 重复计数器的值 
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);  //
	TIM_ClearFlag(TIM2, TIM_FLAG_Update);  // 清除标志
	// 使能更新中断
	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
	
	// 配置NVIC
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  // 设置NVIC优先级分组
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;  // 中断通道
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;  
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;  // 抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;  // 响应优先级
	NVIC_Init(&NVIC_InitStructure);
	
	// 启动定时器
	TIM_Cmd(TIM2, ENABLE);
	return;
}

/*
void TIM2_IRQHandler(void)
{
	// 判断标志位
	if (TIM_GetITStatus(TIM2, TIM_IT_Update)==SET)
	{
		Num++;
		// 清除标志位
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}
*/

注意: 这里与江科大教程中不同, 时钟源采用的是外部时钟模式1

这是因为, PA0除了支持TIM2_ETR(外部时钟模式2) 也支持 TIM2_CH1(外部时钟模式1)

TIM定时器常用函数

函数原型

功能

void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);

根据TIM_TimeBaseInitStruct中指定的参数, 初始化TIMx的时基单位

void TIM_TimeBaseStructInit(TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);

把TIM_TimeBaseInitStruct中的每一个参数按缺省值填入

void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);

使能或失能TIMx外设

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

使能或失能指定的TIM中断

void TIM_InternalClockConfig(TIM_TypeDef* TIMx);

设置TIMx内部时钟

void TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);

设置TIMx内部触发为外部时钟模式

void TIM_TIxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_TIxExternalCLKSource, uint16_t TIM_ICPolarity, uint16_t ICFilter);

设置TIMx触发为外部时钟

void TIM_ETRClockMode1Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter);

配置TIMx外部时钟模式1

void TIM_ETRClockMode2Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter);

配置TIMx外部时钟模式2

void TIM_ETRConfig(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter);

配置TIMx外部触发

void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode);

设置TIMx预分频

void TIM_CounterModeConfig(TIM_TypeDef* TIMx, uint16_t TIM_CounterMode);

设置TIMx计数器模式

void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);

使能或失能TIMx在ARR上的预装载寄存器

void TIM_SetCounter(TIM_TypeDef* TIMx, uint16_t Counter);

设置TIMx计数器寄存器值

void TIM_SetAutoreload(TIM_TypeDef* TIMx, uint16_t Autoreload);

设置TIMx自动重装载寄存器值

uint16_t TIM_GetCounter(TIM_TypeDef* TIMx);

获取TIMx计数器的值

uint16_t TIM_GetPrescaler(TIM_TypeDef* TIMx);

获取TIMx预分频值

FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);

检查指定的TIM标志位设置与否

void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);

清除TIMx的待处理标志位

ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);

检查指定的TIM中断发生与否

void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);

清除TIMx的中断待处理位

Note: ClearFlag()和ClearITPendingBit()的区别, 请参考: http://t.csdn.cn/0KYkq

参考资料:

http://t.csdn.cn/0KYkq

嵌入式单片机STM32原理及应用(机械工业出版社)

[6-2] 定时器定时中断&定时器外部时钟_哔哩哔哩_bilibili

你可能感兴趣的:(单片机学习笔记,stm32,单片机,嵌入式硬件,c语言)