PWM,英文名Pulse Width Modulation,是脉冲宽度调制缩写,它是通过对一系列脉冲的宽度进行调制,等效出所需要的波形(包含形状以及幅值)。
通过调节占空比的变化来调节信号、能量等的变化,占空比就是指在一个周期内,信号处于高电平的时间占据整个信号周期的百分比,例如方波的占空比就是50%(周期T - 低电平T2 = 占空比)
2.怎么实现单片机的PWM引脚输出呢?
(1)可以通过芯片的PWM引脚输出。这种自带有PWM输出功能的芯片在程序设计方面更加简便,同时数据更精确,输出更加平滑,一般来说芯片都会标注明PWM引脚。
(2)对于没有PWM引脚的芯片可以通过模拟输出PWM信号实现。其实PWM 信号其实就是一高一低的一系列电平组合在一起,可以通过定时器计数来实现此类功能。这类方法对于精度、频率等要求不是很高的场合可以这样做。
?PWM信号通常应用于很多场景,比如蜂鸣器驱动,直流电机调试,灯光调光等。
比如呼吸灯,其实就是利用了余辉效应:
呼吸灯的开关频率速度非常快,人眼捕抓的速度有限,通过PWM(脉宽调制)输出驱动LED,逐渐增加PWM的占空比从而实现LED模拟呼吸的过程,即渐亮再渐暗再渐亮再渐暗.......如此往复,再利用LED的余辉和人眼的暂留效应,所以看上去就和人的呼吸一样。
3.应用实例(通过51演示)
8051系列的单片机由于是没有PWM引脚的,所以我们通过普通引脚输出信号模拟PWM的方式实现呼吸灯效果。
3.1呼吸灯
#include <REGX52.H>
//8051单片机呼吸灯程序 (简易版)
sbit LED = P2^0; //定义接LED的IO口
void Delay(unsigned int t) //一个非常快的延时函数,用于改变LED亮灭的时间
{
while(t--);
}
void main()
{
while(1)
{
unsigned int Time;
for(Time=0;Time<600;Time++) //由暗到亮
{
LED=1; //LED亮 ,使用开发板P2口LED这里改成=0
Delay(Time); //经过fou循环,Time从0开始,每次亮的时间+1,直到 >=600 结束
LED=0; //LED灭 ,使用开发板P2口LED这里改成=1
Delay(600-Time); //总的时间 - 亮的时间 = 灭的时间
}
for(Time=600;Time>0;Time--) //由亮到暗
{
LED=1; //LED亮 ,使用开发板P2口LED这里改成=0
Delay(Time); //亮的时间从600开始减,一直到0结束
LED=0; //LED灭 ,使用开发板P2口LED这里改成=1
Delay(600-Time); //总的时间 - 亮的时间 = 灭的时间
}
}
}
3.2 按键调档位(定时器方式)
#include <REGX52.H>
sbit LED = P2^0; //定义电机
sbit Key_1 = P3^1; //定义按键
unsigned char Counter,Compare; //计数值和比较值,用于输出PWM
unsigned char KeyNum,Speed; //全局变量存放按键返回值,占空比速度
/**
* @brief 延时函数,1ms@11.0592MHz 误差 -0.651041666667us
* @param 无
* @retval 无
*/
void Delay(unsigned int i)
{
unsigned char a,b;
for(;i>0;i--)
for(b=102;b>0;b--)
for(a=3;a>0;a--);
}
/**
* @brief 定时器0初始化,100us@11.0592MHz
* @param 无
* @retval 无
*/
void Timer0_Init(void)
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0xA4; //设置定时初始值
TH0 = 0xFF; //设置定时初始值 高八位低八位0xFFA4 组成 100us
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0=1; //允许定时器T0中断
EA=1; //开启总中断
PT0=0; //优先级为低
}
/**
* @brief 获取独立按键键码
* @param 无
* @retval 按下按键的键码,范围:0~1,无按键按下时返回值为0
*/
unsigned char Key()
{
unsigned char KeyNumber = 0; //键码初始值为0
if(Key_1 == 0) //按键按下
{
Delay(20); //按键消抖 Delay(20) = 20ms
while(Key_1 == 0); //等待按键释放
Delay(20);
KeyNumber = 1; //键码值变为 1
}
return KeyNumber; //返回键码值
}
/**
* @brief 主程序
* @param 无
* @retval 无
*/
void main()
{
Timer0_Init(); //定时器初始化
while(1)
{
KeyNum=Key();
if(KeyNum==1) //按键按下
{
Speed++; //速度加1
Speed%=4; //速度范围0~3,等于4的时候清0
if(Speed==0) {Compare=0;} //速度0档,PWM占空比为0
if(Speed==1) {Compare=25;} //速度1档,PWM占空比为25
if(Speed==2) {Compare=60;} //速度2档,PWM占空比为60
if(Speed==3) {Compare=100;} //速度3档,PWM占空比全速
}
}
}
void Timer0() interrupt 1 //进入定时器中断
{
TL0 = 0xA4; //重新赋初始值
TH0 = 0xFF;
Counter++; //计数值自加
Counter%=100; //计数值变化范围限制在0~99
if(Counter < Compare) //计数值小于比较值
LED = 1; //输出高电平 点亮 (注意:51开发板LED为低电平点亮)
else //计数值大于比较值
LED = 0; //输出低电平 熄灭
}
相关资料链接:
延时函数的计算方法http://t.csdn.cn/4yiAb
51定时器详解http://t.csdn.cn/lYJOY
由于工作问题,博客也很少更了,在这里也希望自己的一些文章能帮到大家。
|