基于AT89S52单片机的双路频率计的程序源码
#include <REG51.H>#include<INTRINS.H>
#define uchar unsigned char
#define uint unsigned int
uint time1=0,time2=0,frequency1=0,frequency2=0;
uint test_error1,test_error2,test_button;
uchar Fw,Fq,Fb,Fs,Fg;
#define DataPort P0 //定义液晶数据传输口
sbit LCM_RS=P1^0; //定义液晶显示控制口
sbit LCM_RW=P1^1;
sbit LCM_EN=P1^2;
sbit Switch_button1=P1^3; //定义第一路频率计开关控制口
sbit Switch_button2=P1^4; //定义第二路频率计开关控制口
uchar code Welcome_str[]={"--Welcome!-- "};
uchar code Startcommand_str[]={"Switch--Start! "};
uchar code Error_str[]={"Error! "};
uchar code Freq_str[]={" Freq1 Freq2 "};
uchar code Hz_str[]={"00000Hz 00000Hz"};
/**********************************************************
函数名:Delay5ms
功能:延时约5ms
参数:无
返回值:无
***********************************************************/
void Delay5ms(void)
{
uint i=2000;
while (i !=0)
{i--;}
}
/**********************************************************
/**********************************************************
函数名:Wait_Enable
功能:等待1602液晶完成内部操作
参数:无
返回值:无
***********************************************************/
void Wait_Enable(void)
{
DataPort=0xff; //DataPort=11111111切换PO口为输入状态
LCM_RS=0; //RS为低电平,RW为高电平时才可以读忙信号
LCM_RW=1;
_nop_();
LCM_EN=1;
_nop_();
_nop_();
while(DataPort&0x80){}; //相与等于0,说明BF为0,不忙;等于1,BF=1,忙碌
LCM_EN=0; //判断忙碌之后,置位EN=0,液晶不执行任何操作
}
/**********************************************************
函数名:Write_Command
功能:向液晶模块写入命令
参数:cmd--命令
chk--是否判忙的标志,1:判忙,0:不判
返回值:无
***********************************************************/
void Write_Command(uchar cmd,uchar chk)
{
if(chk)Wait_Enable();
LCM_RS=0; //当RS和RW都为低电平时才可以写入指令或者显示地址
LCM_RW=0;
_nop_();
DataPort=cmd; //将命令置入数据总线
_nop_();
LCM_EN=1;
_nop_();
_nop_();
LCM_EN=0; //EN由高电平到低电平,液晶执行写指令操作
}
/**********************************************************
函数名:Write_Data
功能:向液晶显示的当前地址写入显示数据
参数:data--显示字符数据
返回值:无
***********************************************************/
void Write_Data (uchar datas)
{
Wait_Enable();
LCM_RS=1; //RS高电平,RW低电平时可以写入数据
LCM_RW=0;
_nop_();
DataPort=datas; //置数据到数据总线
_nop_();
LCM_EN=1;
_nop_();
_nop_();
LCM_EN=0;
}
/**********************************************************
函数名:void InitLcd()
功能:对LCD1602进行初始化
参数:无
返回值:无
**********************************************************/
void InitLcd()
{
Write_Command(0x3c,1); //设置显示模式:8位2行5*7点阵
Write_Command(0x08,1); //显示器关,不显示光标,光标不闪烁
Write_Command(0x01,1); //清屏并光标复位
Write_Command(0x06,1); //文字不动,光标自动右移
Write_Command(0x0c,1); //显示开,不开光标,不闪烁
}
/**********************************************************
函数名:void DisplayOneChar(uchar X,uchar Y,uchar Data)
功能:在指定位置第y行第x列显示一个字符
参数:X--列坐标 Y--行坐标 Data--欲显示字符
返回值:无
**********************************************************/
void DisplayOneChar(uchar X,uchar Y,uchar Datas)
{
Y&=1;
X&=15;
if(Y)X|=0x40;
X|=0x80;
Write_Command(X,0);
Write_Data(Datas);
}
/**********************************************************
函数名:void DisplayListChar(uchar X,uchar Y,uchar code *Data
功能:以起始位置第Y行第X列开始显示一串字符
参数:X--起始列坐标 Y--起始行坐标 Data--欲显示字符串首地址
返回值:无
**********************************************************/
void DisplayListChar(uchar X,uchar Y,uchar code *Datas)
{
uchar ListLength=0;
Y&=0x1;
X&=0xF;
while(X<=15)
{
DisplayOneChar(X,Y,Datas[ListLength]);
ListLength++;
X++;
}
}
/**********************************************************
函数名:void display()
功能:提取欲显示数字各位送显示
参数:k--欲显示的行 kk--显示的最后一位列地址
返回值:无
**********************************************************/
void display(uint count ,uint k )
{
Fw=count/10000+0x30; //提取万位
Fq=count/1000%10+0x30; //提取千位
Fb=count/100%10+0x30; //提取百位
Fs=count/10%10+0x30; // 提取十位
Fg=count%10+0x30; //提取个位
DisplayOneChar(k,1,Fg);
DisplayOneChar(--k,1,Fs);
DisplayOneChar(--k,1,Fb);
DisplayOneChar(--k,1,Fq);
DisplayOneChar(--k,1,Fw);
}
/********************************************************
函数名:void Set_singlechip(void)
功能: 单片机中断设置
参数:无
返回值:无
**********************************************************/
void Set_singlechip(void)
{
TCON=0x05; //外中断INT0、INT1工作于下跳沿触发方式
TMOD=0x11; //定时计数器T0、T1工作在16位定时器方式
EA=1; //设置CPU开放中断
ET0=1;ET1=1; //定时器T0、T1中断允许
PT0=1;PT1=1; //设定定时器T0、T1为高优先级
}
/*********************************************************
函数名:void Set_Interrupt(void)
功能:根据二路测频开关开闭情况对对应中断与定时器设置
参数:无
返回值:无
***********************************************************/
void Set_Interrupt(void)
{
if((Switch_button1==0)&(Switch_button2==1))
{
EX0=1;TR0=1;
EX1=0;TR1=0;
}
else if((Switch_button1==1)&(Switch_button2==0))
{
EX1=1;TR1=1;
EX0=0;TR0=0;
}
else if((Switch_button1==0)&(Switch_button2==0))
{
EX1=1;TR1=1;
EX0=1;TR0=1;
}
else if((Switch_button1==1)&(Switch_button2==1))
{
while(1){;}
}
}
/**********************************************************
函数名:void Interrupt_counter1(void)small interrupt 0
功能:外中断INT0服务模块,进入中断则计数单元加一
参数:无
返回值:无
**********************************************************/
void Interrupt_counter1(void)small interrupt 0
{
frequency1+=1;
if(frequency1==0)test_error1+=1;
}
/**********************************************************
函数名:void Interrupt_counter2(void)small interrupt 2
功能:外中断INT1服务模块,进入中断则计数单元加一
参数:无
返回值:无
**********************************************************/
void Interrupt_counter2(void)small interrupt 2
{
frequency2+=1;
if(frequency2==0)test_error2+=1;
}
/**********************************************************
函数名:void Interrupt_timer1(void)small interrupt 1
功能:让定时器T0以10000us每次工作100次,总定时1s
参数:无
返回值:无
**********************************************************/
void Interrupt_timer1(void)small interrupt 1
{
if(time1>100)
{
TR0=0;
EX0=0;
if(test_error1)
{
test_error1=0;
DisplayListChar(0, 1,Error_str);
}
else
{
frequency1=((uint)(((float)frequency1)/1024.0*1000.0))+1;
display(frequency1,4);
TH0=0xD8;TL0=0xF0;
time1=0;
frequency1=0;
Set_Interrupt();
}
}
else
{
TH0=0xD8;TL0=0xF0;
time1++;
}
}
/**********************************************************
函数名:void Interrupt_timer2(void)small interrupt 3
功能:让定时器T1以10000us每次工作100次,总定时1s
参数:无
返回值:无
**********************************************************/
void Interrupt_timer2(void)small interrupt 3
{
if(time2>100)
{
TR1=0;
EX1=0;
if(test_error2)
{
test_error2=0;
DisplayListChar(9, 1,Error_str);
}
else
{
frequency2=((uint)(((float)frequency2)/1024.0*1000.0))+1;
display(frequency2,13);
TH1=0xD8;TL1=0xF0;
time2=0;
frequency2=0;
Set_Interrupt();
}
}
else
{
TH1=0xD8;TL1=0xF0;
time2++;
}
}
/**********************************************************
函数名:void main(void)
作用:主函数
**********************************************************/
void main(void)
{
InitLcd(); //LCD初始化设置
DisplayListChar(2,0,Welcome_str); //显示“欢迎”界面
DisplayListChar(1,1,Startcommand_str); //显示“开启记数”提示
Set_singlechip(); //单片机中断设置
TH0=0xD8;TL0=0xF0; //定时器装入初值
TH1=0xD8;TL1=0xF0;
while((Switch_button1==1)&(Switch_button2==1)){;} //等待计数开关开启
InitLcd(); //液晶复位
DisplayListChar(0,0,Freq_str);
DisplayListChar(0,1,Hz_str);
Set_Interrupt();
while(1){;}
}
电路图见附件
[[it] 本帖最后由 hlmzrdongdong 于 2008-10-24 23:14 编辑 [/it]]