一:电路原理和器件选择
制作电路:单片机(AT89S52)实现多功能数字钟
性能指标:该数字钟实现时钟运行,调整,倒计时,秒表功能,且精确度经调试一天的误差在2S内。
实现原理:利用单片机定时器及计数器产生定时效果通过编程形成数字钟效果,再利用数码管动态扫描显示单片机内部处理的数据。同时通过端口读入当前外部控制状态来改变程序的不同状态,实现不同功能。
电路主要模块及原理图:
1.数码显示硬件驱动
数码管驱动电路
2.单片机最小系统:
单片机最小系统
3.LED及单片机电源原理图
LED及单片机电源
4.外部控制状态输入模块原理图
外部控制状态输入模块原理图
主要元器件选择:
单片机:AT89S52采用市场上比较常用的AT89S52,这里采用AT89S52而不是AT89S51是为了最大限度减小误差,因为要实现多功能(例如秒表,时钟,倒计时)为了相互之间不干扰而要用到3个定时/计数器,而51系列只有2个,而52系列有3个,故采用52系列
三极管:用来进行数码管显示的位选,这里采用PNP管
数码管:采用共阳级四位数码管
晶振:采用的是11.0592MHZ的晶振
电源部分:采用5V电压供电,采用的是L7805稳压芯片供电(加滤波)
电阻:大部分时限流电阻,阻值为4.7K或10K,1K
端口分配及连接:
P0:LED数码管显示内容通过P1口从单片机传送到数码管
P2.4-P2.7:数码管位选控制端口
P2.0-P2.3:分别连接开关K0,K1,K2,K3通过不同的组合实现外部控制程序状态
P1.0:蜂鸣器,倒计时完毕产生鸣响
P1.2-P1.5:四个发光二极管,显示当前时钟状态
完整的源程序如下:
附程序源代码及注释
#include <reg52.h>
#include <absacc.h>
#define uint unsigned int
#define uchar unsigned char
/*定义P2口各管脚*/
sbit K0=P2^2;
sbit K1=P2^1;
sbit K2=P2^0;
sbit K3=P2^3;
sbit D0=P2^4;
sbit D1=P2^5;
sbit D2=P2^6;
sbit D3=P2^7;
/*定义P1口各管脚*/
sbit beep=P1^0;
sbit L0=P1^5;
sbit L1=P1^4;
sbit L2=P1^3;
sbit L3=P1^2;
uchar data BUFFER[4]={0,0,0,0}; //显示缓冲区(依次从低位到高位,共四位数码管)
uchar data CLOCK[4]={0,0,0,0}; //存放时钟时间(依次是百分秒,秒,分,时)
uchar data SECOND[3]={0,0,0}; //存放秒表时间(依次时百分秒,秒,分)
uchar data SEVER[4]={0,0,0,0}; //存放倒计时时间(依次是百分秒,秒,分,时)
/*定义程序运行状态*/
uchar data STATE=0;
/*STATE=0;时钟运行*/
/*STATE=1;时钟分调整*/
/*STATE=2;未定义状态,可添加*/
/*STATE=3;时钟时调整*/
/*STATE=4;倒计时分调整*/
/*STATE=5;倒计时时调整*/
/*STATE=6;秒表*/
/*STATE=7;倒计时运行*/
/*定义辅助计时全局变量*/
uchar m=60;
/*共阳数码管显示"0"-"9","-" */
uchar code TABLE[]={0xC0,0xf9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x98,0xbf};
/*自定义子函数*/
void display(); //显示函数
void delay(); //显示延时函数
void intsvr(); //调整时间时加1子函数
void delay10ms(); //延时函数
/*主函数体*/
void main(void)
{
EA=1;ET0=1; //开总中断源,开T0中断
TMOD=0x61; //T1方式2计数,T0方式1计时
TH0=-9460/256;TL0=-9460%256; //初始化计数器初值
TH1=0xff;TL1=0xff;
T2CON=0;TH2=-9452/256;TL2=-9452%256;
K0=1;K1=1;K2=1; //初始化控制状态位
STATE=P2&0x07;
for(;;)
{
switch(STATE)
{
case 1: //时钟分调整程序
{
TR0=0;ET0=0;EX0=0;TR2=0; //关闭定时器,时钟停止运行,同时关闭外中断IT0
L3=0;L1=0;L2=0;L0=1;
intsvr(); //调用加1函数
BUFFER[0]=CLOCK[2]%10; //数码管显示分钟个位
BUFFER[1]=CLOCK[2]/10; //数码管显示分钟十位
BUFFER[2]=10; //显示"-"
BUFFER[3]=10; //显示"-"
}break;
case 3: //时钟时调整程序
{
TR0=0;ET0=0;EX0=0;TR2=0; //关闭定时器,时钟停止运行
L3=0;L1=0;L2=0;L0=1;
intsvr(); //调用加1函数
BUFFER[0]=CLOCK[2]%10; //数码管显示分钟个位
BUFFER[1]=CLOCK[2]/10; //数码管显示分钟十位
BUFFER[2]=CLOCK[3]%10; //数码管显示时钟个位
BUFFER[3]=CLOCK[3]/10; //数码管显示时钟十位
}break;
case 4: //倒计时分钟调整程序
{
TR0=1;ET0=1;EX0=0;TR2=0; //保持T0正常运行,即时钟正常运行,同时关闭外中断IT0
L3=0;L2=0;L1=0;
intsvr(); //调用加1函数
BUFFER[0]=SEVER[2]%10; //数码管显示分钟个位
BUFFER[1]=SEVER[2]/10; //数码管显示分钟十位
BUFFER[2]=10; //显示"-"
BUFFER[3]=10; //显示"-"
SECOND[1]=0; //秒表初始化为0
SECOND[2]=0;
}break;
case 5: //倒计时时钟调整程序
{
TR0=1;ET0=1;EX0=0;TR2=0; //保持T0正常运行,即时钟正常运行,同时关闭外中断IT0
L3=0;L2=0;L1=0;
intsvr(); //调用加1子函数
BUFFER[0]=SEVER[2]%10; //数码管显示分钟个位
BUFFER[1]=SEVER[2]/10; //数码管显示分钟十位
BUFFER[2]=SEVER[3]%10; //数码管显示时钟个位
BUFFER[3]=SEVER[3]/10; //数码管显示时钟十位
SECOND[1]=0; //秒表初始化为0
SECOND[2]=0;
}break;
case 6:
{
TR0=1;ET0=1;EX0=1;ET2=1;//保持T0正常运行,即时钟正常运行,同时开外中断IT0
BUFFER[0]=SECOND[1]%10; //数码管显示秒表秒个位
BUFFER[1]=SECOND[1]/10; //数码管显示秒表秒十位
BUFFER[2]=SECOND[2]%10; //数码管显示秒表分个位
BUFFER[3]=SECOND[2]/10; //数码管显示秒表分十位
}break;
case 7:
{
TR0=1;ET0=1;EX0=0;ET2=1; //倒计时运行,同时时钟也正常运行,关闭外中断T0
if((SEVER[2]==0)&&(SEVER[3]==0)) //当预置时间(分,时)变为0时,计时完毕
{
beep=!beep; //蜂鸣器响
BUFFER[0]=10; //显示"-"
BUFFER[1]=10;
BUFFER[2]=10;
BUFFER[3]=10;
TR2=0; //关闭T2
}
else
{
TR2=1; //开启T2
}
SECOND[1]=0; //秒表时间初始化
SECOND[2]=0;
}break;
default:
{
ET0=1;TR0=1;EX0=0; //开启T0,时钟运行,关闭外中断
L1=1;L3=1;L2=1;
BUFFER[0]=CLOCK[2]%10; //数码管显示分钟个位
BUFFER[1]=CLOCK[2]/10; //数码管显示分钟十位
BUFFER[2]=CLOCK[3]%10; //数码管显示时钟个位
BUFFER[3]=CLOCK[3]/10; //数码管显示时钟十位
}
}
K0=1;K1=1;K2=1; //重新预置状态位
display(); //调用显示函数
STATE=P2&0x07; //通过P2口提取当前状态
}
}
/*T0中断服务*/
void time0(void) interrupt 1 using 1 //T0中断函数
{
TH0=-9460/256; //计时器放入预置时间,大概10毫秒
TL0=-9460%256;
CLOCK[0]=CLOCK[0]+1; //一次中断加1
if(CLOCK[0]==50) //0.5秒到
{
L0=!L0; //L0取反
}
if(CLOCK[0]==100) //1秒到