2014 4 6
/*主函数:
功能描述: 利用AT89S51单片机的T0、T1的定时计数器功能,来完成对输入的信号进行
频率计数,计数的频率结果通过8位动态数码管显示出来。要求能够对0-250KHZ
的信号频率进行准确计数,计数误差不超过±hz
程序设计内容:
1)定时/计数器T0和T1的工作方式设置,由图可知,T0是工作在计数状态下,
对输入的频率信号进行计数,当T/C工作在定时器时,计数脉冲来自外部脉冲
输入管脚T0(P3。4)或T1(P3。5),当T0或T1产生负跳变时计数器加1。识别
管脚的负跳变需要两个机器周期,即24个振荡周期。所以,以T0或T1脚输入的
可计数外部脉冲的最高频率为1/24Fosc。但对工作在计数状态下的T0,
最大计数值为fOSC/24,由于fOSC=12MHz 因此:T0的最大计数频率为500KHz?
高于此频率将出错。
对于频率的概念就是在一秒只数脉冲的个数,即为频率值
所以T1工作在定时状态下,每定时1秒钟到,就停止T0的计数,
而从T0的计数单元中读取计数的数值,然后进行数据处理。
送到数码管显示出来。
2)T1工作在定时状态下,最大定时时间为65ms,达不到1秒的定时,
*/
//;==================================================================================
//;主程序开始
//;==================================================================================
#include<reg52.h>
#include<absacc.h>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char
extern const uchar NoDisp=0; //无显示
extern const uchar NoCur=1; //有显示无光标
extern const uchar CurNoFlash=2; //有光标但不闪烁
extern const uchar CurFlash=3; //有光标且闪烁
extern void LcdPos(uchar,uchar); //确定光标位置
extern void LcdWd(uchar); //写字符
extern void LcdWc(uchar); //送控制字(检测忙信号)
extern void LcdWcn(uchar ); //送控制字子程序(不检测忙信号)
extern void mDelay(uchar ); //延时,毫秒数由j决定
extern void WaitIdle(void); //正常读写操作之前检测LCD控制器状态
extern void RstLcd(void); //复位LCD控制器
extern void WriteChar(uchar c,uchar xPos,uchar yPos);//在指定的行与列显示指定的字符,xpos:行,ypos:列,c:待显示字符
extern void WriteString(uchar *s,uchar xPos,uchar yPos);
extern void SetCur(uchar Para); //设置光标
extern void ClrLcd(void); //清屏命令
extern void WaitIdle(void); // 正常读写操作之前检测LCD控制器状态
extern void mDelay(uchar j);
#include <reg52.h>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char
sbit RS=P3^5;
sbit RW=P3^6;
sbit EN=P3^7;
#define DPORT P2
unsigned char code table1[]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39};//0123456789
//unsigned char code table2[]={0x41,0x42,0x43,0x44,0x45,0x46};//abcdef
uchar *s=" CYMOMETER ";
uchar *s1="FREQ: Hz ";
uchar T0count; //从T0的计数单元中读取计数的数值
uchar timecount; //
bit flag; //标志位
unsigned long x;
uchar xPos,yPos;
uchar i;
void LcdPos(uchar,uchar); //确定光标位置
void LcdWd(uchar); //写字符
void LcdWc(uchar); //送控制字(检测忙信号)
void LcdWcn(uchar ); //送控制字子程序(不检测忙信号)
void mDelay(uchar ); //延时,毫秒数由j决定
void WaitIdle(); //正常读写操作之前检测LCD控制器状态
//在指定的行与列显示指定的字符,xpos:行,ypos:列,c:待显示字符
void WriteChar(uchar c,uchar xPos,uchar yPos)
{
LcdPos(xPos,yPos);
LcdWd(c);
}
void WriteString(uchar *s,uchar xPos,uchar yPos)
{ uchar i;
if(*s==0) //遇到字符串结束
return;
for(i=0;;i++)
{
if(*(s+i)==0)
break;
WriteChar(*(s+i),xPos,yPos);
xPos++;
if(xPos>=15) //如果XPOS中的值未到15(可显示的最多位)
break;
}
}
void SetCur(uchar Para) //设置光标
{ mDelay(2);
switch(Para)
{ case 0:
{ LcdWc(0x08); //关显示
break;
}
case 1:
{ LcdWc(0x0c); //开显示但无光标
break;
}
case 2:
{ LcdWc(0x0e); //开显示有光标但不闪烁
break;
}
case 3:
{ LcdWc(0x0f); //开显示有光标且闪烁
break;
}
default:
break;
}
}
void ClrLcd() //清屏命令
{ LcdWc(0x01);
}
// 正常读写操作之前检测LCD控制器状态
void WaitIdle()
{ uchar tmp;
RS=0;
RW=1;
EN=1;
_nop_();
for(;;)
{ tmp=DPORT;
tmp&=0x80;
if( tmp==0)
break;
}
EN=0;
}
void LcdWd(uchar c) //写字符子程序
{ WaitIdle();
RS=1;
RW=0;
DPORT=c; //将待写数据送到数据端口
EN=1;
_nop_();
_nop_();
EN=0;
}
void LcdWc(uchar c) //送控制字子程序(检测忙信号)
{ WaitIdle();
LcdWcn(c);
}
void LcdWcn(uchar c) //送控制字子程序(不检测忙信号)
{ RS=0;
RW=0;
DPORT=c;
EN=1;
_nop_();
EN=0;
}
void LcdPos(uchar xPos,uchar yPos) //设置第(xPos,yPos)个字符的DDRAM地址
{ unsigned char tmp;
xPos&=0x0f; //x位置范围是0~15
yPos&=0x01; //y位置范围是0~1
if(yPos==0) //显示第一行
tmp=xPos;
else
tmp=xPos+0x40;
tmp|=0x80;
LcdWc(tmp);
}
void RstLcd() //复位LCD控制器
{ mDelay(15); //如果使用12M或以下晶振,此数值不必改,如用24M晶振,须用30
LcdWc(0x38); //显示模式设置
LcdWc(0x08); //显示关闭
LcdWc(0x01); //显示清屏
LcdWc(0x06); //显示光标移动位置
LcdWc(0x0c); //显示开及光标设置
}
void mDelay(uchar j) //延时,毫秒数由j决定
{ uint i=0;
for(;j>0;j--)
{ for(i=0;i<124;i++)
{;}
}
}
void main(void)
{
RstLcd(); //初始化LCD
ClrLcd(); //清屏
SetCur(1); //开光标显示、闪烁
WriteString(s,0,0);
WriteString(s1,0,1);
TMOD=0x15; //T0工作为16位计数器(方式1),T1工作方式为16位定时器
TH0=0; //计数为65536
TL0=0; //
TH1=(65536-4000)/256; //定时器采用定时4ms. 初值为4000
TL1=(65536-4000)%256;
TR1=1; //TR1=1,控制开关闭合,计数脉冲进入T1计数器,启动定时
TR0=1; //TR0=1,控制开关闭合,计数脉冲进入T1计数器,启动计数
ET0=1; //定时器0开中断
ET1=1; //定时器1开中断
EA=1; //CPU开中断
while(1)
{
if(flag==1) //
{
flag=0; //清标志位
x=T0count*65536+TH0*256+TL0; //取得时间宽度参数
//LCD显示部分代码
// ;==================================================================================
LcdPos(15,1);
WriteChar(table1[x%10],11,1);
WriteChar(table1[(x/10)%10],10,1);
WriteChar(table1[(x/100)%10],9,1);
WriteChar(table1[(x/1000)%10],8,1);
WriteChar(table1[(x/10000)%10],7,1);
WriteChar(table1[(x/100000)%10],6,1);
//;==================================================================================
timecount=0;
T0count=0;
TH0=0;
TL0=0;
TR0=1; //TR0=1,控制开关闭合,计数脉冲进入T1计数器,启动计数
}
}
}
//;==================================================================================
void t0() interrupt 1 using 0 //T0中断服务
{
T0count++; //对P3.4口的脉冲进行计数
}
//;==================================================================================
void t1(void) interrupt 3 using 0 //T1中断服务
{
TH1=(65536-4000)/256; //计数初值重装载
TL1=(65536-4000)%256;
timecount++;
if(timecount==250)
{
TR0=0;
timecount=0;
flag=1; // 置标志
}
}