stm32(十二)通用定时器&输出PWM

1、STM32F407ZGT6的通用定时器&PWM输出简介

STM32F407ZGT6有高级定时器、通用用定时器、基本定时器,不管什么类型的定时器都有定时的功能,不管什么类型的定时器都有时基单元。通用定时有TIM2~TIM5,TIM9~TIM14。

通用定时器和基本定时器的最主要的区别是:是否有“捕获/比较通道”(capture/compare channels)。

“捕获/比较通道”顾名思义,可以是“输入捕获功能”,可以是“输出比较功能”,“捕获/比较通道”的功能只能是“捕获”或者“比较”两者一种。

2、PWM简介

占空比:IO口的输出脉冲的高电平时间宽度占整个脉冲周期的百分比。PWM的主要作用是调节占空比。

常见:手机背光调节、呼吸灯、手机马达震动强度调节。

3、STM32F407ZGT6的通用定时器TIM10/TIM11 和TIM13/TIM14的框图讲解

 

通用定时器TIM10/TIM11 和TIM13/TIM14 的时基单元和基本定时器一致,本章节主要分析“比较输出”功能,屏蔽掉了“捕获输入”部分的框图。

“捕获比较寄存器”也有“缓冲”。

PWM占空比调节就是属于“比较输出”中的一个功能,该功能的工作原理如下:

  • 提示:“捕获/比较寄存器1”对应下图的CCR1(capture/compare register 1),该寄存器是16位的。
  • CNT在时钟节拍的基础下进行自增,CNT的值小于CCR1的值时,输出一个“电平”。
  • CNT在时钟节拍的基础下进行自增,CNT的值大于等于CCR1的值时,输出一个“电平”。
  • CNT的值计数到ARR的值时,则溢出,从0开始从新计数自增。

总结1:“比较输出”就是CNT寄存器不断的和CCR1进行比较,同时和ARR进行比较,根据比较的结果,输出“相应的电平”。

总结2:通过调节ARR的值可以调节输出脉冲的脉冲周期

总结3:通过调节CCR1的值可以调节占空比

4、通用定时器TIM10/TIM11 和TIM13/TIM14的寄存器

通用定时器TIM10/TIM11 和TIM13/TIM14的CR1、CNT、PSC、ARR寄存器和基本定时器6/7的一样。

4.1、TIM10/11/13/14 状态寄存器 (TIMx_SR)

位 1 CC1IF   捕获/比较 1 中断标志 (Capture/compare 1 interrupt flag)

如果通道 CC1 配置为输出:
当计数器寄存器的值与捕获/比较寄存器的值匹配时,此标志由硬件置 1。但需要通过软件清零。
0:不匹配。
1: TIMx_CNT 计数器的值与 TIMx_CCR1 寄存器的值匹配。当 TIMx_CCR1 的值大于 TIMx_ARR的值时, CC1IF 位将在计数器发生上溢时变为高电平。

位 0 UIF  更新中断标志 (Update interrupt flag)

该位有硬件置1,软件清零。

0:未发生更新(即:定时时间还没到)。
1:更新中断挂起,由以下两种因素导致该位硬件置1:

①定时器计数器上溢会导致该位置1(即该位置1表示定时时间到达)

②UG位置1也会导致该位置1(前提:TIMx_CR1 寄存器中 URS = 0 且 UDIS = 0)

总结:导致产生更新中断标志位置1并且产生更新中断的因素有两个。

定时器10的捕获比较中断函数

void TIM1_UP_TIM10_IRQHandler(void)
{
  if(TIM10->SR&(1<<1))
  {
    TIM10->SR&=~(1<<1);
  }
}

 4.2、TIM10/11/13/14 事件生成寄存器 (TIMx_EGR)

 

 

位 1 CC1G 捕获/比较 1 生成 (Capture/compare 1 generation)

此位由软件置 1 以生成事件,并由硬件自动清零。
0:不执行任何操作。
1:捕获比较通道 1 上生成捕获/比较事件:
如果通道 CC1 配置为输出:
使能捕获/比较 1 中断 , CC1IF 标志置 1 并发送相应的中断。

位 0 UG 更新生成 (Update generation)

该位可通过软件置 1,并由硬件自动清零。

0:不执行任何操作。

1:重新初始化定时器计数器(TIMx_CNT)并生成寄存器更新事件。

4.3、TIM10/11/13/14 捕获/比较模式寄存器 1 (TIMx_CCMR1)

位 6:4 OC1M  输出比较 1 模式 (Output compare 1 mode) 

110: PWM 模式 1,只要 TIMx_CNT < TIMx_CCR1,通道 1 便为有效状态,否则为无效状态。
111: PWM 模式 2,只要 TIMx_CNT < TIMx_CCR1,通道 1 便为无效状态,否则为有效状态。

位 3 OC1PE  输出比较 1 预装载使能 (Output compare 1 preload enable)

0:CCR1的影子寄存器无效

1:CCR1的影子寄存器有效

位 2 OC1FE 输出比较 1 快速使能 (Output compare 1 fast enable) 一般置1

位 1:0 CC1S  捕获/比较 1 选择 (Capture/Compare 1 selection) 

00: CC1 通道配置为输出。
01: CC1 通道配置为输入, IC1 映射到 TI1 上。

举例:定时器10捕获比较通道1的输出比较模式为PWM模式1,CCR1的影子寄存器有效,CC1配置为输出

TIM10->CCMR1 &= ~(3<<0);
TIM10->CCMR1 |= 1<<1;
TIM10->CCMR1 |= 1<<2;
TIM10->CCMR1 |= 6<<4;

4.4、TIM10/11/13/14 捕获/比较使能寄存器 (TIMx_CCER)

位 1 CC1P  CC1 通道配置为输出:

0: OC1 高电平有效
1: OC1 低电平有效

位 0 CC1E  捕获/比较 1 输出使能 (Capture/Compare 1 output enable)。

CC1 通道配置为输出:
0:关闭——OC1 未激活
1:开启——在相应输出引脚上输出 OC1 信号

举例:定时器10有效电平为低电平,开启OC1输出(开启PWM输出)

TIM10->CCER |= 1<<1;

TIM10->CCER |= 1<<0;

4.5、TIM10/11/13/14 捕获/比较寄存器 1 (TIMx_CCR1)

写入该寄存器的值,主要和TIMx_CNT的值进行比较,如果匹配,则输出相应的电平。

4.6、中断使能寄存器 (TIMx_DIER)

位 1 CC1IE  捕获/比较 1 中断使能 (Capture/Compare 1 interrupt enable)

0:禁止 CC1 中断。
1:使能 CC1 中断。

位 0 UIE  更新中断使能 (Update interrupt enable)

0:禁止更新中断。
1:使能更新中断。所谓的“更新中断”可以理解为“定时器中断”。

5、TIM10/11/13/14中断函数与中断通道

该表格主要查阅startup_stm32f40_41xxx.s 和 stm32f4xx.h/

6、​​​​​​​​​​​​​​PWM输出与GPIO的复用功能的关系

PWM输出是属于GPIO复用功能的一种,GPIO口有很多的复用功能,具体请参考STM32F407ZGT6.pdf】的P56。

7、PWM输出的配置步骤

  • 使能相应的GPIO口的时钟
  • 配置相应的GPIO口为复用功能推挽输出
  • 选择复用功能
  • 使能定时器的相应时钟,即RCC->APB1ENR的相应位置1
  • TIMx_ARR 寄存器进行缓冲
  • 计数器在发生更新事件时不会停止计数(循环计数,循环定时)
  • 使能更新 (UEV)
  • UG位置1重新初始化定时器计数器(TIMx_CNT)
  • 状态寄存器清零
  • 配置预分频值 
  • 配置自动重装载值 (用于控制脉冲的周期)
  • CCMR1配置为PWM的模式
  • CCR1影子寄存器有效
  • CC1 通道配置为输出。
  • 配置OC1 有效电平
  • 捕获/比较 1 中断使能
  • 使能定时器中断中断通道,调用NVIC_EnableIRQ函数,如果要调整抢占和响应的优先级,请参考第五章的内容。
  • 捕获/比较 1 输出使能
  • 使能定时器

改变CCR1的值可以改变占空比

8、软件设计

PWM输出驱动PF6,实现LED1以呼吸灯的效果闪烁

寄存器版

 

#include "stm32f4xx.h"

void TIM10_CH1Init(u16 psc,u16 arr)
{
	RCC->APB2ENR |= 1<<17;//使能定时器10的时钟(168MHZ)
	RCC->AHB1ENR   |= 1<<5; //使能GPIOF口时钟
	
	//设置GPIOF6模式为:复用功能模式
	GPIOF->MODER &=~(3<<12);  //清零 
	GPIOF->MODER |= 2<<12; 
	//将GPIOF6选择为AF3复用功能3→TIM10_CH1
	GPIOF->AFR[0] &=~(0xF<<24); //清零
	GPIOF->AFR[0] |= 3<<24;
	
	TIM10->CR1 |= 1<<7;//使用TIM10_ARR 寄存器的“影子寄存器”。
	TIM10->CR1 &=~(1<<3);//选择为循环定时模式
	TIM10->CR1 &=~(1<<2);//选择更新请求源:计数器上溢、UG 位置 1都可以生成更新事件。
	TIM10->CR1 &=~(1<<1);//允许产生更新事件
	TIM10->PSC = psc - 1;//设置预分频值
	TIM10->ARR = arr;//设置重装载值
	TIM10->CCMR1 &=~(7<<4); //清零
	TIM10->CCMR1 |= 6<<4;//选择PWM的模式:模式1
	TIM10->CCMR1 |= 1<<3;//使用CCR1寄存器的影子寄存器
	TIM10->CCMR1 &=~(3<<0);//通道1配置为输出
	TIM10->CCER |= 1<<1;//选择有效电平为低电平
	TIM10->CCR1 = 500;//设置CCR1的值。
	TIM10->EGR |= 1<<0;//UG 位置 1,主动生成更新事件,初始化计数器和影子寄存器。
	TIM10->SR = 0;//状态寄存器清零。
	TIM10->DIER |= 1<<1; //使能捕获/比较中断
	NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn);//使能中断通道
	TIM10->CCER |= 1<<0;//开启PWM输出
	TIM10->CR1 |= 1<<0;//使能计数器
}
void TIM1_UP_TIM10_IRQHandler(void)
{

	u16  compareValue = 0; //比较值
	static u8  compareFlag = 1;   //标志位,1:CCR1变大,0:CCR1变小
	if(TIM10->SR &(1<<1))  //判断CNT 计数器的值与 CCR1 寄存器的值是否匹配,即是否相等
	{
		TIM10->SR &=~(1<<1);//清零
		compareValue = TIM10->CCR1;
		if(1 == compareFlag )
		{
			if(compareValue <= 900)  
			{
				compareValue = compareValue +3;
				TIM10->CCR1 = compareValue;
			}
			else
			{
				compareFlag =0;
			}
		}
		if(0 == compareFlag )
		{
			if(compareValue >=50)
			{
				compareValue = compareValue -3;
				TIM10->CCR1 = compareValue;
			}
			else
			{
				compareFlag =1;
			}
		}
	}
}
int main(void)
{
  //实现输出PWM驱动LED1灯:PWM周期为1ms,初始状态高电平和低电平各0.5ms。
	//TIM10:168MHZ
	TIM10_CH1Init(1680,1000);
	while(1)
	{
	}
}

库函数版

#include "stm32f4xx.h"

void TIM10_CH1Init(u16 psc,u16 arr)
{

	GPIO_InitTypeDef GPIO_InitTypeDeS;
	TIM_TimeBaseInitTypeDef TIM10_TimeBaseInitTypeDef;
	TIM_OCInitTypeDef PWM_OCInitTypeDef;
	/*结构体定义*/
	NVIC_InitTypeDef NVIC_InitStructure;
	//	/*时钟初始化*/
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE); //GPIO 时钟初始化
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM10,ENABLE); //TIM 时钟初始化
	/*GPIO 口模式配置*/
	GPIO_InitTypeDeS.GPIO_Mode =GPIO_Mode_AF; //复用功能
	GPIO_InitTypeDeS.GPIO_Pin =GPIO_Pin_6; //配置 GPIOF9
	GPIO_Init(GPIOF,&GPIO_InitTypeDeS);
	GPIO_PinAFConfig(GPIOF,GPIO_PinSource6,GPIO_AF_TIM10); //复用
	
	//定时器模式配置
	TIM10_TimeBaseInitTypeDef.TIM_ClockDivision=TIM_CKD_DIV1; // 时钟分频
	TIM10_TimeBaseInitTypeDef.TIM_Period =arr;
	TIM10_TimeBaseInitTypeDef.TIM_CounterMode=TIM_CounterMode_Up; //计数模式为向上计数
	TIM10_TimeBaseInitTypeDef.TIM_Prescaler=psc-1;
	TIM_TimeBaseInit(TIM10,&TIM10_TimeBaseInitTypeDef);
	//PWM 模式配置
	PWM_OCInitTypeDef.TIM_OCMode=TIM_OCMode_PWM1; //PWM2 模式
	PWM_OCInitTypeDef.TIM_OutputState= TIM_OutputState_Enable; //使能比较输出
	PWM_OCInitTypeDef.TIM_OCPolarity =TIM_OCPolarity_Low; //低电平有效电平
	PWM_OCInitTypeDef.TIM_Pulse = 500;
	TIM_OC1Init(TIM10,&PWM_OCInitTypeDef);

	TIM_ITConfig(TIM10,TIM_IT_CC1,ENABLE); //③允许定时器10 更新中断
	TIM_OC1PreloadConfig(TIM10,TIM_OCPreload_Enable);
	TIM_ARRPreloadConfig(TIM10,ENABLE);
	
	NVIC_InitStructure.NVIC_IRQChannel=TIM1_UP_TIM10_IRQn; //定时器10中断
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_Init(&NVIC_InitStructure);// ④初始化 NVIC

	TIM_Cmd(TIM10,ENABLE); //使能定时器 10
}
void TIM1_UP_TIM10_IRQHandler(void)
{

	u16  compareValue = 0; //比较值
	static u8  compareFlag = 1;   //标志位,1:CCR1变大,0:CCR1变小
	if(TIM_GetITStatus(TIM10, TIM_IT_CC1) != RESET)  //判断CNT 计数器的值与 CCR1 寄存器的值是否匹配,即是否相等
	{
		TIM_ClearFlag(TIM10, TIM_IT_CC1);
		compareValue = TIM_GetCapture1(TIM10);;
		if(1 == compareFlag )
		{
			if(compareValue <= 900)  
			{
				compareValue = compareValue +3;
				TIM_SetCompare1(TIM10,compareValue);
			}
			else
			{
				compareFlag =0;
			}
		}
		if(0 == compareFlag )
		{
			if(compareValue >=50)
			{
				compareValue = compareValue -3;
				TIM_SetCompare1(TIM10,compareValue);
			}
			else
			{
				compareFlag =1;
			}
		}
	}
}
int main(void)
{
  //实现输出PWM驱动LED1灯:PWM周期为1ms,初始状态高电平和低电平各0.5ms。
	//TIM10:168MHZ
	TIM10_CH1Init(1680,1000);
	while(1)
	{
	}
}
  • 2
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值