STM32 中用定时器产生脉冲宽度调制(PWM)输出
STM32 中的定时器除了 TIM6 和 TIM7,其它的定时器都可以用来产生 PWM 输出。其中高级定时器 TIM1、TIM8 可以同时产生多达 7 路的 PWM 输出。而通用定时器也能同时产生多达 4 路的 PWM 输出
STM32 中占空比寄存器
STM32 的 PWM 是 TIMx_ARR 寄存器确定频率(周期)、由能 TIMx_CCRx寄存器确认占空比的信号。在 TIM1_CCMRx 寄存器中的 OCxM 位写入“110”(PWM 模式 1)或“111”(PWM 模式 2),能够独立地设置每个通道工作在PWM 模式,每个 OCx 输出一路 PWM。必须通过设置 TIM1_CCMRx 寄存器 OCxPE位使能相应的预装载寄存器, 最后还要设置 TIM1_CR1 寄存器的 ARPE 位使能自动重装载的预处理计数器
STM32 PWM 边沿对齐模式
向上计数的配置
当 TIM1_CR1 寄存器中的 DIR 位为低的时候执行向上计数。
在 PWM 模式 1,TIM1_CNT<TIM1_CCRx 时 PWM 参考信号,OCxREF 为高,否则为低。如果,TIM1_CCRx 中的比较值大于自动重装载值(TIM1_ARR),则 TIM1_OCxREF 保持为“1”,如果比较值为“0”,则 TIM1_OCxREF 保持为
“0”
向下计数的配置
当 TIM1_CR1 寄存器中的 DIR 位为高的时候执行向下计数
在 PWM 模式 1,TIM1_CNT>TIM1_CCRx 时 PWM 参考信号,OCxREF 为低, 否则为高。 如果, TIM1_CCRx 中的比较值大于自动重装载值 (TIM1_ARR) ,则 TIM1_OCxREF 保持为“1”,该模式下不产生 0%的 PWM 波形.
从上图可以清晰的看出,在 PWM 模式 1,TIM1_CNT>TIM1_CCRx 时 PWM 参考信号,OCxREF 为高,否则为低。如果,TIM1_CCRx 中的比较值大于自动重装载值(TIM1_ARR),则 TIM1_OCxREF 保持为“1”,IM1_CCRx 中的比较值为“0”时,则 TIM1_OCxREF 保持为“0”
GPIO 引脚时钟使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//设置定时器 3 时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//功能复用 IO 时钟函数
本节实验用到了 PB 端口, 所以要把 PB 端口的时钟打开; 定时器 3 (TIM3)时钟源是通过 APB1 预分频器得到的,时器 3 时钟初始化;因为要产生 PWM波形,所以要打开功能复用时钟。
PB5对应TIM3_CH2所以可以用于PWM输出。
工程结构
#ifndef _pbdata_H
#define _pbdata_H
#include "stm32f10x.h"
#include "misc.h"
#include "stm32f10x_exti.h"
#include "stm32f10x_tim.h"
//¶¨Òå±äÁ¿
extern u8 dt;
//¶¨Ò庯Êý
void RCC_HSE_Configuration(void);
void delay(u32 nCount);
void delay_us(u32 nus);
void delay_ms(u16 nms);
#endif
引入头文件
#include "pbdata.h"
void RCC_Configuration(void);
void GPIO_Configuration(void);
void TIM3_Configuration(void);
int main(void)
{
u8 led_fx=1;
u16 led_dt=0;
RCC_Configuration(); //ϵͳʱÖÓ³õʼ»¯
GPIO_Configuration();//¶Ë¿Ú³õʼ»¯
TIM3_Configuration();//¶¨Ê±Æ÷ºÍpwmÅäÖÃ
while(1)
{
delay_ms(10);
if(led_fx==1)
{
led_dt++;
}
else
{
led_dt--;
}
if(led_dt>910) led_fx=0;
if(led_dt==0) led_fx=1;
TIM_SetCompare2(TIM3,led_dt);
}
}
//ÅäÖÃʱÖÓ
void RCC_Configuration(void)
{
SystemInit();
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//ÒòΪÓõ½PWMÊä³öËùÒÔ¿ªÆô¸´ÓÃʱÖÓ
}
//GPIOÅäÖÃ
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
//LED
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_Init(GPIOB,&GPIO_InitStructure);
}
void TIM3_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
TIM_OCInitTypeDef TIM_OCInitStructure;
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE);
//¶¨Ê±Æ÷³õʼ»¯
TIM_TimeBaseStruct.TIM_Period=899;//PMWƵÂÊΪ72000000/900 = 80000,//
//Õ¼¿Õ±È±ÈÈçÄãÐèÒª°Ù·ÖÖ®50µÄÕ¼¿Õ±ÈÄÇô900*0.5
TIM_TimeBaseStruct.TIM_Prescaler=0;//Ô¤·ÖƵ
TIM_TimeBaseStruct.TIM_ClockDivision=0;
TIM_TimeBaseStruct.TIM_CounterMode=TIM_CounterMode_Up;//ÏòÉÏ
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStruct);
//pwm ³õʼ»¯
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low;
TIM_OC2Init(TIM3,&TIM_OCInitStructure);
TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Enable);
TIM_Cmd(TIM3,ENABLE);
}
源代码
//PWM频率为72000000/900 = 80000,//
//占空比假如你需要百分之50的占空比那么900*0.5
PWM频率计算方法 假设现在定时器时钟是48000000 PWM频率是50000 那么占空比的最大值为48000000/50000 = 960。超过9600为直通