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为直通