一、前言
PWM简介
PWM(脉宽调制)是一种通过调节信号的脉冲宽度来控制功率输出的技术。其基本原理是保持固定频率的信号,将其高电平和低电平的持续时间调整,达到控制平均功率的目的。应用方面,PWM广泛用于电机控制、LED调光、音频放大、以及电源管理等领域,因为它能有效提高能效并减少热量生成。
STM32F103ZET6的PWM
STM32F103ZET6的定时器,除了TIM6和TIM7,都可以用来产生PWM。高级定时器1和8甚至同时可以产生7路PWM输出,通用定时器也可以同时各自产生4路PWM输出。STM32定时器的脉冲宽度调制模式可以产生一个由TIMx_ARR寄存器确定频率、由TIMx_CCRx寄存器确定占空比的信号。如下图所示:
图中显示的是向上计数模式的PWM,且当 CNT<CCRx 时,输出 0,当 CNT>=CCRx 时输出 1。那么就可以得到如上的 PWM示意图:当 CNT 值小于 CCRx 的时候,IO 输出低电平(0),当 CNT 值大于等于 CCRx 的时候,IO 输出高电平(1),当 CNT 达到 ARR 值的时候,重新归零,然后重新向上计数,依次循环。改变 CCRx 的值,就可以改变 PWM 输出的占空比,改变 ARR 的值,就可以改变 PWM 输出的频率,这就是 PWM 输出的原理。
本次DEMO目标
本次DEMO我们将使用TIM3的CH2,并将CH2重映射到PB5,产生PWM来控制DS0的亮度。
二、时钟树分析
对于时钟树的分析与【STM32开发之寄存器版】(六)-通用定时器中断 相同,供给TIM3的时钟TIM3CLK=72MHz,具体的时钟树配置如下图所示:
三、寄存器介绍
对于PWM的设置主要涉及以下几个寄存器:
寄存器 | 作用 |
---|---|
TIMx_CCMR1/2 | 捕获/比较模式寄存器1/2 |
TIMx_CCER | 捕获/比较使能寄存器 |
TIMx_CCR1-4 | 捕获/比较寄存器1-4 |
AFIO_MAPR | 复用重映射和调试I/O配置寄存器 |
下面将对这四个寄存器进行一一介绍:
3.1 TIMx_CCMR捕获/比较模式寄存器
《STM32中文参考手册》对TIMx_CCMR寄存器的描述如下:
TIMx_CCMR寄存器总共有 2 个,TIMx _CCMR1和 TIMx _CCMR2。TIMx_CCMR1 控制 CH1 和 2,而 TIMx_CCMR2 控制 CH3 和 4。本文使用PB5,即TIM3_CH2,故仅需关注TIMx _CCMR1即可。
TIMx_CCMR1中的某些位,在输入和输出模式下具备不同的功能,因此将这个寄存器分为2层,上面这层表示输出,下面这层表示输入,本次DEMO仅需关注输出PWM。这里我们需要说明的是模式设置位 OCxM,此部分由 3 位组成。总共可以配置成 7 种模式,我们使用的是 PWM 模式,所以这 3 位必须设置为 110/111。这两种 PWM 模式的区别就是输出电平的极性相反。另外 CCxS 用于设置通道的方向(输入/输出)默认设置为 0,就是设置通道作为输出使用。
3.2 TIMx_CCER捕获/比较使能寄存器
《STM32中文参考手册》对TIMx_CCER寄存器的描述如下:
对于这个寄存器,我们只用到了CC2E位,该位是输入/捕获 2 输出使能位,要想PWM 从 IO 口输出,这个位必须设置为 1。
3.3 TIMx_CCR捕获/比较寄存器
《STM32中文参考手册》对TIMx_CCR寄存器的描述如下:
对于TIM3,CCR寄存器共有4个,分别对应CH1-CH4,本文使用的PB5对应CH2,故我们仅需关注TIM3_CCR2寄存器。在输出模式下,该寄存器的值与 CNT 的值比较,根据比较结果产生相应动作。利用这点,我们通过修改这个寄存器的值,就可以控制 PWM 的输出脉宽了。本章,我们使用的是 TIM3 的通道 2,所以我们需要修改 TIM3_CCR2 以实现脉宽控制 DS0 的亮度。
3.4 AFIO_MAPR复用重映射和调试I/O配置寄存器
《STM32中文参考手册》对AFIO_MAPR寄存器的描述如下:
由于本文要使用TIM3的CH2输出PWM来控制DS0的亮度,但是TIM3_CH2默认接在PA7上面,而DS0接在PB5上面,因此需要通过重映射功能,将TIM3_CH2映射到PB5上。描述重映射的寄存器是AFIO_MAPR,我们只需要关注其TIM3_REMAP[1:0]位。在本DEMO中,我们要将TIM3_REMAP[1:0]设置为10,部分映像可以将CH2通道映射到PB5引脚上。
四、程序设计
本DEMO的程序主要涉及定时器3的PWM功能初始化和轮询主函数。
4.1 定时器3的PWM功能初始化
该部分代码位于HARDWARE/timer.c/TIM3_PWM_Init(),主要功能是完成定时器3时钟使能、PB5复用功能配置、PWM模式配置和使能。具体代码如下所示:
//TIM3 PWM部分初始化
//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM3_PWM_Init(u16 arr,u16 psc)
{
//此部分需手动修改IO口设置
RCC->APB1ENR|=1<<1; //TIM3时钟使能
RCC->APB2ENR|=1<<3; //使能PORTB时钟
GPIOB->CRL&=0XFF0FFFFF; //PB5输出
GPIOB->CRL|=0X00B00000; //复用功能输出
RCC->APB2ENR|=1<<0; //开启辅助时钟
AFIO->MAPR&=0XFFFFF3FF; //清除MAPR的[11:10]
AFIO->MAPR|=1<<11; //部分重映像,TIM3_CH2->PB5
TIM3->ARR=arr; //设定计数器自动重装值
TIM3->PSC=psc; //预分频器不分频
TIM3->CCMR1|=7<<12; //CH2 PWM2模式
TIM3->CCMR1|=1<<11; //CH2预装载使能
TIM3->CCER|=1<<4; //OC2 输出使能
TIM3->CR1=0x0080; //ARPE使能
TIM3->CR1|=0x01; //使能定时器3
}
4.2 轮询主函数
该部分代码位于USER/test.c,具体作用是不断改变TIM3的CCR2装载值,从而改变PWM占空比,实现DS0的亮度调整。具体代码如下所示:
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "timer.h"
int main(void)
{
u16 led0pwmval=0;
u8 dir=1;
Stm32_Clock_Init(9); //系统时钟设置
uart_init(72,115200); //串口初始化为115200
delay_init(72); //延时初始化
LED_Init(); //初始化与LED连接的硬件接口
TIM3_PWM_Init(899,0); //不分频。PWM频率=72000/(899+1)=80Khz
while(1)
{
delay_ms(10);
if(dir)led0pwmval++;
else led0pwmval--;
if(led0pwmval>300)dir=0;
if(led0pwmval==0)dir=1;
LED0_PWM_VAL=led0pwmval;
}
}
五、上机实验
将代码烧录到STM32F103ZET6,可以观察到DS0的呼吸灯效果。如下所示:
至此完成PWM呼吸灯实验!