stm32 定时器中断

目录

定时器分类

通用定时器框图

时钟源

内部时钟(CK_INT)

外部时钟模式 1( TI1、 TI2)

时钟信号输入引脚

滤波器

        如果来自外部的时钟信号的频率过高或者混杂有高频干扰信号的话,我们就需要使用滤波器对信号重新采样,来达到降频或者去除高频干扰的目的,也可以设置不使用滤波器

边沿检测

触发输入选择器:触发选择

从模式选择

使能计数器

外部时钟模式 2( ETR)

内部触发输入(ITRx)

控制器

时基单元

预分频器 PSC

自动重载寄存器 ARR

计数器 CNT

hal库代码

标准库代码


定时器分类

        STM32F1系列最多有8个常规定时器, 2个基本定时器( TIM6、 TIM7)、 4个通用定时器( TIM2、 TIM3、 TIM4、TIM5)、 2个高级定时器( TIM1、 TIM8)

        STM32F103C8T6定时器资源:TIM1TIM2TIM3TIM4

        

图1

图2

通用定时器框图

时钟源

内部时钟(CK_INT)

        STM32F1 系列的定时器 TIM2-7都是挂载在 APB1 总线上,时钟不是直接由 APB1 总线直接提供,而是先经过一个倍频器。当 APB1 的预分频器系数为 1 时,这个倍频器系数为 1,即定时器的时钟频率等于 APB1 总线时钟频率;当 APB1 的预分频器系数≥2 分频时,这个倍频 器系 数就 为 2, 即定 时器的 时钟 频率 等于 APB1 总 线时 钟频 率的 两倍,一般设置 APB1 总线时钟频率为 36M, APB1 总线的预分频器分频系数是 2,所以挂载在 APB1 总线的定时器时钟频率为 72Mhz。一般情况下都是使用内部时钟。当从模式控制寄存器 TIMx_SMCR 的 SMS 位等于 000 时,则使用内部时钟。

        高级定时器 TIM1 和 TIM8 是挂载在 APB2 总线上的,如果 APB2 预分频系数为 1,挂载在该总线的定时器时钟频率不变,否则频率是该总线时钟频率的 2 倍。一般设置 APB2 总线时钟频率为 72MHz, APB2 预分频器的预分频系数为1,所以 TIM1 和 TIM8 时钟源频率为 72MHz。

外部时钟模式 1( TI1、 TI2)

        顾名思义时钟信号来自芯片外部。时钟源进入定时器的流程如下:外部时钟源信号→IO→TIMx_CH1(或者 TIMx_CH2),这里需要注意的是:从 IO到 TIMx_CH1(或者 TIMx_CH2),就需要配置 IO 的复用功能,才能使 IO 和定时器通道相连通。

时钟信号输入引脚

        当使用外部时钟模式 1 的时候,时钟信号来自于定时器的输入通道,总共有 4 个,分别为 TI1/2/3/4,即 TIMx_CH1/2/3/4。具体使用哪一路信号,由 TIM_CCMRx 的位 CCxS[1:0] 配置,其中 CCMR1控制 TI1/2, CCMR2 控制 TI3/4。外部时钟模式 1 下,时钟源信号只能从 CH1 或者 CH2 输入到定时器, CH3 和 CH4 都是不可以的。这以 CH2(通道 2)为例的,时钟源信号到达 CH2 后,那么这里这个时钟源信号用 TI2 表示

滤波器
        如果来自外部的时钟信号的频率过高或者混杂有高频干扰信号的话,我们就需要使用滤波器对信号重新采样,来达到降频或者去除高频干扰的目的,也可以设置不使用滤波器
边沿检测

        边沿检测的信号来自于滤波器的输出,在成为触发信号之前,需要进行边沿检测,决定是上升沿有效还是下降沿有效

触发输入选择器:触发选择

        图中框出了 TI1F_ED、 TI1FP1 和 TI2FP2 三个触发输入信号(TRGI)。 TI1F_ED 表示来自于 CH1,并且没有经过边沿检测器过滤的信号,所以它是 CH1 的双边沿信号,即上升沿或者下降沿都是有效的。 TI1FP1 表示来自 CH1 并经过边沿检测器后的信号,可以是上升沿或者下降沿。 TI2FP2 表示来自 CH2 并经过边沿检测器后的信号,可以是上升沿或者下降沿。这里以CH2 为例,那只能选择 TI2FP2。如果是 CH1 为例,那就可以选择 TI1F_ED 或者 TI1FP1

从模式选择

        选定了触发源信号后,最后需把信号连接到 TRGI 引脚,让触发信号成为外部时钟模式 1 的输入,最终等于 CK_PSC,然后驱动计数器 CNT 计数。由 ECE 位和 SMS[2:0]位来选择定时器的时钟源,外部时钟模式 1,所以 ECE 位置 0, SMS[2:0] = 111 即可。

使能计数器

        最后只需使能计数器开始计数,外部时钟模式 1 的配置就算完成。使能计数器由 TIMx_CR1 的位 CEN 配置

外部时钟模式 2( ETR)

        在外部时钟模式 2 下,定时器时钟信号首先从 ETR 引脚进来,信号只有 1 个;接着经过外部触发极性选择器,由 ETP 位来设置上升沿有效还是下降沿有效;然后经过外部触发预分频器,由 ETPS[1:0]位来设置预分频系数,频率不能超过 TIMx_CLK(72M)的 1/4;紧接着经过滤波器器,由 ETF[3:0]位来设置滤波方式,也可以设置不使用滤波器;最后经过从模式选择器,由 ECE 位和 SMS[2:0]位来选择定时器的时钟源,体的配置 TIMx_SMCR 的位 ECE 为 1 即可选择外部时
钟模式 2;最后只需使能计数器开始计数,外部时钟模式 2 的配置就完成。使能计数器由 TIMx_CR1 的位 CEN 配置

内部触发输入(ITRx)

        内部触发输入是使用一个定时器作为另一个定时器的预分频器。在硬件上高级控制定时器和通用定时器在内部连接在一起,可以实现定时器同步或级联。主模式的定时器可以对从模式定时器执行复位、启动、停止或提供时钟

假如TIM1 作为 TIM2 的预分频器:

        TIM1_CR2 寄存器的 MMS[2:0]位设置为 010,即 TIM1 的主模式选择为更新(选择更新
事件作为触发输出 (TRGO));

        TIM2_SMCR 寄存器的 TS[2:0]位设置为 000,即使用 ITR1 作为内部触发,如下图

        外部时钟模式 1 的时候 TI1F_ED、TI1FP1 和 TI2FP2,以及外部时钟模式 2 的ETRF,它们都是属于外部的,其余的都是内部触发了。TS[2:0]位设置为 000,使用 ITR0 作为内部触发,这个 ITR0 什么意思?看下图

        当从模式定时器为 TIM2 时, ITR1 表示主模式定时器就是 TIM2,TIM1 和 TIM2 的 CEN 位都要置 1,即启动计数器

控制器

        控制器包括:从模式控制器、编码器接口和触发控制器(TRGO)。从模式控制器可以控制
计数器复位、启动、递增/递减、计数。编码器接口针对编码器计数。触发控制器用来提供触发信号给别的外设,比如为其它定时器提供时钟或者为 DAC/ADC 的触发转换提供信号。

时基单元

预分频器 PSC

        预分频器 PSC,有一个输入时钟 CK_PSC 和一个输出时钟 CK_CNT。输入时钟 CK_PSC 就是上面时钟源的输出,输出 CK_CNT 则用来驱动计数器 CNT 计数。通过设置预分频器 PSC 的值可以得到不同的 CK_CNT,PSC预分频的范围为0~65535

自动重载寄存器 ARR

        自动重载寄存器 ARR 用来存放与计数器 CNT 比较的值,可以向上计数、向下计数或向上/向上双向计数。当计数值达到设定值时,会产生溢出事件,可以发出中断或DMA请求,然后再由自动装载寄存器进行重新加载或更新。通过 TIMx_CR1 寄存器的 ARPE 位控制自动重载影子寄存器功能,如果 ARPE 位置 1,自动重载影子寄存器有效,只有在事件更新时才把 TIMx_ARR 值赋给影子寄存器。如果 ARPE 位为 0,则修改 TIMx_ARR 值马上有效

计数器 CNT

        高级控制定时器的计数器有三种计数模式,分别为递增计数模式、递减计数模式和递增/递减 (中心对齐) 计数模式,CNT计数器的范围为0~65535。

        纵轴表示计数器的计数值,横轴表示时间, ARR 表示自动重载寄存器的值,小红点就是更新事件发生的时间点。例如:递增计数模式下,当计数值等于 ARR 时,计数器的值被复位为 0,定时器溢出,并伴随着更新事件的发生,后面继续递增计数
        定时器的定时时间主要取决于预分频系数和定时周期,计算公式为:

 当前系统时钟频率为72MHz, APB1二分频为36MHz, TIMxCLK则为72MHz。预分频系数任意取一值,假设为PSC=10000-1,自动装载器值假设为ARR=7200-1,则此时定时器定时为:

 即,定时器每间隔1s,将产生一次溢出事件,产生中断

hal库代码

/*1毫秒后会触发中断,然后执行中断服务函数操作。*/
TIM_HandleTypeDef g_timer;/*定时器中断初始化函数*/
void general_timer_init()
{TIM_ClockConfigTypeDef tim_config = {0};g_timer.Instance = TIM2;/*选择定时器*//*72MHz经过72分频后,定时器时钟为1MHz,即定时器计数1次的时间,刚好为1us;*/g_timer.Init.Prescaler = 72-1;/*设置预分频系数*/g_timer.Init.CounterMode = TIM_COUNTERMODE_UP;/*递增计数模式*/g_timer.Init.Period = 0;/*自动重载值ARR,任意,后面代码再修改*/g_timer.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; /*时钟分频*/g_timer.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; /*不自动重载*/HAL_TIM_Base_Init(&g_timer);tim_config.ClockSource = TIM_CLOCKSOURCE_INTERNAL;/*用内部时钟作为定时器时钟源*/HAL_TIM_ConfigClockSource(&g_timer , &tim_config);HAL_TIM_Base_Start_IT(&g_timer);/*使能定时器中断*/}
/*定时器MSP初始化函数*/
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM2){__HAL_RCC_TIM2_CLK_ENABLE();/*使能时钟*/HAL_NVIC_SetPriority(TIM2_IRQn, 1, 1);/*设置中断抢占和响应优先级*/HAL_NVIC_EnableIRQ(TIM2_IRQn);/*使能中断*/}
}/*定时器实现的延时函数,延时时间为 t us , 最多能延时65535us*/
void timer_us_delay(uint16_t t)
{uint16_t counter = 0;__HAL_TIM_SET_AUTORELOAD(&g_timer, t);/*直接设置ARR寄存器的值*/__HAL_TIM_SET_COUNTER(&g_timer, counter);/*直接设置CNT计数器的值,保证定时器从0开始计数;*/HAL_TIM_Base_Start(&g_timer);/*启动定时器*/while( counter != t){counter = __HAL_TIM_GET_COUNTER(&g_timer);/*获取定时器当前计数*/}/*直到定时器计数从 0 计数到 t 结束循环,刚好 t us*/HAL_TIM_Base_Stop(&g_timer);/*停止定时器*/
}/*定时器实现的延时函数,延时时间为 t ms, 最多65ms多点*/
void timer_ms_delay(uint16_t t)
{int i = 0;for(; i<t; i++)timer_us_delay(1000);/*设置定时器的自动重载值(ARR)为1000*/
}#if 1
/*中断服务函数:配置了使能中断,当计数器的值达到1000时,会触发中断*/
void TIM2_IRQHandler(void)
{HAL_TIM_IRQHandler(&g_timer);
}void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if(htim ->Instance == TIM2){/*中断触发*/}}
#endif

标准库代码


void tim_init(void)
{/*开启时钟*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);/*使用内部时钟*/TIM_InternalClockConfig(TIM2);/*初始化定时器*//*计数器溢出频率= 72Mhz/(TIM_Prescaler+1)/(TIM_Period+1),这里定1秒 */TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;/*设置时钟分频因子为1,即没有分频*/TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;/*向上计数*/TIM_TimeBaseInitStruct.TIM_Period = 10000-1;/*自动重装值*/TIM_TimeBaseInitStruct.TIM_Prescaler = 7200-1;/*预分频值*/TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;/*重复计数器,高级定时器才有,这里给0*/TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);/*清除更新中断标志位,避免系统初始化(或复位)后立刻更新进入中断*/TIM_ClearFlag(TIM2,TIM_IT_Update);/*使能中断*//*TIM_IT_Update表示更新中断,也就是定时器计数溢出时产生的中断*/TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);/*配置NVIC*//*分组*/NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NVIC_InitStruct;NVIC_InitStruct.NVIC_IRQChannel = TIM2_IRQn;/*中断通道*/NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;/* 使能中断 */NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2; /* 抢断优先级*/NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;  /* 子优先级 */NVIC_Init(&NVIC_InitStruct);/*开启Tim*/TIM_Cmd(TIM2,ENABLE);
}/*中断服务函数*/
void TIM2_IRQHandler(void)
{/*检查中断标志*/if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET){/*中断触发*//*清除标志位*/TIM_ClearITPendingBit(TIM2,TIM_IT_Update);}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/156961.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

解决pycharm中,远程服务器上文件找不到的问题

一、问题描述 pycharm中&#xff0c;当我们连接到远程服务器上时。编译器中出现报错问题&#xff1a; cant open file /tmp/OV2IRamaar/test.py: [Errno 2] No such file or directory 第二节是原理解释&#xff0c;第三节是解决方法。 二、原理解释 实际上这是由于我们没有设置…

Debian或Ubuntu静态交叉编译arm和aarch64

Debian或Ubuntu静态交叉编译arm和aarch64 介绍术语ARM架构前置条件从源代码编译一个简单的C程序configure和make交叉编译关于静态链接和依赖关系使用 musl libc 实现与 configure 和 make 进行交叉编译 ARM 正在获得越来越多的关注&#xff0c;并且越来越受欢迎。直接在这些基于…

【广州华锐互动】牛顿运动定律VR虚拟教学软件

在科技日新月异的今天&#xff0c;虚拟现实&#xff08;VR&#xff09;技术已经逐渐渗透到各个领域&#xff0c;为我们带来了前所未有的沉浸式体验。在教育领域&#xff0c;VR技术的应用也日益广泛&#xff0c;尤其是在物理教学中&#xff0c;牛顿运动定律VR虚拟教学软件为学生…

云安全—K8S API Server 未授权访问

0x00 前言 master节点的核心就是api服务&#xff0c;k8s通过REST API来进行控制&#xff0c;在k8s中的一切都可以抽象成api对象&#xff0c;通过api的调用来进行资源调整&#xff0c;分配和操作。 通常情况下k8s的默认api服务是开启在8080端口&#xff0c;如果此接口存在未授…

Variations-of-SFANet-for-Crowd-Counting可视化代码

前文对Variations-of-SFANet-for-Crowd-Counting做了一点基础梳理&#xff0c;链接如下&#xff1a;Variations-of-SFANet-for-Crowd-Counting记录-CSDN博客 本次对其中两个可视化代码进行梳理 1.Visualization_ShanghaiTech.ipynb 不太习惯用jupyter notebook, 这里改成了p…

人工智能AI 全栈体系(十一)

第一章 神经网络是如何实现的 这些神经网络越来越复杂&#xff0c;都是用BP算法求解。网络有些变化就可能需要重新推导&#xff0c;而在实验过程中可能会做很多尝试&#xff0c;这样每次都重新推导BP算法太麻烦了。 十、深度学习框架 现在有了很多深度学习框架&#xff0c;这…

AQS面试题总结

一&#xff1a;线程等待唤醒的实现方法 方式一&#xff1a;使用Object中的wait()方法让线程等待&#xff0c;使用Object中的notify()方法唤醒线程 必须都在synchronized同步代码块内使用&#xff0c;调用wait&#xff0c;notify是锁定的对象&#xff1b; notify必须在wait后执…

QT5交叉编译保姆级教程(arm64、mips64)

什么是交叉编译&#xff1f; 简单说&#xff0c;就是在当前系统平台上&#xff0c;开发编译运行于其它平台的程序。 比如本文硬件环境是x86平台&#xff0c;但是编译出来的程序是在arm64架构、mips64等架构上运行 本文使用的操作系统&#xff1a;统信UOS家庭版22.0 一、安装…

由QTableView/QTableWidget显示进度条和按钮,理解qt代理delegate用法

背景&#xff1a; 我的最初应用场景&#xff0c;就是要在表格上用进度条显示数据&#xff0c;以及放一个按钮。 qt-creator中有自带的delegate示例可以参考&#xff0c;但终归自己动手还是需要理解细节&#xff0c;否则不能随心所欲。 自认没那个天赋&#xff0c;于是记录下…

8. 一文快速学懂常用工具——Linux命令(上)

本章讲解知识点 引言 指令学习 本专栏适合于软件开发刚入职的学生或人士&#xff0c;有一定的编程基础&#xff0c;帮助大家快速掌握工作中必会的工具和指令。本专栏针对面试题答案进行了优化&#xff0c;尽量做到好记、言简意赅。如专栏内容有错漏&#xff0c;欢迎在评论区指…

瑞数专题五

今日文案&#xff1a;焦虑&#xff0c;想象力过度发酵的产物。 网址&#xff1a;https://www.iyiou.com/ 专题五主要是分享瑞数6代。6代很少见&#xff0c;所以找理想哥要的&#xff0c;感谢感谢。 关于瑞数作者之前已经分享过4篇文章&#xff0c;全都收录在瑞数专栏中了&am…

【计算机网络】浏览器的通信能力

1. 用户代理 浏览器可以代替用户完成http请求&#xff0c;代替用户解析响应结果&#xff0c;所以我们称之为用户代理 user agent。 浏览器两大核心能力&#xff1a; 自动发送请求的能力自动解析响应的能力 1.1 自动发送请求的能力 用户在地址栏输入了一个url地址&#xff0…