STM32-TIM定时器中断

目录

一、TIM(Timer)定时器简介

二、定时器类型

2.1基本定时器结构

2.2通用定时器结构

2.3高级定时器结构

三、定时中断基本结构

四、时序图分析

[4.1 预分频器时序](#4.1 预分频器时序)

[4.2 计数器时序](#4.2 计数器时序)

[4.3 计数器无预装时序(无影子寄存器)](#4.3 计数器无预装时序(无影子寄存器))

[4.4 计数器有预装时序(有影子寄存器)](#4.4 计数器有预装时序(有影子寄存器))

五、RCC时钟树

六、开发步骤

七、定时器函数

八、实验

8.1定时器定时中断

8.2定时器外部时钟


一、TIM(Timer)定时器简介

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

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

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

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

自动重装寄存器:计数的目标值,计多少个时钟来申请一次中断

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

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

二、定时器类型

2.1基本定时器结构

主模式触发DAC功能:把定时器的更新事件映射到触发输出TRGO(Trigger Out)的位置,TRGO直接接到DAC的触发转换引脚上,这样就不需要通过中断来触发DAC转换了。实现了硬件的自动化。
通用定时器和高级定时器除了向上计数 模式,还有向下计数 模式和中央对齐模式

2.2通用定时器结构

2.3高级定时器结构

三、定时中断基本结构

四、时序图分析

4.1 预分频器时序

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

4.2 计数器时序

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

计数器时间:(PSC + 1)(ARR + 1)/CK_PSC

4.3 计数器无预装时序(无影子寄存器)

4.4 计数器有预装时序(有影子寄存器)

五、RCC时钟树

作用:产生和配置时钟,将配置好的时钟发送到各个外设系统

开发技巧:

在SystemInit函数中,首先启动内部8MHz时钟为系统时钟运行,然后再启动外部时钟,进入PLL锁相环进行倍频,8MHz倍频9倍,得到72MHz,锁相环输出稳定之后,选择锁相环输出为系统时钟,这样就把系统时钟由8MHz变成了72MHz。

实际问题:

如果外部晶振出现问题,程序时钟慢了大概10倍,定时器定时1s,结果过了大概10s才进中断。是因为现在是以内部时钟8MHz运行的

六、开发步骤

①RCC打开时钟

②选择时基单元的时钟源

③结构体配置时基单元(预分频器,自动重装器,计数模式)

④配置输出中断控制,允许更新中断输出到NVIC

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

⑥运行控制,使能计数器

⑦写定时器中断函数

七、定时器函数

=====================================================================

=================================基本函数=============================

void TIM_DeInit(TIM_TypeDef* TIMx);

//定时器恢复缺省配置

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

//使能计数器

//第一个参数:TIMx选择定时器,第二个参数:使能或失能

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

//使能中断输出信号(中断输出控制)

//第一个参数:TIMx选择定时器,第二个参数:哪个中断输出,第三个参数:使能或失能

=====================================================================

=========================配置时钟输入的函数=============================

void TIM_InternalClockConfig(TIM_TypeDef* TIMx);

//选择内部时钟

void TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);

//选择ITRx其他定时器时钟

//第一个参数:选择配置哪个定时器,第二个参数:选择要接入哪个定时器

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

//选择TIx捕获通道的时钟

//第一个参数:TIMx,第二个参数:TIMx具体哪个引脚,第三、四个参数:输入极性和滤波器

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

//ETR通过外部时钟模式1输入时钟

//第一个参数:TIMx,第二个参数:外部触发预分频器,第三、四个参数:输入极性和滤波器

void TIM_ETRClockMode2Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler,

uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter);

//ETR通过外部时钟模式2输入时钟

//第一个参数:TIMx,第二个参数:外部触发预分频器,第三、四个参数:输入极性和滤波器

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

//单独配置ETR引脚的预分频器、极性、滤波器

//第一个参数: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_SelectInputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);

//自动重装器预装功能配置

//第一个参数:TIMx,第二个参数:预装功能使能或失能

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

//获取计数器值

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

八、实验

8.1定时器定时中断

实验现象:1s计数加一

代码实现:

Timer.c

复制代码
#include "stm32f10x.h"                  // Device header

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 = 10000 - 1;//ARR自动重装器值
	TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;//PSC预分频器值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//重复计数器值(高级定时器才有)
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
	
	/*避免刚初始化就进入中断(复位就是1,而不是0)*/
	TIM_ClearFlag(TIM2,TIM_FLAG_Update);
	
	/*四、配置输出中断控制,允许更新中断输出到NVIC*/
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//开启更新中断到NVIC的通路
	
	/*五、配置NVIC,在NVIC打开定时器中断的通道,分配优先级*/
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;//中断通道
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStructure);
	
	/*六、运行控制,使能计数器*/
	TIM_Cmd(TIM2,ENABLE);
}

/*中断函数模板
void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET)
	{
		
		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
	}
}
*/

Timer.h

复制代码
#ifndef __TIMER_H
#define __TIMER_H

void Timer_Init(void);

#endif

main.c

复制代码
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"

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);//观察CNT计数器值的变化情况
	}
}

void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET)
	{
		Num ++;
		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
	}
}

8.2定时器外部时钟

方法:定时器指定的外部引脚输入一个方波信号,来提供定时器计数的时钟

实验现象:利用对射式红外传感器来手动模拟一个外部时钟,用挡光片,依次遮挡、移开来模拟一个方波,定时器计数值(CNT)逐次加一,当CNT到9后,产生一次中断,Num加一,CNT清零重新计数

代码实现:

Timer.c

复制代码
#include "stm32f10x.h"                  // Device header

void Timer_Init(void)
{
	/*一、RCC开启时钟 + GPIOA的初始化*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	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);
	
	/*二、选择时基单元的时钟源*/
	TIM_ETRClockMode2Config(TIM2,TIM_ExtTRGPSC_OFF,TIM_ExtTRGPolarity_NonInverted,0x00);
	//通过ETR的外部时钟模式2,不分频,不反向(高电平/上升沿有效),外部触发滤波器
	
	/*三、配置时基单元(预分频器,自动重装器,计数模式)*/
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 10 - 1;//ARR自动重装器值
	TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;//PSC预分频器值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//重复计数器值
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
	
	/*避免刚初始化就进入中断(复位就是1,而不是0)*/
	TIM_ClearFlag(TIM2,TIM_FLAG_Update);
	
	/*四、配置输出中断控制,允许更新中断输出到NVIC*/
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
	
	/*五、配置NVIC,在NVIC打开定时器中断的通道,分配优先级*/
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStructure);
	
	/*六、运行控制,使能计数器*/
	TIM_Cmd(TIM2,ENABLE);
}

/*查看CNT的值*/
uint16_t Timer_GetCounter(void)
{
	return TIM_GetCounter(TIM2);
}

/*中断函数模板
void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET)
	{
		
		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
	}
}
*/

Timer.h

复制代码
#ifndef __TIMER_H
#define __TIMER_H

void Timer_Init(void);
uint16_t Timer_GetCounter(void);

#endif

main.c

复制代码
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"

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,Timer_GetCounter(),5);//观察CNT计数器值的变化情况
	}
}

void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET)
	{
		Num ++;
		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
	}
}
相关推荐
HQB20266 小时前
EG1198|屹晶微电子 120V 内置 MOS 异步降压 DC‑DC(高性价比)
嵌入式硬件·硬件工程
果壳science8 小时前
张祥前实验如何获取正电荷
笔记·科技·嵌入式硬件·硬件工程·制造
南山电子nscn8 小时前
中科芯CETC汽车电池管理系统BMS进口芯片国产型号替代指南
单片机·汽车·bms
沉淀的.晴天8 小时前
can总线
stm32
桀人8 小时前
认识AT24C02
stm32·单片机·嵌入式硬件
国科安芯10 小时前
星间激光通信终端CANFD控制网络的时延确定性与辐射可靠性
网络·嵌入式硬件·信息与通信·canfd·低轨卫星·商业航天·抗辐射
一直C10 小时前
嵌入式 Linux 驱动开发学习笔记:内核定时器、platform 总线与 I²C 驱动
linux·驱动开发·嵌入式硬件·学习·imx6ull
传感器与混合集成电路10 小时前
150MHz主频、8路DAC与6路PWM:JLH221360伺服控制SIP解析
嵌入式硬件
comyccccc10 小时前
STM32PID控制板设计全解析学习笔记
单片机·嵌入式硬件
碧海银沙音频科技研究院11 小时前
实现炬芯ATS308X的usb cdc 串口IAP 固件升级功能实现
人工智能·嵌入式硬件·深度学习·算法