zoukankan      html  css  js  c++  java
  • 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 亮度变化就不明显了。



  • 相关阅读:
    Building Java Projects with Gradle
    Vert.x简介
    Spring及Spring Boot 国内快速开发框架
    dip vs di vs ioc
    Tools (StExBar vs Cmder)which can switch to command line window on context menu in windows OS
    SSO的定义、原理、组件及应用
    ModSecurity is an open source, cross-platform web application firewall (WAF) module.
    TDD中测试替身学习总结
    Spring事务银行转账示例
    台式机(华硕主板)前面板音频接口(耳机和麦克风)均无声的解决办法
  • 原文地址:https://www.cnblogs.com/longintchar/p/5224422.html
Copyright © 2011-2022 走看看