【STM32定时器(一)内部时钟定时与外部时钟 TIM小总结】

news2024/11/25 8:14:48

STM32 TIM详解

  • TIM介绍
  • 定时器类型
    • 基本定时器
    • 通用定时器
    • 高级定时器
    • 常用名词
    • 时序图
      • 预分频时序
      • 计数器时序图
  • 定时器中断配置图
      • 定时器定时
  • 代码调试
    • 代码案例1
    • 代码案例2

TIM介绍

定时器(Timer)是微控制器中的一个重要模块,用于生成定时和延时信号,以及处理定时事件。在STM32系列微控制器中,定时器通常用于以下几个方面:

  1. 定时器功能: 定时器可以生成精确的定时信号,用于定时器中断、PWM(脉冲宽度调制)、计时等应用。它可以产生周期性的计数器溢出事件,也可以产生比较匹配和捕获事件。

  2. PWM生成: 定时器可以用于产生PWM信号,用于控制电机速度、调光、音频产生等应用。

  3. 计时功能: 定时器可以用于测量时间间隔,计算时间延迟,或者用于定时测量外部事件的频率。

  4. 输入捕获和输出比较: 定时器可以用于捕获外部事件的时间戳,也可以用于与比较器进行比较,并产生相应的事件。

在STM32系列微控制器中,定时器模块非常灵活,通常包括多个独立的定时器单元,每个定时器单元都有自己的计数器、自动重载寄存器、预分频器、比较器等功能。此外,定时器模块通常还支持多种工作模式、计数模式和时钟源选择,可以满足各种不同的应用需求。

  • 定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断
  • 16位计数器、预分频器、自动重装寄存器的时基单元,在72MHz计数时-钟下可以实现最大59.65s的定时(72MHZ/65535+1)*(65535+1)
    该公式后续会说明。
  • 不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能
  • 根据复杂度和应用场景分为了高级定时器通用定时器基本定时器三种类型

定时器类型

在这里插入图片描述

基本定时器

在这里插入图片描述

为何PSC+1?PSC为0则不分频即72MHz,为1 则分频率为36Mhz也即是72MHz/1+1 =36MHz,为2则分频为72Mhz/2+1=24MHz …最大值分频值为为65535 则72MHz/65535+1

默认情况下,定时器的输入时钟源(CK_INT)与定时器预分频器的输入时钟(CK_PSC)的时钟频率是相同的。

在STM32系列微控制器中,默认情况下,定时器的输入时钟源是微控制器的主时钟(一般是内部时钟源,比如HSI或者HSI16),而定时器预分频器的输入时钟则是来自于定时器输入时钟源。因此,如果没有对定时器的时钟源进行特别的配置,那么默认情况下,CK_INT和CK_PSC的时钟频率是相同的。

通用定时器

在这里插入图片描述

高级定时器

在这里插入图片描述

常用名词

CK_CNT_OV:时器计数器溢出频率,即定时器溢出的频率,通常以 Hz(赫兹)为单位。
CK_CNT: 定时器计数器时钟频率,即定时器计数器的输入时钟频率,通常以 Hz 为单位。
ARR : 自动重载寄存器的值,决定了定时器计数器溢出的周期。
CK_PSC: 定时器预分频器的输入时钟频率,通常也是定时器的输入时钟频率,在这里是72MHz,不需要我们处理。
PSC : 定时器预分频器的分频系数,决定了定时器计数器时钟频率。
这些参数的英文全称分别是:
- CK_CNT_OV: Timer Counter Overflow Frequency
- CK_CNT: Timer Counter Clock Frequency
- ARR: Auto-reload Register Value
- CK_PSC: Timer Prescaler Clock Frequency
- PSC: Prescaler Value
公式(重要 计算定时用):

输入时钟频率:CK_CNT = CK_PSC / (PSC + 1)
计数器溢出频率:CK_CNT_OV = CK_CNT / (ARR + 1)   
将CK_CNT= CK_PSC / (PSC + 1)带入得到下式= CK_PSC / (PSC + 1) / (ARR + 1)

时序图

预分频时序

在这里插入图片描述

计数器时序图

在这里插入图片描述

定时器中断配置图

在这里插入图片描述
需要一个一个配置,打通所在的线路配置即可。

定时器定时

计时1s如何设置计时?
1s=1/1Hz 即  t=1/f
f(频率)=计数器溢出频率;  t(时间)=1/f;  计时1s等于t=1/1(CK_CNT_OV) 故而f=CK_CNT_OV=1 ;此时CK_PSC / (PSC + 1) * (ARR + 1)=1   
又因为	CK_PSC 是预分频器的输入时钟频率,为72MHz,故而(PSC + 1) * (ARR + 1)=CK_PSC=72000000,凑PSC和ARR的值(但不要超过65535)使得式子成立即可。
这里PSC可以给7200-1  为什么-1?因为(PSC + 1) * (ARR + 1)式子PSC+1了,为了凑整数好计算取PSC=7200(注意:不要超过65535)。ARR+1=72000000/(PSC+1)=10000;

如此 1ms ,1 us的配置也就通过计算可以计算出了。

故而配置时基单元就可以这样写:

    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//配置为向上计数
	
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//这里随便配置个其中的参数
	TIM_TimeBaseInitStructure.TIM_Period=10000;//Auto-Reload,重装值 ARR 其值不得超过65536
	TIM_TimeBaseInitStructure.TIM_Prescaler=7200;//预分频系数  根据上方公式计算  PSC,其值不得超过65536
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//这个是高级定时器才会用到的,通用随便给个直接给0
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);

在这里插入图片描述

代码调试

代码案例1

使用定时器,每1s进入一次定时器中断函数,完成Num++操作,并将它显示到OLED显示屏幕上。
Timer.c

#include "stm32f10x.h"                  // Device header
extern uint16_t Num; //Extern 声明变量在其他文件里(在main.c定义了),让编译器自己去找,这里引用的是main.c定义过的变量
void Timer_Init(void)
{
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//TIM2,通用计时器使能
	TIM_InternalClockConfig(TIM2);//配置为内部时钟模式
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//配置为向上计数
	//@72MHz  1s
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//这里随便配置个其中的参数
	TIM_TimeBaseInitStructure.TIM_Period=10000;//Auto-Reload,重装值 ARR 其值不得超过65536
	TIM_TimeBaseInitStructure.TIM_Prescaler=7200;//预分频系数PSC,其值不得超过65536
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//这个是高级定时器才会用到的,通用随便给个直接给0
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
	
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//使能定时器中断
	//下面这行程序后面还有中断使能开关,中断标志置1了,但后面的中断使能没开,也进不了中断,所以在使能开关前面清除就能达到目的
	TIM_ClearFlag( TIM2,TIM_FLAG_Update);//清除标志位,因为TIM_TimeBaseInit函数里有这样一句话
	/* Generate an update event to reload the Prescaler and the Repetition counter
	values immediately->立即 */ //就会导致刚初始化就进入中断,导致下方Num不是从0开始,而是从1开始。
    // TIMx->EGR = TIM_PSCReloadMode_Immediate;    因此需要清除标志位。
	//NVIC配置
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//分组2
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;//配置为TIM2
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//使能NVIC
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;//抢占优先级
	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)
	{
		Num++;
		Num%=100;//100重新计时
		TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//清楚标志位
	}
}
	

main.c

#include "stm32f10x.h"                  // Device header
#include "OLED.h"  
#include "Timer.h"
uint16_t Num;//定义Num,在Timer引用
int main()
{
    OLED_Init();
	Timer_Init();
	while(1)
	{
		OLED_ShowNum(1,1,Num,4);
	}

}

现象:每1s加一次。一直加到99,再加清零 继续从0开始
在这里插入图片描述

代码案例2

对射式红外,遮挡一次cnt加1次,满十次cnt清零 ,同时Num+1。

因为使用的是ETR外部时钟模式2,故而接线图Do->PA0(PA0有复用TIM2_ETR功能)
在这里插入图片描述
Timer.c

#include "stm32f10x.h"                  // Device header
extern uint16_t Num; //Extern 声明变量在其他文件里(在main.c定义了),让编译器自己去找,这里引用的是main.c定义过的变量


void Timer_Init(void)
{
	//TIM2通用定时器 时钟使能
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//TIM2,通用计时器使能
	//GPIO时钟使能
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

	//外部时钟模式2使能
	TIM_ETRClockMode2Config(TIM2,TIM_ExtTRGPSC_OFF,TIM_ExtTRGPolarity_Inverted,0xff);//外部时钟模式2,下降沿触发,滤波 
	
	//GPIO配置
	GPIO_InitTypeDef GPIO_InitStructure;
	//模式看手册的 GPIO章节的8.1.11 外设的GPIO配置中的TIM ETR
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;//上拉输入,手册给的浮空输入,但不建议,因为电平会跳个不停
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;//PA0端口,因为PA0有TIM2_ETR复用功能
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	//时基单元配置
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//配置为向上计数
	
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//这里随便配置个其中的参数
	TIM_TimeBaseInitStructure.TIM_Period=10-1;//Auto-Reload,重装值 ARR 其值不得超过65536
	TIM_TimeBaseInitStructure.TIM_Prescaler=1-1;//预分频系数PSC,其值不得超过65536
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//这个是高级定时器才会用到的,通用随便给个直接给0
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
	
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//使能定时器中断
	//这个程序后面还有中断使能开关,中断标志置1了,但后面的中断使能没开,也进不了中断,所以在使能开关前面清除就能达到目的
	TIM_ClearFlag( TIM2,TIM_FLAG_Update);//清除标志位,因为TIM_TimeBaseInit函数里有这样一句话
	/* Generate an update event to reload the Prescaler and the Repetition counter
	values immediately->立即 */ //就会导致刚初始化就进入中断,导致下方Num不是从0开始,而是从1开始。
    // TIMx->EGR = TIM_PSCReloadMode_Immediate;    因此需要清除标志位。
	
	
	//NVIC配置
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//分组2
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;//配置为TIM2
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//使能NVIC
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;//响应优先级
	NVIC_Init(& NVIC_InitStructure);
	
	//一定记得启动定时器
	TIM_Cmd(TIM2,ENABLE);

}

/**
  * @brief    得到TIM2的计数值
  * @param    无  
  * @retval   计数器的值
  */
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);//清楚标志位
	}
}
*/


解释一下Period与Prescaler的值的意义(以红外对射为例)

上述情况:Period为10-1(重传值910时清零) ,Prescaler为1-1 不分频(频率),假如改为2-1,频率就会比1-1变慢2倍,此时红外遮挡两次CNT才增加一次。

表示当红外对射遮挡一次,Timer_GetCounter加1

        当Timer_GetCounter到9时,再加1,就进入TIM更新事件中断,同时Timer_GetCounter清除为0

拓展:Period为M-1 ,Prescaler为N-1

表示当红外对射遮挡N次,Timer_GetCounter加1


个人总结复习使用,如果对你也有帮助,那可真是小舞的荣幸。

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

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

相关文章

Linux/Ubuntu/Debian从控制台启动程序隐藏终端窗口

如果你想从终端运行应用程序但隐藏终端窗口. 你可以这样做: 在后台运行: 你只需在命令末尾添加一个与号 (&) 即可在后台运行它。 例如: your_command &将 your_command 替换为你要运行的命令。 这将在后台启动该命令&#xff0c…

THM学习笔记—Simple CTF

nmap扫描,发现2222端口很奇怪啊,重新换一种方式扫描2222端口 发现是ssh 先用ftp试试,尝试匿名登录 下载所有文件 发现只有一个ForMitch.txt,告诉我们其账号密码为弱密码,我们猜测Mitch为其用户名,尝试暴力…

python 爬取人民新闻

基础信息获取: 要闻url:https://www.gov.cn/yaowen/liebiao/home.htm 下一页的url:https://www.gov.cn/yaowen/liebiao/home_1.htm 基础代码: import re import openpyxl import requests from lxml import etree import osdef …

【Java】图书管理系统,完整版+源代码!!!

1. 图书管理系统菜单 1.1 管理员菜单 查找图书新增图书删除图书显示图书退出系统 1.2普通用户菜单 查找图书借阅图书归还图书退出系统 2.基本框架的实现 首先我们要建立一个新的文件,在文件内建立三个包,分别命名为user(用户)、book(图书&#xff…

基于FPGA的图像锐化算法(USM)设计

免费获取源码请关注微信号《FPGA学习笔记册》! 1.图像锐化算法说明 图像锐化算法在实际的图像处理应用很广泛,例如:医学成像、工业检测和军事领域等;它的作用就是将模糊的图像变的更加清晰。常用的图像锐化算法有拉普拉斯算子、s…

【全开源】JAVA情侣扭蛋机情侣游戏系统源码支持微信小程序+微信公众号+H5

一、功能介绍 会员功能、情侣扭蛋 收到的券、送出的券 合伙代理、意见反馈 我们技术使用JAVA后台服务 前后端分离 springbootmybatisplusmysql 用户端 uniapp(vue语法)管理后台 vueelementUi 适配小程序H5公众号,一套源码,无…

LeetCode 2684.矩阵中移动的最大次数:一列一列处理,只记能到哪行(BFS)

【LetMeFly】2684.矩阵中移动的最大次数:一列一列处理,只记能到哪行(BFS) 力扣题目链接:https://leetcode.cn/problems/maximum-number-of-moves-in-a-grid/ 给你一个下标从 0 开始、大小为 m x n 的矩阵 grid ,矩阵由若干 正 整…

VsCode 配置go开发环境之下载go tools

ctrl shift P 选择 go install/update tools,下载go tools 报错, 提升dial err。 将GOPROXY 和 GOSUMDB 按照如下配置,重启IDE即可成功下载 set GOPROXYhttps://goproxy.cn set GOSUMDBoff

oops-framework框架 之 启动流程(三)

引擎: CocosCreator 3.8.0 环境: Mac Gitee: oops-game-kit 回顾 上篇博客中我们通过 oops-game-kit 模版构建了基础的项目,另外讲解了下assets目录结构和游戏配置文件的基本使用相关,详情内容可参考: oops-framewo…

「黄钊的AI日报·第三季」正式发布!

每天5条AI内容点:不是新闻汇总,而是站在11年AI产品经理的视角,将原AI信息中的干货认知,提炼成我自己的文字、展示“what I see”。 做社群“AI产品经理大本营”6年以来,我都是在非常用心的输出AI干货;这份“…

html5使用Websocket

html5使用Websocket 前言1、html5中的websocket2、创建一个 WebSocket 对象3、监听 WebSocket 连接事件4、监听 WebSocket 收到消息事件5、监听 WebSocket 关闭事件6、 监听 WebSocket 出错事件7、发送消息8、整体代码 前言 在即时通讯的交互方式中websocket是一个很使用的方式…

C/C++整数和浮点数在内存中存储

1. 整数在内存中的存储: 整数的2进制表⽰⽅法有三种,即 原码、反码和补码 三种表⽰⽅法均有符号位和数值位两部分,符号位都是⽤0表⽰“正”,⽤1表⽰“负”,⽽数值位最 ⾼位的⼀位是被当做符号位,剩余的都是…

蓝桥杯2022年第十三届省赛真题-GCD

solution1(通过60%) 观察数据发现,最大公约数为abs(a-b) 当abs(a-b) > min(a, b)时&#xff0c;最小增量为g - min(a, b) #include<iostream> #include<algorithm>typedef long long LL;using namespace std; int main(){LL a, b, g, k -1, t1, t2;scanf(&qu…

Django验证码(二)

一、生成图片 1.1、说明 通过pillow模板库生成图片,步骤如下 安装pillow模板建立 生成验证码内容 方法建立 生成验证码颜色 方法建立 生成验证码 方法1.2、需要安装 Pillow 库 pip install Pillow==9.3.01.3、生成验证码内容 import randomdef random_str(length=4):"…

5 分钟小工具:使用 dive 分析 docker 镜像

需求 拿到一个镜像之后&#xff0c;我想知道&#xff1a; 分层查看镜像里都有哪些文件各层使用了什么命令构建的这个镜像镜像里比较大的文件有哪些&#xff08;可能需要优化&#xff09; dive 工具介绍 dive 工具可以做这些分析。dive 的 github 地址是 wagoodman/dive&…

由浅到深认识C语言(13):共用体

该文章Github地址&#xff1a;https://github.com/AntonyCheng/c-notes 在此介绍一下作者开源的SpringBoot项目初始化模板&#xff08;Github仓库地址&#xff1a;https://github.com/AntonyCheng/spring-boot-init-template & CSDN文章地址&#xff1a;https://blog.csdn…

S4 Hana SD -信贷管理 - 03

6. 自动信贷控制及检查规则 6.1 自动信贷控制与检查规则简介 自动信用控制将针对同一信用控制范围的不同的客户风险类别和信贷组执行不同的信用控制政策。对于ECC系统而言,无需单独设置检查规则,可在自动信贷控制进行设置即可,如图1-5-2。在S4 HANA版本中,自动信贷控制和检…

Day39:安全开发-JavaEE应用SpringBoot框架Actuator监控泄漏Swagger自动化

目录 SpringBoot-监控系统-Actuator SpringBoot-接口系统-Swagger 思维导图 Java知识点&#xff1a; 功能&#xff1a;数据库操作&#xff0c;文件操作&#xff0c;序列化数据&#xff0c;身份验证&#xff0c;框架开发&#xff0c;第三方组件使用等. 框架库&#xff1a;MyB…

[沉淀之华] 自研基于SpringBoot Mybaits 构建低代码数据治理脚手架分享:涵盖数据同步、数据比对、数据归档、数据恢复为一体

文章目录 成果演示背景整体能力功能描述相关细节安装使用 成果演示 Github地址&#xff1a;数据治理脚手架 wiki&#xff1a;kg-ctl-core使用文档 背景 为什么要做这个&#xff1f; 一个老生常谈且不得不谈问题&#xff1a;随着业务日益发展&#xff0c;如果不做数据迁移&…

LabVIEW湍流等离子体束热效率优化

LabVIEW湍流等离子体束热效率优化 利用LabVIEW虚拟仪器技术&#xff0c;对湍流等离子体束的热效率进行了实时监测与优化&#xff0c;提高其在材料处理领域的应用效率和精度。通过双进气湍流等离子体发生器&#xff0c;实现了在不同工作参数下对热效率的实时在线监测&#xff0…