stm32 定时器中断

news2024/11/28 11:57:38

目录

定时器分类

通用定时器框图

时钟源

内部时钟(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.coloradmin.cn/o/1160218.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

入栏需看——管理类联考——英语——知识+记忆篇——导航页

文章目录 Section I Use of English——完型填空Section II Reading ComprehensionPart A——阅读理解 A 节&#xff08;Part A&#xff09;&#xff08;四篇&#xff09;Part B——阅读理解 B 节&#xff08;Part B&#xff09;&#xff08;只有一篇&#xff09;Part C——翻译…

Linux shell编程学习笔记19:until循环语句

Linux shell编程中的until语句&#xff0c;在功能上与其它编程语言一致&#xff0c;但在结构与其它编程语言又不太一样。在大多数编程语言中&#xff0c;until语句的循环条件表达式一般位于循环体语句的后面&#xff0c;但是在Linux shell编程中&#xff0c;until语句的循环条件…

教您如何去除照片上的水印!

许多网友都在寻找方法去除照片上的水印&#xff0c;水印通常用于保护版权或标识来源&#xff0c;但有时候我们可能需要使用带有水印的照片&#xff0c;却又不希望水印影响观感&#xff0c;今天我将向大家介绍两种有效的方法&#xff0c;帮助解决“如何去除照片上的水印”这一难…

从内存管理的角度来看,Python语言的变量和参数传递情况解析

从内存管理的角度来看&#xff0c;Python语言的变量和参数传递情况解析 概述 从内存管理的角度来看&#xff0c;Python中的变量和参数传递有一些特点&#xff1a; ☆ 变量是对象的引用&#xff1a;在Python中&#xff0c;变量实际上是对象的引用&#xff0c;而不是对象本身。…

Mysql数据库 7.SQL语言 关联关系

关联关系介绍 Mysql是一个关系型数据库&#xff0c;不仅可以存储数据&#xff0c;还可以维护数据与数据之间的关系——通过在数据表中添加字段建立约束 数据与数据之间的关联关系&#xff1a; 1.一对一关联 2.一对多关联 3.多对一关联 4.多对多关联 一个表的外键对应另一…

2023年【道路运输企业主要负责人】考试技巧及道路运输企业主要负责人复审模拟考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2023年【道路运输企业主要负责人】考试技巧及道路运输企业主要负责人复审模拟考试&#xff0c;包含道路运输企业主要负责人考试技巧答案和解析及道路运输企业主要负责人复审模拟考试练习。安全生产模拟考试一点通结合…

leetcode:1446. 连续字符(python3解法)

难度&#xff1a;简单 给你一个字符串 s &#xff0c;字符串的「能量」定义为&#xff1a;只包含一种字符的最长非空子字符串的长度。 请你返回字符串 s 的 能量。 示例 1&#xff1a; 输入&#xff1a;s "leetcode" 输出&#xff1a;2 解释&#xff1a;子字符串 &q…

虹科资讯 | 10月智能制造行业动态回顾

文章来源&#xff1a;虹科工业控制 阅读原文&#xff1a;https://mp.weixin.qq.com/s/0jR_QgmR6tmrRoTFAo8mFw 10月&#xff0c;虹科与PLCopen合作开展IEC 61131-3培训&#xff0c;目前正在火热报名中&#xff1b;人工智能领域的迅猛发展引起了智能制造业的广泛关注&#xff…

Flink1.18新特性生产环境应用的重点解读!

大家好&#xff0c;我是你们的群主王知无呀。 Flink 1.18已经于近期发布了。在这个新版本中新增了很多新的功能和特性。在这些特性中&#xff0c;有一些是生产环境非常重要的能力&#xff0c;大家在使用过程中可以重点参考和了解其中的原理。 算子级别状态保留时间TTL设置 首先…

CSS3媒体查询与页面自适应

2017年9月&#xff0c;W3C发布媒体查询(Media Query Level 4)候选推荐标准规范&#xff0c;它扩展了已经发布的媒体查询的功能。该规范用于CSS的media规则&#xff0c;可以为文档设定特定条件的样式&#xff0c;也可以用于HTML、JavaScript等语言。 1、媒体查询基础 媒体查询…

苹果AirTag平替产品选择,国内外支持苹果Find My芯片功耗全面对比

2021年4月20,苹果在春季产品发布会上推出了全新的产品类型- AirTag,将哆啦A梦的追踪徽章带到了现实。这个小产品当年并没有像其它苹果新品那样一朝爆红。随着年轮缓缓而坚定地前行, AirTag也缓缓而坚定地前行,并被越来越多的人接受和喜欢。 深入思考AirTag背后的产品逻辑和实现…

双11价格博弈之下,电商大战走向何方?

第十五个双11&#xff0c;电商平台内卷越发激烈。 10月18日&#xff0c;短视频平台快手迫不及待地打响第一枪&#xff0c;随后拼多多、淘宝天猫、京东纷纷启动双11。 不过&#xff0c;和以往不同的是&#xff0c;今年双11是随着“高端商战”一起拉开帷幕的。从京东采销喊话头…

Web安全系列——注入攻击

文章首发公众号&#xff1a; 海天二路搬砖工 前言 在Web应用程序开发中&#xff0c;防SQL注入最基本的安全防护要求了。其实除了SQL注入&#xff0c; 还有很多其他的注入攻击方式。注入攻击是最常见的Web应用攻击方式之一。 本文将介绍注入攻击的概念、种类、原理&#xff0…

删除链表的倒数第n个节点(C++解法)

题目 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5]示例 2&#xff1a; 输入&#xff1a;head [1], n 1 输出&#xff1a;[]示例 3&#…

Linux 服务器 Oracle19C安装

原文:【精选】Oracle | CentOS7安装Oracle19c数据库(RPM包)_oracle-database-preinstall-19c-1.0-1.el7.x86_64.rp_Thorolds Deer的博客-CSDN博客 下载 第一个软件包:Oracle Database 19c Download for Linux x86-64 第二个包:Oracle Linux 7 (x86_64) Latest | Oracle,…

【Springboot】集成Swagger

引入依赖 <dependency><groupId>io.springfox</groupId><artifactId>springfox-boot-starter</artifactId><version>3.0.0</version> </dependency> 浏览器 启动项目后 在浏览器中输入地址 localhost:端口号/swagger-ui/ 使…

Android各版本对应的SDK及JDK版本要求

1、Android Gradle 插件版本说明 | Android 开发者 | Android Developers 2、 3、Android Gradle 插件 7.3.0&#xff08;2022 年 9 月&#xff09; | Android 开发者 | Android Developers 4、 5、参考 Android中Gradle版本和Gradle插件版本 - 简书

深度学习实战:基于TensorFlow与OpenCV的手语识别系统

文章目录 写在前面基于TensorFlow与OpenCV的手语识别系统安装环境一、导入工具库二、导入数据集三、数据预处理四、训练模型基于CNN基于LeNet5基于ResNet50 五、模型预测基于OpenCV 写在后面 写在前面 本期内容&#xff1a;基于TensorFlow与OpenCV的手语识别系统 实验环境&…

物联网AI MicroPython传感器学习 之 MFRC522 RFID射频IC卡感应模块

学物联网&#xff0c;来万物简单IoT物联网&#xff01;&#xff01; 一、产品简介 MFRC522是应用于13.56MHz非接触式通信中高集成度的读写卡芯片&#xff0c;其特点低电压、低成本、体积小的非接触式读写芯片。MFRC522支持MIFARE系列更高速的非接触式通信&#xff0c;双向数据…

如何理解傅里叶变换?

当提到什么是傅里叶变换&#xff1f; 大家的回答一般是&#xff1a;将信号从时域转化到频域&#xff1f; 那为什么要转换到频域呢&#xff1f; 因为在频域可将一些信号分离。 为什么转换到频域就可分离呢&#xff1f;好像不会回答了。 实际上&#xff0c;从线性代数的角度…