STN32定时器配置

目录

一、TIM定时器

1、定时器类型

2、定时中断

1、外部时钟配置

2、时基单元选择

计数器寄存器(CNT) 

 预分频器(PSC)

自动装载寄存器(ARR)

3、中断输出控制

4、NVIC配置

5、运行控制配置

3、常用库函数

4、整体定时器中断实现步骤

二、定时器PWM输出

1、PWM简介

OC(Output Compare)输出比较

2、PWM基本结构

3、PWM参数计算

4、定时器PWM库函数配置

5、整体定时器PWM配置步骤

6、实例


一、TIM定时器

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

1、定时器类型

2、定时中断

那如果配置定时器中断如何配置相关寄存器呢?

相关配置如图所示:1、选择外部时钟配置  

                                2、时基单元选择

                                3、中断输出控制

                                4、NVIC配置

                                5、运行控制配置

1、外部时钟配置

外部时钟源选择可以用以下函数:

void TIM_InternalClockConfig(TIM_TypeDef* TIMx);

void TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);

void TIM_TIxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_TIxExternalCLKSource,uint16_t TIM_ICPolarity, uint16_t ICFilter);

void TIM_ETRClockMode1Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,uint16_t ExtTRGFilter);

void TIM_ETRClockMode2Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler,uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter);

void TIM_ETRConfig(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,

2、时基单元选择

时基单元可以用TimeBaseInit函数

void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);

 结构体内部成员:

typedef struct
{
  uint16_t TIM_Prescaler;        
  uint16_t TIM_CounterMode;     
  uint16_t TIM_Period;        
  uint16_t TIM_ClockDivision;  
  uint8_t TIM_RepetitionCounter;
} TIM_TimeBaseInitTypeDef; 

声明方式(一般):

TIM_TimeBaseStructure.TIM_Period = 4999;//Period即定时器周期,即ARR自动重装器值
TIM_TimeBaseStructure.TIM_Prescaler =7199;//Prescaler即PSC预分频值
TIM_TimeBaseStructure.TIM_ClockDivision =   TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode =   TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//重复计数器,高级定时器才用到 
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); 

时基单元就是定时器框图 组成部分之一。它包括三个寄存器,分别是:计数器寄存器(TIMx_CNT)、预分频器寄存器(TIMx_PSC)和自动装载寄存器(TIMx_ARR)。


计数器寄存器(CNT) 

其计数模式分为向上计数、向下计数或者中心对齐计数;

可将时钟频率按1到65535之间的任意值进行分频,可在运行时改变其设置值;

相关函数:

void TIM_CounterModeConfig(TIM_TypeDef* TIMx, uint16_t TIM_CounterMode);   
 预分频器(PSC)

预分频器的作用是对定时器的输入时钟信号进行分频,以降低定时器计数器的计数速率。简单来说,它就像是一个缩小器,能够将高速的时钟信号缩减成定时器能够使用的更低频率的信号。

相关函数:

void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode);

函数中的Prescaler指:预分频值            TIM_PSCReloadMode:写入的模式

自动装载寄存器(ARR)

如果TIMx_CR1寄存器中的ARPE位为0,ARR寄存器的内容将直接写入影子寄存器;如果ARPE为1,ARR寄存器的那日同将在每次的更新时间UEV发生时,传送到影子寄存器;

如果TIM1_CR1中的UDIS位为0,当计数器产生溢出条件时,产生更新事件。

相关函数:

void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);

3、中断输出控制

中断输出控制可以用ITConfig函数

void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);

4、NVIC配置

NVIC配置需要用NVIC_Init函数     

5、运行控制配置

运行控制配置需要用到TIM_Cmd函数

void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState); 

3、常用库函数

状态标志位获取和清除

uint16_t TIM_GetCounter(TIM_TypeDef* TIMx);

uint16_t TIM_GetPrescaler(TIM_TypeDef* TIMx);

FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);

void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);

ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);

void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);

4、整体定时器中断实现步骤

①使能定时器时钟。
       RCC_APB1PeriphClockCmd();

②  初始化定时器,配置ARR,PSC。

      TIM_TimeBaseInit();

③开启定时器中断,配置NVIC。
      void TIM_ITConfig();

      NVIC_Init();

④  使能定时器。

      TIM_Cmd();

⑥  编写中断服务函数。

      TIMx_IRQHandler();

 应用案例

#include "stm32f10x.h"                  

void Timer_Init(void)
{
	/*开启时钟*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);			//开启TIM2的时钟
	
	/*配置时钟源*/
	TIM_InternalClockConfig(TIM2);		//选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟
	
	/*时基单元初始化*/
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				//定义结构体变量
	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;			//重复计数器,高级定时器才会用到
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);				//将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元	
	
	/*中断输出配置*/
	TIM_ClearFlag(TIM2, TIM_FLAG_Update);						//清除定时器更新标志位
																//TIM_TimeBaseInit函数末尾,手动产生了更新事件
																//若不清除此标志位,则开启中断后,会立刻进入一次中断
																//如果不介意此问题,则不清除此标志位也可
	
	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);					//开启TIM2的更新中断
	
	/*NVIC中断分组*/
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);				//配置NVIC为分组2
																//即抢占优先级范围:0~3,响应优先级范围:0~3
																//此分组配置在整个工程中仅需调用一次
																//若有多个中断,可以把此代码放在main函数内,while循环之前
																//若调用多次配置分组的代码,则后执行的配置会覆盖先执行的配置
	
	/*NVIC配置*/
	NVIC_InitTypeDef NVIC_InitStructure;						//定义结构体变量
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;				//选择配置NVIC的TIM2线
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//指定NVIC线路使能
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;	//指定NVIC线路的抢占优先级为2
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;			//指定NVIC线路的响应优先级为1
	NVIC_Init(&NVIC_InitStructure);								//将结构体变量交给NVIC_Init,配置NVIC外设
	
	/*TIM使能*/
	TIM_Cmd(TIM2, ENABLE);			//使能TIM2,定时器开始运行
}
void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{
		
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}

               

二、定时器PWM输出

1、PWM简介

  • PWMPulse Width Modulation)脉冲宽度调制
  • 在具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量,通俗的讲就是等效地实现一个模拟信号的输出,常应用于电机控速等领域
  • PWM参数:
  •  频率 = 1 / TS                       频率越快,等效模拟信号就越平稳   
  • 占空比 = TON / TS             TON:高电平时间      TS:一个周期时间 
  • 分辨率 = 占空比变化步距

OC(Output Compare)输出比较

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

定时器的输出比较模块是怎么样输出PWM波形的?

如图所示:左边为CNT计数器CCR1第一路的捕获/比较寄存器当CNT>=CCR1的时候,就会给输出控制模拟信号传一个信号,然后输出模拟器就会改变oc1ref的高电平,oc1ref在这就是指信号的高低电平,ref指的是reference的缩写,指参考信号,ref第一路可前往指至主模式控制器,可以把ref映射到主模式的TRGO输出上去,第二路前往OC1P进行极限选择。

输出模式选择如下图所示:

有效电平可了解为:高电平                           无效电平可了解为:低电平 

相关函数:  

void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);

2、PWM基本结构

PWM基本结构如图所示:

图中蓝色线:CNT      黄色线:ARR      红色线:CCR       绿色线:输出

如图所示:蓝色线从0开始自增到ARR,也就是99后清零继续自增, 红色线设置为30,最开始时CNT<CCR,所以置高电平,当30<=CNT<99,置低电平,溢出清零后重新循坏开始。CCR设置得高一些,输出的占空比就变大,低则变小。 

图中的REF指的是频率可调,占空比可调的PWM波形 

3、PWM参数计算

PWM频率:  Freq = CK_PSC / (PSC + 1) / (ARR + 1)

PWM占空比:  Duty = CCR / (ARR + 1)

PWM分辨率(占空比变化的步距):  Reso = 1 / (ARR + 1)           

4、定时器PWM库函数配置

输出库函数配置

void TIM_OCxInit(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);

其结构体成员如下:

typedef struct
{
  uint16_t TIM_OCMode;  //PWM模式1或者模式2
  uint16_t TIM_OutputState; //输出使能 OR失能
  uint16_t TIM_OutputNState;
  uint16_t TIM_Pulse; //比较值,写CCRx
  uint16_t TIM_OCPolarity; //比较输出极性
  uint16_t TIM_OCNPolarity; 
  uint16_t TIM_OCIdleState;  
  uint16_t TIM_OCNIdleState; 
} TIM_OCInitTypeDef;

初始化实例:

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//输出比较模式,选择PWM模式1

TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//输出极性,选择为高,若选择极性为低,则输出高低电平取反

TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//输出使能

TIM_OCInitStructure.TIM_Pulse = 0;//初始的CCR值

TIM_OC2Init(TIM2, &TIM_OCInitStructure);//将结构体变量交给TIM_OC2Init,配置TIM2的输出比较通道2
  • 输出比较单元配置:
void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);

  • 单独更改CCR函数
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);
void TIM_SetCompare2(TIM_TypeDef* TIMx, uint16_t Compare2);
void TIM_SetCompare3(TIM_TypeDef* TIMx, uint16_t Compare3);
void TIM_SetCompare4(TIM_TypeDef* TIMx, uint16_t Compare4);
  • 单独更改输出极性:
void TIM_OC1PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
void TIM_OC1NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);
void TIM_OC2PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
void TIM_OC2NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);
void TIM_OC3PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
void TIM_OC3NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);
void TIM_OC4PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
  • 高级定时器需要额外使用函数:
void TIM_CtrlPWMOutputs(TIM_TypeDef* TIMx, FunctionalState NewState);

5、整体定时器PWM配置步骤

①开启TIM2的时钟和开启GPIOA的时钟

RCC_APB1PeriphClockCmd(); //通用定时器TIM2连接在APB1总线上

RCC_APB2PeriphClockCmd();

②初始化IO口为复用推挽输出

GPIO_Init();

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//选择推挽输出的原因是定时器需要来控制引脚

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;        

③当选用PA15用作定时器的PWM输出引脚,需用重映射配置,故要开启AFIO时钟,同时设置重映射,而PA15又作为调试端口,故将JTAG引脚失能才可。

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); 

GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE); 

GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); //若不是调试端口,此条不用写
 ④初始化定时器:ARR,PSC等TIM_TimeBaseInit();  

⑤初始化输出比较参数:TIM_OC1Init();

⑥使能定时器:TIM_Cmd();

⑦改变比较值CCRx,达到不同的占空比效果:TIM_SetCompare1();

6、实例

改变PWM输出占空比来改变LED的亮度,间接实现呼吸灯的现象

//PWM.c源文件
#include "stm32f10x.h" 

void PWM_Init(void)
{
	/*开启时钟*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);			//开启TIM2的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);			//开启GPIOA的时钟
	
	/*GPIO重映射*/
//	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);//开启AFIO的时钟,重映射必须先开启AFIO的时钟

//	GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);			//将TIM2的引脚部分重映射,具体的映射方案需查看参考手册

//	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);		//将JTAG引脚失能,作为普通GPIO引脚使用
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;		//GPIO_Pin_15;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);							//将PA0引脚初始化为复用推挽输出	
																	//受外设控制的引脚,均需要配置为复用模式		
	
	/*配置时钟源*/
	TIM_InternalClockConfig(TIM2);		//选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟
	
	/*时基单元初始化*/
	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_TimeBaseInit,配置TIM2的时基单元
	
	/*输出比较初始化*/
	TIM_OCInitTypeDef TIM_OCInitStructure;							//定义结构体变量
	TIM_OCStructInit(&TIM_OCInitStructure);							//结构体初始化,若结构体没有完整赋值
																	//则最好执行此函数,给结构体所有成员都赋一个默认值
																	//避免结构体初值不确定的问题
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;				//输出比较模式,选择PWM模式1
	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_OC1Init,配置TIM2的输出比较通道1
	
	/*TIM使能*/
	TIM_Cmd(TIM2, ENABLE);			//使能TIM2,定时器开始运行
}

/**
  * 函    数:PWM设置CCR
  * 参    数:Compare 要写入的CCR的值,范围:0~100
  * 返 回 值:无
  * 注意事项:CCR和ARR共同决定占空比,此函数仅设置CCR的值,并不直接是占空比
  *           占空比Duty = CCR / (ARR + 1)
  */
void PWM_SetCompare1(uint16_t Compare)
{
	TIM_SetCompare1(TIM2, Compare);		//设置CCR1的值
}
//PWM.h头文件
#ifndef __PWM_H
#define __PWM_H

void PWM_Init(void);
void PWM_SetCompare1(uint16_t Compare);

#endif
//main.c源文件
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"

uint8_t i;			//定义for循环的变量

int main(void)
{
	/*模块初始化*/
	OLED_Init();		//OLED初始化
	PWM_Init();			//PWM初始化
	
	while (1)
	{
		for (i = 0; i <= 100; i++)
		{
			PWM_SetCompare1(i);			//依次将定时器的CCR寄存器设置为0~100,PWM占空比逐渐增大,LED逐渐变亮
			Delay_ms(10);				//延时10ms
		}
		for (i = 0; i <= 100; i++)
		{
			PWM_SetCompare1(100 - i);	//依次将定时器的CCR寄存器设置为100~0,PWM占空比逐渐减小,LED逐渐变暗
			Delay_ms(10);				//延时10ms
		}
	}
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值