打印
[STM32F1]

STM32F103之定时器(TIM6,TIM7)

[复制链接]
157|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
一、定时器
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

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

105

主题

4286

帖子

2

粉丝