用STC15W404AS单片机的方波发生器程序.docx
《用STC15W404AS单片机的方波发生器程序.docx》由会员分享,可在线阅读,更多相关《用STC15W404AS单片机的方波发生器程序.docx(16页珍藏版)》请在冰豆网上搜索。
用STC15W404AS单片机的方波发生器程序
/**************************************************
**方波发生器程序朱铮南编写
**单片机STC15W404AS方波输出端P1.1时钟频率20MHz
**F<80KHz占空比80%--20%
**F>80KHz占空比50%
**占空比分辨率:
1%
**方波频率分辨率:
**0--999Hz1Hz
**1KHz--9.99KHz0.01KHz
**10KHz--99.9KHz0.1KHz
**100KHz--200KHz1KHz
**设定的频率和占空比保存在EEPROM,不会丢失
**频率保存在第一扇区,占空比保存在第二扇区
**外部中断0--3,分别用于频率增减和占空比增减
**************************************************/
#include
#include
#defineucharunsignedchar
#defineuintunsignedint
#defineulongunsignedlong
ulongfreq;//Hz,输出方波频率
ucharduty;//%,占空比
sbitint0=P3^2;//输出频率增
sbitint1=P3^3;//输出频率减
sbitint2=P3^6;//输出占空比增
sbitint3=P3^7;//输出占空比减
sbitD7=P1^5;//1602数据线
sbitD6=P1^4;
sbitD5=P1^3;
sbitD4=P1^2;
sbitRS=P5^4;//1602数据/命令选择端
sbitEN=P5^5;//1602使能信号端
//RW接地
uchartable0[]="F:
0000Hz";
uchartable1[]="D:
00%";
/**************************************************
**延时1ms
**************************************************/
voiddelay1ms(ucharx)//@20.000MHz
{
uchari,j;
do
{
i=113;
j=20;
do
{
while(--i);
}while(--j);
}while(--x);
}
/**************************************************
**向LCD1602写指令或数据
**************************************************/
voidlcd_write(ucharcom,date)//com=0则写指令,com=1则写数据
{
delay1ms(3);
RS=com;
EN=1;
D7=date>>7;
D6=date>>6&0x1;
D5=date>>5&0x1;
D4=date>>4&0x1;
EN=0;//RW=0,EN从1跳到0时LCD1602执行写入
delay1ms(3);
EN=1;
D7=date>>3&0x1;
D6=date>>2&0x1;
D5=date>>1&0x1;
D4=date&0x1;
EN=0;
}
/**************************************************
**LCD1602初始化
**************************************************/
voidlcd_init(void)
{
lcd_write(0,0x28);
EN=1;//四线时没有这两行会乱码
EN=0;
lcd_write(0,0x28);
lcd_write(0,0x28);
lcd_write(0,0x0c);//显示开,无光标
}
/**************************************************
**LCD1602显示
**************************************************/
voidlcd_display(void)
{
uchari;
if(freq<=9)
{
table0[3]=freq+'0';
table0[4]='';
table0[5]='H';
table0[6]='z';
table0[7]='';
table0[8]='';
table0[9]='';
table0[10]='';
}
else
{
if(freq<=99)
{
table0[3]=freq/10+'0';
table0[4]=freq%10+'0';
table0[5]='';
table0[6]='H';
table0[7]='z';
table0[8]='';
table0[9]='';
table0[10]='';
}
else
{
if(freq<=999)
{
table0[3]=freq/100+'0';
table0[4]=freq%100/10+'0';
table0[5]=freq%10+'0';
table0[6]='';
table0[7]='H';
table0[8]='z';
table0[9]='';
table0[10]='';
}
else
{
table0[7]='';
table0[8]='K';
table0[9]='H';
table0[10]='z';
if(freq<=9999)
{
table0[3]=freq/1000+'0';
table0[4]='.';
table0[5]=freq%1000/100+'0';
table0[6]=freq%100/10+'0';
}
else
{
if(freq<=99999)
{
table0[3]=freq/10000+'0';
table0[4]=freq%10000/1000+'0';
table0[5]='.';
table0[6]=freq%1000/100+'0';
}
else
{
table0[3]=freq/100000+'0';
table0[4]=freq%100000/10000+'0';
table0[5]=freq%10000/1000+'0';
table0[6]='';
table0[7]='K';
table0[8]='H';
table0[9]='z';
table0[10]='';
}
}
}
}
}
table1[3]=duty/10+'0';
table1[4]=duty%10+'0';
lcd_write(0,0x00|0x80);//指定第一行的位置
for(i=0;i<11;i++)lcd_write(1,table0[i]);//写入第一行
lcd_write(0,0x40|0x80);//指定第二行的位置
for(i=0;i<7;i++)lcd_write(1,table1[i]);//写入第二行
}
/**************************************************
**频率写入EEPROM
**************************************************/
voidf_write(ulongdat)
{
uchari;
IAP_CMD=3;//擦除命令
IAP_ADDRL=0x0000;//擦除扇区的地址
IAP_ADDRH=0x0000>>8;
IAP_TRIG=0x5A;//激活命令
IAP_TRIG=0xA5;
IAP_CMD=2;//写入命令
for(i=0;i<3;i++)
{
switch(i)
{
case2:
IAP_DATA=dat;break;//要写入的数据
case1:
IAP_DATA=dat>>8;break;
case0:
IAP_DATA=dat>>16;
}
IAP_ADDRL=0x0000+i;//写入的地址
IAP_ADDRH=(0x0000+i)>>8;
IAP_TRIG=0x5A;//激活命令
IAP_TRIG=0xA5;
}
}
/**************************************************
**从EEPROM读出频率
**************************************************/
voidf_read(void)
{
uchari;
IAP_CMD=1;//读出命令
for(i=0;i<3;i++)
{
IAP_ADDRL=0x0000+i;//写入的地址
IAP_ADDRH=(0x0000+i)>>8;
IAP_TRIG=0x5A;//激活命令
IAP_TRIG=0xA5;
_nop_();
freq=freq<<8|IAP_DATA;//将读出的数据存入频率
}
}
/**************************************************
**占空比写入EEPROM
**************************************************/
voidd_write(uchardat)
{
IAP_CMD=3;//擦除命令
IAP_ADDRL=0x0200;//擦除扇区的地址
IAP_ADDRH=0x0200>>8;
IAP_TRIG=0x5A;//激活命令
IAP_TRIG=0xA5;
IAP_CMD=2;//写入命令
IAP_DATA=dat;//要写入的数据
IAP_ADDRL=0x0200;//写入的地址
IAP_ADDRH=0x0200>>8;
IAP_TRIG=0x5A;//激活命令
IAP_TRIG=0xA5;
}
/**************************************************
**从EEPROM读出占空比
**************************************************/
voidd_read(void)
{
IAP_CMD=1;//读出命令
IAP_ADDRL=0x0200;//读出的地址
IAP_ADDRH=0x0200>>8;
IAP_TRIG=0x5A;//激活命令
IAP_TRIG=0xA5;
_nop_();
duty=IAP_DATA;//将读出的数据存入占空比
}
/**************************************************
**初始化定时器0
**************************************************/
voidinit_time0(uchari)//@20MHz1T
{
AUXR|=0x80;//定时器0时钟工作在1T模式
TMOD&=0xF0;//设置定时器0工作在16位自动重载模式
switch(i)
{
case1:
//20MHz
{
TL0=0xFF;
TH0=0xFF;
}break;
case2:
//2MHz
{
TL0=0xF6;
TH0=0xFF;
}break;
case3:
//200KHz
{
TL0=0x9C;
TH0=0xFF;
}break;
case4:
//20KHz
{
TL0=0x18;
TH0=0xFC;
}
}
TR0=1;//定时器0开始计时
}
/**************************************************
**主函数
**************************************************/
voidmain(void)
{
ulongS_freq;//PCA计数源频率
ulongcycle;//输出方波的周期
uintplus;//输出方波的正半周
uintminus;//输出方波的负半周
uintV;//存放正负半周的临时变量
bitj=1;//输出方波的正负半周标志
uchark;//传递给初始化定时器0函数的实参
lcd_init();//1602初始化
EA=1;//中断总开关开
CMOD=0x04;//PCA计数源选定为定时器0的溢出
IT0=1;//外部中断0下降沿触发
IT1=1;//外部中断1下降沿触发
EX0=1;//允许外部中断0
EX1=1;//允许外部中断1
INT_CLKO|=0x30;//允许外部中断2、3
IAP_CONTR=0x82;//允许对EEPROM读写
d_read();//从EEPROM读出占空比
f_read();//从EEPROM读出频率
if(freq>80000)duty=50;
lcd_write(0,0x01);//清屏
lcd_display();//显示
//选择定时器0的溢出频率,保证输出方波周期在65535内
if(freq>=306){k=1;S_freq=20000000;}
if(freq<306&&freq>=31){k=2;S_freq=2000000;}
if(freq<31&&freq>=4){k=3;S_freq=200000;}
if(freq<4){k=4;S_freq=20000;}
init_time0(k);//初始化定时器0
cycle=S_freq/freq;//输出方波周期
plus=cycle*duty/100;//计算正半周值。
第一步cycle*=duty
//第二步cycle/=100,
//第三步plus=cycle,
//从第一步看出cycle必须是long类型
minus=cycle-plus;//负半周值
V=plus;
CCAP0L=V;//置正半周值
CCAP0H=V>>8;
CCAPM0=0x4C;//使能CCP0的比较、匹配、翻转
CL=0;//置PCA计数器初值
CH=0;
CR=1;//启动PCA计数器
while
(1)
{
if(CCF0)//要在短的半周内执行完以下代码
//(约占计数源40T),PWM才能产生
//50KHz时,极限占空比是10%。
//50KHz-70KHz时,占空比可以是15%。
//80KHz时,极限占空比是20%。
//占空比50%时,最高可输出200KHz。
{
j=~j;
if(j)V+=plus;//交替递增正半周和负半周的值
elseV+=minus;
CCAP0L=V;
CCAP0H=V>>8;
CCF0=0;
}
}
}
/**************************************************
**外部中断0(输出频率增)
**************************************************/
voidInt0_Routine(void)interrupt0
{
while(!
int0)//频率递增
{
if(freq<=999)freq+=1;
else
{
if(freq<=9999)freq+=10;
else
{
if(freq<=99999)freq+=100;
elseif(freq<200000)freq+=1000;
}
}
lcd_display();//显示
delay1ms(250);//延时1秒
delay1ms(250);
delay1ms(250);
delay1ms(250);
while(!
int0)//1秒后转成快速递增
{
if(freq<=999)freq+=5;
else
{
if(freq<=9999)freq+=50;
else
{
if(freq<=99999)freq+=500;
elseif(freq<200000)freq+=1000;
}
}
lcd_display();//显示
}
}
f_write(freq);//写入EEPROM
IAP_CONTR=0x20;//单片机软复位
}
/**************************************************
**外部中断1(输出频率减)
**************************************************/
voidInt1_Routine(void)interrupt2
{
while(!
int1)//频率递减
{
if(freq>100000)freq-=1000;
else
{
if(freq>10000)freq-=100;
else
{
if(freq>1000)freq-=10;
elseif(freq>1)freq-=1;
}
}
lcd_display();//显示
delay1ms(250);//延时1秒
delay1ms(250);
delay1ms(250);
delay1ms(250);
while(!
int1)//1秒后转成快速递减
{
if(freq>100000)freq-=1000;
else
{
if(freq>10000)freq-=500;
else
{
if(freq>1000)freq-=50;
else
{
if(freq>100)freq-=5;
elseif(freq>1)freq-=1;
}
}
}
lcd_display();//显示
}
}
f_write(freq);//写入EEPROM
IAP_CONTR=0x20;//单片机软复位
}
/**************************************************
**外部中断2(输出占空比增)
**************************************************/
voidInt2_Routine(void)interrupt10
{
while(!
int2)
{
if(duty<80)duty+=1;//占空比递增
lcd_display();//显示
delay1ms(250);
}
d_write(duty);//写入EEPROM
IAP_CONTR=0x20;//单片机软复位
}
/**************************************************
**外部中断3(输出占空比减)
**************************************************/
voidInt3_Routine(void)interrupt11
{
while(!
int3)
{
if(duty>20)duty-=1;//占空比递减
lcd_display();//显示
delay1ms(250);
}
d_write(duty);//写入EEPROM
IAP_CONTR=0x20;//单片机软复位
}