剛剛搜了一下,發現壇里還沒有這樣分析PWM的帖子,然后發了一個。
手電LED控制或馬達轉速控制都離不開PWM,下面有兩種方法可以模擬PWM的。如果不正確希望各位指教。
無標題.png (9.12 KB, 下載次數: 145)
下載附件
2017-3-12 17:05 上傳
IMG_20170312_163104.jpg (151.76 KB, 下載次數: 131)
下載附件
2017-3-12 17:05 上傳
//用定時器裝載方式模擬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;//輸出低電位
}
}
---------------------------------------------------------------------------------------------------------------------------
IMG_20170312_161030.jpg (135.09 KB, 下載次數: 136)
下載附件
2017-3-12 17:06 上傳
//用定時器計算方式模擬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;//輸出低電位
}
|