前日看到一篇很好的代码。有好代码就要拿出来与坛友分享嘛
程序可以利用51
单片机输出频率和占空比可调的PWM波程序。作者写的很详细,程序写的很漂亮!!!但我还是有地方不明白
现在咱们大家来探讨探讨吧!!!
我有三个问题,恳求网友不吝赐教。
1. 频率计算函数,当频率变化,计算出定时器0初值;
2. 脉宽计算函数,脉宽变化时,计算出定时器1初值;
3. 关定时器1,一定要这一步,因为定时器1的定时短于定时器0;
//------------------------------------------------------------------------------------
//程序功能简介:本程序产生15HZ~~~50KHZ的方波,并且实现频率和脉宽的独立调制,即可
//在改变频率的同时不改变脉宽,再改变脉宽的同时不改变频率;同时设置
//两个调节步长------在KEY键按下时,粗调,没有按下时,细调;
//程序思路: 本程序用到两个定时器------定时器0和定时器1,其中定时器0工作在定时方式下,
//决定方波的频率;定时器1,同样工作在定时方式下,用于设定脉宽;
//------------------------------------------------------------------------------------
#include <reg52.h>
#include <math.h>
#define uchar unsigned char
#define uint unsigned int
#define ALL 65536 //定时器工作方式1时,最大基数长度 65536;
#define F_osc 12000000 //晶振频率12M;
sbit KEY_F_UP=P0^2; //频率上调按钮;
sbit KEY_F_DOWN=P0^3; //频率下调按钮;
sbit KEY_W_UP=P0^4; //脉宽上调按钮;
sbit KEY_W_DOWN=P0^5; //脉宽下调按钮;
sbit KEY=P0^6; //粗细调节按钮-----按下为粗调,否则为细调;
sbit OUTPUT=P1^0; //波形输出;
uchar
tiMER0_H,TIMER0_L,TIMER1_H,TIMER1_L; //定时器0和定时器1的初值设置;
uchar PERCENT=50; //初始占空比;
uchar FLAG_F=0,FLAG_W=0; //频率调节标志和脉宽调制标志;
uint FREQ=50000; //初始频率;
float temp; //临时全局变量,用于数据传递;
void delay(uchar t); //延时函数,用于按键去抖;
void init(); //初始化函数,用于定时器的初始化;
void calculate_F(); //频率计算函数,当频率变化,计算出定时器0初值;
void calculate_W(); //脉宽计算函数,脉宽变化时,计算出定时器1初值;
void key_scan(); //按键扫描函数;
void timer0(); //定时器0中断函数;
void timer1(); //定时器1中断函数;
void delay(uchar t)
{
uchar i,j;
while(t--) //每个脉冲为1us
{
for(i=0;i<100;i++)
for(j=0;j<100;j++);
}
}
void calculate_F()
{
temp = ALL - F_osc/12.0/FREQ;
TIMER0_H = (uint)temp/256;
TIMER0_L = (uint)temp%256;
}
void calculate_W()
{
float TEMP;
TEMP = (1 - PERCENT/100.0)*ALL + temp*PERCENT/100.0;
TIMER1_H = (uint)TEMP/256;
TIMER1_L = (uint)TEMP%256;
}
void key_scan()
{
delay(4);
if(!KEY_F_UP) //频率上调键按下;
{
FLAG_F=1; //置标志位;
if(!KEY)
FREQ+=10;
else
FREQ++;
if(FREQ>50000)
FREQ=1;
}
else if(!KEY_F_DOWN) //频率下调键按下;
{
FLAG_F=1; //置标志位;
if(!KEY)
FREQ-=10;
else
FREQ--;
if(FREQ<1)
FREQ=50000;
}
else if(!KEY_W_UP) //脉宽上调键按下;
{
FLAG_W=1; //置标志位;
if(!KEY)
PERCENT+=5;
else
PERCENT++;
if(PERCENT>49)
PERCENT=1;
}
else if(!KEY_W_DOWN) //脉宽下调键按下;
{
FLAG_W=1; //置标志位;
if(!KEY)
PERCENT-=5;
else
PERCENT--;
if(PERCENT<1)
PERCENT=49;
}
else ;
}
void timer0() interrupt 1 //决定频率
{
TH0=TIMER0_H;
TL0=TIMER0_L;
TR1=1; //开定时器1;
OUTPUT=1;
}
void timer1() interrupt 3 //决定脉宽
{
TH1=TIMER1_H;
TL1=TIMER1_L;
TR1=0;
//关定时器1,一定要这一步,因为定时器1的定时短于定时器0;
OUTPUT=0;
}
void init()
{
TMOD=0x11; //定时器0和定时器1都工作在方式1,16位计数器;
calculate_F(); //初始为1KHZ,占空比为50%;
calculate_W();
TH0=TIMER0_H;
TL0=TIMER0_L;
TH1=TIMER1_H;
TL1=TIMER1_L;
ET0=1;
ET1=1;
EA=1;
TR0=1;
TR1=1;
}
main()
{
init();
while(1)
{
key_scan();
if(FLAG_F) //改变频率时要注意要进行脉宽的重新设置;
{
calculate_F();
calculate_W();
FLAG_F=0;
}
if(FLAG_W) // 脉宽改变,频率不改变;
{
calculate_W();
FLAG_W=0;
}
}
}
偶然间看到这段代码,我解释下面这段代码:========================================================
void calculate_F()
{
temp = ALL - F_osc/12.0/FREQ;
// 理解这段程序的关键点,在于理解时钟周期和机器周期;
// 从程序上看,这个单片机的时钟周期(即外部晶振周期)是1/(12 MHz)=1/F_osc ,而机器周期是12个时钟周期,即12/F_osc。
// 所以,如果要得到频率=FREQ的方波,必须赋予计数器一个初始值temp,然后计数器进行自加(ALL-temp)次,就有如下等式:
// (ALL-temp)*(12/F_osc)=1/FREQ,做等式变换,把temp做变量就可以得到:
// temp = ALL - F_osc/12.0/FREQ
TIMER0_H = (uint)temp/256;
TIMER0_L = (uint)temp%256;
}
void calculate_W()
{
float TEMP;
TEMP = (1 - PERCENT/100.0)*ALL + temp*PERCENT/100.0;
// 如果你理解了上面那段,这段我相信你也理解了;
TIMER1_H = (uint)TEMP/256;
TIMER1_L = (uint)TEMP%256;
}
=====================================================================
不谢!
最佳答案
评分
查看全部评分
一周热门 更多>