• 【STM32】PWM输出


    PWM输出学习。

    PWM认识

    PWM是“Pulse Width Modulation”的缩写,即脉冲宽度调制,简称脉宽调制。是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。简单来说,就是对脉冲宽度的控制。

    在这里插入图片描述

    这里会用到定时器,STM32有多个定时器,这里我们仅利用 TIM3的 CH2 产生一路 PWM 输出。如果要产生多路输出,请查阅文档。

    要使 STM32 的通用定时器 TIMx 产生 PWM 输出,还需要用到 3 个寄存器:捕获/比较模式寄存器
    (TIMx_CCMR1/2)、捕获/比较使能寄存器(TIMx_CCER)、捕获/比较寄存器(TIMx_CCR1~4)。简单来说,通过修改捕获/比较寄存器的值就能控制PWM的输出脉宽。

    这个例子我们使用的是 TIM3的通道 2,所以我们需要修改 TIM3_CCR2 以实现脉宽控制 DS0 的亮度。

    TIM3_CH2 默认是接在 PA7上面的,而我们的 DS0 接在 PB5 上面,普通MCU是需要飞线的,而STM32有重映射功能,可以将TIM3_CH2映射到 PB5 上。

    STM32 的重映射控制是由复用重映射和调试 IO 配置寄存器(AFIO_MAPR)控制的。自己编程序时可查看重映射控制表。

    PWM有两个重要参数:
    arr-自动装载值
    psc-预分频数,即对时钟频率的分频,去顶定时时长

    eg:stm32时钟频率为72MHz,设计定时100ms。
    分析:设置预分频为:7199,则72M/(7199+1)=10KHz,即一秒计数10K次,想要定时100ms,则自动重装值为10K*0.1s - 1=999。

    硬件电路

    这里,我们将使用 TIM3 的通道 2,把通道 2 重映射到 PB5,产生 PWM 来控制 DS0 的亮度,实现PWM呼吸灯的效果。

    硬件资源:

    • 指示灯DS0(低电平亮)
    • 定时器TIM3(重映射PB5,连接DS0)

    在这里插入图片描述

    软件编写

    PWM 相关的函数设置在库函数文件 stm32f10x_tim.h 和 stm32f10x_tim.c文件中。

    timer.h

    #ifndef __TIMER_H
    #define __TIMER_H
    #include "sys.h"
    
    void TIM3_Int_Init(u16 arr,u16 psc);
    void TIM3_PWM_Init(u16 arr,u16 psc);
    #endif
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    timer.c

    #include "timer.h"
    #include "led.h"
    #include "usart.h"
       	  
    //通用定时器3中断初始化
    //这里时钟选择为APB1的2倍,而APB1为36M
    //arr:自动重装值。
    //psc:时钟预分频数
    //这里使用的是定时器3!
    void TIM3_Int_Init(u16 arr,u16 psc)
    {
      TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    	NVIC_InitTypeDef NVIC_InitStructure;
    
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
    
    	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	 计数到5000为500ms
    	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值  10Khz的计数频率  
    	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
    	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
    	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
     
    	TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断
    
    	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断
    	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级
    	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级
    	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
    	NVIC_Init(&NVIC_InitStructure);  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
    
    	TIM_Cmd(TIM3, ENABLE);  //使能TIMx外设
    							 
    }
    //定时器3中断服务程序
    void TIM3_IRQHandler(void)   //TIM3中断
    {
    	if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源 
    		{
    		TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //清除TIMx的中断待处理位:TIM 中断源 
    		LED1=!LED1;
    		}
    }
    
    //TIM3 PWM部分初始化 
    //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);	//使能定时器3时钟
     	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB  | RCC_APB2Periph_AFIO, ENABLE);  //使能GPIO外设和AFIO复用功能模块时钟
    	
    	GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //Timer3部分重映射  TIM3_CH2->PB5    
     
       //设置该引脚为复用输出功能,输出TIM3 CH2的PWM脉冲波形	GPIOB.5
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //TIM_CH2
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO
     
       //初始化TIM3
    	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(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
    	
    	//初始化TIM3 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(TIM3, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM3 OC2
    
    	TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM3在CCR2上的预装载寄存器
     
    	TIM_Cmd(TIM3, ENABLE);  //使能TIM3
    	
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85

    main函数如下:

     int main(void)
     {		
     	u16 led0pwmval=0;	//PWM比较值
    	u8 dir=1;	
    	delay_init();	    	 //延时函数初始化	  
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 	 //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
    	uart_init(115200);	 //串口初始化为115200
     	LED_Init();			     //LED端口初始化
     	TIM3_PWM_Init(899,0);	 //不分频。PWM频率=72000000/900=80Khz
       	while(1)
    	{
     		delay_ms(10);	 
    		if(dir)led0pwmval++;
    		else led0pwmval--;
    
     		if(led0pwmval>300)dir=0;
    		if(led0pwmval==0)dir=1;										 
    		TIM_SetCompare2(TIM3,led0pwmval);		   
    	}	 
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    以上。

  • 相关阅读:
    考研大作文模板与实战(图表为主+部分图画)
    (附源码)小程序 工程技术研究中心 毕业设计 201738
    面向对象复习(java)
    ENVI+ERDAS实现Hyperion叶绿素含量反演:经验比值法、一阶微分法
    引导滤波融合matlab
    day10每日3题(1):逐步求和得到正数的最小值
    【算法练习Day25】 重新安排行程&&N 皇后&& 解数独
    [激光原理与应用-109]:南京科耐激光-激光焊接-焊中检测-智能制程监测系统IPM介绍 - 12 - 焊接工艺之影响焊接效果的因素
    linux more,less,tail,cat,grep命令
    并查集模板及思想
  • 原文地址:https://blog.csdn.net/qq_40344790/article/details/127448209