TIM介绍

计数器(CNT)是执行计数定时的寄存器,来一个时钟计数加一;预分频器(PSC)可以对计数器的时钟分频,使得计数更灵活;自动重装寄存器(ARR)是计数的目标值,到达目标值就申请中断。他们都是16位的,最大值是2的16次方=65536

赫兹就是频率,周期就是赫兹的倒数,最大定时时间=自动重装寄存器最大值*预分频器最大值*周期(1MHZ=10^6HZ),单位秒

三种定时器

基本定时器结构

基本定时器只能选择内部时钟,即系统频率

定时中断功能:通过内部时钟连接到预分频器,预分频器设置分频数,预分频器值为x,输出频率=输入频率/(x+1),然后计数器自增,增加到自动重装寄存器设定的值就清零,再自增。自动重装寄存器连接NVIC,达到设定值后可以申请中断,让CPU来处理,这样的中断叫更新中断;也可以不中断,而是引发一个事件,让别的电路运行,这叫更新事件。

主模式触发DAC功能:有时需要隔一段时间就让DAC输出一段波形,虽然可以在中断里触发DAC,但是这样主程序会被频繁中断。于是通过把更新事件通过主模式映射到TRGO(触发输出),TRGO再接到DAC的触发转换引脚,就不需要软件来触发了,实现了硬件自动化

通用定时器结构

通用定时器可以选择内部时钟,也可选择外部时钟

外部时钟可以来自TIMx_ETR引脚,经过极性选择,边沿检测和滤波等对波形进行整形。滤波之后就可以通过ETRF进入控制器再到时基单元,这一路叫外部时钟模式2;

还可以通过TRGI进入控制器作为时钟,这是外部时钟模式1,这个模式可以通过ETR引脚信号,此时和模式2没什么区别,只是会占用TRGI触发输入通道。也可以通过ITR信号,图中TRGO可以连接其他定时器,就是连接的其他定时器的ITR引脚,他们的ITR信号就可以作为这个定时器的时钟,实现了定时器级联。还可以选择TI1F_ED,它连接了下面CH1引脚。最后还有TI1FP1,TI2FP2,他们各自连接了CH1和CH2引脚,从这里获取时钟。

一般都使用内部时钟,外部时钟的话选择外部时钟模式2最直接简单。

下面左边是输入捕获电路,右边是输出比较电路,这二者不会同时发生,所以引脚和寄存器都是共用的。

高级定时器结构

相对于通用定时器,高级定时器在时基单元新加了重复次数计时器,可以实现几个计时周期才中断一次,不会每次到目标值都中断了。在输出比较电路上加了DTG寄存器,用来生成死区电路,防止开关转换瞬间桥臂直通;右边引脚也变为了一对,可生成互补PWM波形;最下面是刹车输入电路,当外部引脚BKIN产生刹车信号或者内部时钟故障时,就会关闭电机

定时中断结构

运行控制是控制定时开启关闭的,中断输出控制即是否允许对应中断

相关时序

预分频器时序

预分频缓冲器,也叫影子寄存器,当在计时途中改变了分频值时,有缓冲器就不会马上生效,而是在当前计时完后下一个周期才起作用。这是为了防止不同步产生的影响。自动重装器也有这样的影子寄存器

计数器时序

由这个公式,那么所需定时时间=(PSC+1)*(ARR+1)/72MHZ

无预装

无预装即没有缓冲,这是可以自行设置ARPE改变的。

有预装

此时改变重装值也只会在下一个周期开始生效

RCC时钟树

RCC时钟树是产生、配置时钟,并发送到各个外设的系统。图中左边是产生,右边分配

在产生时钟的电路中有四个振荡源:内部8MHZ的高速RC振荡源,外部4~16MHZ的高速石英晶体振荡器,即晶振,外部32.768KHZ的低速晶振,给RTC提供时钟,内部40KHZ的低速RC振荡器,给看门狗提供时钟。两个高速振荡源是给外设提供时钟的

系统会先暂时开启内部8MHZ的RC时钟,然后开启8MHZ的高速晶振进入PLL锁相环进行9倍倍频,得到72MHZ稳定后最终作为系统时钟。CSS是时钟安全系统,检测外部时钟状态,外部时钟失效时它会切换到8MHZRC内部时钟。

定时器内部时钟代码

要对定时器进行初始化,根据结构图,需要选择内外时钟源,配置时基单元,配置中断控制,配置NVIC,启动定时器。在此之前需要开启对应总线的时钟,以TIM2为例

初始化代码
void timer_init(void)
{
	//依旧需要先开启时钟
	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;//自动重装值
	TIM_TimeBaseInitStructure.TIM_Prescaler=7200-1;//分频值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//重复次数计数器,高级定时器才需要,这里通用不用
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
	
	//然后配置中断控制
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//itconfig就是允许外设中断的函数
	
	//然后NVIC
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//分组2
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;//选择TIM2的通道
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//使能
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;//抢占优先级
	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);
	}
	
}

定时器外部时钟初始化代码

void timer_init(void)
{
	//依旧需要先开启时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	
	//接下来选择内外时钟源,这里选ETR外部时钟模式2
	TIM_ETRClockMode2Config(TIM2,TIM_ExtTRGPSC_OFF,TIM_ExtTRGPolarity_NonInverted,0X0F);
	
	//使用了引脚,所以需要初始化GPIO,TIM2的ETR引脚在PA0
	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_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);//这里之后为了让重装值马上起作用,生成了一个更新事件和中断,使得一初始化就引脚中断了一次,不会从0开始
	TIM_ClearFlag(TIM2,TIM_FLAG_Update);//所以使用清除一下标志位,不马上进入中断
	
	//然后配置中断控制
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//itconfig就是允许外设中断的函数
	
	//然后NVIC
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//分组2
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;//选择TIM2的通道
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//使能
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;//响应优先级
	NVIC_Init(&NVIC_InitStructure);
	
	//最后启动定时器
	TIM_Cmd(TIM2,ENABLE);
}

中断函数代码类似

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐