初学STM32之定时器中断

2023-11-16

初学STM32之定时器中断


一、定时器概述

1.定时器的分类

STM32F10x系列总共最多有8个定时器分为高级定时器,通用定时器和基本定时器。三种定时器的主要区别如下图所示:

本文章仅介绍通用定时器的一些知识。

2.通用定时器功能概述

通用定时器的功能包括:

  • 16位向上、向下、向上/向下自动装载计数器;
  • 16位可编程(可以实时修改)预分频器,计数器时钟频率的分频系数为1~65536之间的任意数值;
  • 位于低速的APB1总线上;
  • 4个独立通道:
    ─ 输入捕获
    ─ 输出比较
    ─ PWM生成(边缘或中间对齐模式)
    ─ 单脉冲模式输出
  • 使用外部信号控制定时器和定时器互连的同步电路
  • 如下事件发生时产生中断/DMA:
    ─ 更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
    ─ 触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)
    ─ 输入捕获
    ─ 输出比较
  • 支持针对定位的增量(正交)编码器和霍尔传感器电路
  • 触发输入作为外部时钟或者按周期的电流管理

通用定时器经常被用于测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和PWM)等。
注:使用定时器预分频器和RCC时钟预分频器,脉冲长度和波形周期可以在几微秒和几毫秒间调整。STM32的每个通用定时器是完全独立的,没有相互共享的任何资源。

3.通用定时器工作过程

通用定时器的工作过程如图所示:

在这里插入图片描述
如图所示,通用定时器的工作过程大致可以分为时钟发生器、时基单元、输入捕获和输出比较四个部分。

在时钟发生器中,由内部时钟或外部TIMx_ETR等经过一系列处理产生时钟源,送入时基单元;在时基单元中经过预分频产生一个时钟,再由CNT进行计数(向上或向下),计数到自动重装载值时可以触发相应的中断;在输入捕获部分中,对TIMx_CHx中的信号进行捕获,再进行滤波等操作,再通过捕获比较寄存器中捕获到两次信号后的计数器的值,就可以得到脉冲宽度等;在输出比较的部分中,可以在捕获比较寄存器中设置一个数值,用计数器中的值与其比较,当高于该数值时,输出高/低电平,低于该数值时,输出低/高电平。

二、通用定时器的简单应用

1.定时器中断

定时器中断主要应用到通用定时器的时钟发生器和时基单元两个部分。

1.时钟选择

计数器的时钟可以由以下时钟源提供:

  1. 内部时钟(CK_INT)
  2. 外部时钟模式1:外部输入脚(TIx)
  3. 外部时钟模式2:外部触发输入(ETR)
  4. 内部触发输入(ITRx):使用一个定时器作为另一个定时器的预分频器,如可以配置一个定时器Timer1而作为另一个定时器Timer2的预分频器。

时钟计算方法如图所示:

2.计数器模式

通用计数器模式分为三种:向上计数、向下计数、向上向下双向计数。
向上计数模式:计数器从0计数到自动加载值,然后从0重新开始计数并产生一个计数器溢出事件;
向下计数模式:计数器从自动装入值开始向下计数到0,然后从自动装入的值重新开始并产生一个计数器向下溢出事件;
向上/向下计数(中央对齐模式):计数器从0开始计数到自动装入的值-1,产生一个计数器溢出事件,然后向下计数到1并且产生一个计数器溢出事件;然后再从0开始重新计数。

3.定时器中断实现步骤

  1. 使能定时器时钟;
  2. 初始化定时器,配置自动装载寄存器ARR,预分频器寄存器PSC;
  3. 开启定时器中断;
  4. 配置NVIC;
  5. 使能定时器;
  6. 编写中断服务函数;

代码如下:

void Tim3_Int_Init(u16 arr,u16 psc)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	NVIC_InitTypeDef NVIC_InitStruct;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//使能定时器时钟
	
	TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStruct.TIM_Period = arr;
	TIM_TimeBaseInitStruct.TIM_Prescaler = psc;
	
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);//初始化定时器
	
	TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);//开启定时器中断
	
	NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 3;
	NVIC_Init(&NVIC_InitStruct);//配置NVIC
	
	TIM_Cmd(TIM3,ENABLE);//使能定时器
}

void TIM3_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM3,TIM_IT_Update) == 1)//检查是否更新中断
	{
		TIM_ClearITPendingBit(TIM3,TIM_IT_Update);//清除更新中断标志
		LED1 = !LED1;
	}
	
}

2.PWM输出

PWM输出主要依靠通用定时器的输出比较部分。

1.工作过程

在输出比较的部分中,可以在捕获比较寄存器中设置一个数值,用计数器中的值与其比较,当高于该数值时,输出高/低电平,低于该数值时,输出低/高电平。
工作过程如图所示:

由图可知,ARR控制PWM输出的周期,CCRx控制PWM输出的占空比。

2.PWM输出的实现步骤

  1. 使能定时器时钟;
  2. 使能相应IO口的时钟;
  3. 使能AFIO时钟(本实验需要把PB5用作PWM的输出引脚,所以需要重映射配置,所以要开启AFIO时钟);
  4. 初始化IO口(GPIO的模式配置为复用输出);
  5. 重映射;
  6. 初始化定时器;
  7. 初始化输出比较参数;
  8. 使能预装载寄存器;
  9. 使能定时器;
    注: 可以通过改变CCRx的值达到改变占空比的效果[TIM_SetCompare2()]

代码如下:

void Tim3_PWM_Init(u16 arr,u16 psc)
{
	GPIO_InitTypeDef GPIO_InitStruxture;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_OCInitTypeDef TIM_OCInitStruct;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//使能定时器时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO,ENABLE);//使能相应的GPIO口并且开启AFIO时钟
	
	GPIO_InitStruxture.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStruxture.GPIO_Pin = GPIO_Pin_5;
	GPIO_InitStruxture.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStruxture);//配置GPIO口
	
	GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE);//重映射
	
	TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStruct.TIM_Period = arr;
	TIM_TimeBaseInitStruct.TIM_Prescaler = psc;
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);//初始化定时器
	
	TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM2;
	TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OC2Init(TIM3,&TIM_OCInitStruct);//初始化比较参数
	
	TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Enable);//使能预装载寄存器
	TIM_Cmd(TIM3,ENABLE);//使能定时器
}

3.输入捕获

输入捕获主要依靠通用定时器中的输入捕获部分

1.工作过程

通过检测TIMx_CHx的边沿信号,在边沿信号发生跳变(上升沿/下降沿)时,将当前定时器的值(TIMx_CNT)存放到相应的捕获比较寄存器(TIMx_CCRx)里面,完成一次捕获。
注:完成一次捕获后,如果要记录高/低电平时长,不能忘记可能高/低电平持续时间过长导致中断再次刷新。

2.输入捕获配置步骤

  1. 使能定时器和通道对应IO口的时钟;
  2. 初始化IO口(模式为GPIO_Mode_IPD);
  3. 初始化定时器;
  4. 初始化输入捕获通道;
  5. 开启捕获中断;
  6. 配置NVIC;
  7. 使能定时器;
  8. 编写中断服务函数;

代码如下:

TIM_ICInitTypeDef TIM_ICInitStruct;


void TIM5_Cap_Init(u16 arr,u16 psc)
{
	GPIO_InitTypeDef GPIO_InitStruxture;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;

	NVIC_InitTypeDef NVIC_InitStruct;

	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);//使能定时器对应时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能GPIO对应时钟
	
	GPIO_InitStruxture.GPIO_Mode = GPIO_Mode_IPD;
	GPIO_InitStruxture.GPIO_Pin = GPIO_Pin_0;
	GPIO_Init(GPIOA,&GPIO_InitStruxture);//配置GPIO
	//GPIO_ResetBits(GPIOA,GPIO_Pin_0);	
	
	TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStruct.TIM_Period = arr;
	TIM_TimeBaseInitStruct.TIM_Prescaler = psc;
	TIM_TimeBaseInit(TIM5,&TIM_TimeBaseInitStruct);//初始化定时器
	
	TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;
	TIM_ICInitStruct.TIM_ICFilter = 0x00;
	TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;
	TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;
	TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;
	TIM_ICInit(TIM5,&TIM_ICInitStruct);//初始化输入捕获通道

	
	NVIC_InitStruct.NVIC_IRQChannel = TIM5_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
	NVIC_Init(&NVIC_InitStruct);//配置NVIC

	TIM_ITConfig(TIM5,TIM_IT_Update | TIM_IT_CC1,ENABLE);//开启捕获中断
	TIM_Cmd(TIM5,ENABLE);//使能定时器
	
}

总结

以上是STM32定时器的一些工作过程与应用,在实验过程中我用PWM控制输出实现了一个呼吸灯,紧接着再进行对按键的进行输入捕获,获取按键按下时长在编写代码时我发现,在while循环中如果不加一个delay的延迟函数,则呼吸灯无法正常工作,只能处于一个常亮的状态,而输入捕获却可以正常运行。加上延时函数则可以正常工作。目前原因还没有找到

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

初学STM32之定时器中断 的相关文章

随机推荐

  • 论文查找路径 查找IEEE、ScienceDirect论文 免费查看的方法

    IEEE ScienceDirect转免费查看网站网址 IEEE和ScienceDirect上的论文不少质量不错的 但是不少都是要收费才能下载查看的 怎么办呢 有国外大神提供的工具来帮忙 打开上面的网址 里面提供了三个网址 随便打开一个 仅
  • RabbitMQ--扩展--2.2--性能测试--linux.md

    RabbitMQ 扩展 2 2 性能测试 linux md 1 下载 https github com rabbitmq rabbitmq perf test releases tag v2 18 0 rabbitmq perf test
  • python发邮件--中文附件报错问题

    coding utf 8 Created on Thu Apr 11 14 01 30 2019 author zhang peng coding utf 8 import os import sys import smtplib from
  • 擎创技术流

    上期跟大家聊了下eBPF的发展历史还有特性 点击这里 擎创技术流 深入浅出运维可观测工具 一 聊聊eBPF的前世今生 一键回看上期精彩内容 这期主要跟大家分享下eBPF在应用过程中可能出现的问题 希望能帮到遇到类似问题的朋友 话不多说 我们
  • GIOU:Generalized Intersection over Union: A Metric and A Loss for Bounding Box Regression

    废话不多说 先看motivation There is a gap between optimizing the commonly used distance losses and maximizing this metric value
  • 高并发应用实践——缓存简介

    简介 随着互联网的普及 内容越来越复杂 用户和数据量越来越大 所以我们的应用应该支持更高的并发数 但是由于我们的服务器和数据库服务器资源量是有限的 所以如何更加高效的利用这有限的资源 并提供尽可能大的数据吞吐量 一个有效可行的办法就是引入缓
  • shell调用php脚本,并传递参数

    命令行执行带参数的php脚本 并取得参数 张映 发表于 2011 07 15 分类目录 php 一 为什么我们要在命令行下运行php脚本呢 个人理解 主要有二个原因 1 利用crontab去跑php 可以给服务器减压 当然在这里有一个条件
  • 如何导出mysql数据库

    mysql数据库是非常常用的一种数据库 属于中小型数据库 常用于网站业务和一些WEB系统业务 这个数据库非常简单 体积比较小 使用起来比较方便简洁 今天重点来介绍一下该数据的三种导出方法 1 使用工具软件导出数据库文件 这里推荐使用navi
  • ElementUI浅尝辄止30:PageHeader 页头

    如果页面的路径比较简单 推荐使用页头组件而非面包屑组件 1 如何使用
  • 信号处理之FFT(如何求幅度、相位、画频谱图)

    信号处理 可以理解为对信号进行某种加工或变换来达到削弱信号中的多余内容 滤除混杂的噪声和干扰 将信号变换成容易分析与识别的形式 便于估计和选择它的特征参量等目的 快速傅里叶变换 FFT 是信号处理的重要组成部分 是离散傅里叶变换 DFT 的
  • Python调用MMDetection实现AI抠图去背景

    这篇文章的内容是以 使用MMDetection进行目标检测 实例和全景分割 为基础 需要安装好 MMDetection 的运行环境 同时完成目标检测 实例分割和全景分割的功能实践 之后再看下面的内容 想要实现AI抠图去背景的需求 我们需要利
  • JavaWeb-13-Tomcat&Servlet学习笔记

    JavaWeb 13 Tomcat Servlet Web核心模块 1 web相关概念回顾 1 1软件架构 1 2资源分类 1 3网络通信三要素 2 web服务器软件 2 1常见的java相关的web服务器软件 2 2Tomcat web服
  • RDP远程桌面密码凭证获取

    前言 在渗透过程中获取到一台Windows服务器后 可以尝试获取当前机器保存的RDP远程桌面密码凭证 进而在内网横向渗透中进一步扩大战果 0x01 密码凭证获取 查看当前主机本地连接过的目标机器记录 reg query HKEY CURRE
  • 设置useSSL=true 的出现的问题

    一 环境 springboot mybaits plus mysql linux 服务器 服务器修改了SSL配置 对应的服务需要修改 二 问题1 Access without SSL denied Caused by java sql SQ
  • Base64图片编码的使用

    一 base64编码介绍 二 base64图片使用介绍 三 base64图片编码大小与原图文件大小之间的联系 四 代码实现 一 base64编码介绍 Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一 Base64编码可用于
  • JUC学习系列六(计数器 CountDownLatch)

    一个同步辅助类 在完成一组正在其他线程中执行的操作之前 它允许一个或多个线程一直等待 用给定的计数 初始化 CountDownLatch 由于调用了 countDown 方法 所以在当前计数到达零之前 await 方法会一直受阻塞 之后 会
  • 以一己之力搭建分布式ChatGPT

    原以为去年年底ChatGPT已经火过一阵子了 慢慢热度会降下来 出乎意料的是 其热度有增无减 我也是从去年年底一直关注并使用 包括ChatGPT网页版 GPT3 API以及ChatGPT内测API 还包括其他国内外一些人工智能算法的体验 为
  • python回声程序_python 包详解

    包 包是一种管理 Python 模块命名空间的形式 采用 点模块名称 比如一个模块的名称是 A B 那么他表示一个包 A中的子模块 B 就好像使用模块的时候 你不用担心不同模块之间的全局变量相互影响一样 采用点模块名称这种形式也不用担心不同
  • pyspark修炼手册(长期帖)

    2020 03 31 在进行pyspark开发时 需要先安装hadoop spark的环境 或者只安装spark环境即可 配置集群or单机环境都可以 在配置好环境后 不需要单独启动hadoop spark 直接运行pyspark程序即可 一
  • 初学STM32之定时器中断

    初学STM32之定时器中断 一 定时器概述 1 定时器的分类 STM32F10x系列总共最多有8个定时器分为高级定时器 通用定时器和基本定时器 三种定时器的主要区别如下图所示 本文章仅介绍通用定时器的一些知识 2 通用定时器功能概述 通用定