刚刚搜了一下,发现坛里还没有这样分析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-13 10:04
设计资源 培训 开发板 精华推荐
- 使用 Semtech 的 LP2951A 的参考设计
- 具有基准的 LT1086CT-5 低压差稳压器的典型应用
- LTM4650IY-1A 的典型应用电路 典型 4.5 至 15 Vin、1.5V 和 1.2V at 25A 输出降压稳压器
- 使用无线MCU AXM0F243将RF收发器参考设计调整为868 MHz
- EVAL-AD7687CB,用于评估 AD7687BRM 16 位、250 K 高分辨率 ADC 的评估板
- EVAL-ADXL375Z-S,用于评估 ADXL375 3 轴 ±200 g 数字加速度计的评估板
- DAP-Link_V2.0
- 使用 8MHz MCU 器件的无传感器三相无刷电机控制应用电路
- 使用 Analog Devices 的 RREF02 的参考设计
- 指纹开门