STM32-TIM定时器中断

目录

一、TIM(Timer)定时器简介

二、定时器类型

2.1基本定时器结构

2.2通用定时器结构

2.3高级定时器结构

三、定时中断基本结构

四、时序图分析

4.1 预分频器时序

4.2 计数器时序

4.3 计数器无预装时序(无影子寄存器)

4.4 计数器有预装时序(有影子寄存器)

五、RCC时钟树 

六、开发步骤

七、定时器函数

八、实验

8.1定时器定时中断

8.2定时器外部时钟


一、TIM(Timer)定时器简介

①定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断
②16位计数器、预分频器、自动重装寄存器的时基单元,在72MHz计数时钟下可以实现最大59.65s的定时

计数器:执行计数定时的一个寄存器,每来一个时钟,计数器加1

预分频器:对计数器的时钟进行分频,让这个计数更加灵活

自动重装寄存器:计数的目标值,计多少个时钟来申请一次中断
③不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能
④根据复杂度和应用场景分为了高级定时器、通用定时器、基本定时器三种类型

二、定时器类型

2.1基本定时器结构

主模式触发DAC功能:把定时器的更新事件映射到触发输出TRGO(Trigger Out)的位置,TRGO直接接到DAC的触发转换引脚上,这样就不需要通过中断来触发DAC转换了。实现了硬件的自动化。  

 通用定时器和高级定时器除了向上计数模式,还有向下计数模式和中央对齐模式

2.2通用定时器结构

2.3高级定时器结构

三、定时中断基本结构

四、时序图分析

4.1 预分频器时序

计数器计数频率:CK_CNT = CK_PSC / (PSC + 1)

4.2 计数器时序

计数器溢出频率:CK_CNT_OV = CK_CNT / (ARR + 1)= CK_PSC / (PSC + 1) / (ARR + 1)

计数器时间:(PSC + 1)(ARR + 1)/CK_PSC

4.3 计数器无预装时序(无影子寄存器)

4.4 计数器有预装时序(有影子寄存器)

五、RCC时钟树 

作用:产生和配置时钟,将配置好的时钟发送到各个外设系统

开发技巧:

在SystemInit函数中,首先启动内部8MHz时钟为系统时钟运行,然后再启动外部时钟,进入PLL锁相环进行倍频,8MHz倍频9倍,得到72MHz,锁相环输出稳定之后,选择锁相环输出为系统时钟,这样就把系统时钟由8MHz变成了72MHz。

实际问题:

如果外部晶振出现问题,程序时钟慢了大概10倍,定时器定时1s,结果过了大概10s才进中断。是因为现在是以内部时钟8MHz运行的

六、开发步骤

①RCC打开时钟

②选择时基单元的时钟源

③结构体配置时基单元(预分频器,自动重装器,计数模式)

④配置输出中断控制,允许更新中断输出到NVIC

⑤配置NVIC,在NVIC中打开定时器中断的通道,并分配一个优先级

⑥运行控制,使能计数器

⑦写定时器中断函数

七、定时器函数

=====================================================================

=================================基本函数=============================

void TIM_DeInit(TIM_TypeDef* TIMx);

//定时器恢复缺省配置


void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);

//时基单元初始化

//第一个参数:某个定时器,第二个参数:结构体

void TIM_TimeBaseStructInit(TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);

//把结构体变量赋默认值

void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);

//使能计数器

//第一个参数:TIMx选择定时器,第二个参数:使能或失能

void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);

//使能中断输出信号(中断输出控制)

//第一个参数:TIMx选择定时器,第二个参数:哪个中断输出,第三个参数:使能或失能

=====================================================================

=========================配置时钟输入的函数=============================

void TIM_InternalClockConfig(TIM_TypeDef* TIMx);

//选择内部时钟


void TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);

//选择ITRx其他定时器时钟

//第一个参数:选择配置哪个定时器,第二个参数:选择要接入哪个定时器


void TIM_TIxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_TIxExternalCLKSource,uint16_t TIM_ICPolarity, uint16_t ICFilter);

//选择TIx捕获通道的时钟

//第一个参数:TIMx,第二个参数:TIMx具体哪个引脚,第三、四个参数:输入极性和滤波器


void TIM_ETRClockMode1Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,uint16_t ExtTRGFilter);

//ETR通过外部时钟模式1输入时钟

//第一个参数:TIMx,第二个参数:外部触发预分频器,第三、四个参数:输入极性和滤波器


void TIM_ETRClockMode2Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, 
uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter);

//ETR通过外部时钟模式2输入时钟

//第一个参数:TIMx,第二个参数:外部触发预分频器,第三、四个参数:输入极性和滤波器


void TIM_ETRConfig(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,uint16_t ExtTRGFilter);

//单独配置ETR引脚的预分频器、极性、滤波器

//第一个参数:TIMx,第二个参数:外部触发预分频器,第三、四个参数:输入极性和滤波器

=====================================================================

===================更改关键参数函数(预分频值,自动重装载值)==============

void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode);

//修改预分频值

//第一个参数:TIMx,第二个参数:预分频值,第三个参数:写入模式


void TIM_CounterModeConfig(TIM_TypeDef* TIMx, uint16_t TIM_CounterMode);

//修改计数器的计数模式

//第一个参数:TIMx,第二个参数:新的计数器模式


void TIM_SelectInputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);

//自动重装器预装功能配置

//第一个参数:TIMx,第二个参数:预装功能使能或失能

void TIM_SetCounter(TIM_TypeDef* TIMx, uint16_t Counter);

//给计数器值

//第一个参数:TIMx,第二个参数:计数器值


void TIM_SetAutoreload(TIM_TypeDef* TIMx, uint16_t Autoreload);

//给自动重装器写入值

//第一个参数:TIMx,第二个参数:自动重装值

uint16_t TIM_GetCounter(TIM_TypeDef* TIMx);

//获取计数器值


uint16_t TIM_GetPrescaler(TIM_TypeDef* TIMx);

//获取预分频值

=====================================================================

============================获取和清除标志位函数========================

//主函数

FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);

//中断函数

ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);
void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);

八、实验

8.1定时器定时中断

实验现象:1s计数加一

代码实现

Timer.c

#include "stm32f10x.h"                  // Device header

void Timer_Init(void)
{
	/*一、RCC开启时钟*/
	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;//计数器模式
	TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;//ARR自动重装器值
	TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;//PSC预分频器值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//重复计数器值(高级定时器才有)
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
	
	/*避免刚初始化就进入中断(复位就是1,而不是0)*/
	TIM_ClearFlag(TIM2,TIM_FLAG_Update);
	
	/*四、配置输出中断控制,允许更新中断输出到NVIC*/
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//开启更新中断到NVIC的通路
	
	/*五、配置NVIC,在NVIC打开定时器中断的通道,分配优先级*/
	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)
	{
		
		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
	}
}
*/

Timer.h

#ifndef __TIMER_H
#define __TIMER_H

void Timer_Init(void);

#endif

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"

uint16_t Num;

int main(void)
{
	OLED_Init();
	Timer_Init();
	
	OLED_ShowString(1,1,"Num:");
	OLED_ShowString(2,1,"CNT:");

	while (1)
	{
		OLED_ShowNum(1,5,Num,5);
		OLED_ShowNum(2,5,TIM_GetCounter(TIM2),5);//观察CNT计数器值的变化情况
	}
}

void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET)
	{
		Num ++;
		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
	}
}

8.2定时器外部时钟

方法:定时器指定的外部引脚输入一个方波信号,来提供定时器计数的时钟 

实验现象:利用对射式红外传感器来手动模拟一个外部时钟,用挡光片,依次遮挡、移开来模拟一个方波,定时器计数值(CNT)逐次加一,当CNT到9后,产生一次中断,Num加一,CNT清零重新计数

代码实现

Timer.c

#include "stm32f10x.h"                  // Device header

void Timer_Init(void)
{
	/*一、RCC开启时钟 + GPIOA的初始化*/
	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,0x00);
	//通过ETR的外部时钟模式2,不分频,不反向(高电平/上升沿有效),外部触发滤波器
	
	/*三、配置时基单元(预分频器,自动重装器,计数模式)*/
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 10 - 1;//ARR自动重装器值
	TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;//PSC预分频器值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//重复计数器值
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
	
	/*避免刚初始化就进入中断(复位就是1,而不是0)*/
	TIM_ClearFlag(TIM2,TIM_FLAG_Update);
	
	/*四、配置输出中断控制,允许更新中断输出到NVIC*/
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
	
	/*五、配置NVIC,在NVIC打开定时器中断的通道,分配优先级*/
	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);
}

/*查看CNT的值*/
uint16_t Timer_GetCounter(void)
{
	return TIM_GetCounter(TIM2);
}

/*中断函数模板
void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET)
	{
		
		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
	}
}
*/

Timer.h

#ifndef __TIMER_H
#define __TIMER_H

void Timer_Init(void);
uint16_t Timer_GetCounter(void);

#endif

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"

uint16_t Num;

int main(void)
{
	OLED_Init();
	Timer_Init();
	
	OLED_ShowString(1,1,"Num:");
	OLED_ShowString(2,1,"CNT:");

	while (1)
	{
		OLED_ShowNum(1,5,Num,5);
		OLED_ShowNum(2,5,Timer_GetCounter(),5);//观察CNT计数器值的变化情况
	}
}

void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET)
	{
		Num ++;
		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
	}
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

静态HTTP应用的未来趋势与展望

随着互联网的快速发展,静态HTTP应用作为一种简单、快速和安全的Web应用形式,已经得到了广泛的应用。然而,随着技术的不断进步和创新,静态HTTP应用也在不断发展和变化。下面,我们就来谈谈静态HTTP应用的未来趋势和展望。…

腾讯云 - 日志服务(CLS)Bug 体验官

问题描述 最近在学习日志服务,发现了腾讯云上面一款CLS产品,致力于解决日志采集分析,刚开始用的时候感觉还不错,但是发现当创建第二个日志主题的时候发现不对劲了,前一个竟然失效了,排查了老半天也没发现啥…

dockerfile创建镜像lnmp

dockerfile创建镜像 LNMPwordpress nginx 172.111.0.10 docker-nginx mysql 172.111.0.20 docker-mysql php 172.111.0.30 docker-php systemctl stop firewalld setenforce 0 cd /opt mkdir nginx mysql php cd nginx/ 拖进去 nginx wordpress vim Dockerfile #声明基…

电动工具调速控制电路芯片GS016 GS069的芯片描述

GS016 直流有刷电机调速电路。输出端内置14V钳位结构,通过桥接内部电阻网络,可以改变PWM占空比输出,达到控制电机转速作用。采用SOP14封装形式 GS069 直流有刷电机调速电路。通过外接电阻网络,改变与之相接的VMOS管的输出&#x…

外发加工ERP软件功能有哪些?外发加工ERP系统哪家好

不同的外发加工业务有不同的业务流程和管理策略与方式,在当前这个激烈竞争的时代,如何降低经营成本,打通各种信息流,优化资源配置和降低成本,提升生产过程联动效率,加强企业核心竞争力管理等,是…

【Database】什么是数据库?常见的数据库类型有哪些?

什么是数据库?常见的数据库类型有哪些? 首先,什么是数据库?把它想象成一个数字游乐场,我们以结构化的方式组织和存储大量信息。现在,让我们来谈谈数据库的主要类型。 关系型数据库: 想象一下…

已经写完的论文怎么降低查重率 papergpt

大家好,今天来聊聊已经写完的论文怎么降低查重率,希望能给大家提供一点参考。 以下是针对论文重复率高的情况,提供一些修改建议和技巧: 已经写完的论文怎么降低查重率 背景介绍 在学术界,论文的查重率是评价论文质量的…

静态路由原理与配置

文章目录 静态路由原理与配置一、路由器的工作原理1、路由概述2、路由器的工作原理 二、路由表的形成1、路由表2、路由表的形成 三、静态路由和默认路由1、静态路由的缺点2、默认路由(是特殊的静态路由)3、查看路由表 四、路由器转发数据包的封装过程五、…

Python从入门到精通八:Python文件操作

文件的编码 思考:计算机只能识别:0和1,那么我们丰富的文本文件是如何被计算机识别,并存储在硬盘中呢? 答案:使用编码技术(密码本)将内容翻译成0和1存入。 编码技术即:…

网神 SecGate 3600 防火墙 多处任意文件上传漏洞复现

0x01 产品简介 网神SecGate 3600防火墙是基于状态检测包过滤和应用级代理的复合型硬件防火墙,是专门面向大中型企业、政府、军队、高校等用户开发的新一代专业防火墙设备,支持外部攻击防范、内网安全、网络访问权限控制、网络流量监控和带宽管理、动态路由、网页内容过滤、邮…

【论文解读】System 2 Attention提高大语言模型客观性和事实性

一、简要介绍 本文简要介绍了论文“System 2 Attention (is something you might need too) ”的相关工作。基于transformer的大语言模型(LLM)中的软注意很容易将上下文中的不相关信息合并到其潜在的表征中,这将对下一token的生成产生不利影响…

基于R语言piecewiseSEM结构方程模型在生态环境领域实践技术应用

结构方程模型(Sructural Equation Modeling,SEM)可分析系统内变量间的相互关系,并通过图形化方式清晰展示系统中多变量因果关系网,具有强大的数据分析功能和广泛的适用性,是近年来生态、进化、环境、地学、…

Linux --绘制地图投影出现报错:无法成功下载地图背景数据

Linux --绘制地图投影出现报错:无法成功下载地图背景数据 主要原因是由于使用学院集群,该集群无法连接外网,在使用cartopy绘制地图投影时,导致无法成功加载地图背景数据解决方法也很简单,自己手动下载所需要的地形数据…

【数据结构和算法】--队列

目录 队列的概念及结构队列的实现初始化入队出队其他一些队列函数 小结队列相关题目 队列的概念及结构 队列是只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out) 的原则。 入队列&#xf…

2023 巅峰之作 | AIGC、AGI、GhatGPT、人工智能大语言模型的崛起与挑战

文章目录 01 《ChatGPT 驱动软件开发》内容简介 02 《ChatGPT原理与实战》内容简介 03 《神经网络与深度学习》04 《AIGC重塑教育》内容简介 05 《通用人工智能》目  录 2023年是人工智能大语言模型大爆发的一年,一些概念和英文缩写也在这一年里集中出现&#xff…

Java反射(2)

我是南城余!阿里云开发者平台专家博士证书获得者! 欢迎关注我的博客!一同成长! 一名从事运维开发的worker,记录分享学习。 专注于AI,运维开发,windows Linux 系统领域的分享! 本…

Docker-compose单机容器编排

YML文件是什么? YAML文件是一种标记语言,以竖列的形式展示序列化的数据格式。可读性很高类似于json格式。语法简单。 YAML通过缩进来表示数据结构,连续的项目用-符号来表示。 YML文件使用的注意事项 1、 大小写敏感 2、 通过缩进表示层级…

代码随想录刷题题Day11

刷题的第十一天,希望自己能够不断坚持下去,迎来蜕变。😀😀😀 刷题语言:C / Python Day11 任务 ● 理论基础 ● 递归遍历 ● 迭代遍历 ● 统一迭代 1 二叉树理论基础 1.1 二叉树的种类 (1&…

Linux----内核及发行版

1. Linux内核 Linux内核是操作系统内部操作和控制硬件设备的核心程序,它是由芬兰人林纳斯开发的。 内核效果图: 说明: 真正操作和控制硬件是由内核来完成的,操作系统是基于内核开发出来的。 2. Linux发行版 是Linux内核与各种常用软件的组合产品&am…

这些Pads技术问题,你还在继续犯错吗?

随着时代发展,Mentor Pads很快成为国内半导体公司的常用EDA软件之一,也就是说起码有数万个电子工程师在使用Pads设计PCB,当然也有很多工程师在使用Pads时遇到了很多问题,下面来看看有哪些技术问题仍然还在继续犯? 1、走…