初级会员

- 积分
- 58
- 金钱
- 58
- 注册时间
- 2020-5-24
- 在线时间
- 9 小时
|
本帖最后由 leelzj 于 2020-5-25 19:35 编辑
在开始我们的工程之前,首先来了解一个概念:PWM。
PWM是脉冲宽度调制的英文单词的缩写。脉冲宽度调制(PWM)是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,广泛应用在从测量、通信到功率控制与变换的许多领域中。脉宽调制是开关型稳压电源中的术语。这是按稳压的控制方式分类的,除了PWM型,还有PFM型和PWM、PFM混合型。脉宽调制式开关型稳压电路是在控制电路输出频率不变的情况下,通过电压反馈调整其占空比,从而达到稳定输出电压的目的。
读起来有点晦涩难懂。其实简单的说来,PWM技术就是通过调整一个周期固定的方波的占空比,来调节输出电压的平均当电压,电流或者功率等被控量。我们可以用一个水龙头来类比,把1S时间分成50等份,即每一个等份20MS。在这20MS时间里如果我们把水龙头水阀一直打开,那么在这20MS里流过的水肯定是最多的,如果我们把水阀打开15MS,剩下的5MS关闭水阀,那么流出的水相比刚才20MS全开肯定要小的多。同样的道理,我们可以通过控制20MS时间里水阀开启的时间的长短来控制流过的水的多少。那么在1S内平均流出的水流量也就可以被控制了。
当我们调整PWM的占空比时,就会引起电压或者电流的改变,LED的明暗状态就会随之发生相应的变化,听起来好像可以通过这种方法来实现我们想要的渐明渐暗的效果。让我们来试一下吧。
大家都知道人眼有一个临界频率,当LED的闪烁频率达到一定的时候,人眼就分辨不出LED是否在闪烁了。为了让我们的LED在变化的过程中,我们感觉不到其在闪烁,可以将其闪烁的频率定在50Hz以上。同时为了看起来明暗过渡的效果更加明显,我们在这里定义其变化范围为0~99(100等分).即最亮的时候其灰度等级为99,为0的时候最暗,也就是熄灭了。
于是乎我们定义PWM的占空比上限为99,下限定义为0。
假定我们LED的闪烁频率为50HZ,而亮度变化的范围为0~99共100等分。则每一等分所占用的时间为1/(50*100)=200us即我们在改变LED的亮灭状态时,应该是在200us整数倍时刻时。在这里我们用单片机的定时器产生200us的中断,同时每20MS调整一次LED的占空比。这样在20MS*100=2S的时间内LED可以从暗逐渐变亮,在下一个2S内可以从亮逐渐变暗,然后不断循环。
由于大部分的内容都可以在中断中完成,主函数中除了初始化之外,就是一个空的死循环。
下面附完整程序代码,然后具体分析:
timer.c:
#include "timer.h"
void timer_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitstruct;
NVIC_InitTypeDef NVIC_Initstruct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
TIM_TimeBaseInitstruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitstruct.TIM_Period = arr;
TIM_TimeBaseInitstruct.TIM_Prescaler = psc;
TIM_TimeBaseInitstruct.TIM_RepetitionCounter = TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitstruct);
TIM_Cmd(TIM3,ENABLE);
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);
NVIC_Initstruct.NVIC_IRQChannel = TIM3_IRQn;
NVIC_Initstruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Initstruct.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_Initstruct.NVIC_IRQChannelSubPriority = 2;
NVIC_Init(&NVIC_Initstruct);
}
u8 dir = 1;
u8 ledpwmval;
u8 ledpwmcount;
u8 timecount;
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3,TIM_FLAG_Update))
{
if(++timecount > 100)
{
timecount = 0;
if((dir==1)&&(ledpwmcount<=99))
{
ledpwmcount++;
if(ledpwmcount > 99)
{
ledpwmcount = 99;
dir = 0;
}
}
if((dir==0)&&(ledpwmcount>=0))
{
ledpwmcount--;
if(ledpwmcount == 0)
{
ledpwmcount = 0;
dir = 1;
}
}
ledpwmval = ledpwmcount;
}
if(ledpwmval>0)
{
GPIO_ResetBits(GPIOG,GPIO_Pin_9);
ledpwmval--;
}
else
GPIO_SetBits(GPIOG,GPIO_Pin_9);
}
TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
}
main.c:
int main(void){
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
delay_init(168);
ledInit();
timer_Init(2-1,8400-1);//200us
while(1){}
}
|
|