文章归档友情连接照片地图

STM32 脉冲宽度调制(PWM)输出

分类:电子设计  作者:rming  时间:2012-07-21

脉冲宽度调制(PWM)

使用之前学过的通用定时器TIM3产生PWM输出。

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

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

要实用STM32的通用定时器TIMx产生PWM输出,除了之前介绍的寄存器,还需要使用到一下三个寄存器:

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

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

捕获/比较据存期(TIMx_CCR1~4)

下面我们着重介绍下着三个寄存器

寄存器介绍

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

该寄存器总共有 2 个,TIMx _CCMR1TIMx _CCMR2。TIMx_CCMR1控制 CH1 和2,而 TIMx_CCMR2控制CH3 和4。该寄存器的各位描述如下:

寄存器的有些位在不同模式下,功能不一样,所以上图把寄存器分了2 层,上面一层对应输出而下面的则对应输入。关于该寄存器的详细说明,请参考《STM32参考手册》第 288 页。

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

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

寄存器控制着各个输入输出通道的开关。该寄存器的各位描述如下

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

该寄存器总共有 4 个,对应 4 个输通道CH1~4

输出模式下,该寄存器的值与CNT 的值比较根据比较结果产生相应动作。利用这点,我们通过修改这个寄存器的值,就可以控制PWM 的输出脉宽了。

寄存器操作步骤

1、开启TIM3 时钟,配置PA7 为复用输出。 

要使用TIM3,我们必须先开启 TIM3的时钟(通过APB1ENR设置),这点相信大家看了这么多代码,应该明白了。这里我们还要配置PA 7 为复用输出,这是因为TIM3_CH2 通道是以 IO复用的形式连接到PA 7 上的,这里我们要使用复用输出功能

2、设置TIM3 的ARR和PSC

在开启了TIM3 的时钟之后,我们要设置 ARR和PSC 两个寄存器的值来控制输出 PWM 的周期。当PWM 周期太慢(低于50Hz)的时候,我们就会明显感觉到闪烁了。因此,PWM 周期在这里不宜设置的太小

3、设置TIM3_CH2 的PWM 模式。

接下来,我们要设置 TIM3_CH2 为PMW 模式(默认是冻结的),因为我们的DS0 是低电平亮,而我们希望当CCR2 的值小的时候,DS0 就暗,CCR2 值大的时候,DS0 就亮,所以我们要通过配置TIM3_CCMR1的相关位来控制 TIM3_CH2 的模式

4、使能TIM3 的CH2 输出,使能TIM3。

在完成以上设置了之后,我们需要开启TIM3的通道 2 输出以及TIM3。前者通过TIM3_CCER1来设置,是单个通道的开关,而后者则通过TIM3_CR1 来设置,是整个 TIM3的总开关。只有设置了这两个寄存器,这样我们才能在TIM3的通道 2 上看到 PWM 波输出

5、修改TIM3_CCR2 来控制占空比。

最后,在经过以上设置之后,PWM 其实已经开始输出了,只是其占空比和频率都是固定的,而我们通过修改TIM3_CCR2则可以控制 CH2 的输出占空比。继而控制 DS0 的亮度。

硬件设计

我们 DS0 是连接在PA 8 上的,而我们的 PWM 输出是在PA 7 ,应该把PA 7 和PA 8 通过跳线帽短接起来,然后配置 PA 8 为浮空输入(IO口复位后的状态),以免干扰PA 7 的信号。

程序设计

MAIN.C

#include <stm32f10x_lib.h>
#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "led.h"
#include "key.h"
#include "exti.h"
#include "wdg.h"
#include "timer.h"
//PWM输出 实验
int main(void)
{
u16 led0pwmval=0;
u8 dir=1;
Stm32_Clock_Init(9); //系统时钟设置
delay_init(72);	//延时初始化
uart_init(72,9600); //串口初始化
led_init();	//初始化与LED连接的硬件接口
pwm_init(900,0);	//不分频。PWM频率=72000/900=8Khz
while(1)
{
delay_ms(10);
if(dir)led0pwmval++;
else led0pwmval--;
if(led0pwmval>300)dir=0;
if(led0pwmval==0)dir=1;
LED0_PWM_VAL=led0pwmval;
}
}

TIMER.C

#include "timer.h"
#include "led.h"
//通用定时器 驱动代码
//定时器3中断服务程序
void TIM3_IRQHandler(void)
{
if(TIM3->SR&0X0001)//溢出中断
{
LED1=!LED1;
}
TIM3->SR&=~(1<<0);//清除中断标志位
}
//通用定时器中断初始化
//这里时钟选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
//这里使用的是定时器3!
void timerx_init(u16 arr,u16 psc)
{
RCC->APB1ENR|=1<<1;//TIM3时钟使能
TIM3->ARR=arr; //设定计数器自动重装值//刚好1ms
TIM3->PSC=psc; //预分频器7200,得到10Khz的计数时钟
//这两个东东要同时设置才可以使用中断
TIM3->DIER|=1<<0; //允许更新中断
TIM3->DIER|=1<<6; //允许触发中断
TIM3->CR1|=0x01; //使能定时器3
MY_NVIC_Init(1,3,TIM3_IRQChannel,2);//抢占1,子优先级3,组2
}
//TIM3 PWM部分
//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void pwm_init(u16 arr,u16 psc)
{
//此部分需手动修改IO口设置
RCC->APB1ENR|=1<<1; //TIM3时钟使能
GPIOA->CRH&=0XFFFFFFF0;//PA8输出
GPIOA->CRH|=0X00000004;//浮空输入
GPIOA->CRL&=0X0FFFFFFF;//PA7输出
GPIOA->CRL|=0XB0000000;//复用功能输出
GPIOA->ODR|=1<<7;//PA7上拉
TIM3->ARR=arr;//设定计数器自动重装值
TIM3->PSC=psc;//预分频器不分频
TIM3->CCMR1|=7<<12; //CH2 PWM2模式
TIM3->CCMR1|=1<<11; //CH2预装载使能
TIM3->CCER|=1<<4; //OC2 输出使能
TIM3->CR1=0x8000; //ARPE使能
TIM3->CR1|=0x01; //使能定时器3
}

TIMER.H

#ifndef __TIMER_H
#define __TIMER_H
#include "sys.h"
//通用定时器 驱动代码
#define LED0_PWM_VAL TIM3->CCR2
void timerx_init(u16 arr,u16 psc);
void pwm_init(u16 arr,u16 psc);
#endif


提交评论