当前位置: 首页 > article >正文

TIM定时中断

TIM定时中断

文章目录

  • TIM定时中断
    • 1.TIM定时器
      • 1.1定时器的定义
        • 1.1.1基本定时器
        • 1.1.2通用定时器
        • 1.1.3高级定时器
    • 2.计数器有预装时序
    • 3.定时器结构及涉及的函数解析
      • 3.1定时中断基本结构
      • 3.2实现步骤
      • 3.3TIM本小节的库函数解释说明
      • 3.4计数器计数频率和计数器溢出频率
    • 4.定时器定时中断
      • 4.1接线图
      • 4.2代码编写
        • 4.2.1主函数main.c
        • 4.2.2定时中断函数定义Timer.c
        • 4.2.3定时中断函数定义Timer.h
    • 5.定时器外部时钟
      • 5.1接线图
      • 5.2代码实现
        • 5.2.1主函数main.c
        • 5.2.2定时器函数定义Timer.c
        • 5.2.3定时器函数声明Timer.h

1.TIM定时器

1.1定时器的定义

  • TIM(Timer)定时器

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

  • 16位计数器,预分频器,自动重装寄存器的时基单元,在72MHz计数时钟下可以实现最大59.65s的定时

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

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

计数器:用来执行计数定时的一个寄存器,每来一个时钟,计数器加1,

分频器:可以对计数器的时钟进行分频,让这个计数更加灵活

自动重装寄存器:就是计数的目标值,就是想要计多少个时钟申请中断

类型编号总线功能
高级定时器TIM1、TIM8APB2拥有通用定时器全部功能,并额外具有重复计数器、死区生成、互补输出、刹车输入等功能
通用定时器TIM2、TIM3、TIM4、TIM5APB1拥有基本定时器全部功能,并额外具有内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等功能
基本定时器TIM6、TIM7APB1拥有定时中断、主模式触发DAC的功能

STM32F103C8T6定时器资源:TIM1、TIM2、TIM3、TIM4

操作之前查一下是否包含需要的外设

1.1.1基本定时器

基本定时器

主模式触发DAC的功能:它能让内部的硬件在不受程序控制下实现自动运行,在某些情景下会极大地减轻CPU的负担

1.1.2通用定时器

通用定时器

1.1.3高级定时器

高级定时器

2.计数器有预装时序

有预装时序

高电平工作,影子寄存器才是真实作用的寄存器

3.定时器结构及涉及的函数解析

3.1定时中断基本结构

定时器中断基本结构

3.2实现步骤

第一步 RCC开启时钟,定时器的基准时钟和整个外设的工作时钟就都会同时打开了

第二步 选择时基单元的时钟源,对于定时中断,我们就选择内部时钟源

第三步 配置时基单元,包括预分频器、自动重装器、计数模式等等

第四步 配置输出中断控制、允许更新中断输出到NVIC

第五步 配置NVIC,在NVIC中打开定时器中断的通道,并分配一个优先级

第六步 运行控制

整个模块配置完成后,还需要使能一下计数器,否则计数器是不会运行的,当定时器使能后,计数器就会开始计数了,当计数器更新时,触发中断,最后再写一个定时器的中断函数

3.3TIM本小节的库函数解释说明

void TIM_DeInit(TIM_TypeDef* TIMx);
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* 
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);
  1. void TIM_DeInit(TIM_TypeDef* TIMx);恢复缺省配置
  2. void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);时基单元初始化,用来配置图中的时基单元的,第一个TIMx选择某个定时器,第二个是结构体,里面包含了配置时基单元的一些参数
  3. void TIM_TimeBaseStructInit(TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);这个函数可以把结构体变量赋一个默认值
  4. void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);运行控制,用来使能计数器的,第一个参数TIMx选择定时器,第二个NewState新的状态,使能或失能,使能可运行,失能不可运行
  5. void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);中断输出控制,使能更新中断,第一个TIMx,选择定时器,第二个TIM_IT,选择要配置哪个中断输出,第三个NewState,新的状态,使能还是失能

时钟源选择函数

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);
void TIM_ETRClockMode2Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity, 
                             uint16_t ExtTRGFilter);
void TIM_ETRConfig(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,uint16_t ExtTRGFilter);
  1. void TIM_InternalClockConfig(TIM_TypeDef* TIMx);选择内部时钟
  2. void TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);选择ITRx其他定时器的时钟,参数为TIMx选择要配置的定时器和InputTriggerSource,选择要接入哪个其他的定时器
  3. void TIM_TIxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_TIxExternalCLKSource,uint16_t TIM_ICPolarity, uint16_t ICFilter);选择TIx捕获通道的时钟,第一个参数是要配置的定时器,第二个TIxExternalClkSource,选择具体的某个引脚,最后两个参数ICPolarity和ICFilter,输入的极性和滤波器
  4. void TIM_ETRClockMode1Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter);选择ETR通过外部时钟模式1输入的时钟,参数ExTRGOrescaler,外部触发预分频器,Polarity和Filter,极性和滤波器
  5. void TIM_ETRClockMode2Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter);在不触发输入功能时,上下两个函数可以互换
  6. void TIM_ETRConfig(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter);不是用来选择时钟,就是单独用来配置ETR引脚的预分频器、极性、滤波器这些参数的

可单独修改参数的函数

void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode);
void TIM_CounterModeConfig(TIM_TypeDef* TIMx, uint16_t TIM_CounterMode);
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);
void TIM_SetCounter(TIM_TypeDef* TIMx, uint16_t Counter);
void TIM_SetAutoreload(TIM_TypeDef* TIMx, uint16_t Autoreload);
uint16_t TIM_GetCounter(TIM_TypeDef* TIMx);
  1. void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode);单独写预分配值的,Prescaler,写入的预分频值,写入的值在更新事件发生后才有效
  2. void TIM_CounterModeConfig(TIM_TypeDef* TIMx, uint16_t TIM_CounterMode);用来改变计数器的计数模式
  3. void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);自动重装器预装功能配置,调用这个函数,给个参数使能或失能就可以了
  4. void TIM_SetCounter(TIM_TypeDef* TIMx, uint16_t Counter);给计数器写入一个值
  5. void TIM_SetAutoreload(TIM_TypeDef* TIMx, uint16_t Autoreload);给一个自动重装值
  6. uint16_t TIM_GetCounter(TIM_TypeDef* TIMx);获取当前计数器的值
  7. uint16_t TIM_GetPrescaler(TIM_TypeDef* TIMx);获取当前预分频器的值

获取和清除标志位的

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);

3.4计数器计数频率和计数器溢出频率

CK_CNT_OV:表示计数器的溢出频率,即计数器从 0 开始计数,当计数值达到自动重装载值(ARR)时,计数器溢出并重新开始计数的频率。

CK_CNT:是计数器的时钟频率,也就是计数器每秒钟接收的时钟脉冲数量,它决定了计数器的计数速度。

ARR(Auto Reload Register):自动重装载值,当计数器的值达到 ARR 时,会触发计数器的溢出事件。计数器将被重置为 0 或根据定时器的工作模式进行相应操作,并且可以触发更新事件,如产生中断或更新输出信号。

CK_PSC:是预分频器的输入时钟频率,通常是系统时钟或外部时钟源的频率,它是进入预分频器的时钟频率。

PSC(Prescaler):预分频器的值,用于对输入时钟 CK_PSC 进行分频操作。

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

计数器溢出频率:CK_CNT_OV = CK_CNT / (ARR + 1)= CK_PSC / (PSC + 1) / (ARR + 1)

4.定时器定时中断

4.1接线图

6-1 接线图

4.2代码编写

4.2.1主函数main.c
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "LED.h"
#include "KEY.h"
#include "OLED.h"
//#include "OLED_Font.h"
#include "Timer.h"

uint16_t NUM;


int main(void){
	
	OLED_Init();
	Timer_Init();
	OLED_ShowString(1,1,"Num:");
	while(1){
		NUM = Get_Num();
		OLED_ShowNum(1,5,NUM,5);
	}
}

4.2.2定时中断函数定义Timer.c
#include "stm32f10x.h"                  // Device header

//extern uint16_t num;
uint16_t num;

//初始化定时器
void Timer_Init(void){
	//开启时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	
	//选择时钟源
	TIM_InternalClockConfig(TIM2);
	
	//配置时基单元
	TIM_TimeBaseInitTypeDef TIM_Structure;
	TIM_Structure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_Structure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_Structure.TIM_Period = 10000 - 1;
	TIM_Structure.TIM_Prescaler = 7200 - 1;
	TIM_Structure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2,&TIM_Structure);
	
	//中断输出配置
	TIM_ClearFlag(TIM2,TIM_FLAG_Update);//手动清除更新中断标志位,避免刚跟新完就进中断的问题
	
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
	
	//配置NVIC
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_Structure;
	NVIC_Structure.NVIC_IRQChannel = TIM2_IRQn;
	NVIC_Structure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Structure.NVIC_IRQChannelPreemptionPriority = 2;
	NVIC_Structure.NVIC_IRQChannelSubPriority = 1;
	
	NVIC_Init(&NVIC_Structure);
	
	//启动定时器
	//产生跟新时就会触发中断
	TIM_Cmd(TIM2,ENABLE);
	
}

uint16_t Get_Num(void){
	return num;
}

//配置中断函数
void TIM2_IRQHandler(void){
	if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET){
		num++;
		
		//清除标志位
		TIM_ClearITPendingBit(TIM2,	TIM_IT_Update);
	}
}

4.2.3定时中断函数定义Timer.h
#ifndef __TIMER_H
#define __TIMER_H

void Timer_Init(void);
uint16_t Get_Num(void);
#endif

5.定时器外部时钟

5.1接线图

外部接线图

5.2代码实现

5.2.1主函数main.c
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "LED.h"
#include "KEY.h"
#include "OLED.h"
//#include "OLED_Font.h"
#include "Timer.h"

uint16_t NUM;
uint16_t CNT;


int main(void){
	
	OLED_Init();
	Timer_Init();
	OLED_ShowString(1,1,"Num:");
	OLED_ShowString(2,1,"Cnt:");
	while(1){
		CNT = Timer_GetCount();
		NUM = Get_Num();
		OLED_ShowNum(1,5,NUM,5);
		OLED_ShowNum(2,5,CNT,5);

	}
}

5.2.2定时器函数定义Timer.c
#include "stm32f10x.h"                  // Device header

//extern uint16_t num;
uint16_t num;

//初始化定时器
void Timer_Init(void){
	//开启时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	GPIO_InitTypeDef Init_Structure;
	Init_Structure.GPIO_Mode = GPIO_Mode_IPU;
	Init_Structure.GPIO_Pin = GPIO_Pin_0;
	Init_Structure.GPIO_Speed = GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOA,&Init_Structure);
	
	//选择时钟源
	TIM_ETRClockMode2Config(TIM2,TIM_ExtTRGPSC_OFF,TIM_ExtTRGPolarity_NonInverted,0x00);
	
	//配置时基单元
	TIM_TimeBaseInitTypeDef TIM_Structure;
	TIM_Structure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_Structure.TIM_CounterMode = TIM_CounterMode_Up;
	//自动重装值
	TIM_Structure.TIM_Period = 10 - 1;
	//预分频
	TIM_Structure.TIM_Prescaler = 1 -1;
	TIM_Structure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2,&TIM_Structure);
	
	//中断输出配置
	TIM_ClearFlag(TIM2,TIM_FLAG_Update);//手动清除更新中断标志位,避免刚跟新完就进中断的问题
	
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
	
	//配置NVIC
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_Structure;
	NVIC_Structure.NVIC_IRQChannel = TIM2_IRQn;
	NVIC_Structure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Structure.NVIC_IRQChannelPreemptionPriority = 2;
	NVIC_Structure.NVIC_IRQChannelSubPriority = 1;
	
	NVIC_Init(&NVIC_Structure);
	
	//启动定时器
	//产生跟新时就会触发中断
	TIM_Cmd(TIM2,ENABLE);
	
}

uint16_t Get_Num(void){
	return num;
}

//CNT计数器的值
uint16_t Timer_GetCount(void){
	return TIM_GetCounter(TIM2);
}

//配置中断函数
void TIM2_IRQHandler(void){
	if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET){
		num++;
		
		//清除标志位
		TIM_ClearITPendingBit(TIM2,	TIM_IT_Update);
	}
}

5.2.3定时器函数声明Timer.h
#ifndef __TIMER_H
#define __TIMER_H

void Timer_Init(void);
uint16_t Get_Num(void);
uint16_t Timer_GetCount(void);
#endif


http://www.kler.cn/a/512365.html

相关文章:

  • vue动态修改网页icon图标【浏览器】
  • ARCGIS国土超级工具集1.3更新说明
  • (7)(7.2) 围栏
  • 第四届机器学习、云计算与智能挖掘国际会议
  • C++:bfs解决多源最短路与拓扑排序问题习题
  • games101笔记-02线性代数回顾
  • 第01章 07 MySQL+VTK C++示例代码,实现医学影像数据的IO数据库存储
  • 构建基于Hadoop的数据湖解决方案
  • 通过以太网加载linux内核、设备树、根文件系统方法(以stm32MP135为例)
  • 插入排序 计数排序 堆排序 快速排序 归并排序
  • 降维算法:主成分分析
  • Dockerfile另一种使用普通用户启动的方式
  • 高效建站指南:通过Portainer快速搭建自己的在线网站
  • 开源许可证(Open Source Licenses)
  • 【React】类组件更新的底层逻辑
  • wordpress网站发布失败:此响应不是合法的JSON响应
  • 模版字符串复制粘贴支持换行
  • 【Block总结】TFF和SFF模块,时间和尺度的特征融合|即插即用
  • 【大数据2025】Yarn 总结
  • Android 11.0 第三方app接收不到开机广播问题的解决以及开机自启动功能实现二