STM32 学习笔记(六)定时器中断:内部时钟模式,外部时钟模式

这篇具有很好参考价值的文章主要介绍了STM32 学习笔记(六)定时器中断:内部时钟模式,外部时钟模式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

TIM

定时器是功能最强大,内容最复杂的32结构。

  1. 之前51用过的功能,定时产生中断。
  2. 输出比较,常用于产生 PWM 波形,驱动电机等。
  3. 输入捕获,测量方波频率。
  4. 编码器,读取正交编码器的波形。

最大定时时间:72M/65536/65536=中断频率,中断频率取倒数是最大定时时间。

定时器可以级联,比如 72MHz的最大定时 59.65s,级联一次 * 65536 * 65536.

类型 编号 总线 功能
高级定时器 TIM1、TIM8 APB2 拥有通用定时器全部功能,并额外具有重复计数器、死区生成、互补输出、刹车输入等功能
通用定时器 TIM2、TIM3、TIM4、TIM5 APB1 拥有基本定时器全部功能,并额外具有内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等功能
基本定时器 TIM6、TIM7 APB1 拥有定时中断、主模式触发DAC的功能

从下到上越来越复杂且强大。f103c8t6 有 TM1-4(不同芯片不一样,要查阅手册!),我们主要学习通用定时器。

stm32内部时钟,# STM32,stm32,单片机,学习

PSC 对 RCC 分频,比如写入1代表2分频的话,就是输出72MHz/2=36MHz. 实际分频系数=预分频器值+1.

计数器按照时钟频率不断自增,=自动重装载寄存器值时清零并产生中断。UI 是中断,U 是事件。

主动触发 DAC:DAC 中断会很频繁,占用很多 CPU 资源。如果定时器可以自己操纵从设备处理 DAC 就节省许多 CPU 资源。上图中的 TRGO 就是。

stm32内部时钟,# STM32,stm32,单片机,学习

在基本计数器基础上,通用寄存器还支持向下计数和中央对齐计数(0-重装值-0-重装值……)

时钟可选内部72MHz时钟或外部时钟。

可以实现定时器级联,参照手册查看哪几个定时器和哪几个级联。自己输出的引脚 CH 也可以作为自己的时钟输入,作用后续展开。

四个输出是输出比较电路,左边是输入捕获电路。

stm32内部时钟,# STM32,stm32,单片机,学习

图中有阴影的就是有缓冲寄存器的,缓冲寄存器下面马上讲。

重复次数计数器允许几个周期才触发一次中断。

输出 CH1-3 可以输出互补的波,有用处。为了防止切换时产生直通现象(两个反相电路同时切换,类似x形),通过 DTG 死区生成电路, 切换前产生死区,让上下管全归零再切换。

左下角刹车输入,异常状态时可以终止定时器。

基本结构如下:

stm32内部时钟,# STM32,stm32,单片机,学习

运行控制就比如设置向上向下计数。

中断输出控制相当于一个标志位,决定这个中断需不需要。

stm32内部时钟,# STM32,stm32,单片机,学习

CK_PSC:预分频器的输入时钟。

CNT_EN:计数器使能,高电平开启。后面预分频器变为1,分频/2了,因此两次上升沿才触发一次。计数器寄存器随之不断自增。

达到自动重装器值后更新事件,计数器归零。

预分频寄存器修改后并不是立刻改变的,而是等触发中断后下一个开始计数周期后才修改预分频缓冲器,预分频缓冲器才能真正控制。

预分频计数器可见分频的原理,比如设置预分频缓冲器=1,也就是实际分频系数为2,那么计数0,1后达到实际分频系数-1,清零并计数器++。

C K _ C N T = C K _ P S C / ( P S C + 1 ) CK\_CNT=CK\_PSC / (PSC+1) CK_CNT=CK_PSC/(PSC+1)

对于计数器来说是这样的:

stm32内部时钟,# STM32,stm32,单片机,学习

实际分频系数为2,2次时钟周期才+1,溢出时更新事件和中断标志寄存器提示现在中断了。中断标志寄存器要在中断程序中手动清零。

计数器溢出频率:

C K _ C N T _ O V = C K _ C N T / ( A R R + 1 ) = C K _ P S C / ( P S C + 1 ) / ( A R R + 1 ) CK\_CNT\_OV = CK\_CNT / (ARR + 1) = CK\_PSC / (PSC + 1) / (ARR + 1) CK_CNT_OV=CK_CNT/(ARR+1)=CK_PSC/(PSC+1)/(ARR+1)

arr 是自动重装寄存器值。溢出时间取倒数即可。

arr 也有缓冲寄存器,可以自己选取用不用。

stm32内部时钟,# STM32,stm32,单片机,学习

如图,虽然 arr 改成了36,但是也得等这轮中断结束了再更新影子寄存器。

这个最好还是打开,因为如果快加到了arr的值,然后arr缩小了,计数器可能就要一直加加到溢出归零再来一圈才能触发中断之类的小问题。

接下来看看时钟,时钟是所有外设需要的东西。systemInit() 函数里就在配置。

stm32内部时钟,# STM32,stm32,单片机,学习

HSI HSE 是内外时钟源,外部更稳定一些。两者都提供系统时钟,一些外设(AHB APB12)就是依靠他俩。

LSE OSC 是 RTC。

LSI RC 是独立看门狗的时钟。

SystemInit() 先启动内部时钟,系统暂时以8MHz运行,再启动外部时钟进入 PLL 锁相环进行倍频,达到稳定 72MHz 后输出。

因此外部时钟电路出问题了,无法正常切换时可能感觉程序跑的慢,是在用8MHz系统内时钟跑。或者CSS时钟安全系统强行把外部电路停了也可能。CSS也参与到了高级控制定时器中的刹车输入电路。

本板APB1预分频系数2,APB2是1.

AHB 预分频器的分频系数直接对PCLK1做除法。定时器2-7则是:“如果预分频系数=1,则频率=36MHz不变;否则频率*2”,所以其内部基准时钟永远是72MHz。APB2上的定时器1,8也是。

所有时钟都连了一个与门,外加一个使能电路。

代码:定时器

流程:

  1. RCC。
  2. 设置时钟源。
  3. 设置时钟源的时基单元(初始化预分频器,自动重装器,计数器模式)。
  4. 设置中断控制(开启)。
  5. 配置 nvic,这个用前面学过的 NIVC_Init。
  6. 设置运行控制。
  7. 启动计数器。

需要的函数列表:

stm32内部时钟,# STM32,stm32,单片机,学习

TimeBaseInit:初始化预分频器,自动重装器,计数器模式。

TimeBaseStructInit:给时基单元赋初值。

Cmd:启动时钟。

ITConfig:开启对应时钟中断。

下面六个是时钟源选择,内部时钟,ITRx其他定时器时钟,TIx捕获通道的时钟,ETR模式1,2的时钟,单独配置ETR时基单元、极性、滤波器等设置的函数。

这五个函数是 Init 后单独修改时基单元的配置的函数(改预分频器,改计数模式,设置是否预装,改计数器值,改自动重装值,。

stm32内部时钟,# STM32,stm32,单片机,学习

stm32内部时钟,# STM32,stm32,单片机,学习

最后是四个获取清除寄存器的函数。

stm32内部时钟,# STM32,stm32,单片机,学习

代码就和exti有一些小的差别。

#include "stm32f10x.h"                  // Device header

extern uint16_t cnt;

void Timer_Init(void){
    //rcc, set timer source, set psc + set arr + set cnt mode(time base unit), set it controller, set nvic it handler, set running control, enable counter
    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;
    //比如我们想定1s中断一次,CK_CNT_OV = CK_CNT / (ARR + 1) = CK_PSC / (PSC + 1) / (ARR + 1),也就是72M / (PSC + 1) / (ARR + 1) = 1
    //所以两者赋值可以是10000-1和7200-1,只要两者都在65535以内就行,赋值不唯一
    TIM_TimeBaseInitStructure.TIM_Period=10000-1;//arr自动重装器值,72M 计数10000次,耗时 10000/72M s
    TIM_TimeBaseInitStructure.TIM_Prescaler=7200-1;//预分频器值,分7200频,即 10000/(72M/7200) s=1s中断一次。
    TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//重复计数器值,高级计数器才用
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
    
    TIM_ITConfig(TIM2,TIM_IT_Update, ENABLE);//设为更新中断
    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    
    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);
    
    TIM_Cmd(TIM2,ENABLE);
    
    
}

void TIM2_IRQHandler(void){
    if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET){//这里设置为update
        cnt++;
        TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
    }
}

这里把cnt变量写在main.c里了,通过extern变量声明“这个变量是在其他文件中的,编译器你去找吧”。其实.h里函数声明也应该加extern,不过可以省略。

启动开发板后,可以看到立刻出发了一次中断,这是为啥呢?TIM_BaseInit最后一句是这样的:

TIMx->EGR = TIM_PSCReloadMode_Immediate;   

我们知道自动重装寄存器写入值不是立刻写入的,是等到更新事件的时候才写入缓冲区。那一开始我们初始化自动重装寄存器后,写不进去呀,触发不了中断呀。

因此我们要在 TIM_BaseInit 里手动触发一次更新事件,就是上面这个语句。代价就是上电立刻触发一次中断。更新事件和更新中断是同时发生的。

想去掉这一次中断,可以在 TIM_BaseInit 后面立刻跟一个 “TIM_ClearFlag”。

接下来我们写一个用例,因为TIM2和PA0是一个引脚,所以我们设定TIM2通过外部时钟模式配置,这样我们把红外遮光器接到PA0后,手动挡一次光就相当于模拟了时钟一次周期。

需要做的修改:

  1. 时钟初始化加上GPIOInit,把内部时钟配置改成外部时钟(模式2)。
void Timer_Init(void){
    //rcc, set timer source, set psc + set arr + set cnt mode(time base unit), set it controller, set nvic it handler, set running control, enable counter
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    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_ETRClockMode2Config(TIM2,TIM_ExtTRGPSC_OFF,TIM_ExtTRGPolarity_NonInverted,0x0F);//这里是滤波,太小的话一次红外检测加好多
    
    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);
    
    TIM_ClearFlag(TIM2, TIM_IT_Update);
    
    TIM_ITConfig(TIM2,TIM_IT_Update, ENABLE);
    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    
    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);
    
    TIM_Cmd(TIM2,ENABLE);
}

这样效果就是通过红外传感器来制造clock波形让定时器读取。文章来源地址https://www.toymoban.com/news/detail-721153.html

到了这里,关于STM32 学习笔记(六)定时器中断:内部时钟模式,外部时钟模式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【STM32笔记】STM32的定时器开发基础(二)(基于STM32CubeMX实现定时器中断)

      传统STM32外部中断 的设计步骤:  (1)将GPIO初始化为输入端口。  (2)配置相关I/O引脚与中断线的映射关系。  (3)设置该I/O引脚对印的中断触发条件。  (4)配置NVIC,并使能中断。  (5)编写中断服务函数。   基于STM32CubeMX的外部中断 设计步骤  (1)在STM3

    2024年02月20日
    浏览(62)
  • STM32学习--定时器中断

    目录  概述 一、STM32 通用定时器简介 1.1 STM32定时器定时原理  1.2 STM32 通用定时器相关寄存器简介 1.3 定时器功能描述 1.4计数器模式 二、定时器中断库函数 2.1 步骤总结 2.2 库函数讲解 总结:         这一章,我们将向大家介绍如何使用 STM32F1 系列 的通用定时器。 TIM

    2024年02月02日
    浏览(50)
  • STM32 hal库使用笔记(二)中断—定时器中断

    目录 一、定时器简介 二、HAL库配置 1.时钟树的配置 2. CubeMX的配置 三、代码编写 四、拓展实验 五、实验效果 实验目的:利用定时器6控制LED灯的亮灭,间隔500ms 实验平台:正点原子精英板 一、定时器简介     定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发

    2024年01月19日
    浏览(60)
  • 【学习记录】STM32利用定时器中断实现定时闪烁指示灯

    任务:定时闪烁指示灯 任务目标: 掌握 CubeMX 软件配置定时器实现定时功能的方法。 任务内容: 控制开发板上的指示灯LED每隔1s闪烁。 任务实现: 使用的STM32芯片是STM32F407ZET6 第一步:设置高速时钟,设置LED 第二步:配置TIM10时钟为100MHz,故可以设置预分频系数PSC为9999,自

    2024年02月05日
    浏览(60)
  • 【ESP32最全学习笔记(基础篇)——8.ESP32 中断定时器】

    关于本教程: 1.ESP32简介                                                                 2.ESP32 Arduino 集成开发环境 3.VS 代码和 PlatformIO 4.ESP32 引脚 5.ESP32 输入输出 6.ESP32 脉宽调制 7.ESP32 模拟输入 8.ESP32 中断定时器 ☑ 9 .ESP32 深度睡眠 ESP32 网络

    2024年02月06日
    浏览(52)
  • STM-32:TIM定时中断—定时器定时中断/定时器外部时钟

    定时器可以对输入的时钟进行计数,并在达到设定值时触发中断 16位计数器、预分频器、自动重装寄存器的时基单元,在72MHz计数时钟下可以实现最大59.65s的定时 不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等

    2024年02月09日
    浏览(58)
  • STM32——定时器——定时中断

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 本节先只讲解定时器的定时中断,内外中断源选择。 TIM(Timer)定时器 定时器可以 对输入的时钟进行计数 ,并在计数值达到设定值时触发中断。 16位计数器、预分频器、自动重装寄存器的时基单元 ,

    2024年04月10日
    浏览(50)
  • STM32定时器-定时器中断功能详解

    STM32的众多定时器中我们使用最多的是高级定时器和通用定时器,而高级定时器一般也是用作通用定时器的功能,下面我们就以通用定时器为例进行讲解,其功能和特点包括: 通用与基本定时器(2~7)位于低速的APB1总线上 高级定时器(1、8)位于高速的APB2总线上 自动装载计

    2024年02月08日
    浏览(56)
  • stm32 定时器部分(定时中断)

    一.定时中断(概念部分) 定时中断主要包含两种中断一种是更新中断还有一种是输入捕获中断 更新中断 :更新中断通常用于定时器的基本定时功能。当定时器计数器溢出并重新从零开始计数时,会触发更新中断。你可以配置定时器的计数周期和预分频器来控制定时器的计时

    2024年03月15日
    浏览(59)
  • 学习笔记|定时器|STC中断|定时器时间计算|STC32G单片机视频开发教程(冲哥)|第十一集:定时器的作用和意义

    什么是定时器:定时器-与非网 上节课的一段代码: TimeCount++然后一个延时1毫秒,每运行1ms,变量就会加一。 系统已经运行了多少个毫秒。 实际使用时的代码如下, 判断按键有沿有按下的时候,我们等待按键松开,还有一个while循环。 如果没有松开,会一直死在这一行。所以,

    2024年02月09日
    浏览(64)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包