STM32 TIM定时器配置

embedded/2025/2/2 7:35:38/

TIM简介

TIM(Timer)定时器

        定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断

        16位计数器、预分频器、自动重装寄存器的时基单元,在72MHz计数时钟下可以实现最大59.65s的定时

        不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能

        根据复杂度和应用场景分为了高级定时器、通用定时器、基本定时器三种类型

定时器类型

定时中断基本结构

计数器时序:

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

                                                              = CK_PSC (72M)/ (PSC + 1) / (ARR + 1)

预分频器时序:

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

定时器中断代码: 

TIM函数介绍:

        下面的函数对应着定时中断的结构

//时基单元初始化
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);//使能中断输出信号
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);//选择内部时钟
void TIM_InternalClockConfig(TIM_TypeDef* TIMx);//选择ITRx其他定时器时钟
void TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);//选择TIx捕获通道的时钟
void TIM_TIxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_TIxExternalCLKSource,uint16_t TIM_ICPolarity, uint16_t ICFilter);//选择ETR通过外部时钟模式1输入的时钟
void TIM_ETRClockMode1Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,uint16_t ExtTRGFilter);//选择ETR通过外部时钟模式2输入的时钟
void TIM_ETRClockMode2Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter);//单独配置ETR引脚的预分频器、极性、滤波器这些参数
void TIM_ETRConfig(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,uint16_t ExtTRGFilter);

参数更改函数:

//单独写预分频值
void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode);//用来更改计数器的计数模式
void TIM_CounterModeConfig(TIM_TypeDef* TIMx, uint16_t TIM_CounterMode);//自动重装器预装功能配置
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);//给计数器写入一个值
void TIM_SetCounter(TIM_TypeDef* TIMx, uint16_t Counter);//给自动重装器写入一个值
void TIM_SetAutoreload(TIM_TypeDef* TIMx, uint16_t Autoreload);//获取当前计数器的值
uint16_t TIM_GetCounter(TIM_TypeDef* TIMx);//获取当前的预分频器的值
uint16_t TIM_GetPrescaler(TIM_TypeDef* TIMx);

配置定时器(内部时钟):

打开时钟

这次初始化TIM2,也就是通用定时器,TIM2是APB1的总线外设。

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//打开TIM2的外设时钟

选择内部时钟

这里不写这行代码也行,因为定时器上电后默认就是使用内部时钟

 TIM_InternalClockConfig(TIM2);//选择内部时钟

配置时基单元

//-----------------------------配置时基单元---------------------------------TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//定义TIM结构体变量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;//重复计数器的值(这个是高级寄存器才有的,这里不需要用直接给0)TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); //TIM初始化//-----------------------------配置时基单元---------------------------------

使能更新中断

 TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);						//开启更新中断到NVIC通路

NVIC配置

这里的中断通道选择TIM2的中断通道。

//-----------------------------NVIC配置-------------------------------------NVIC_InitTypeDef NVIC_InitStructure;//定义NVIC结构体变量NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//选择中断分组2NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;//选择中断通道NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能中断通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;//抢占优先级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;			 //响应优先级NVIC_Init(&NVIC_InitStructure);//NVIC初始化//-----------------------------NVIC配置-------------------------------------

启动定时器:

TIM_Cmd(TIM2,ENABLE);//启动定时器

整体函数:

void Timer_Init(void)
{//---------------------------定义结构体变量-------------------------------TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//定义TIM结构体变量NVIC_InitTypeDef NVIC_InitStructure;//定义NVIC结构体变量//---------------------------定义结构体变量-------------------------------RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//打开TIM2的外设时钟TIM_InternalClockConfig(TIM2);//选择内部时钟//-----------------------------配置时基单元---------------------------------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;						 //重复计数器的值(这个是高级寄存器才有的,这里不需要用直接给0)TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);						 //TIM初始化//-----------------------------配置时基单元---------------------------------TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);						//开启更新中断到NVIC通路//-----------------------------NVIC配置-------------------------------------NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//选择中断分组2NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;//选择中断通道NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能中断通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;//抢占优先级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;			 //响应优先级NVIC_Init(&NVIC_InitStructure);//NVIC初始化//-----------------------------NVIC配置-------------------------------------TIM_Cmd(TIM2,ENABLE);//启动定时器
}

中断函数:

实现定时器计时功能。

uint16_t Num = 0;
//中断函数void TIM2_IRQHandler(void)
{//获取中断标志位,判断是否触发中断if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET){Num++;TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//清除中断标志位}}

这里定义了一个变量Num,所以需要在头文件了extern一下,让其他工程文件也能用这个变量。

主函数:

完成了定时器计时功能,没过一秒,Num + 1.在屏幕上显示出来。

#include "timer.h"
int main(void)
{LED_Init();OLED_Init();Timer_Init();OLED_ShowString(1, 3, "Num:");while(1){OLED_ShowNum(1, 5, Num, 5);}	}

这里上电以及复位不是从零开始,需要在NVIC配置之前清除一下标志位

配置外部时钟:

选择外部时钟模式

与内部时钟配置一样,只需要选择外部时钟模式以及加一个GPIO配置。

配置GPIO

//-----------------------------GPIO配置-------------------------------------GPIO_InitTypeDef GPIO_InitStructure;				//定义GPIO结构体变量GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;		//选择上拉输入GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;    		//配置引脚GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速率GPIO_Init(GPIOA, &GPIO_InitStructure);//GPIO初始化//-----------------------------GPIO配置-------------------------------------

整体函数配置:

void Timer_Init(void)
{//---------------------------定义结构体变量-------------------------------TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//定义TIM结构体变量NVIC_InitTypeDef NVIC_InitStructure;							 //定义NVIC结构体变量GPIO_InitTypeDef GPIO_InitStructure;							 //定义GPIO结构体变量//---------------------------定义结构体变量-------------------------------RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//打开TIM2的外设时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//打开GPIO A族时钟TIM_ETRClockMode2Config(TIM2,TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted,0x0F);//选择外部时钟模式//-----------------------------GPIO配置-------------------------------------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);//GPIO初始化//-----------------------------GPIO配置-------------------------------------//-----------------------------配置时基单元---------------------------------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;						 //重复计数器的值(这个是高级寄存器才有的,这里不需要用直接给0)TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);						 //TIM初始化//-----------------------------配置时基单元---------------------------------TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);						//开启更新中断到NVIC通路TIM_ClearITPendingBit(TIM2,TIM_IT_Update);        		//清除标志位//-----------------------------NVIC配置-------------------------------------NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//选择中断分组2NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;//选择中断通道NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能中断通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;//抢占优先级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;			 //响应优先级NVIC_Init(&NVIC_InitStructure);//NVIC初始化//-----------------------------NVIC配置-------------------------------------TIM_Cmd(TIM2,ENABLE);//启动定时器
}

功能中断函数:

uint16_t Num = 0;
//中断函数void TIM2_IRQHandler(void)
{//获取中断标志位,判断是否触发中断if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET){Num++;TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//清除中断标志位}}uint16_t Timer_Getcount(void)
{return TIM_GetCounter(TIM2);
}

主函数:

#include "timer.h"
int main(void)
{LED_Init();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_Getcount(), 5);}		
}


http://www.ppmy.cn/embedded/158847.html

相关文章

设计转换Apache Hive的HQL语句为Snowflake SQL语句的Python程序方法

首先,根据以下各类HQL语句的基本实例和官方文档记录的这些命令语句各种参数设置,得到各种HQL语句的完整实例,然后在Snowflake的官方文档找到它们对应的Snowflake SQL语句,建立起对应的关系表。在这个过程中要注意HQL语句和Snowfla…

安卓(android)读取手机通讯录【Android移动开发基础案例教程(第2版)黑马程序员】

一、实验目的(如果代码有错漏,可在代码地址查看) 1.熟悉内容提供者(Content Provider)的概念和作用。 2.掌握内容提供者的创建和使用方法。 4.掌握内容URI的结构和用途。 二、实验条件 1.熟悉内容提供者的工作原理。 2.掌握内容提供者访问其…

kamailio-ACC、ACC_JSON 和 ACC_RADIUS 的区别

ACC、ACC_JSON 和 ACC_RADIUS 的区别 ACC、ACC_JSON 和 ACC_RADIUS 都是 Kamailio 中用于计费(Accounting)的模块,但它们的功能和后端支持有所不同。以下是它们的区别及案例说明: 1. ACC 模块 功能:ACC 模块是 Kamai…

深度学习练手小例子——cifar10数据集分类问题

CIFAR-10 是一个经典的计算机视觉数据集,广泛用于图像分类任务。它包含 10 个类别的 60,000 张彩色图像,每张图像的大小是 32x32 像素。数据集被分为 50,000 张训练图像和 10,000 张测试图像。每个类别包含 6,000 张图像,具体类别包括&#x…

Qt 5.14.2 学习记录 —— 이십일 Qt网络和音频

文章目录 1、UDP带有界面的Udp服务器(回显服务器) 2、TCP回显服务器 3、HTTP客户端4、音频 和Linux的网络一样,Qt封装了Linux的网络API,即Socket API。网络编程是在应用层写,需要传输层支持,传输层有UDP和T…

应用层协议 HTTP 讲解实战:从0实现HTTP 服务器

🌈 个人主页:Zfox_ 🔥 系列专栏:Linux 目录 一:🔥 HTTP 协议 🦋 认识 URL🦋 urlencode 和 urldecode 二:🔥 HTTP 协议请求与响应格式 🦋 HTTP 请求…

Node.js——body-parser、防盗链、路由模块化、express-generator应用生成器

个人简介 👀个人主页: 前端杂货铺 🙋‍♂️学习方向: 主攻前端方向,正逐渐往全干发展 📃个人状态: 研发工程师,现效力于中国工业软件事业 🚀人生格言: 积跬步…

开发技巧,vue 中的动态组件的引用 component + is

在项目中很多时候有切换 tab 的场景&#xff0c;一般来说都是用 v-if 或者 v-show 然后根据各种条件来控制显示隐藏。 其实我们可以使用 vue 中的动态组件&#xff0c;也能实现这个效果 <!-- currentTab 改变时组件也改变 --> <component :is"currentTab"…