刚刚搜了一下,发现坛里还没有这样分析PWM的帖子,然后发了一个。
手电LED控制或马达转速控制都离不开PWM,下面有两种方法可以模拟PWM的。如果不正确希望各位指教。
//用定时器装载方式模拟PWM,这种方法PWM周期短,分辩率高,1毫秒内可以做到11000格分辩率,
//缺点:高低电平会的百分之一格不受控制
#include "reg51.h"
#include<intrins.h>
sfr P0M1 = 0x93;
sfr P0M0 = 0x94;
sfr P1M1 = 0x91;
sfr P1M0 = 0x92;
sfr P2M1 = 0x95;
sfr P2M0 = 0x96;
sfr P3M1 = 0xb1;
sfr P3M0 = 0xb2;
sfr AUXR = 0x8e;//辅助寄存器
sbit P20 = P2^0; //PWM输出脚
sbit P17 = P1^7; //按键增量
sbit P16 = P1^6; //按键减少
unsigned int HIGHDUTY,LOWDUTY;//高低时间存放寄存器
unsigned char num;//记录分辩个数
bit flag;
void Delayms(unsigned int ms)//1mS@11.0592MHz
{unsigned char i, j;
while(ms--)
{ _nop_();
_nop_();
_nop_();
i = 11;
j = 190;
do
{
while (--j);
} while (--i);}
}
void main()
{
P0M0 = 0x00;
P0M1 = 0x00;
P1M0 = 0x00;
P1M1 = 0x00;
P2M0 = 0x00;
P2M1 = 0x00;
P3M0 = 0x00;
P3M1 = 0x00;
AUXR = 0x80; //定时器0为1T模式
TMOD &= 0xf0; //设置定时器0为模式0(16位自动重装载)
TR0 = 1; //定时器0开始计时
ET0 = 1; //使能定时器0中断
EA = 1;
HIGHDUTY=54477+(11058/255)*num;
LOWDUTY=54477+(11058/255)*(256-num);
while (1)
{
if(!P17)
{
Delayms(90);
if(!P17)
{
//while(!P17);
num++; //按制分辩率,uchar字符型范围0~255格
HIGHDUTY=54477+(11058/255)*num;/*求占空比高位,0xD4CD = 54477;
程序装载初始值54477一直跑到65535共花时间1000微秒,
65535-54477=11058,11058就是1000微秒。
(11058再除以分辩率255)等于一格所需的时间,要点空比高位多少就剩多少 */
LOWDUTY=54477+(11058/255)*(255-num);//求占空比高位低位
}
}
if(!P16)
{
Delayms(90);
if(!P16)
{
//while(!P16);
num--;
HIGHDUTY=54477+(11058/255)*num;
LOWDUTY=54477+(11058/255)*(255-num);//
}
}
}
}
void tm0() interrupt 1//定时器0中断服务程序
{
flag = !flag;
if (flag)//反转标志去执行高低电平的时间
{
TL0 = HIGHDUTY; //设置定时初值
TH0 = HIGHDUTY>>8;//设置定时初值
P20=1;//输出高电位
}
else
{
TL0 = LOWDUTY; //设置定时初值
TH0 = LOWDUTY>>8; //设置定时初值
P20=0;//输出低电位
}
}
---------------------------------------------------------------------------------------------------------------------------
//用定时器计算方式模拟PWM,高低电平容易控制
//缺点:这种方法周期能做到1KHz以内,大多数马达或调光设置会闪烁
#include "reg51.h"
#include<intrins.h>
sfr P0M1 = 0x93;
sfr P0M0 = 0x94;
sfr P1M1 = 0x91;
sfr P1M0 = 0x92;
sfr P2M1 = 0x95;
sfr P2M0 = 0x96;
sfr P3M1 = 0xb1;
sfr P3M0 = 0xb2;
sfr P4M1 = 0xb3;
sfr P4M0 = 0xb4;
sfr P5M1 = 0xC9;
sfr P5M0 = 0xCA;
sfr P6M1 = 0xCB;
sfr P6M0 = 0xCC;
sfr P7M1 = 0xE1;
sfr P7M0 = 0xE2;
sfr AUXR = 0x8e;//辅助寄存器
sbit P20 = P2^0; //PWM输出脚
sbit P17 = P1^7; //按键增量
sbit P16 = P1^6; //按键减少
unsigned char num;//记录分辩个数
void Delayms(unsigned int ms) //1mS@11.0592MHz
{unsigned char i, j;
while(ms--)
{ _nop_();
_nop_();
_nop_();
i = 11;
j = 190;
do
{
while (--j);
} while (--i);}
}
void main()
{ P0M0 = 0x00;
P0M1 = 0x00;
P1M0 = 0x00;
P1M1 = 0x00;
P2M0 = 0x00;
P2M1 = 0x00;
P3M0 = 0x00;
P3M1 = 0x00;
AUXR = 0x80; //定时器0为1T模式
TMOD &= 0xf0; //设置定时器0为模式0(16位自动重装载)
TR0 = 1; //定时器0开始计时
ET0 = 1; //使能定时器0中断
EA = 1;
num=10; //给初始值
while (1)
{
if(!P17)
{
Delayms(10);
if(!P17)
{
num++;
}
}
if(!P16)
{
Delayms(10);
if(!P16)
{
num--;
}
}
}
}
void tm0() interrupt 1//定时器0中断服务程序
{ static unsigned char k;
TL0 = 0xF5; //设置定时初值 按1T时钟计算,1uS一次
TH0 = 0xFF; //设置定时初值 按1T时钟计算,1uS一次
k++;
if(k>num)P20=1;//输出高电位
else P20=0;//输出低电位
}
|