STM32定时器

本文详细介绍了STM32中的定时器,包括基本定时器和通用定时器的硬件结构、工作原理,以及它们在基本定时、输出比较(PWM)、输入捕获和编码器接口等方面的应用。通过代码示例和概念解析,帮助读者深入理解STM32定时器的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

1.在学习STM32单片机时,我时常会因为急于实现功能,而省略掉原理部分,往往直接看代码,这样的学习使我每日既焦虑,又发现自己学到的东西总容易忘掉,变得更加焦虑,而每当问学长时,学长并不会耗费自己的精力去给你一步一步细讲,而正因如此,当我们遇到问题时,往往会停滞不前,反而更容易陷入焦虑的循环中。
2.学习单片机,嵌入式是一个长时间的事情,让我们放下心中的焦躁,静下心来,才能有所收获。

一、TIM简介

1.定时器是存在于STM32单片机中的一个外设。STM32中一共有8个定时器,分别是2个高级定时器(TIM1、TIM8),4个通用定时器(TIM2、TIM3、TIM4、TIM5)和2个基本定时器(TIM5、TIM6)。
在这里插入图片描述
在这里插入图片描述

2.定时器是16位计数器,2的16次方为65536,所以在72MHz的时钟下,最大的定时时间为59.65s。

二、定时器硬件结构分析

1.基本定时器

在这里插入图片描述

时基单元分析(计数计时电路)

1.由三个重要寄存器构成,预分频器,自动重装载寄存器,cnt计数器。
2.基本定时器只能选择内部时钟,所以,可看作由内部时钟输入,主频为72MHz,之后经过预分频器进行分频(分得的频率=主频/(PSC+1)),之后进入计数器,计数器从0开始,计数器计算每一个上升沿,计数器+1(0~65535),之后计数器的值会与自动重装值对比,自动重装值是一个固定的值,当计数器=自动重装值,计数器清0,执行中断。(这里计数器的模式只能向上计数)
3.这种中断称为更新中断,后通往NVIC,之后要配置NVIC的定时器通道。

2.通用定时器

在这里插入图片描述

电路分析

1.其核心部分和基本定时器一样,同样都是时基单元,不同的是,计数器的计数模式不止向上计数一种模式,还有向下计数模式,中央对齐计数模式。
2.向下计数模式,从自动重装值开始,减到0触发更新中断。
3.中央对齐模式,从0开始,向上自增,到达重装值后触发更新中断,然后向下自减,到达0后再次触发更新中断。
4。选择时钟源的不同,通用定时器可以选择

三、基本功能定时

1.概述

定时,简言之就是用来确定一段时间,然后每相隔这一段时间,产生一个中断,之后执行一个功能(一段程序)。

2.原理

当计数器的值与自动重装值相等时,触发更新中断,之后经过NVIC通道,达到每隔一段时间,执行中断,

3.代码框架

在这里插入图片描述

定时中断所走路线
//第一步,配置RCC,开启时钟
//第二步,配置GPIO,输入模式
//第三步,配置AFIO,
//第四步,配置EXTI,选择边沿触发方式
//第五步,配置NVIC,选择优先级
//第六步,运行控制
//第七步,使能计数器

4.常用函数

void TIM_DeInit
//恢复默认设置
void TIM_TimeBaseInit
//时基单元初始化
void TIM_TimeBaseStructInit
//用结构体给时基单元赋初值
void TIM_Cmd
//使能计数器
void TIM_ITConfig
//使能中断输出函数

时钟选择(分别对应图里的6个通道)
void TIM_InternalClockConfig
//内部时钟
void TIM_ITRxExternalClockConfig
//选择ITRx其他定时器通道
void TIM_TIxExternalClockConfig
//捕获通道时钟
void TIM_ETRClockMode1Config
//选择ETR外部时钟模式1通道
void TIM_ETRClockMode2Config
//选择ETR外部时钟模式2通道

配置ETR参数
TIM_ETRConfig

5.Timer.c与Timer.h文件

1.Timer.c

void Timer_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//开启通用定时器TIM2的时钟
	TIM_InternalClockConfig(TIM2);//选择时基单元的时钟(默认使用内部时钟)
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//指定时钟分频,1表示不分频
	//滤波器作用:滤掉信号的抖动干扰
	//滤波器原理:在一个固定的时钟频率f下采样,若连续N个采样点电平一致,表示输入信号稳定,则输出
	//若N个采样点电平不相同,表示信号有抖动,则直接输出低电平或输出上一次的电平
	//采样频率由内部时钟直接来或由内部时钟加时钟分频来
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//计数器模式(向上/向下/中间3个)
	TIM_TimeBaseInitStructure.TIM_Period=10000-1;//周期(10K的频率下计1w个数即为1s)
	TIM_TimeBaseInitStructure.TIM_Prescaler=7200-1;//预分频器(72M对7200分频,得到10K的计数频率)
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//重复计数器(高级计数器才有)

	
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
	TIM_ClearFlag(TIM2,TIM_FLAG_Update);
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//更新中断,使能
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	//中断分组,2位抢占2位响应(分组只进行一次)
	NVIC_InitTypeDef NVIC_InitStructure;//NVIC结构体
	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);//NVIC初始化函数
	//配置NVIC
	TIM_Cmd(TIM2,ENABLE);//启动定时器
}

2.Timer.h

#ifndef __TIMER_H
#define __TIMER_H

void Timer_Init(void);

#endif

四、定时器输出比较

1.概述

主要是使用输出比较用STM32来s输出一个PWM波形,来驱动舵机直流电机等。

2.原理

1.输出比较OC(Output Compare)

如图
在这里插入图片描述
流程:在进行CNT与CCR比较后,其结果在经过输出比较电路后,通过TIM_CH1输出到GPIO引脚上。

原理:通过进行对CNT计数器CCR捕获比较寄存器的比较,来输出一个电平不断跳变的PWM方波。
每当CNT=RCC时,就会进行一次电平翻转,CNT>CCR且小于ARR(即在一个周期内)时输出高电平。

2.输出比较电路

在这里插入图片描述

原理:当CNT大于或等于CCR时,传输信号至控制器,后改变其输出的电平。

3.PWM.c和PWM.h文件

1.PWM.c

#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "Delay.h"
//1.RCC开启时钟(GPIO和TIM)
//2.选择时基单元的时钟源(定时中断选择内部时钟源)
//3.配置时基单元(预分频器、自动重装器、计数模式)
//4.配置CCR的值、输出比较模式、极性选择、输出使能的等参数
//5.配置GPIO(PWM对应的GPIO使用复用推挽输出模式)

void PWM_Init(void)
{
	double Num;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	//GPIO初始化
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//开启通用定时器TIM2的时钟
	TIM_InternalClockConfig(TIM2);//选择时基单元的时钟(默认使用内部时钟)
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//指定时钟分频,1表示不分频
	//滤波器作用:滤掉信号的抖动干扰
	//滤波器原理:在一个固定的时钟频率f下采样,若连续N个采样点电平一致,表示输入信号稳定,则输出
	//若N个采样点电平不相同,表示信号有抖动,则直接输出低电平或输出上一次的电平
	//采样频率由内部时钟直接来或由内部时钟加时钟分频来
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//计数器模式(向上/向下/中间3个)
	TIM_TimeBaseInitStructure.TIM_Period=100-1;//周期(10K的频率下计1w个数即为1s)(ARR)
	TIM_TimeBaseInitStructure.TIM_Prescaler=6-1;//预分频器(72M对7200分频,得到10K的计数频率)(PSC)
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//重复计数器(高级计数器才有)
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);//初始化结构体
	TIM_OCInitTypeDef TIM_OCInit_InitStructure;
	TIM_OCStructInit(&TIM_OCInit_InitStructure);//给结构体赋初值,以免对高级定时器等造成干扰
	
	TIM_OCInit_InitStructure.TIM_OCMode=TIM_OCMode_PWM1;//设置输出比较的模式
	//TIM_OCMode_Timing        冻结模式            
	//TIM_OCMode_Active        相等时置有效电平        
	//TIM_OCMode_Inactive      相等时置无效电平
	//TIM_OCMode_Toggle        相等时电平翻转      
	//TIM_OCMode_PWM1          PW1模式         
	//TIM_OCMode_PWM2		   PW2模式
	TIM_OCInit_InitStructure.TIM_OCPolarity=TIM_OCPolarity_High;//设置输出比较的极性
	//TIM_OCPolarity_High      极性不翻转,REF有效是高电平,REF有效时输出高电平
	//TIM_OCPolarity_Low  		REF电平取反,有效电平为低电平
	TIM_OCInit_InitStructure.TIM_OutputState=ENABLE;//设置输出使能
	TIM_OCInit_InitStructure.TIM_Pulse=50;//设置CCR
	TIM_OC1Init(TIM2,&TIM_OCInit_InitStructure);
	//初始化输出比较单元
	TIM_Cmd(TIM2,ENABLE);//启动定时器
	}

2.PWM,h

#ifndef __PWM_H
#define __PWM_H

void PWM_Init(void);

#endif

4.PWM简介(Pulse width modulation)

1.定义:PWM,就是脉冲宽度调制,也就是占空比可变的脉冲波形。

2.适用条件:PWM所应用的场景必须为惯性系统,像led,当立即变为低电平时,led并不会瞬间熄灭,而是具有惯性,在短时间内为逐渐熄灭。
3.应用:智能车,机器人等项目。呼吸灯、驱动电机等。

2、频率

频率为Ts的倒数,频率越大,则等效模拟信号越平稳。(即输出的方波整体上较为密集)

3、占空比(Duty Ratio)

1.定义:占空比指在一个脉冲循环内,通电时间相对于总时间所占的比例。(或者说在一个周期中,高电平的时间占整个周期的时间
2.计算:D=Ton/Ts(Ton为一个周期内高电平的时间、Ts为高低电平变换周期的时间)
3.作用:频率一定时,可以通过改变占空比来调节电压
例如高电平为5V,低电平为0V时,占空比为80%时,可以看作为4/5处的电压,即4V。
在这里插入图片描述

4、分辨率

1.定义:是指PWM最小能设定到的高电平时间所占周期的比例,即最小占空比
2.在一个时钟下,若降低频率,则周期变大,分辨率增大。

五、定时器输入捕获的功能

1.概述

六、定时器编码器接口

1.概述

即接收正交信号,自动执行CNT的自增和自减,从而达到

3.Encoder.c和Encoder.h文件

1.Encoder.c

#include "stm32f10x.h"                  // Device header
//1.RCC开启时钟,开启GPIO和定时器时钟
//2.配置GPIO,把其选中的引脚配置成输入模式
//3.配置时基单元,一般选择不分频,自动重装给最大65535,cnt执行计数
//4.配置输入捕获单元,仅对滤波器和极性选择这两个参数有用
//5.配置编码器接口模式(调用函数)
//6.启动定时器
//若选择编码器模式择这个引脚被占用,基本无法执行其他功能
void Encoder_Init(void)
{
	//1.开启时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	//2.GPIO初始化
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	//3.编码器接口就是一个带方向控制的外部时钟,直接驱动计时器
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;		//ARR(满量程计数)
	TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;		//PSC(不分频)
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
	//4.输入捕获单元配置,
	TIM_ICInitTypeDef TIM_ICInitStructure;
	TIM_ICStructInit(&TIM_ICInitStructure);
	//结构体不完整,用函数初始化赋一个初值
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
	TIM_ICInitStructure.TIM_ICFilter = 0xF;//滤波器oxF
	TIM_ICInit(TIM3, &TIM_ICInitStructure);
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
	TIM_ICInitStructure.TIM_ICFilter = 0xF;
	TIM_ICInit(TIM3, &TIM_ICInitStructure);
	//配置编码器接口
	TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
	//参数1TIMX,参数2编码器模式(TI1,TI2,TI12)//TI1计数TI2,计数TI1,TI2都计数
	//参数3,4(IC1与IC2的极性)(Falling通道反向,Rising通道不反向)
	TIM_Cmd(TIM3, ENABLE);
}

int16_t Encoder_Get(void)
{
	return TIM_GetCounter(TIM3);
//	int16_t Temp;
//	Temp = TIM_GetCounter(TIM3);
//	TIM_SetCounter(TIM3, 0);
//	return Temp;
}

2.Encoder.h

#include "stm32f10x.h"
#ifndef __ENCODER_H
#define __ENCODER_H
void Encoder_Init(void);
int16_t Encoder_Get(void);
#endif /* __PWM1_H */

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

c语言15天菜鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值