stm32中定时器产生不同PWM的基本思路
stm32pwm原理

stm32pwm原理STM32是一款高性能、低功耗的微控制器,它具有丰富的外设和强大的处理能力。
其中,PWM(Pulse Width Modulation)是STM32中常用的一种外设,它可以用来控制电机、LED灯等设备的亮度或速度。
本文将介绍STM32中PWM的原理和使用方法。
一、PWM原理PWM是一种通过改变信号占空比来控制电机、LED灯等设备的亮度或速度的技术。
在STM32中,PWM的实现是通过定时器和比较器来完成的。
具体来说,STM32中的定时器可以产生一个周期性的计数器值,而比较器可以将计数器值与预设的比较值进行比较,从而产生PWM信号。
在STM32中,PWM信号的占空比可以通过改变比较器的预设值来实现。
例如,如果比较器的预设值为50,那么当计数器值小于50时,PWM信号为高电平,当计数器值大于等于50时,PWM信号为低电平。
因此,通过改变比较器的预设值,可以改变PWM信号的占空比,从而控制设备的亮度或速度。
二、PWM使用方法在STM32中,使用PWM需要进行以下步骤:1. 初始化定时器和比较器:首先需要初始化定时器和比较器,设置它们的工作模式、时钟源等参数。
2. 设置PWM输出引脚:将定时器和比较器的输出引脚与设备的控制引脚相连,从而将PWM信号输出到设备上。
3. 设置比较器的预设值:根据需要控制设备的亮度或速度,设置比较器的预设值,从而改变PWM信号的占空比。
4. 启动定时器:启动定时器,让它开始产生周期性的计数器值。
5. 控制设备:根据PWM信号的占空比,控制设备的亮度或速度。
下面是一个简单的PWM控制LED灯的例子:```c#include "stm32f10x.h"void PWM_Init(void){GPIO_InitTypeDef GPIO_InitStructure;TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;TIM_OCInitTypeDef TIM_OCInitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_AFIO, ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);TIM_TimeBaseStructure.TIM_Period = 999;TIM_TimeBaseStructure.TIM_Prescaler = 71;TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode =TIM_CounterMode_Up;TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState =TIM_OutputState_Enable;TIM_OCInitStructure.TIM_Pulse = 500;TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC1Init(TIM2, &TIM_OCInitStructure);TIM_Cmd(TIM2, ENABLE);}int main(void){PWM_Init();while (1){}}```在上面的例子中,我们使用了TIM2定时器和PA0引脚来控制LED灯的亮度。
stm32 pwm调节转速原理

STM32的PWM调节转速原理主要基于PWM(Pulse Width Modulation)脉冲宽度调制。
通过编程控制输出方波的频率和占空比(高低电平的比例),可以实现对电机转速的控制。
在直流电机驱动中,PWM调速的基本原理是通过控制电机通电的电压来实现转速的调节。
当提高电压时,反电势升高,进而转速升高。
因此,通过控制PWM信号的占空比,可以实现对电机通电电压的调节,从而控制电机的转速。
在STM32中,可以通过定时器产生PWM信号,并通过调节占空比来控制电机的转速。
具体实现方式如下:
1.设置定时器工作模式为PWM模式,并配置相应的PWM通道和占空比。
2.根据需要调节占空比的值,以控制电机通电的电压。
3.将PWM信号输出到电机驱动器,从而实现对电机转速的控制。
需要注意的是,具体的PWM调速实现方式可能会因电机的类型、驱动器的型号等因素而有所不同。
因此,在实际应用中,需要根据具体情况进行相应的调整和配置。
STM32++定时器与+PWM+快速使用入门

STM32 定时器与 PWM 快速使用入门要求:在万利的开发板 EK-STM32F 上产生周期为1秒,占空比分别为 50% 10%的 PWM 并且点亮板上的 LD1,LD2 灯闪烁。
做法很简单。
STM32的PWM是由定时器来产生的。
可以看出。
定时器3的通道1至4在GPIO端口的映像。
如果是完全映射。
各通道的连接引脚如下:CH1=PC6, CH2=PC7, CH3=PC8, CH4=PC9这样,刚好与板上的LD1,LD2灯符合,因为LD1连接到PC7,LD2连接到PC6引脚。
关于PWM一些知识.STM32的TIMx 是 TIMx_ARR 寄存器确定频率(周期)、由TIMx_CCRx 寄存器确定占空比的信号。
使用定时器3。
而TIM2、3、4的时钟源是 APB1 即是 PCLK1 ( APB1 对应 PCLK1 )PCLK1 = APB1 = HCLK/2 = SYSCLK/2 = 36MHZ (36,000,000 HZ)但是注意:倍频器会自动倍2,即是【72MHZ】!代码如下:voidSTM32_PWM_GPIO_Configuration(void){// 11:完全映像STM32_Afio_Regs->mapr.bit.TIM3_REMAP=3;// LD1 =P7 LD2=PC6/*GPIOA Configuration: ( PC6 PC7 ) TIM3 channel 1 and 2 as alternate function push -pull */STM32_Gpioc_Regs-&F6=Output_Af_push_pull; // PC.06 复用功能推挽输出模式STM32_Gpioc_Regs->crl.bit.MODE6=Output_Mode_50mhz; // PC.06 输出模式,最大速度50MHzSTM32_Gpioc_Regs-&F7=Output_Af_push_pull; // PC.07 复用功能推挽输出模式STM32_Gpioc_Regs->crl.bit.MODE7=Output_Mode_50mhz; // PC.07 输出模式,最大速度50MHz}//end subvoidSTM32_TIM3_Configuration(void){// TIM_DeInit( TIM3);//复位TIM3定时器STM32_Rcc_Regs->apb1rstr.all |= RCC_TIM3RST;STM32_Rcc_Regs->apb1rstr.all &= ~RCC_TIM3RST;//时钟使能STM32_Rcc_Regs->apb1enr.all |=RCC_TIM3EN;/* TIM3 base configuration *///TIM_TimeBaseStructure.TIM_Period = 9999;//TIM_TimeBaseStructure.TIM_Prescaler = 7200;//TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;//TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);STM32_Tim3_Regs->arr.all=9999; // 定时周期,PWM频率! 10毫秒*100=1秒STM32_Tim3_Regs->psc.all=720; // 7200分频 72MHZ/72,00 72,000,000/72,00=10,000STM32_Tim3_Regs->cr1.bit.CKD=0; // 时钟分频因子STM32_Tim3_Regs->cr1.bit.DIR=0; // 0:计数器向上计数/* Clear TIM3 update pending flag[清除TIM3溢出中断标志] *///TIM_ClearFlag(TIM3, TIM_FLAG_Update);STM32_Tim3_Regs->sr.bit.UIF=0; //更新中断标记由软件清0 ,例如当上溢或下溢时,软件对CNT重新初始化/* PWM1 Mode configuration: Channel1 Channel2 *///TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//TIM_OCInitStructure.TIM_Pulse = CCR1_Val;//TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//TIM_OC1Init(TIM3, &TIM_OCInitStructure);// timer3 的通道1 是 PC6 引脚, AFIO完全映射STM32_Tim3_Regs-&1P=0; // 输入/捕获1输出极性 0:OC1高电平有效 1:OC1低电平有效STM32_Tim3_Regs-&1E=1; // 输入/捕获1输出使能 1:开启- OC1信号输出到对应的输出引脚。
stm32中定时器产生不同PWM的基本思路

在stm32中利用定时器TIM调制PWM的几种方法:说说我的学习经历:从开始接触到现在有好几个月了,但是学习还是比较的费劲,而且速度也比较的缓慢,当然相比之前还是有很大的进步,记得刚刚学习的时候,建工程都是大四学长手把手教的。
废话不多说先来讲讲定时器的配置:STM32F10系列最少3个、做多有8个定时器,都是16位定时器,且相互之间是独立的,计数范围为0x0000-0xffff,最大计数值为65535.可以用于测量输入信号的脉冲长度或者产生输出波形(输出比较和PWM)分为通用定时器,高级定时器,以及看门狗定时器下面主要讲通用定时器的配置问题:以定时器TIM1为例:先进行函数的配置void timer1_config(){TIM_TimeBaseInitTypDef TIM_TimeBaseStructure;//开定时器1外设时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM1,ENABLE);//计时50000次时间为50000/10M=500msTIM_TimeBaseStructure.TIM_Period=50000 ;TIM_TimeBaseStructure.TIM_Prescaler = 720-1;//720分频TIM_TimeBaseStructure.TIM_ClockDivision =0;//时钟分割为0;//计数模式向上计数TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;TIM_TimeBaseInit(TIM1,&TIM_TimeBaseStructure)//初始化TIM1TIM_ITConfig(TIM1,TIM_IT_Update,ENABLE);//开启定时器中断TIM_Cmd(TIM1,ENABLE); //使能定时器}关于时间的计算问题:外设系统时钟的频率为72M,进行720分频以后,频率f=72M/720=100khz. 如果要定时0.1s则计数值为10000,计算公式为:时间(t)=计数值(n)/频率(f).注意计数值n介于0到65535之间有定时器则一定会有中断发生,所以要配置中断优先级,对于中断优先级函数配置如下:V oid nvic_config(){NVIC_InitTypDef NVIC_InitStructure;//抢占优先级为1位,从优先级为3位NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1) ;NVIC_InitStructure.NVIC_IRQChannel=TIM1_IRQn; //定义定时器1为请求通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0; //抢占式优先级为0NVIC_InitStructure.NVIC_IRQChannelSubPriority=2; //从优先级为2NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; //使能中断优先级NVIC_Init(&NVIC_InitStructure); //初始化中断}对于优先级中的抢占式和从优先级做如下解释:抢占式优先级:是可以抢占的中断,比如正在执行的优先级为10的中断,突然来了一个优先级为5的中断,此时cpu会转向优先级为5的中断;从优先级:从优先级不会抢占正在执行的中断程序,但是如果两个事件同时发生,那么cpu 会执行优先级高的事件,但是已经执行就不会再更改了,即使优先级比正在执行的高,这正好和抢占式优先级不同,抢占式优先级不论程序是否在执行,只要现在发生的中断优先级比正在执行的要高,就会更改。
使用STM32的定时器产生两路相位互为180度的PWM输出波形

④计数器继续向下计数,减到0时开始调头向上计数;当计数器的数值上升到TIMx_CC2时,CC2再次匹配成功,CC2的输出电平再次翻转;
如此循环,得到连续的相位互为180度的两路输出波形。
基本设置如下:
1)配置定时器的计数器为中间对齐计数,即先向上计数再向下计数。
2)在该定时器上选择2个通道,并分别配置为输出比较模式,并配置在比较成功时翻转对应的引脚输出。
3)配置自动重装载寄存器TIMx_ARR为要求输出频率的一半。
4)假定CC1为第一个输出信号的通道,再假定第一个信号的正脉冲宽度对应为W1,则配置TIMx_CCR1为TIMx_ARR-W1/2。
5) 同4),假定CC2为第二个输出信号的通道,正脉冲宽度对应为W2,配置TIMx_CCR2为W2/2。
----------------------------------------------
下面以一个例子说明:
假设要求输出的信号频率为10kHz,占空比为1:3。
再假设定时器的输入时钟为72MHz。
按照上述5),设置TIMx_CC2=W2/2=450
参照下图,图中红线表示计数器的数值变化:
①当计数器的数值从0向上计数,达到TIMx_CC1时,CC1匹配成功,CC1的输出电平翻转;
②计数器继续向上计数,达到TIMx_ARR时开始调头向下计数;当计数器的数值下降到TIMx_CC1时,CC1再次匹配成功,CC1的输出电平再次翻转;
输出信号的频率10kHz,换算为计数器的数值为7200。
按照上述电平时间W1,换算为计数器的数值为W1=7200/4=1800
STM32之PWM波形输出配置总结

STM32之PWM波形输出配置总结1.TIMER分类STM32中一共有11个定时器,其中TIM6、TIM7是基本定时器;TIM2、TIM3、TIM4、TIM5是通用定时器;TIM1和TIM8是高级定时器,以及2个看门狗定时器和1个系统嘀嗒定时器。
其中系统嘀嗒定时器是前文中所描述的SysTick。
其中TIM1和TIM8是能够产生3对PWM互补输出,常用于三相电机的驱动,时钟由APB2的输出产生。
TIM2-TIM5是普通定时器,TIM6和TIM7是基本定时器,其时钟由APB1输出产生。
2.PWM波形产生的原理通用定时器可以利用GPIO引脚进行脉冲输出,在配置为比较输出、PWM输出功能时,捕获/比较寄存器TIMx_CCR被用作比较功能,下面把它简称为比较寄存器。
举例说明定时器的PWM输出工作过程:若配置脉冲计数器TIMx_CNT为向上计数,而重载寄存器TIMx_ARR被配置为N,即TIMx_CNT的当前计数值数值X 在TIMxCLK时钟源的驱动下不断累加,当TIMx_CNT的数值X大于N时,会重置TIMx_CNT数值为0重新计数。
而在TIMxCNT计数的同时,TIMxCNT的计数值X会与比较寄存器TIMx_CCR 预先存储了的数值A进行比较,当脉冲计数器TIMx_CNT的数值X小于比较寄存器TIMx_CCR的值A时,输出高电平(或低电平),相反地,当脉冲计数器的数值X大于或等于比较寄存器的值A时,输出低电平(或高电平)。
如此循环,得到的输出脉冲周期就为重载寄存器TIMx_ARR存储的数值(N+1)乘以触发脉冲的时钟周期,其脉冲宽度则为比较寄存器TIMx_CCR的值A 乘以触发脉冲的时钟周期,即输出PWM的占空比为 A/(N+1) 。
3.STM32产生PWM的配置方法1)配置GPIO口不是每一个IO引脚都可以直接使用于PWM输出,下面是定时器的引脚重映像,其实就是引脚的复用功能选择:表3-1 定时器1的引脚复用功能映像表3-2 定时器2的引脚复用功能映像表3-3 定时器3的引脚复用功能映像表3-4 定时器4的引脚复用功能映像根据以上重映像表,我们使用定时器3的通道2作为PWM的输出引脚,所以需要对PB5引脚进行配置,对IO口操作代码:2)初始化定时器3)设置TIM3_CH2的PWM模式、使能TIM3的CH2输出4)使能定时器3经过以上的操作,定时器3的第二通道已经可以正常工作并输出PWM波了,只是其占空比和频率都是固定的,我们可以通过改变TIM3_CCR2,则可以控制它的占空比。
STM32F103使用TIM3产生四路PWM

STM32F103使⽤TIM3产⽣四路PWMSTM32F103 使⽤TIM3产⽣四路PWM程序如下:/******************************************************************************** 程序说明 : 思路PWM波⽣成函数* 函数功能 : 使⽤TIM3的PWM功能⽣成思路PWM,* 输⼊ : ⽆* 输出 : 四路PWM,通过GPIO引脚复⽤,对TIM3的四个输出通道引脚重映射为PC6、PC7、PC8、PC9*******************************************************************************/#include"stm32f10x.h"void RCC_Cfg(void);void GPIO_Cfg(void);void TIM_Cfg(void);void NVIC_Cfg(void);void delay_ms(u32 i);void PWM_Cfg(float dutyfactor1,float dutyfactor2,float dutyfactor3,float dutyfactor4);int main(){u8 flag = 1;float ooo=0.5;RCC_Cfg();NVIC_Cfg();GPIO_Cfg();TIM_Cfg();//开启定时器2TIM_Cmd(TIM3,ENABLE);//呼吸灯while(1){PWM_Cfg(ooo,10,50+0.5*ooo,200-2*ooo);if(flag == 1){ooo=ooo+0.002;}if(flag == 0){ooo=ooo-0.002;}if(ooo>100){flag = 0;}if(ooo<0.5){flag = 1;}}}void GPIO_Cfg(void){GPIO_InitTypeDef GPIO_InitStructure;//RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);//全部映射,将TIM3_CH2映射到PB5//根据STM32中⽂参考⼿册2010中第第119页可知://当没有重映射时,TIM3的四个通道CH1,CH2,CH3,CH4分别对应PA6,PA7,PB0,PB1//当部分重映射时,TIM3的四个通道CH1,CH2,CH3,CH4分别对应PB4,PB5,PB0,PB1//当完全重映射时,TIM3的四个通道CH1,CH2,CH3,CH4分别对应PC6,PC7,PC8,PC9//也即是说,完全重映射之后,四个通道的PWM输出引脚分别为PC6,PC7,PC8,PC9,我们⽤到了通道1和通道2,所以对应引脚为PC6,PC7,PC8,PC9,我们⽤到了通道1和通道2,所以对应引脚为 GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE);//部分重映射的参数//GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);//设置PC6、PC7、PC8、PC9为复⽤输出,输出4路PWMGPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9;GPIO_Init(GPIOC,&GPIO_InitStructure);}void TIM_Cfg(void){//定义结构体TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;//重新将Timer设置为缺省值TIM_DeInit(TIM3);//采⽤内部时钟给TIM2提供时钟源TIM_InternalClockConfig(TIM3);//预分频系数为0,即不进⾏预分频,此时TIMER的频率为72MHzre.TIM_Prescaler =0;TIM_TimeBaseStructure.TIM_Prescaler = 0;//设置计数溢出⼤⼩,每计20000个数就产⽣⼀个更新事件TIM_TimeBaseStructure.TIM_Period = 7200 - 1;//设置时钟分割TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//设置计数器模式为向上计数模式TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//将配置应⽤到TIM2中TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);//清除溢出中断标志//TIM_ClearFlag(TIM2, TIM_FLAG_Update);//禁⽌ARR预装载缓冲器//TIM_ARRPreloadConfig(TIM2, DISABLE);//开启TIM2的中断//TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);}/******************************************************************************** 函数名 : PWM波产⽣配置函数* 函数功能 : PWM_Cfg* 输⼊ : dutyfactor 占空⽐数值,⼤⼩从0.014到100* 输出 : ⽆*******************************************************************************/void PWM_Cfg(float dutyfactor1,float dutyfactor2,float dutyfactor3,float dutyfactor4){TIM_OCInitTypeDef TIM_OCInitStructure;//设置缺省值TIM_OCStructInit(&TIM_OCInitStructure);//TIM3的CH1输出TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //设置是PWM模式还是⽐较模式TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //⽐较输出使能,使能PWM输出到端⼝ TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //设置极性是⾼还是低//设置占空⽐,占空⽐=(CCRx/ARR)*100%或(TIM_Pulse/TIM_Period)*100%TIM_OCInitStructure.TIM_Pulse = dutyfactor1 * 7200 / 100;TIM_OC1Init(TIM3, &TIM_OCInitStructure);//TIM3的CH2输出TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //设置是PWM模式还是⽐较模式TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //⽐较输出使能,使能PWM输出到端⼝ TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //设置极性是⾼还是低//设置占空⽐,占空⽐=(CCRx/ARR)*100%或(TIM_Pulse/TIM_Period)*100%TIM_OCInitStructure.TIM_Pulse = dutyfactor2 * 7200 / 100;TIM_OC2Init(TIM3, &TIM_OCInitStructure);//TIM3的CH3输出TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //设置是PWM模式还是⽐较模式TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //⽐较输出使能,使能PWM输出到端⼝ TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //设置极性是⾼还是低//设置占空⽐,占空⽐=(CCRx/ARR)*100%或(TIM_Pulse/TIM_Period)*100%TIM_OCInitStructure.TIM_Pulse = dutyfactor3 * 7200 / 100;TIM_OC3Init(TIM3, &TIM_OCInitStructure);//TIM3的CH4输出TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //设置是PWM模式还是⽐较模式TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //⽐较输出使能,使能PWM输出到端⼝ TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //设置极性是⾼还是低//设置占空⽐,占空⽐=(CCRx/ARR)*100%或(TIM_Pulse/TIM_Period)*100%TIM_OCInitStructure.TIM_Pulse = dutyfactor4 * 7200 / 100;TIM_OC4Init(TIM3, &TIM_OCInitStructure);//使能输出状态TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//设置TIM3的PWM输出为使能TIM_CtrlPWMOutputs(TIM3,ENABLE);}void NVIC_Cfg(void){//定义结构体NVIC_InitTypeDef NVIC_InitStructure;//选择中断分组1NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);//选择TIM2的中断通道NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;//抢占式中断优先级设置为0NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//响应式中断优先级设置为0NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;//使能中断NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);}void RCC_Cfg(void){//定义错误状态变量ErrorStatus HSEStartUpStatus;//将RCC寄存器重新设置为默认值RCC_DeInit();//打开外部⾼速时钟晶振RCC_HSEConfig(RCC_HSE_ON);//等待外部⾼速时钟晶振⼯作HSEStartUpStatus = RCC_WaitForHSEStartUp();if(HSEStartUpStatus == SUCCESS){//设置AHB时钟(HCLK)为系统时钟RCC_HCLKConfig(RCC_SYSCLK_Div1);//设置⾼速AHB时钟(APB2)为HCLK时钟RCC_PCLK2Config(RCC_HCLK_Div1);//设置低速AHB时钟(APB1)为HCLK的2分频RCC_PCLK1Config(RCC_HCLK_Div2);//设置FLASH代码延时FLASH_SetLatency(FLASH_Latency_2);//使能预取指缓存FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);//设置PLL时钟,为HSE的9倍频 8MHz * 9 = 72MHzRCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);//使能PLLRCC_PLLCmd(ENABLE);//等待PLL准备就绪while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);//设置PLL为系统时钟源RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);//判断PLL是否是系统时钟while(RCC_GetSYSCLKSource() != 0x08);}//允许TIM2的时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//允许GPIO的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC|RCC_APB2Periph_AFIO,ENABLE); }void TIM2_IRQHandler(void){u16 aa=10;if(TIM_GetFlagStatus(TIM2,TIM_IT_Update)!=RESET){//清除TIM2的中断待处理位TIM_ClearITPendingBit(TIM2 , TIM_FLAG_Update);TIM_Cmd(TIM2,DISABLE);//通过循环让灯闪烁while (aa){GPIO_SetBits(GPIOC,GPIO_Pin_3);delay_ms(10);GPIO_ResetBits(GPIOC,GPIO_Pin_3);delay_ms(10);aa--;}//使灯的状态为灭GPIO_SetBits(GPIOC,GPIO_Pin_3);TIM_Cmd(TIM2,ENABLE);}}void delay_ms(u32 i){u32 temp;SysTick->LOAD=9000*i; //设置重装数值, 72MHZ时SysTick->CTRL=0X01; //使能,减到零是⽆动作,采⽤外部时钟源SysTick->VAL=0; //清零计数器do{temp=SysTick->CTRL; //读取当前倒计数值}while((temp&0x01)&&(!(temp&(1<<16)))); //等待时间到达SysTick->CTRL=0; //关闭计数器SysTick->VAL=0; //清空计数器}在产⽣PWM时,如果输出引脚已经被使⽤,就要对引脚进⾏重映射,阅读《STM32中⽂参考⼿册2010》第119页可知:对TIM3⽽⾔:1、当没有重映射时,TIM3的四个通道CH1,CH2,CH3,CH4分别对应PA6,PA7,PB0,PB12、当部分重映射时,TIM3的四个通道CH1,CH2,CH3,CH4分别对应PB4,PB5,PB0,PB13、当完全重映射时,TIM3的四个通道CH1,CH2,CH3,CH4分别对应PC6,PC7,PC8,PC9为了整齐,我们选择完全重映射,使⽤的函数是:GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE);如果想使⽤部分映射,参数⽤GPIO_PartialRemap_TIM3:GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);。
基于寄存器操作的STM32高级定时器TIM1的四路PWM输出程序讲解

基于寄存器操作的STM32高级定时器TIM1的四路PWM输出程序讲解STM32高级定时器TIM1具有四个独立的PWM输出通道,可以用来控制四个不同的设备或驱动器。
在本篇文章中,我们将详细讲解如何使用寄存器操作实现TIM1的四路PWM输出。
首先,需要了解几个相关的概念。
STM32的定时器是通过寄存器进行配置和操作的,其中TIM1是高级定时器,具有更高级的功能和更多的寄存器。
PWM(脉冲宽度调制)是一种常见的控制技术,可实现模拟信号的数字化控制,通过调整高电平和低电平的时间比例来控制目标设备或驱动器的动作。
在开始编写程序之前,我们首先需要对TIM1进行初始化和配置。
以下是一个基本的初始化函数示例:```void TIM1_PWM_Init//开启TIM1的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);//初始化TIM1的配置TIM_TimeBaseInitTypeDef TIM_BaseStruct;TIM_OCInitTypeDef TIM_OCStruct;TIM_BaseStruct.TIM_Prescaler = 0;TIM_BaseStruct.TIM_CounterMode = TIM_CounterMode_Up;TIM_BaseStruct.TIM_Period = 999; // 设置周期为1000TIM_BaseStruct.TIM_ClockDivision = TIM_CKD_DIV1;TIM_BaseStruct.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM1, &TIM_BaseStruct);//配置输出比较通道TIM_OCStruct.TIM_OCMode = TIM_OCMode_PWM1;TIM_OCStruct.TIM_OutputState = TIM_OutputState_Enable;TIM_OCStruct.TIM_Pulse = 0; // 设置脉冲宽度,0表示低电平TIM_OCStruct.TIM_OCPolarity = TIM_OCPolarity_High;TIM_OC1Init(TIM1, &TIM_OCStruct);TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);TIM_OC2Init(TIM1, &TIM_OCStruct);TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);TIM_OC3Init(TIM1, &TIM_OCStruct);TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);TIM_OC4Init(TIM1, &TIM_OCStruct);TIM_OC4PreloadConfig(TIM1, TIM_OCPreload_Enable);//启动定时器TIM_Cmd(TIM1, ENABLE);```上述代码是一个初始化TIM1的函数示例,其中包含了基本的配置步骤。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
NVIC_InitStructure.NVIC_IRQChannelSubPriority=2; //从优先级为2
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; //使能中断优先级
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
/* PA8设置为功能脚(PWM) */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出(该脚已经用过)
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;//输出极性
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High; //互补端的极性
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set; //输出空闲非工作状态
在stm32中利用定时器TIM调制PWM的几种方法:
说说我的学习经历:从开始接触到现在有好几个月了,但是学习还是比较的费劲,而且速度也比较的缓慢,当然相比之前还是有很大的进步,记得刚刚学习的时候,建工程都是大四学长手把手教的。废话不多说先来讲讲定时器的配置:
STM32F10系列最少3个、做多有8个定时器,都是16位定时器,且相互之间是独立的,计数范围为0x0000-0xffff,最大计数值为65535.可以用于测量输入信号的脉冲长度或者产生输出波形(输出比较和PWM)分为通用定时器,高级定时器,以及看门狗定时器
TIM_Cmd(TIM1,ENABLE); //使能定时器
}
关于时间的计算问题:
外设系统时钟的频率为72M,进行720分频以后,频率f=72M/720=100khz.如果要定时0.1s则计数值为10000,计算公式为:时间(t)=计数值(n)/频率(f).注意计数值n介于0到65535之间
有定时器则一定会有中断发生,所以要配置中断优先级,对于中断优先
第二种情况:频率一定占空比可以任意设置,频率一定的情况下可以改变定时器输出通道TIM_OCInitStructure.TIM_Pulse的值,
这种情况下可以通过给定时器的捕获寄存器的值进行改变,即改变脉冲的大小,从而改变占空比
在上述的程序的基础上增加如下程序:
//设置捕获寄存器1
void SetT1Pwm1(u16 pulse)
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//正向通道有效
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;//反向通道无效
TIM_OCInitStructure.TIM_Pulse = 72; //占空时间总的周期为8ms占空时间为约为4ms
功能模块2
.....
}
}
功能模块中写上自己需要实现的功能
至此,一个完整的定时器函数模块定义完成,
下面我给大家写一下如何调制PWM,定时器中对于PWM的调制有几种状态,第一种频率占空比一定,第二种频率和占空比可以改变,第三种频率一定,占空比可以改变。
先讲第一种情况:频率和占空比一定时的配置情况
void Tim1_Configuration(void)
接下来写中断处理函数:
Void TIM1_IRQHandler(void)
{
If(TIM_GetITStatus(TIM1,TIM_IT_Update)!=Reset) //接受到中断
{
TIM_ClearnITPendingBit(TIM1,TIM_IT_Update); //清除中断位
功能模块1,需要实现的功能
NVIC_Init(&NVIC_InitStructure);//初始化中断
}
对于优先级中的抢占式和从优先级做如下解释:
抢占式优先级:是可以抢占的中断,比如正在执行的优先级为10的中断,突然来了一个优先级为5的中断,此时cpu会转向优先级为5的中断;
从优先级:从优先级不会抢占正在执行的中断程序,但是如果两个事件同时发生,那么cpu会执行优先级高的事件,但是已经执行就不会再更改了,即使优先级比正在执行的高,这正好和抢占式优先级不同,抢占式优先级不论程序是否在执行,只要现在发生的中断优先级比正在执行的要高,就会更改。
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;//输出极性
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High; //互补端的极性
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set; //输出空闲非工作状态
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);//开TMI1外设时钟
TIM_DeInit(TIM1);//将TMI寄存器设置为缺省状态
/*TIM1时钟配置*/
TIM_TimeBaseStructure.TIM_Prescaler = 4000;//预分频(时钟分频)72M/4000=18K
//计数模式向上计数
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM1,&TIM_TimeBaseStructure)//初始化TIM1
TIM_ITConfig(TIM1,TIM_IT_Update,ENABLE);//开启定时器中断
//计时50000次时间为50000/10M=500ms
TIM_TimeBaseStructure.TIM_Period=50000;
TIM_TimeBaseStructure.TIM_Prescaler = 720-1;//720分频
TIM_TimeBaseStructure.TIM_ClockDivision =0;//时钟分割为0;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//正向通道有效
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;//反向通道无效
TIM_OCInitStructure.TIM_Pulse = 40;//占空时间总的周期为8ms占空时间为约为2.4ms
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;//输出互补空闲非工作状态
TIM_OC2Init(TIM1,&TIM_OCInitStructure);//初始化通道2
/* TIM1 counter enable */
TIM_Cmd(TIM1,ENABLE);//使能定时器1
/* TIM1 Main Output Enable */
TIM_CtrlPWMOutputs(TIM1,ENABLE);//使能定时器1的主输出
}
//一般定时器一种有个四个通道OC1、OC2、OC3、OC4;
//注意占空比TIM_OCInitStructure.TIM_Pulse的值不能超过定时器的周期,也即TIM_TimeBaseStructure.TIM_Period的值,
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0x0;//Repetition重复计数器
//TIM_TimeBaseStructure.TIM_RepetitionCounter = 0x0;//Repetition重复计数器。
TIM_RepetitionCounter:设置周期计数器,其值必须在0x00---0xFF之间,且此参数只适用于TMI1和TMI8种
{
TIM1->CCR1=pulse;
}
通过外接函数不断调用给函数 不断的改变pulse的值,从而会改变定时器输出通道中的TIM_OCInitStructure.TIM_Pulse,这就意味着占空比可以任意的设置。
第三种情况:根据情况二
以此类推,我们可以改变定时器的预分频值,从而改变其频率的大小,在此基础上就实现了第三种情况,既改变频率有改变占空比。具体操作读者自己发挥想象,我就不再写出具体操作步骤。
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;//输出互补空闲非工作状态
/* Channel 2 Configuration in PWM mode设置TIM1通道2的参数*/
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;//PWM模式2
TIM_TimeBaseInit(TIM1,&TIM_TimeBaseStructure);