一、定时器
1.1 TIM定时器分类
stm32f103外设一共有8个定时器,八个定时器可分为三组;
基本定时器:(TIM6~TIM7)一般只能完成定时器或者延时功能
通用定时器:(TIM2~TIM5)包含基本定时器所有功能,还有输入捕获、输出比较、输出PWM功能
高级定时器:(TIM1,TIM8)包含通过定时器所有功能,还有死区等功能
1.1STM32F103性能线框图
1.2 TIM定时器内部时钟
如何确定提供定时器的时钟有多大呢?不少人可能会看图1.1,通用定时器与基本定时器挂在时钟线APB1上,所以定时器的时钟为36MHz;高级定时器挂在时钟线APB2上,所以TIM1,TIM8时钟频率为72MHz,这是不正确的!
需要通过时钟树确定各个定时器的输入时钟:
1.2TIM定时器时钟树
图1.2中红色方框为系统输入时钟72MHz,然后红色箭头上的时钟均为72MHz,
72MHz时钟进入蓝色方框(APB1预分频器)后为36MHz,说明APB1 prescaler=2,所以说36MHz 2倍频后给到了定时器TIM2~TIM7,即72MHz
72MHz时钟进入黄色方框(APB2预分频器)后为72MHz,说明APB2 prescaler=1,所以说72MHz直接给到了定时器TIM1,定时器TIM8,即72MHz
所以说定时器TIM1~TIM8时钟均为72MHz
1.3 计数方式介绍
TIM定时器计数方式可分为三种:
递减计数:从给定的计数值开始,一直递减计数,直到递减到0;
递增计数:从0开始一直递增计数,直到递增到给定的计数值(TIM6,TIM7仅支持递增计数)
中间计数:从0开始一直递增计数,递增到给定的计数值后再递减计数,计数到0
二、基本定时器
2.1 简介
基本定时器TIM6、TIM7各包含一个16位自动装载计数器,由各自的可编程预分频器驱动。它们可以作为通用定时器提供时间基准,特别地可以为数模转换器(DAC)提供时钟。实际上,它们在芯片内部直接连接到DAC并通过触发输出直接驱动DAC。这2个定时器是互相独立的,不共享任何资源。
<1>TIM6,TIM7可以从0计数到二进制的16位:0xFFFF->65535
<2>预分频器:对输入时钟进行分频,16位,可将时钟分为65536份
2.2 时基单元
可编程定时器的主要部分是一个带有自动重装载的16位累加计数器,计数器的时钟通过一个预分频器得到。软件可以读写计数器、自动重装载寄存器和预分频寄存器,即使计数器运行时也可以操作
时基单元包含:
<1>计数器寄存器(TIMx_CNT)
<2>预分频寄存器(TIMx_PSC)
<3>自动重装载寄存器(TIMx_ARR)
2.3 基本定时器框图
2.1基本框图
<1>自动重装载寄存器(ARR),该寄存器16bit,由用户设定其值(0~65535),该寄存器存放的就是用户想要计数的次数;ARR有一个影子寄存器, 控制寄存器(CR1)的ARPE位可决定是否需要该影子寄存器;
<2> 预分频器(PSC),该寄存器16bit,由用户设定其值(0~65535)用于分频时钟,注意:如果用户设定其值为0,则将时钟1分频,设置为1,则将时钟2分频;PSC有一个影子寄存器,该影子寄存器为必选的
<3>计数器:该寄存器为16bit,可以计数值0~65535,TIM6,TIM7仅支持递增计数
2.3.1 何为溢出事件?
溢出事件:当计数器从0开始计数到设定的数值时,计数器的值将于设定的值进行比较;例如:设定计数值1000,该计数值(1000)将会装载到自动装载寄存器(ARR)中或者对应的影子寄存器中,当计数器从0技术到1000,再计数就会发生溢出事件。
当事件发生时:自动重装载寄存器中的值会由硬件加载到对应影子寄存器(如果开启了影子寄存器)中,同时会将预分频器中的值由硬件加载到对应的影子寄存器。
注意:只有当数值加载到对应的影子寄存器(如果有影子寄存器)中时才起作用,如何才能加载到对应的影子寄存器中呢?(方法一)当事件发生时硬件会自动加载!所以说必须要发生事件
2.4 溢出事件/中断事件
想要定时器开始正常计数,不可避免的步骤是设定自动重装载寄存器(ARR),预分频器(PSC)的值,加入已经设定好了值,首次计时该怎么将值加载到对应的影子寄存器呢?
上述方法一是发生(溢出)事件时,也就是计数溢出时;但是首次使用,影子寄存器里面没有值计数器就不会工作,计数器不工作就不会产生溢出事件!
方法二:软件(手动)产生溢出
2.4.1 手动产生事件
2.2 事件产生寄存器 UG位
2.3控制寄存器 UDIS位
UDIS位默认为0,也就是说允许产生事件 1.溢出可以产生事件,2.设置UG位可以产生事件;由于首次使用定时器,值不加载到对应的影子寄存器中,不可能工作,更别提溢出产生事件了;所以只能设定UG位;
2.4状态寄存器 UIF位
上述讲到UDIS=0允许事件产生,所以当UDIS=0且UG=1时将会产生事件,也就是说用户设定的值会被手动加载到对应的影子计数器中(首次使用定时器情况下);当UDIS=0且UG=1时产生事件的状态位UIF会被硬件置1
总的来说:手动将UDIS=0,UG=1会发生更新事件,硬件会将UIF置1
注意,当UIF=1时,说明产生了更新(或者事件),该位由硬件置1,软件清除;若是被硬件置1后不清除则一直为1
2.4.2 中断
2.5 中断使能寄存器 UIE
由上文可知手动将UDIS=0,UG=1会发生更新事件,硬件会将UIF置1,如若此时已经将UIE位置1,则cpu会即刻进入中断!
所以说如果启用了中断的情况下,手动更新事件后导致的UIF置1需要清除UIF位从而避免烧录代码后cpu立即进入TIM中断。
若是不启用中断,作者建议也是要清除一下的。
三、代码实现
3.1 TIM6 配置
/*************************************************
*@brief 初始化Tim6定时器&&中断
*@param uint16_t psc,预分频器的值(0~65535)
*@return uint16_t arr,重装载的值(0~65535)
*@NOTE void
*@time 2025-6-6
**************************************************/
void TIM6_Init(uint16_t psc,uint16_t arr)
{
//1.打开tim6时钟,tim6时钟位于APB1
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6,ENABLE) ;
//2.初始化tim6时间基,时钟分割(暂无)、计数模式(TIM6只支持默认递增计数)、计数值、预分频值、计数周期数(仅TIM1,TIM8)
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_Period = arr ;//取值区间0~65535
TIM_TimeBaseInitStruct.TIM_Prescaler = psc ;//可将72MHz时钟分频0~65535
TIM_TimeBaseInit(TIM6,&TIM_TimeBaseInitStruct) ;
//3.开启(自动装载寄存器的影子寄存器)
TIM_ARRPreloadConfig(TIM6,ENABLE) ;//默认为关闭的,现在开启(重装载的缓存)
//4.手动产生更新事件,让ARR/PSC值写入影子寄存器
TIM_GenerateEvent(TIM6,TIM_EventSource_Update) ;//手动更新事件后,将ARR/PSC的值写对应的入影子寄存器,该操作将UG位置1->硬件使UIF置1,
//5.清除更新事件标志位
TIM_ClearFlag(TIM6,TIM_FLAG_Update) ;//该操作是将SR寄存器的UIF位置0防止代码烧录后直接进入中断
#if 1
//6.开启中断使能
TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE) ;TIM6定时器开启了中断
//7.配置NVIC
NVIC_InitTypeDef NVIC_InitStruct ;
NVIC_InitStruct.NVIC_IRQChannel = TIM6_IRQn ;//中断通道
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE ;//中断使能
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1 ;//响应先级
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2 ;//抢占优先级
NVIC_Init(&NVIC_InitStruct) ;
#endif
//8.使能TIM6
TIM_Cmd(TIM6,ENABLE) ;
}
上述代码是配置了TIM6定时器以及中断,若禁止发生中断仅需要将代码中的”#if 1“改为”#if 0“
只有当(UIDS=0默认) UIF=1,UIE=1时将发生中断;当(UIDS=0默认) UIF=1,UIE=0时只发生更新事件
3.2 中断函数
/****************************
*@brief TIM6定时器中断
*@param void
*@return void
*@note void
*@time 2025-6-6
******************************/
void TIM6_IRQHandler()
{
//请添加自己的代码.......
//清除中断标志位
TIM_ClearITPendingBit(TIM6,TIM_FLAG_Update) ;//该操作是将SR寄存器的UIF置0;要不然无法退出中断
}
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/DK3314219995/article/details/148491712
|