STM32时钟树和定时器详解

本文详细介绍了单片机中的时钟系统,包括HSI、HSE、PLL、LSE、LSI等不同时钟源的选择与作用,以及如何配置系统时钟和APB总线时钟。特别关注了通用定时器的工作原理、时钟源配置和中断管理,以TIM2为例演示了实际应用中的配置过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

时钟树

简介

时钟就像心脏一样,推动单片机各个部分运作以及执行相应的指令。例如IIC/SPI时钟线、定时器、ADC采样间隔等。

内部时钟简介

以下三种不同的时钟源可被用来驱动系统时钟(SYSCLK)

HSI(高速内部时钟):HSI时钟信号由内部8MHz的RC振荡器产生,可直接作为系统时钟或在2分频后作为PLL输入。

HSE(高速外部时钟):来源为外部无源晶振,速度8M(可提供精确主时钟)。

PLL(锁相环时钟):来源为HSI/2或HSE经过倍频所得。

其余为:

LSE(低速外部时钟):一个32.768kHz的低速外部晶体或陶瓷谐振器。它为实时时钟或者其他定时功能提供一个低功耗且精确的时钟源。

LSI(低速内部时钟):一个低功耗时钟源的角色,它可以在停机和待机模式下保持运行为独立看门狗和自动唤醒单元提供时钟。 LSI时钟频率大约40kHz(在30kHz和60kHz之间)。

系统时钟选择(SYSCLK)

系统复位后会先选择HSI作为系统时钟,若时钟源被直接选择为HSE或者PLL锁相环时钟时,并不会直接切换时钟源,而是需等被选择时钟稳定运行后才会切换系统时钟源

时钟线

HCLK(AHB先进高性能总线时钟)

SYSCLK(系统时钟)通过AHB预分频之后得到的时钟叫HCLK(AHB总线时钟)

为内存、DMA(直接存储器访问)、SysTick提供时钟

APB1总线时钟

通过桥接2接入AHB系统总线,通过APB1预分频器进行分频,APB1操作速度限于36MHz。但作用于通用定时器时,默认会2倍频,所以为72MHz。此倍频器的值无法更改,但会根据APB1预分频器自动修改倍频数值为x1或x2。

APB2总线时钟

通过桥接1接入AHB系统总线,通过APB2预分频器进行分频,APB2操作于全速(最高72MHz)。

APB连接外设参考图
9beed53fb5d446b28b2c4d8f104f3919.png

2ca56e61f86f43dd9dd70df4bf5db62e.jpeg

其他时钟及接口

FCLK自由运行时钟

进入低功耗的停止模式时,HCLK总线会停止运行,所有连接到AHB总线上的外设都会停止运行。

当再次唤醒设备时,就需要通过外部中断与FCLK来完成。

FCLK的时钟真正来源为AHB的预分频器,所以当AHB总线关闭时,FCLK还可以继续运行

Flash编程接口时钟        永远连接HSI

USB接口时钟                来自PLL锁相环

CSS时钟安全系统

当时钟源是HSE或者是经过锁相环倍频的HSE时,可以选择开启CSS功能。当时钟源出问题时,会自动切换为HSI时钟,并且可以产生中断,让使用者可以进行紧急处理。

RTC与看门狗时钟可参考上图时钟树

定时器

简介

定时器分为基本定时器、通用定时器和高级定时器
这里主要介绍通用定时器。

fa6a68e558ec4161b47535774bafd0c0.png通用定时器

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

时钟来源

1.内部时钟(CK_INT):可上一部分APB1总线输出的时钟,频率为72MHz。

2.外部时钟模式1:可接ETR外部时钟、ITRx其他定时器或TIx捕获通道

3.外部时钟模式2:可以接ETR外部时钟。

4.编码器模式:读取正交编码器波形

时基单元

由PSC、ARR和CNT组成

PSC预分频器:预分频器可以将计数器的时钟频率按1到65536之间的任意值分频。

ARR自动重装器:ARR是一个 16 位的寄存器,这里面装着计数器能计数的最大数值。当计数到这个值的时候,如果使能了中断的话,定时器就产生溢出中断。

影子寄存器:开启后当预分频器数值改变时,并不立刻改变时钟分频系数,而是等当前周期跑完憨批,下一个周期开始执行更新的分频系数。

CNT计数器:计数到自动重装器ARR的值后进行更新事件并置一个标志位,可以通过中断输出控制(判断是否需要中断),需要则到NVIC请求中断。CNT有三种模式,向上计数,向下计数和中央对齐。

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

8429adf73deb4479aafd47812cc7822d.png

预分频器PSC传值为需要分频数-1。比如二分频则传值2-1,预分频计数器则0  1  0  1计数改变定时器时钟频率。

0405c511cf94457d96ad4698c4234f1a.png

通用定时器框图

3ac11a019c4c48ee9cb52a50d9bcf157.jpeg

定时器配置

流程

1.选择时钟源RCC开启时钟

2.选择时基单元的时钟源

3.配置时基单元

4.配置输出中断控制

5.配置NVIC

6.运行控制,使能计数器

标准库函数
//略
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);
//使能终端输出控制,中断允许位
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);

//时钟源选择
//选择内部时钟
void TIM_InternalClockConfig(TIM_TypeDef* TIMx);
//选择ITRx其他定时器时钟
void TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);
//选择TIx捕获通道的时钟
void TIM_TIxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_TIxExternalCLKSource,
uint16_t TIM_ICPolarity, uint16_t ICFilter);
//选择ETR通过外部模式1输入的时钟
void TIM_ETRClockMode1Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,uint16_t ExtTRGFilter);
//选择ETR通过外部模式2输入的时钟
void TIM_ETRClockMode2Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler,uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter);
//配置ETR引脚预分频器、极性、滤波器这些
void TIM_ETRConfig(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,uint16_t ExtTRGFilter);

//单独函数
//单独写预分频值
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);
//获取当前预分频器的值
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);
配置
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);			//开启TIM2的时钟
	
TIM_InternalClockConfig(TIM2);		//选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟
	
//时基单元初始化
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);			//初始化TIM_TimeBaseInit
	
/*中断输出配置*/
TIM_ClearFlag(TIM2, TIM_FLAG_Update);	//清除定时器更新标志位
										//TIM_TimeBaseInit函数末尾,手动产生了一次更新事件
										//若不清除此标志位,则开启中断后,会立刻进入一次中断
								
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);					//开启TIM2的更新中断,允许中断
	
/*NVIC中断分组*/
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);				//配置NVIC为分组2
															
/*NVIC配置*/
NVIC_InitTypeDef NVIC_InitStructure;						//定义结构体变量
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;				//选择配置NVIC的TIM2线
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//指定NVIC线路使能
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;	//指定NVIC线路的抢占优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;			//指定NVIC线路的响应优先级为1
NVIC_Init(&NVIC_InitStructure);								//初始化NVIC_Init
	
TIM_Cmd(TIM2, ENABLE);			//使能TIM2,定时器开始运行
定时器中断函数
void TIM2_IRQHandler(void)  //函数名参考启动文件
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)//查看TIM2的更新中断标志位
	{
		
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);//清除标志位
	}
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值