STM32之定时器


STM32定时器

串口通信在STM32开发中有着非常实用的功能,作为最基础的通信模块和调试模块,学好STM32串口接受和发送有着重要的意义。

本文可以看作是江科大STM32入门教程的学习笔记。


一、定时器基本介绍

  • TIM(Timer)定时器
  • 定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断
  • 16位计数器、预分频器、自动重装寄存器的时基单元,在72MHz计数时钟下可以实现最大59.65s的定时(定时时间最大—>频率最低:65536*65536/72M)
  • 不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能
  • 根据复杂度和应用场景分为了高级定时器、通用定时器、基本定时器三种类型
    在这里插入图片描述
  • 即:高级定时器具有捕获/比较通道和互补输出,通用定时器只有捕获/比较通道,基本定时器没有以上两者。
  • STM32F103C8T6定时器资源:TIM1、TIM2、TIM3、TIM4(只有高级定时器和通用定时器)

基本定时器

在这里插入图片描述

  • 预分频器、计数器、自动重装载寄存器构成了最基本的计数器电路(时基单元)
  • 基本定时器的时钟输入只能选择内部时钟(72MHz)
  • 预分频器:对输入时钟进行预分频(实际分频系数=预分频器值+1)
  • 计数器:对预分频后的计数时钟进行计数(向上计数)
  • 自动重装载寄存器:存入写入目标值,当计数值等于自动重装值,定时时间到,产生定时中断,并清零计数器

通用定时器

  • 位于低速的APB1总线上(APB1)

  • 16 位向上、向下、向上/向下(中心对齐)计数模式,自动装载计数器(TIMx_CNT)。

  • 16 位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数 为 1~65535 之间的任意数值。

  • 4 个独立通道(TIMx_CH1~4),这些通道可以用来作为:
    ① 输入捕获
    ② 输出比较
    ③ PWM 生成(边缘或中间对齐模式)
    ④ 单脉冲模式输出

  • TIMX_ETR引脚的外部时钟(需要配置极性选择、边沿检测和预分频器电路、输入滤波电路);可使用外部信号(TIMx_ETR)控制定时器和定时器互连(可以用 1 个定时器控制另外一个定时器)的同步电路。-----外部时钟模式2

  • TRGI-----外部时钟模式1

  • 如下事件发生时产生中断/DMA(6个独立的IRQ/DMA请求生成器):

    ①更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
    ②触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)
    ③输入捕获
    ④输出比较
    ⑤支持针对定位的增量(正交)编码器和霍尔传感器电路
    ⑥触发输入作为外部时钟或者按周期的电流管理

STM32 的通用定时器可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和 PWM)等。

计数器模式

通用定时器有向上计数、向下计数、向上向下双向计数(中心对齐计数)三种模式。
在这里插入图片描述

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

③向下计数模式:计数器从自动装入的值(TIMx_ARR)开始向下计数到0,然后从自动装入的值重新开始,并产生一个计数器向下溢出事件。

定时中断基本结构

在这里插入图片描述

a.时钟源选择

1.RCC提供的内部时钟
2.ETR引脚提供的外部时钟模式2
3.触发输入作外部时钟,即外部时钟模式1

  • ETR外部时钟
  • ITRx其他定时器
  • TIx捕获通道

4.编码器模式

b.时基单元

1.PSC预分频器
2.CNT计数器
3.ARR自动重装器

c.运行控制

  • 操作控制寄存器

d.中断控制
计时时间到产生更新中断,置中断标志位,再通过中断输出控制到NVIC申请中断。
需要申请中断的位置:

  • 时基单元更新中断
  • 触发信号TRGI
  • 输入捕获匹配中断
  • 输出比较匹配中断

预分频器时序

在这里插入图片描述

  • 计数器计数频率:CK_CNT = CK_PSC / (PSC + 1)
    CK_CNT 是计数器的计数频率,也就是计数器每秒钟计数的次数。
    CK_PSC 是预分频器的输入频率,通常是微控制器的系统时钟频率。
    PSC 是预分频器的值,这个值可以用来降低计数器的计数频率。
  • 预分频器的工作原理是每过 PSC + 1个时钟周期,计数器就计数一次。因此,计数器的计数频率 CK_CNT 就等于预分频器的输入频率 CK_PSC 除以 PSC + 1。
  • 例如,如果系统时钟频率是72MHz,预分频器的值是7199,那么计数器的计数频率就是 72MHz / (7199 + 1) = 10kHz。

计数器时序

在这里插入图片描述

  • 计数器溢出频率:
    CK_CNT_OV = CK_CNT / (ARR + 1) = CK_PSC / (PSC + 1) / (ARR + 1)
    CK_CNT_OV 是定时器的溢出频率,也就是定时器每秒溢出(或更新)的次数。
    CK_CNT 是定时器的计数频率,也就是定时器每秒钟计数的次数。
    ARR 是自动重装载寄存器的值,这个值可以用来设置定时器的溢出时间。
  • 定时器的工作原理是每计数 ARR + 1 次,就产生一次溢出(或更新)。因此,定时器的溢出频率 CK_CNT_OV 就等于定时器的计数频率 CK_CNT 除以 ARR + 1。
  • 例如,如果定时器的计数频率是10kHz,自动重装载寄存器的值是9999,那么定时器的溢出频率就是 10kHz / (9999 + 1) = 1Hz。
  • 计数器溢出时间:
    1 C K _ C N T _ O V \frac{1}{CK\_CNT\_OV} CK_CNT_OV1

二、输出比较

  • OC(Output Compare)输出比较
  • 输出比较可以通过比较CNT与CCR寄存器值的关系,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形
  • 每个高级定时器和通用定时器都拥有4个输出比较通道
  • 高级定时器的前3个通道额外拥有死区生成和互补输出的功能

PWM

  • PWM(Pulse Width Modulation)脉冲宽度调制
  • 在具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量,常应用于电机控速等领域
  • PWM参数:
  • 频率 = 1 / TS
  • 占空比 = TON / TS
  • 分辨率 = 占空比变化步距
    在这里插入图片描述

输出比较通道
在这里插入图片描述

  • CNT与CCR1进行比较,当CNT=CCR1或者CNT>CCR1时,输出模式控制器接收到信号然后改变它输出OC1REF的高低电平。
  • 经过极性选择控制是否反转电平信号,然后通过输出使能电路输出高低电平

输出模式控制器执行逻辑
在这里插入图片描述

  • 输入为CNT和CCR的大小关系,输出是REF的高低电平
  • PWM模式1其实就是PWM模式2输出的取反。

PWM基本结构
在这里插入图片描述
在这里插入图片描述

  • 蓝色线为CNT的值,黄色为ARR的值,CNT从0自增到与设定的ARR值(99)相等时清零,从新开始计数
  • 红色线为CCR,假设设置为30。绿色线为REF

当CNT<CCR时,REF置有效电平(高电平)
当CNT>CCR时,REF置无效电平(低电平)
这里就可以看出占空比是受CCR的值控制的:CCR越接近ARR,占空比越大(此逻辑根据输出模式控制器执行逻辑改变而改变)

  • 参数计算
    PWM频率: Freq = CK_PSC / (PSC + 1) / (ARR + 1)
    PWM占空比: Duty = CCR / (ARR + 1)
    PWM分辨率: Reso = 1 / (ARR + 1)

代码
PWM.c

void PWM_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	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);
	
	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 = 100 - 1;		    //ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1;		//PSC
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
	
	TIM_OCInitTypeDef TIM_OCInitStructure;
	TIM_OCStructInit(&TIM_OCInitStructure);
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_Pulse = 0;		                //CCR
	TIM_OC1Init(TIM2, &TIM_OCInitStructure);
	
	TIM_Cmd(TIM2, ENABLE);
}

1.开启定时器和GPIO时钟
2.GPIO引脚初始化(引脚是与定时器输出计较通道对应的,查手册),例如:TIM2通道1对应PA0引脚。ps:GPIO_Mode要设置成复用推挽输出,因为普通的开漏/推挽输出,引脚的控制权是来自输出数据寄存器的,如果想要定时器来控制引脚,就要使用复用开漏/推挽输出模式
3.配置定时器时钟源为内部时钟72MHz。
4.时基单元初始化:

  定时器时钟分频系数为TIM_CKD_DIV1(不分频)
  定时器计数模式为向上计数
  定时器周期(Period)为100-1(ARR
  预分频值(Prescaler)为720-1(PSC)
  不使用重复计数器

5.输出比较单元初始化

  输出比较模式为PWM1模式
  输出比较通道的极性为高电平
  输出比较通道的状态为启用
  设置了脉冲宽度(Pulse)(CCR),设置为0是为了方便外部修改其值,改变占空比。
  不使用重复计数器

6.使能定时器2

设置占空比:通过设置CCR1的值来改变PWM波的占空比

void PWM_SetCompare1(uint16_t Compare)
{
	TIM_SetCompare1(TIM2, Compare);
}

void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1)
{
  assert_param(IS_TIM_LIST8_PERIPH(TIMx));
  TIMx->CCR1 = Compare1;
}

实验main.c
在main函数中,不断调用PWM_SetCompare1()函数改变PWM的占空比,在PA0口放置一个二极管,就可以看到亮度从暗到亮的呼吸灯效果。

  • 参数计算
    PWM频率: Freq = CK_PSC / (PSC + 1) / (ARR + 1)
            =72M/(719+1)(99+1)
            =1KHz
while (1)
	{
		for (i = 0; i <= 100; i++)
		{
			PWM_SetCompare1(i);
			Delay_ms(10);
		}
		for (i = 0; i <= 100; i++)
		{
			PWM_SetCompare1(100 - i);
			Delay_ms(10);
		}
	}

三、输入捕获

  • IC(Input Capture)输入捕获
  • 输入捕获模式下,当通道输入引脚出现指定电平跳变时,当前CNT的值将被锁存到CCR中,可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数
  • 每个高级定时器和通用定时器都拥有4个输入捕获通道
  • 可配置为PWMI模式,同时测量频率和占空比
  • 可配合主从触发模式,实现硬件全自动测量

对于同一个定时器而言,输入捕获和输出比较只能使用一个

频率测量
在这里插入图片描述

测频法:在闸门时间T内,对上升沿计次,得到N,则频率

                f x f_x fx =N/T

  • 在T时间内对上升沿从0开始计次,每来一个上升沿,计次+1。T时间内总共的周期个数/T时间=单位时间内周期的个数,也就是频率。

测周法:两个上升沿内,以标准频率fc计次,得到N ,则频率

                f x f_x fx = f c f_c fc/N

  • 捕获信号的两个上升沿,持续时间就是周期。使用一个已知标准频率 f c f_c fc的计次时钟,驱动计数器从一个上升沿从0开始计次,到下一个上升沿结束。一个数的时间是1/ f c f_c fc,计N个数,时间就是N/ f c f_c fc,再取倒数就是频率。
  • 测频法适合高频信号;测周法适合低频信号
  • 测频法更新 速度慢;测周法更新速度快

输入捕获通道在这里插入图片描述

  • 信号---->滤波器---->边沿检测器---->TI1FP1

输入捕获基本结构
在这里插入图片描述

  • GPIO输入信号先后经过滤波器和边沿检测,设置为上升沿触发,当TI1FP1出现上升沿后,CNT当前的计数值会转运到CCR1中,然后触发源选择TI1FP1信号,从模式选择Reset复位操作,就可以实现自动清零CNT。在一个周期内,CNT 在标准时钟的驱动下,从0不断自增直到下一个上升沿来临,重复上述操作。至此可以知道CCR1中更新的值就是一个周期的计数值。

PWMI基本结构
在这里插入图片描述

  • 配置第二路信号TI1FP2为下降沿触发,通过交叉通道去触发通道2的捕获单元。最开始上升沿,CCR1捕获,同时清零CNT,之后CNT++,在下降沿的时候,触发CCR2捕获,此时CNT的值就是高电平期间的值,CCR2捕获不触发CNT清零,CNT继续++,到下一个上升沿的时候,CCR1捕获,CNT清零。至此得到CCR1是整个周期的计数值,CCR2是高电平期间的计数值,CCR2/CCR1得到占空比。

代码
IC.c

void IC_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	TIM_InternalClockConfig(TIM3);
	
	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 = 72 - 1;		//PSC
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
	
	TIM_ICInitTypeDef TIM_ICInitStructure;
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
	TIM_ICInitStructure.TIM_ICFilter = 0xF;
	TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
	TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
	TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
	TIM_ICInit(TIM3, &TIM_ICInitStructure);
	
	TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);
	TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
	
	TIM_Cmd(TIM3, ENABLE);
}

1.开启定时器和GPIO 时钟
2.GPIO初始化
3.定时器时钟源选择内部时钟72MHz。
4.定时器初始化
5.初始化输入捕获单元

  • 设置输入捕获通道为通道1(TIM_Channel_1)
  • 设置输入滤波器的值为0xF(0x0~0xF,数值越大滤波效果越好)
  • 设置输入捕获的极性为上升沿(TIM_ICPolarity_Rising)
  • 设置输入捕获预分频值为1(TIM_ICPSC_DIV1)
  • 设置了输入捕获选择模式为直接TI模式

6.设置TIM3定时器的输入触发源为TI1FP1
7.设置TIM3定时器的从模式为重置模式
8.使能定时器

总结

因为入门的时候是跟着江科大的视频学习的,就想着边学边写一个学习笔记,方便字节会过来复习。

内容基本和视频内容一致,个别地方加入了自己的理解。
欢迎指正。

  • 32
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值