STM32快速复习(三)定时器中断(TIM)部分一


前言

我总感觉定时器是单片机的核心。在所有入门章节中基本上是最难的,也是我认为对于单片机是否入门的判断标准

大一玩51单片机,定时器我看了俩个星期多。(主要大一还在体验大学的美好并没有认真较真的学习)51单片机从学完定时器后感觉就没什么瓶颈了。(在大学51用的不深,后面做项目接外设,可能也就串口部分麻烦了些,其他的基本上都是看看例程,使用使用,了解了解外设的原理,差不多就能实现相应的功能)

大二学STM32,也是,定时器是我感觉入门章节中最难的,(进阶的RTOS和PID等不算入门)后面的ADC,DMA,PWM等等都要用到定时器。

也方便更深刻的学习的TIM定时器。
定时器部分打算分几章写完
定时中断,输入输出比较,时钟树系统,PWM等等吧。尽量清晰,方便用于复习。


提示:以下是本篇文章正文内容,下面案例可供参考

一、TIM是什么?TIM结构?

TIM(Timer)定时器
最基本的功能 是对输入的时钟进行计数,并在计数值达到设定值时触发中断。若这个输入是一个可靠的基准时钟,那么对这个基准时钟技术就实现了计时的功能。
定时器分三种,基本定时器,通用定时器,高级定时器。
我学STM32时,师从江科大。一直在用通用定时器。最近马上放假过五一,有时间我也打算搞搞基本定时器,高级定时器看看效果。
在这里插入图片描述
时基单元:中间的粉色部分。
运行控制:控制寄存器的一些位,如启动停止、向上或向下计数等,操作这些寄存器就可以控制时基单元的运行了。
内部时钟模式、外部时钟模式2、外部时钟模式1:外部时钟源选择。这个选择器的输出就是为时基单元提供时钟。
编码器模式:编码器独有的模式,一般用不到。
中断申请控制:由于定时器内部有很多地方要申请中断,“中断申请控制”就用来使能控制这些中断是否使能。比如,中断信号会先在状态寄存器里置一个中断标志位,这个
标志位会通过中断输出控制,到NVIC申请中断
在这里插入图片描述
定时器核心的部位我感觉是时基单元,理解时基单元,并可以写出相应的代码。定时器就算理解的七七八八了
单说原理,内部晶振常用为8MHZ,但是STM32会将8MHZ的定时器进行倍频至72MHZ
1MHZ=1000KHZ=1000000HZ 所以72MHZ=72000000HZ,这就是默认的频率
有了单片机的频率,就可以进入系统预分频器PSC
TIM_TimeBaseInitStructure.TIM_Prescaler = 7200-1;//PSC预分频的值7200
72000000/7200=10000,此时,进入时基单元的频率为10000HZ
最后再操纵自动重装值,使内部的频率达到自动重装值后进行定时函数。
TIM_TimeBaseInitStructure.TIM_Period = 10000-1;//ARR自动重装器的值10000
这就是时基单元部分的原理

公式概括:计数器=内部晶振/预分频器
计数器-自动重装值=0,定时器代码执行。

中断函数执行后记得清除定时中断标志位的状态。
计数器,自动重装值,预分频器 均为16进制,最大数据65536;

在这里插入图片描述
内外时钟源选择和主从触发模式结构:上面的一大块。下面介绍各种各样的内外时钟源:

  1. 内部时钟CK_INT【常用】:通常为72MHz,基本定时器只能选择CK_INT,通用定时器和高级定时器则新增了下面的时钟源。
  2. 外部TIMx_ETR【常用】:引脚的位置可以参考引脚定义表,如stm32f103c8t6的PA0引脚复用了TIM2_CH1_ETR等。外部输入了方波时钟,然后通过极性选择、滤波
    等电路进行整形,然后兵分两路,一路ETRF进入触发控制器,紧跟着就可以选择成为时基单元的时钟(外部时钟模式2);一路进入选择器等待成为TRGI。
    TRGI主要用作触发输入来使用,可以触发定时器的从模式,本小节仅用做外部时钟(外部时钟模式1),其他功能后续再讲。
  3. 外部ITR信号:包括ITR0~ITR4(引脚定义见参考手册“表78 TIMx内部触发连接”),来自其他定时器,实现了定时器的级联。这个ITR信号从上一级定时器的主模式
    TRGO引脚来(图片右上方)。
  4. 外部TI1F-ED:来自于输入捕获单元的TIMx_CH1引脚,后缀“ED”意为边沿,也就是说该路时钟的上升沿和下降沿均有效,也就是CH1引脚的边沿。
  5. 外部TI1FP1:来自CH1引脚时钟。
  6. 外部TI2FP2:来自CH2引脚时钟。
    编码器接口:可以读取正交编码器的输出波形,后续会再介绍。
    TRGO引脚:定时器的主模式输出,可以将内部的一些事件映射到TRGO上,相比基本定时器这些事件的范围显然更广。
    注:最后三种外部时钟用于输入捕获和测频率,后续介绍

在这里插入图片描述
相比于通用定时器,高级定时器主要增加了以下功能:对输出比较模块的升级
重复次数计数器:可以实现每个几个计数周期,才发生一次更新事件和更新中断,相当于自带一级的定时器级联。
DTG(Dead Time Generate):死区生成电路。将输出引脚由原来的一个变为两个互补的输出,可以输出一对互补的有死区的PWM波(防止出现短暂的直通现象),可以
驱动三相无刷电机(如四轴飞行器、电动车后轮、电钻等)。
BRK刹车输入:为了给电机驱动提供安全保障,如果外部引脚BKIN(Break IN)产生了刹车信号或者内部时钟失效,这个电路就会自动切断电机的输出,防止意外的发生。

TIPS:有人问倍频后的频率为什么还要过预分频器;
倍频用来提升性能,预分频器给用户选择,毕竟不是所有的外设都需要最高频率来使用。

看懂公式,就已经掌握了基本定时器。此时再翻到上面的基本定时器结构,应该一目了然。
通用定时器相比较基本定时器,可选配置增加,原理不变
例如晶振选择有多种,内部晶振,外部晶振。

二、TIM标准库函数

TIM_DeInit :恢复默认配置。
TIM_TimeBaseInit 【重要】:时基单元初始化。用于配置时基单元。
TIM_TimeBaseStructInit :为时基单元结构体赋一个默认值。
TIM_Cmd 【常用】:对应定时中断基本结构的“运行控制”模块,用于使能时基单元的计数器。
TIM_ITConfig 【常用】:“中断输出控制”模块,用于使能中断输出信号。
下面6个函数对应时基单元的时钟源选择部分。
TIM_InternalClockConfig 【常用】:选择 内部时钟。
TIM_ITRxExternalClockConfig :选择 ITRx其他定时器 的时钟。
TIM_TIxExternalClockConfig :选择 TIx捕获通道 的时钟。
TIM_ETRClockMode1Config :选择 ETR通过外部时钟模式1 输入的时钟。
TIM_ETRClockMode2Config :选择 ETR通过外部时钟模式2 输入的时钟。
TIM_ETRConfig :不是用于选择时钟的,而是单独用来配置ETR引脚的预分频器、极性、滤波器等参数。
下面是一些可以单独更改某些参数的函数,可以防止每次更改参数都要进行一次初始化。
TIM_PrescalerConfig :单独更改时基单元 预分频 的值。还可以选择 预分频器 是否启用缓冲寄存器。
TIM_CounterModeConfig :单独改变时基单元计数器的计数模式。
TIM_ARRPreloadConfig :自动重装器的预装功能配置,也就是选择时基单元的 计数器 是否启用缓冲寄存器。
TIM_SetClockDivision :单独配置时基单元的 时钟分频系数。这个系数的作用位置比预分频器靠前,但功能与预分频器相同,只不过只能选择固定的分频系数(不分频、2分频、4
分频),对分频要求不高则一般配置为不分频。
TIM_SetCounter :给计数器写入一个值。
TIM_SetAutoreload :给自动重装载寄存器写入一个值。
TIM_GetCounter :获取当前计数器的值。
TIM_GetPrescaler :获取当前的预分频器的值。
最后4个是获取定时中断标志位和清除定时中断标志位的函数。
TIM_GetFlagStatus :用于主函数,获取定时中断标志位的状态。
TIM_ClearFlag :用于主函数,清除定时中断标志位的状态。
TIM_GetITStatus :用于中断函数,获取定时中断标志位的状态。
TIM_ClearITPendingBit :用于中断函数,清除定时中断标志位的状态。

三、TIM标准库代码

#include "stm32f10x.h"                  // Device header
 // 定时器初始化-TIM2
 void Timer_Init(void){
    //1.初始化RCC内部时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    //2.选择时基单元的时钟
    TIM_InternalClockConfig(TIM2);//默认使用内部时钟,也可以不写
    //3.配置时基单元
    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自动重装器的值10000
    TIM_TimeBaseInitStructure.TIM_Prescaler = 7200-1;//PSC预分频的值7200
    TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//重复计数器的值(高级定时器才有)
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);//时基单元初始化。用于配置时基单元。
    TIM_ClearFlag(TIM2,TIM_FLAG_Update);//消除上一行TIM_TimeBaseInit立刻产生更新事件影响
    //4.配置中断输出控制
    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
    //5.配置NVIC
    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);
    //6.配置运行控制
    TIM_Cmd(TIM2, ENABLE);    
}
 /*
 //TIM2定时中断后的中断函数
void TIM2_IRQHandler(void){
    if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET){
        ??    
        TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
    }
 }
 */

主函数中放入Timer_Init();
按照第一个图进行系统配置,有前面两章的基础,上面代码应该理解很快。
理解时基单元,并可以写出相应的代码。定时器中断就算理解的七七八八了
中断函数执行后记得清除定时中断标志位的状态。


总结

复位后计数器的值从1开始而不是从0开始,说明上电初始化后TIM2就立刻中断了一次。这是因为时基单元初始化函数TIM_TimeBaseInit,在函数的最后生成了一个更新事件,来保证可以立刻重新装载预分频器和重复计数器的值。要消除这个影响,就在TIM_TimeBaseInit后面加一句TIM_ClearFlag来清除相应的中断标志位

高级定时器写的很不详细,我总认为没有看懂时钟树,使用这些有点云里雾里的感觉,下一章把时钟树写出来,再配合定时器等。自认为就算彻底理解定时器的使用了。
结合时钟树系统一块理解比较方便

  • 19
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值