欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

怎样用STM32 通用定时器 输出PWM信号

程序员文章站 2022-03-13 17:18:29
...

概述

脉宽调制(PWM)是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,广泛应用在电机控制,电力电子功率控制与变换的许多领域中。可以将其看作是数模转换的一种。配合DAC模块,还可以输出正弦波。STM32 的四个通用定时器TIM2~TIM5均可以同时产生4路PWM输出。

STM32 定时器输出PWM的原理

怎样用STM32 通用定时器 输出PWM信号

如上图,ARR是STM32中自动重装载寄存器的值,计数器从0开始计数,当计数到ARR时,又返回从0开始计数。CCRx是捕获比较寄存器中的值,当计数值小于CCRx时,输出端输出低电平,当计数值大于CCRx时,输出端输出高电平,如果改变CCRx的值,就能改变输出方波的占空比,调整ARR的值,就能改变输出方波的频率。

通用定时器功能框图

怎样用STM32 通用定时器 输出PWM信号

要想正确配置STM32 的PWM输出功能,必须了解定时器的功能框图,上面的功能框图可以大致分为五个部分,即1.时钟源部分,2.控制器.3.时基单元.4.输入通道.5.输出通道.

比较输出通道的功能框图

怎样用STM32 通用定时器 输出PWM信号

由比较输出通道的功能框的功能框图可知,比较输出通道的管理和配置主要由TIMx_CCMR1(捕获比较模式寄存器1)和TIM_CCER(捕获比较使能寄存器)进行.

PWM输出配置步骤:

1.使能定时器和相关IO口时钟。

2. 初始化IO口为复用功能输出。  

3. 根据实际需要开启AFIO时钟。同时设置重映射。

 4.初始化定时器时基单元.

5.初始化输出比较功能.

6.使能预装载寄存器.

7. 使能定时器。

下面根据这个步骤来编写PWM输出的代码,假设我们要使用通用定时器TIM2和TIM2的CH2输出通道来输出PWM信号。先查阅一下STM32的官方资料看看TIM2是挂载在APB1还是APB2上?TIM2的CH2对应哪个GPIO。

系统功能图

怎样用STM32 通用定时器 输出PWM信号

TIM2重映射图

怎样用STM32 通用定时器 输出PWM信号

从上面两图可知,TIM2 挂载在APB1上,TIM2_CH2不重映射时对应的是PA1。下面开始编写代码。

//假设我们我们使用通用定时器TIM2,通道使用TIM2的CH2,即PA1,不需要端口映射
//TIM2 PWM部分初始化 
//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM2_PWM_Config(u16 arr,u16 psc)
{  
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	
//STEP1  使能定时器和相关IO时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);	//使能定时器2时钟
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA  | RCC_APB2Periph_AFIO, ENABLE);  //使能GPIO外设和AFIO复用功能模块时钟
	
//STEP2 初始化IO口为复用功能	 
   //设置该引脚为复用输出功能,输出TIM2 CH2的PWM脉冲波形	GPIOA.1
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //TIM_CH2
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO

//STEP3 根据需要设置重映射,此处不需要,因此省略
//STEP4 初始化时基单元 
 
   //初始化TIM2
	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位


//STEP5 初始化比较输出参数 	
	//初始化TIM2 Channel2 PWM模式	 
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
	TIM_OC2Init(TIM2, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM2 OC2

//STEP6 使能预装载寄存器 
	TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);  //使能TIM2在CCR2上的预装载寄存器
 
//STEP7  使能定时器
	TIM_Cmd(TIM2, ENABLE);  //使能TIM2
	

}

下面利用上面编写的函数TIM2_PWM_Config()来实现的输出脉宽可变的PWM波形,如果TIM_CH2(PA1)上接一个LED,将会看到LED由亮变暗,再由暗变亮。

 int main(void)
 {		
 	u16 pwm_ccr_val=0;
	u8 dir=1;	
	delay_init();	    	 //延时函数初始化	  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 	 //设置NVIC中断分组2:2位抢占优先级,2位响应优先级

 	TIM2_PWM_Config(899,0);	 //不分频。PWM频率=72000000/900=80Khz
   	while(1)
	{
 		delay_ms(10);	 
		if(dir)pwm_ccr_val++;
		else pwm_ccr_val--;

 		if(pwm_ccr_val>300)dir=0;
		if(pwm_ccr_val==0)dir=1;										 
		TIM_SetCompare2(TIM2,pwm_ccr_val);		   
	}	 
 }