• stm32 PWM输出学习


    STM32 的定时器除了 TIM6 和 7,其他的定时器都可以用来产生 PWM 输出。其中高级定时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出。通用定时器也能同时产生多达 4路的 PWM 输出。

    今天的实验,我们仅利用 TIM3的 CH2 通道产生一路 PWM 输出。

    1.相关寄存器介绍

    1)捕获/比较模式寄存器 (TIMx_CCMR1/2) 

    捕获/比较模式寄存器(TIMx_CCMR1/2),该寄存器总共有 2 个,TIMx  _CCMR1和 TIMx _CCMR2。TIMx_CCMR1 控制 CH1 和 CH2,而 TIMx_CCMR2 控制 CH3 和 CH4。


    OCxx描述了通道在输出模式下的功能(上行),ICxx描述了通道在输出模式下的功能(下行)。因此必须注意,同一个位在输出模式和输入模式下的功能是不同的。 

    这里我们需要说明的是模式设置位 OCxM,此部分由 3 位组成。总共可以配置成 7 种模式,我们使用的是 PWM 模式,所以这 3 位必须设置为 110/111。这两种PWM 模式的区别就是输出电平的极性相反。 


    这里的有效电平或者无效电平是可以配置的。

    2) 捕获/比较使能寄存器(TIMx_CCER) 



    3)捕获/比较寄存器(TIMx_CCR1~4)

    该寄存器总共有 4 个,对应 4 个通道 CH1~CH4。因为这 4 个寄存器都差不多,我们仅以 TIMx_CCR1 为例介绍。


    我们通过修改这个寄存器的值,就可以控制 PWM 的输出脉宽。

    2. TIM3_REMAP 重映射

    我们要利用 TIM3 的 CH2 输出 PWM 来控制 LED的亮度,但是 TIM3_CH2 默认是接在 PA7上面的,而我们的 LED接在 PB5 上面,如果是普通 MCU,可能就只能用飞线把 PA7 飞到 PB5上;不过,我们用的是 STM32,可以通过重映射功能,把 TIM3_CH2映射到 PB5 上。 


    3.代码难点分析

    1)RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);//使能TIM3时钟
          RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);  
    //使能GPIOB时钟(PB5连接LED)和AFIO复用功能时钟

    为什么要使能RCC_APB2Periph_AFIO呢?

    参考手册上说:

    对寄存器AFIO_EVCR(事件控制寄存器),AFIO_MAPR( 复用重映射和调试I/O配置寄存器),AFIO_EXTICRX(外部中断配置寄存器)进行读写操作前,应当首先打开AFIO的时钟。

    因为我们在这个实验中用到了AFIO_MAPR,所以要打开AFIO时钟。

    2)GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //Timer3部分重映射,TIM3_CH2->PB5 

    3)GPIO配置

    //设置该引脚为复用输出功能,输出TIM3-CH2的PWM波形
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; 
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //推挽复用输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);


    4)TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; 

         可以参考捕获/比较使能寄存器(TIMx_CCER)位0, 输出使能。

    5)TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; 

         可以参考捕获/比较使能寄存器(TIMx_CCER)位1, 高/低 电平有效。

    6)TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); 预装载使能

         可以参考捕获/比较模式寄存器 (TIMx_CCMR1/2) 位3.


    7)TIM_SetCompare2(TIM3,300);

    参考捕获/比较寄存器(TIMx_CCR1~4),这里设置比较值为300.

    4. 代码参考

    //PWM输出初始化函数
    //arr:自动重装载值
    //psc: 预分频系数
    void TIM3_PWM_Init(u16 arr,u16 psc)
    {  
    	GPIO_InitTypeDef GPIO_InitStructure;
    	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    	TIM_OCInitTypeDef  TIM_OCInitStructure;
    	
    
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);	//使能TIM3时钟
     	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);  
    	//使能GPIOB时钟(PB5连接LED)和AFIO复用功能时钟
    	
    	GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //Timer3部分重映射,TIM3_CH2->PB5    
     
        //设置该引脚为复用输出功能,输出TIM3-CH2的PWM波形
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; 
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOB, &GPIO_InitStructure);
     
        //初始化TIM3
    	TIM_TimeBaseStructure.TIM_Period = arr; 
    	TIM_TimeBaseStructure.TIM_Prescaler = psc; 
    	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //向上计数
    	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); 
    	
    	//TIM3 Channel2 PWM 初始化
    	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //PWM2模式
     	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //捕获/比较使能寄存器(TIMx_CCER) 输出使能
    	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //高电平有效
    	TIM_OC2Init(TIM3, &TIM_OCInitStructure);  
    
    	TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);  //预装载使能
    		
    	TIM_Cmd(TIM3, ENABLE);  //开启TIM3
    
    }
    

    main函数如下

    int main(void)
    {	
    	
    	TIM3_PWM_Init(999,71); //72/(71+1)=1MHz, T=1us*(999+1) = 1ms
    	TIM_SetCompare2(TIM3,300);	//脉宽= 300/1000 *1ms = 0.3ms
       	while(1)
    	{
    		;	   
    	}	 
    }

    仿真说明:我们的代码设置为:

    PWM2模式,向上计数,高电平有效。

    所以,TIMx_CNT<TIMx_CCRx时通道x为低,否则为高。

    5.仿真效果图如下


    6. 疑问

    如果调换main函数两句的顺序,则无法达到预期效果。

    <span style="font-size:18px;">int main(void) //实验失败
    {	
    	TIM_SetCompare2(TIM3,300);	//脉宽= 300/1000 *1ms = 0.3ms
    	TIM3_PWM_Init(999,71); //72/(71+1)=1MHz, T=1us*(999+1) = 1ms
    	
       	while(1)
    	{
    		;	   
    	}	 
    }</span>

    至于原因,这里不讨论,留待以后思考。

    7. 用PWM控制LED的亮度

    int main(void)
    {		
     	u16 led0pwmval = 0; //比较值
    	u8 dir = 1;	
    	delay_init();	    	 
    	
     	TIM3_PWM_Init(899,0);	 
    	
       	while(1)
    	{
     		delay_ms(10);	 
    		
    		if(dir)
    			led0pwmval++;
    		else 
    			led0pwmval--;
    
     		if(led0pwmval>300)
    			dir=0;
    		if(led0pwmval==0)
    			dir=1;										 
    		
    		TIM_SetCompare2(TIM3,led0pwmval);		   
    	}	 
    }
    

    这里,我们将 led0pwmval 这个值设置为 PWM 比较值,也就是通过 led0pwmval 来控制 PWM 的占空比,进而控制LED的平均电流,达到控制LED亮度的目的。

     led0pwmval 的值从 0 变到 301,然后又从 301 变到 0,如此循环,LED的亮度也会跟着从暗变到亮,然后又从亮变到暗。至于这里的值,我们为什么取 300,是因为 PWM 的输出占空比达到并且超过这个值的时候, LED 亮度变化就不明显了。



  • 相关阅读:
    表的管理
    子查询
    sql语句
    基本sql语句与oracle函数
    Visual C# 2008+SQL Server 2005 数据库与网络开发6.1.1 报表服务概述
    Visual C# 2008+SQL Server 2005 数据库与网络开发 5.4 小结
    Visual C# 2008+SQL Server 2005 数据库与网络开发5.3.1 日期时间函数
    Visual C# 2008+SQL Server 2005 数据库与网络开发 5.3 函数
    Visual C# 2008+SQL Server 2005 数据库与网络开发第6章 数据报表
    Visual C# 2008+SQL Server 2005 数据库与网络开发5.2.2 GROUP BY
  • 原文地址:https://www.cnblogs.com/longintchar/p/5224422.html
Copyright © 2020-2023  润新知