STM32(七)———TIM定时器(基本and通用)

文章目录


前言

一个学习STM32的小白~ 有错误评论区或私信指出

一、通用定时器TIM简介

1.STM32F10X系列总共最多有八个定时器:

2.三种STM32定时器的区别:

3.STM32 的通用定时器功能:

  • 16 位/32 位(仅 TIM2 和 TIM5)向上、向下、向上/向下自动装载计数器
    (TIMx_CNT),注意:TIM9~TIM14 只支持向上(递增)计数方式
  • 16 位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数为 1~ 65535 之间的任意数值
  • 4 个独立通道(TIMx_CH14,TIM9TIM14 最多 2 个通道),这些通道可以用来作为:
    • 输入捕获
    • 输出比较
    • PWM 生成(边缘或中间对齐模式) ,注意:TIM9~TIM14 不支持中间对齐模式
    • 单脉冲模式输出
  • 可使用外部信号(TIMx_ETR)控制定时器和定时器互连(可以用 1 个定时器控制另外一个定时器)的同步电路。
    • 如下事件发生时产生中断/DMA(TIM9~TIM14 不支持 DMA):
    • 更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
    • 触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)
    • 输入捕获
    • 输出比较
    • 支持针对定位的增量(正交)编码器和霍尔传感器电路(TIM9~TIM14 不支持)
    • 触发输入作为外部时钟或者按周期的电流管理(TIM9~TIM14 不支持)

4.计数器模式

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

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

二、基本定时器

1.基本定时器的结构框图

  1. 时钟源
  2. 控制器
  3. 时基单元

    时钟源
  • 时钟源来自RCC的TIMx_CLK(属于内部的CK_INIT)
    控制器
  • 控制器用于控制定时器:复位、使能、计数、触发ADC
    涉及到的寄存器:CR1/2,DIER,EGR,SR
    时基(定时器的心脏)
  • 定时器最重要的就是时基部分:包括预分频器、计数器、自动重装载寄存器
    • 预分频器:16位预分频器(1~65536)PSC对内部时钟CK_PSC进行分频之后,得到计数器时钟CK_INT=CK_PSC/(PSC+1)
    • CNT在计数器时钟的驱动下开始计数,计数一次的时间为1/CK_INT
    • 计数器、重装在寄存器:定时器使能(CEN置1)后,计数器CNT在CK_CNT驱动下计数,当TNT值与ARR的设定值相等时就自动生成事件并CNT自动清零,然后自动重新开始计数,如此重复以上过程。

影子寄存器

1.PSC和ARR都有影子寄存器,功能框图上有个影子

2.影子寄存器的存在起到一个缓冲的作用,用户值->寄存器->影子寄存器->起作用,

如果不使用影子寄存器则用户值在写到寄存器之后则里面起作用,ARR影子,

TIMx_CR1:APRE位控制。

2.定时时间的计算

  • PSC=72-1,定时器的频率 = 72M/(PSC+1) = 1MHZ
  • ARR = 1000 -1,从0计数到999,则计了1000次
  • 中断周期T = 1000 * 1 /1 000 000 = 1ms

3.定时器的结构体和库函数

c 复制代码
时基初始化结构体:
 typedef struct
 {
 uint16_t TIM_Prescaler;    
uint16_t TIM_CounterMode;       
uint16_t TIM_Period;           
//分频因子      
//计数模式,基本定时器只能向上计数
//自动重装载值
uint16_t TIM_ClockDivision;     
uint8_t TIM_RepetitionCounter;  //重复计数值,基本定时器没有,高级定时器
专用
} TIM_TimeBaseInitTypeDef;  
常用的库函数:
//外部输入时钟分频因子,基本定时器没有
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* 
TIM_TimeBaseInitStruct);
 void TIM_TimeBaseStructInit(TIM_TimeBaseInitTypeDef* 
TIM_TimeBaseInitStruct);
 void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);
 void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState 
NewState);
 void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, 
uint16_t TIM_PSCReloadMode);
 void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState 
NewState);  
FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
 void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
 ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);
 void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);

练习:

如何实现500ms的定时?

c 复制代码
void tim_Init(void)
{
	TIM_TimeBaseInitTypeDef  tim_InitStructure;
	NVIC_InitTypeDef nvic_InitStructure;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	
	tim_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//不分频
	tim_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
	tim_InitStructure.TIM_Prescaler = 36000-1;//预分频
	tim_InitStructure.TIM_Period = 1000-1;//ARR自动重装
	
	TIM_ClearFlag(TIM2,TIM_FLAG_Update);
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
	TIM_TimeBaseInit(TIM2,&tim_InitStructure);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	nvic_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
	nvic_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	nvic_InitStructure.NVIC_IRQChannelSubPriority = 1;
	nvic_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	
	NVIC_Init(&nvic_InitStructure);
	
	TIM_Cmd(TIM2,ENABLE);

}

定时器控制LED闪烁

软件流程设计

  • 初始化系统
    • 初始化定时器和LED的IO时钟
    • 初始化LED的引脚IO
  • 定时器中断中驱动LED灯
c 复制代码
#include "tim.h"
#include "stm32f10x.h"                  // Device header

void tim_Init(void)
{
	TIM_TimeBaseInitTypeDef  tim_InitStructure;
	NVIC_InitTypeDef nvic_InitStructure;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	
	tim_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//不分频
	tim_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
	tim_InitStructure.TIM_Prescaler = 36000-1;//预分频
	tim_InitStructure.TIM_Period = 1000-1;//ARR自动重装
	
	TIM_ClearFlag(TIM2,TIM_FLAG_Update);//清楚更新事件标志位防止一进来就更新
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//开中断
	TIM_TimeBaseInit(TIM2,&tim_InitStructure);
	

	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	nvic_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
	nvic_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	nvic_InitStructure.NVIC_IRQChannelSubPriority = 1;
	nvic_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	
	NVIC_Init(&nvic_InitStructure);
	
	TIM_Cmd(TIM2,ENABLE);//开定时器

}

void TIM2_IRQHandler(void)
{
	static uint16_t Count;
	if(TIM_GetITStatus(TIM2,TIM_IT_Update) != RESET)
	{
		if(Count++ % 2 == 1)
		{
			GPIO_ResetBits(GPIOA,GPIO_Pin_1);
		
		}
		else
		{
			GPIO_SetBits(GPIOA,GPIO_Pin_1);
		}
	
	}
	TIM_ClearFlag(TIM2,TIM_IT_Update);//清除中断标志位


}

总结

定时器非常重要!!!

注:定时器中断要软件开启(TIM_ITConfig),要开启定时器(TIM_cmd)!!!

相关推荐
蓝斯4978 小时前
从.到实现一个Windows上的虚拟hid键盘设备
windows·单片机·计算机外设
熙芯XiChip9 小时前
硬实时与软实时RTOS核心区别
嵌入式硬件
伟大的前程9 小时前
unsigned int 定义的变量 在 电脑的 64 位系统中 和 32 位 cortex-m0 和 8 位的 51 单片机
单片机·嵌入式硬件
小渔村的拉线工9 小时前
1.HPM6E80 解析芯片整体工作原理和存储架构
单片机·嵌入式硬件·mcu·架构·hpm6e80
熙芯XiChip10 小时前
CAN与CANopen的本质区别
单片机
lilihewo11 小时前
Altium Designer 封装库的创建(分享pcb 3D封装库)
嵌入式硬件·51单片机
神罚天下ET12 小时前
典型arm位单片机启动流程(从上电到main.c)
c语言·arm开发·单片机
碧海银沙音频科技研究院12 小时前
蓝牙耳机使用WSDF5361锂保芯片进入船运模式实现方法
嵌入式硬件·算法
Zevalin爱灰灰13 小时前
模拟信号链电路——基于TL431的电压基准电路
单片机·嵌入式硬件
csdn杰哥14 小时前
瑞萨单片机开发教程[二十七] DTC 外部中断触发传输实验
单片机·嵌入式硬件·mongodb·瑞萨·ra6m5