一、PWM的介绍
PWM(脉冲宽度调制)控制技术
通过对一系列脉冲的宽度进行调制,来等效地获得所需要波形(含形状和幅值)。
PWM 控制的基本原理
冲量相等而开头不同的窄脉冲加在具有惯性的环节上时,其效果基本相同。其中冲量指窄脉冲的面积;效果相同指环节输出响应波形基本相同。
参考例子
用一系列等幅不等宽的脉冲来代替一个正弦半波
:
其划分方式是将正弦半波分成 N 等分,可看成 N 个彼此相连的脉冲序列,宽度相等,但幅值不等;接下来使用矩形脉冲代替,而各个矩形脉冲等幅,不等宽,中点与脉冲序列重合,脉冲宽度按正弦规律变化,脉冲的总面积(冲量)与正弦半波相等。这个脉冲波形被称为 SPWM 波形,是一种极其典型的PWM波形。
二、了解定时器实现PWM波形输出
1.PWM工作过程
寄存器的值从0开始到ARR值的过程中,当其比CCRx中的值小的时候,输出低电平(0),当其值大于CCRx值时,输出高电平(1)。从图中可以看出周期是由ARR决定的,跟定时器的时钟有关系,而占空比则跟CCRx有关。
2.PWM的通道
①CCR1寄存器:捕获/比较值寄存器:设置比较值;
②CCMR1寄存器:OC1M[2:0]位:对于PWM方式下,用于设置PWM模式1或者PWM模式2;
③CCER寄存器:CC1P位:输入/捕获1输出极性。0:高电平有效,1:低电平有效。
④CCER寄存器:CC1E位:输入/捕获1输出使能。0:关闭,1:打开。
PWM输出的模式区别
通过设置寄存器TIMx_CCMR1的OC1M[2:0]位来确定PWM的输出模式:
PWM模式1:在向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道1为有效电平,否则为无效电平;在向下计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为无效电平(OC1REF=0),否则为有效电平(OC1REF=1)。
PWM模式2:在向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道1为无效电平,否则为有效电平;在向下计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为有效电平,否则为无效电平。
注意:并未说明1就表示有效电平
3.定时器3的输出通道引脚
TIM3_CH1:PA6,完全重映像PC6
TIM3_CH2:PA7,完全重映像PC7
TIM3_CH3:PB0,完全重映像PC8
TIM3_CH4:PB1,完全重映像PC9
更多详细信息,请参考STM32芯片手册。
三、相关配置
1.捕获/比较模式寄存器1(TIMx_CCMR1)
在PWM输出模式下,确定PWM的模式、使能相应的预装载寄存器等操作。
2.捕获/比较使能寄存器(TIMx_CCER)
在PWM输出模式下,确定PWM的输出极性和输出使能。
3.捕获/比较寄存器1(TIMx_CCR1)
在PWM输出模式下,确定比较的值。
具体配置方式,请参考STM32的中文手册
四、实现输出PWM
1.定时器TIM1的初始化
//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM1_PWM_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);//
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE); //使能GPIO外设时钟使能
//设置该引脚为复用输出功能,输出TIM1 CH1的PWM脉冲波形
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //TIM_CH1,引脚是PA8
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 80K
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 不分频
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_Pulse = 0; //设置待装入捕获比较寄存器的脉冲值
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
TIM_OC1Init(TIM1, &TIM_OCInitStructure); //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
TIM_CtrlPWMOutputs(TIM1,ENABLE); //MOE 主输出使能
TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable); //CH1预装载使能
TIM_ARRPreloadConfig(TIM1, ENABLE); //使能TIMx在ARR上的预装载寄存器
TIM_Cmd(TIM1, ENABLE); //使能TIM1
}
2.main函数
int main(void)
{
u16 led0pwmval=0;
u8 dir=1;
delay_init(); //延时函数初始化
LED_Init(); //初始化与LED连接的硬件接口
TIM1_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;
TIM_SetCompare1(TIM1,led0pwmval);//设置不同的占空比
}
}
3.最终效果
烧录后,可以看到LED灯由亮变暗的过程。
利用keil仿真查看输出的波形如下
从图中可以发现该过程的占空比是逐渐在发送变化。
通过示波器可以观察到其波形如下
五、小结
通过输出的波形,可以认为输出的占空比是发生变化。当然也可以利用库函数提供的函数,实现改变频率。仿真得到的波形,不像示波器给出的那么明显,实现动态改变。
六、参考资料
1.【STM32】通用定时器的PWM输出(实例:PWM输出)
2.STM32学习笔记一一PWM 输出
3.KEIL里如何实现仿真 查看输出波形
4.PWM输出实验