一、通用定时器
通用定时器是在基本定时器的基础上引入了外部引脚,拥有基本定时器全部功能,并额外具有内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等功能。STM32F1系列有TIM2,TIM3,TIM4,TIM5等4个通用定时器,通用定时器都是挂载在APB1总线上。
二、通用定时器结构框图
2.1时钟源
通用定时器有4个时钟源选择:
内部时钟源 CK_INT
内部时钟 CK_INT 即来自于芯片内部,等于 72M,一般情况下,我们都是使用内部时钟。当从模式控制寄存器 TIMx_SMCR 的 SMS 位等于 000 时,则使用内部时钟。
外部时钟模式 1:外部输入引脚 TIx(x=1,2,3,4)
1:当使用外部时钟模式 1 的时候,时钟信号来自于定时器的输入通道,总共有 4 个,分别为 TI1/2/3/4,即 TIMx_CH1/2/3/4。具体使用哪一路信号,由 TIM_CCMRx 的位 CCxS[1:0] 配置,其中 CCMR1控制 TI1/2, CCMR2 控制 TI3/4。
2:滤波器
如果来自外部的时钟信号的频率过高或者混杂有高频干扰信号的话,我们就需要使用滤波器对
信号重新采样,来达到降频或者去除高频干扰的目的,具体的由 TIMx_CCMRx 的位 ICxF[3:0] 配
置。
3:边沿检测
边沿检测的信号来自于滤波器的输出,在成为触发信号之前,需要进行边沿检测,决定是上升沿
有效还是下降沿有效,具体的由 TIMx_CCER 的位 CCxP 和 CCxNP 配置。
4:触发选择
当使用外部时钟模式 1 时,触发源有两个,一个是滤波后的定时器输入 1(TI1FP1)和滤波后的
定时器输入 2(TI2FP2),具体的由 TIMxSMCR 的位 TS[2:0] 配置。
5:从模式选择
选定了触发源信号后,最后我们需把信号连接到 TRGI 引脚,让触发信号成为外部时钟模式 1 的
输入,最终等于 CK_PSC,然后驱动计数器 CNT 计数。具体的配置 TIMx_SMCR 的位 SMS[2:0]
为 000 即可选择外部时钟模式 1。
6:使能计数器
经过上面的 5 个步骤之后,最后我们只需使能计数器开始计数,外部时钟模式 1 的配置就算完
成。使能计数器由 TIMx_CR1 的位 CEN 配置。
外部时钟模式 2:外部触发输入 ETR
1:时钟信号输入引脚
当使用外部时钟模式 2 的时候,时钟信号来自于定时器的特定输入通道 TIMx_ETR,只有 1 个。
2:外部触发极性
来自 ETR 引脚输入的信号可以选择为上升沿或者下降沿有效,具体的由 TIMx_SMCR 的位 ETP
配置。
3:外部触发预分频器
由于 ETRP 的信号的频率不能超过 TIMx_CLK(72M)的 1/4,当触发信号的频率很高的情况下,
就必须使用分频器来降频,具体的由 TIMx_SMCR 的位 ETPS[1:0] 配置。
4:滤波器
如果 ETRP 的信号的频率过高或者混杂有高频干扰信号的话,我们就需要使用滤波器对 ETRP 信
号重新采样,来达到降频或者去除高频干扰的目的。具体的由 TIMx_SMCR 的位 ETF[3:0] 配置,
其中的 fDTS 是由内部时钟 CK_INT 分频得到,具体的由 TIMx_CR1 的位 CKD[1:0] 配置。
5:从模式选择
经过滤波器滤波的信号连接到 ETRF 引脚后,触发信号成为外部时钟模式 2 的输入,最终等于
CK_PSC,然后驱动计数器 CNT 计数。具体的配置 TIMx_SMCR 的位 ECE 为 1 即可选择外部时
钟模式 2。
6:使能计数器
经过上面的 5 个步骤之后,最后我们只需使能计数器开始计数,外部时钟模式 2 的配置就算完
成。使能计数器由 TIMx_CR1 的位 CEN 配置。
内部触发输入 (ITRx)
内部触发输入是使用一个定时器作为另一个定时器的预分频器。硬件上高级控制定时器和通用
定时器在内部连接在一起,可以实现定时器同步或级联。主模式的定时器可以对从模式定时器执
行复位、启动、停止或提供时钟。
2.2 控制器
定时器控制器部分包括触发控制器、从模式控制器以及编码器接口。触发控制器用来针
对片内外设输出触发信号,比如为其它定时器提供时钟和触发 DAC/ADC 转换。
编码器接口专门针对编码器计数而设计。从模式控制器可以控制计数器复位、启动、递增/递减、
计数
2.3 时基单元
通用定时器时基单元功能包括3个16位的寄存器,分别是计数器寄存器 (CNT)、预分频器寄存器
(PSC)、自动重载寄存器 (ARR) 和重复计数器寄存器 (RCR)。
2.4 预分频器
预分频器 PSC,有一个输入时钟 CK_PSC 和一个输出时钟 CK_CNT。输入时钟 CK_PSC 就是上
面时钟源的输出,输出 CK_CNT 则用来驱动计数器 CNT 计数。通过设置预分频器 PSC 的值可以
得到不同的 CK_CNT,实际计算为: fCK_CNT 等于 fCK_PSC/(PSC[15:0]+1),可以实现 1 至 65536 分频
2.5 计数器
通用定时器拥有3种计数模式,分别是向上计数模式,向下计数模式,中央对齐模式。
(1) 递增计数模式下,计数器从 0 开始计数,每来一个 CK_CNT 脉冲计数器就增加 1,直到计数器
的值与自动重载寄存器 ARR 值相等,然后计数器又从 0 开始计数并生成计数器上溢事件,计数
器总是如此循环计数。如果禁用重复计数器,在计数器生成上溢事件就马上生成更新事件 (UEV);
如果使能重复计数器,每生成一次上溢事件重复计数器内容就减 1,直到重复计数器内容为 0 时
才会生成更新事件。
(2) 递减计数模式下,计数器从自动重载寄存器 ARR 值开始计数,每来一个 CK_CNT 脉冲计数
器就减 1,直到计数器值为 0,然后计数器又从自动重载寄存器 ARR 值开始递减计数并生成计数
器下溢事件,计数器总是如此循环计数。如果禁用重复计数器,在计数器生成下溢事件就马上生
成更新事件;如果使能重复计数器,每生成一次下溢事件重复计数器内容就减 1,直到重复计数
器内容为 0 时才会生成更新事件。
(3) 中心对齐模式下,计数器从 0 开始递增计数,直到计数值等于 (ARR-1) 值生成计数器上溢事
件,然后从 ARR 值开始递减计数直到 1 生成计数器下溢事件。然后又从 0 开始计数,如此循环。
每次发生计数器上溢和下溢事件都会生成更新事件。
2.6 自动重载寄存器
自动重载寄存器 ARR 用来存放与计数器 CNT 比较的值,如果两个值相等就递减重复计数器。可
以通过 TIMx_CR1 寄存器的 ARPE 位控制自动重载影子寄存器功能,如果 ARPE 位置 1,自动重
载影子寄存器有效,只有在事件更新时才把 TIMx_ARR 值赋给影子寄存器。如果 ARPE 位为 0,
则修改 TIMx_ARR 值马上有效。
三、输出比较
输出比较可以通过比较CNT与CCR寄存器值的关系,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形。每个通用定时器都拥有4个输出比较通道。
3.1PWM 简介
PWM又叫做脉冲宽度调制,在具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量,常应用于电机控速等领域。
占空比是在一个周期高电平时间占用整个周期的百分比
PWM参数 计算公式
频率=1/周期 Freq = CK_PSC / (PSC + 1) / (ARR + 1)
占空比=一个周期高电平时间/整个周期 Duty = CCR / (ARR + 1)
分辨率=占空比变化步距 Reso = 1 / (ARR + 1)
例如要产生1Khz的频率,占空比为50%,分辨率为1%的PWM波形
PSC =720 72000000/(PSC+1)(ARR+1)=1000
ARR =100 CCR/(ARR+1)=50%
CCR =50 1/(ARR+1)=1%
3.2 输出比较模式
一般默认使用PWM模式1。也就是在计数器向上计数过程中小于CCR设定值时,输出比较输出的电平状态是高电平,一旦计数器计数值大于CCR设定值时,输出比较输出的电平状态是低电平。
3.3 输出PWM案例-LED灯闪烁
3.3.1 PWM.H
#ifndef __PWM_H
#define __PWM_H
void PWM_Init(void);
void Set_Tim_CCR(uint16_t ccr);
#endif
3.3.2 PWM.C
#include "stm32f10x.h" // Device header
void PWM_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//引脚重映射配置《《《-------------------------------
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
GPIO_PinRemapConfig(GPIO_FullRemap_TIM2,ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
//引脚重映射配置-------------------------------》》》
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_15;
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;
TIM_TimeBaseInitStructure.TIM_Prescaler=720-1;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;//指定输出比较的模式
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;//选择输出极性
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//指定TIM输出比较状态
TIM_OCInitStructure.TIM_Pulse=0;
TIM_OC1Init(TIM2,&TIM_OCInitStructure);
TIM_Cmd(TIM2,ENABLE);
}
void Set_Tim_CCR(uint16_t ccr)
{
TIM_SetCompare1(TIM2,ccr);
}
3.3.3 Mian.C
#include "stm32f10x.h" // Device header
#include "delay.h"
#include "OLED.H"
#include "PWM.H"
uint16_t num;
int main(void)
{
OLED_Init();
PWM_Init();
while(1)
{
for(num=0;num<100;num++)
{
Set_Tim_CCR(num);
Delay_ms(10);
}
for(num=0;num<100;num++)
{
Set_Tim_CCR(100-num);
Delay_ms(10);
}
}
}