刚刚搜了一下,发现坛里还没有这样分析PWM的帖子,然后发了一个。
手电LED控制或马达转速控制都离不开PWM,下面有两种方法可以模拟PWM的。如果不正确希望各位指教。
//用定时器装载方式模拟PWM,这种方法PWM周期短,分辩率高,1毫秒内可以做到11000格分辩率,
//缺点:高低电平会的百分之一格不受控制
#include "reg51.h"
#include
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
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;//输出低电位
}
上一篇:51单片机(STC15W408AS)映射printf函数 串口收发实现
下一篇:基于51单片机的PID控制的DC/DC电路仿真+程序设计
推荐阅读最新更新时间:2024-11-19 21:14
设计资源 培训 开发板 精华推荐
- LT1764AET-1.8 并联 LDO 稳压器以实现更高输出电流的典型应用
- LTC3723EGN-1 演示板,隔离式电源,Vin = 36 - 72V,Vout1 = 3.3V @ 40A,Vout2 = 2.5V @ 10A
- 使用 LTC3637HMSE 4V 至 64V 输入至 -12V 输出正负稳压器的典型应用
- LT3970IMS 12V 降压转换器的典型应用
- F-51405 LCD 显示驱动器,外部电源和使用内部稳压器
- ESP8266 测速器
- 使用 MaxLinear, Inc 的 SPX385AM1-1.2 的参考设计
- 使用 NXP Semiconductors 的 TDA8927 的参考设计
- ADR420 超精密、低噪声、5.00 Vout XFET 电压基准的典型应用
- MIC2043-2YM 单通道、大电流、低电压、受保护配电开关的典型应用