博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

单片机与时钟

Posted on 2011-05-02 10:11  Code_HXH  阅读(216)  评论(0)    收藏  举报
//************************************************
//					功能说明
//************************************************
/*
 *主要功能:
 *1.提供精确到1/4000秒的时间
 *2.可以自己设定时间
 *3.可以设定闹钟
 *4.支持闹钟再响
 *5.支持闹钟开启和关闭
 *接口说明:
 *1.p3.4接喇叭in接口
 *2.p3.5接口接ls377芯片的时钟口
 *3.p3.6和p3.7分别接两片ls377的锁存端
 *4.p0.0-7和d0.0-7短路
 *5.p2.0-7和s1-8短路
 *p1.0和p1.2随意接任意led灯
 */

//************************************************
//   数据预定义区域
//************************************************
#include <reg52.h>
//数据别名
#define uchar unsigned char
#define uint unsigned int
//接口别名
#define p0 P0
#define p1 P1
#define p2 P2
#define p3 P3
//端口命名
sbit led1 = P1^0;
sbit led2 = P1^1;
sbit CS1 = P3^6;
sbit CS2 = P3^7;
sbit CLK = P3^5;
sbit Buzzer = P3^4;
//全局数据
uint num,temp;
//时钟变量
uchar second=0,
minute=0,
hour=0;
//闹钟变量
sbit Con=P1^3;
uchar Chour = 0;
uchar Cminute = 3;
//秒表变量
uint Ssecond=0;
uint Centisecond=0;
uint StopSecond=0;

//************************************************
//   定义1-16的字符码显示
//************************************************
uchar code table[] = {
	0xc0,0xf9,0xa4,0xb0,
	0x99,0x92,0x82,0xf8,
	0x80,0x90,0x88,0x83,
	0xc6,0xa1,0x86,0x8e,
	0x7f,0xbf,0xff/*18*/,0xc8,/*n,19*/
	0xf8,0xf1,0xf8/*秒表所用变量*/
};

//************************************************
//   选位
//************************************************
uchar code table2[] = {
	0x7f,0xbf,0xdf,0xef,
	0xf7,0xfb,0xfd,0xfe/*0-7*/
};

//************************************************
//   函数声明区,函数请在下面查看
//************************************************
void delay2();
void Setlocalandchar(uchar wei,uchar zi);
uchar CathKey();
void showTime();
void openINT();
void FlashTime(uchar i);
void SetTime();
void SetColock();
void ShowStopWatch(uchar IsStop);
void stopwatch();
void closeINT();

//************************************************
//   主函数区
//************************************************
void main()
{
	Con=1;//闹钟默认开启
	Buzzer=0;//响铃默认关闭
	openINT();//开启中断
	while (1)
	{
		if (CathKey()==1)//关闭闹钟
		{
			Buzzer=0;
			while(CathKey()==1);
		}
		if (CathKey() == 4)//设定时间
		{
			while(CathKey() == 4);
			SetTime();
		}
		if(CathKey() == 8)//设定闹钟
		{
			while (CathKey() == 8);
			SetColock();
		}
		if (CathKey() == 6)//进入秒表模式
		{
			while(CathKey() == 6);
			stopwatch();
		}
		else
		{
			showTime();//默认显示时间
		}
	}
}

//************************************************
//   延迟函数,视觉残留
//************************************************
void delay2()
{
	uchar i,j;
	for (i = 25;i>0;i--)
		for (j = 15;j>0;j--);
}

//************************************************
//   在指定的位置上显示指定的字符
//************************************************
void Setlocalandchar(uchar wei,uchar zi)
{
	//设定位置
	P0 = table2[wei];//wei = 要放进去的为止0-7
	CLK = 0;//时钟端电平拉低
	CS2 = 0;//锁存端打开
	// 默认这时候因为电器特性,p0的值会存进锁存端里面
	CLK = 1;//时钟端电平拉低
	CS2 = 1;//锁存端关闭
	//给初值
	P0 = table[zi];//zi = 要放进去的字
	CLK = 0;//同理
	CS1 = 0;
	CLK = 1;
	CS1 = 1;
	delay2();//延迟函数,余辉效应,如不舒适,可以自行调教
}

//************************************************
//   获取键盘函数
//************************************************
uchar CathKey()
{
	uchar i;
	//软件去按键抖动
	if(p2 != 0xff)
	{
		for (i=500;i>0;i++);
		if (p2 != 0xff)
		{
			if (p2 == 0xfe)//对p2进行获取数字
			{
				return 1;
			}
			if (p2 == 0xfd)
			{
				return 2;
			}
			if (p2 == 0xfb)
			{
				return 3;
			}
			if (p2 == 0xf7)
			{
				return 4;
			}
			if (p2 == 0xef)
			{
				return 5;
			}
			if (p2 == 0xdf)
			{
				return 6;
			}
			if (p2 == 0xbf)
			{
				return 7;
			}
			if (p2 == 0x7f)
			{
				return 8;
			}
		}
	}
	return 0;//没有的话默认返回按键零
}

//************************************************
//   开启中断
//************************************************
void openINT()
{
	TMOD=0x02;//定义为模式2
	TH0=6;//装入初值
	TL0=6;//装入初值
	EA=1;//开总中断
	ET0=1;//开定时器中断
	TR0=1;//启动定时器0
}

//************************************************
//   关闭中断
//************************************************
void closeINT()
{
	TMOD=0x02;//定义为模式2
	TH0=0;//装入初值
	TL0=0;//装入初值
	EA=0;//开总中断
	ET0=0;//开定时器中断
	TR0=0;//启动定时器0
}

//************************************************
//   中断1所进行的动作,每个时钟周期都会中断一次
//************************************************
void T0_time() interrupt 1	//中断1
{
	num++;
	if (num >= 4000)//这时候的num会大于256,所以要用uint定义
	{
		num = 0;
		led1 = ~led1;
		second++;
		Ssecond++;
	}
	//这里每个中断检查一次而不是一秒检查一次是因为
	// 如果我们手动调节太快可能不会在秒过十的时候自动进1
	//对秒表进行响应
	if(Ssecond == 999)
	{
		Ssecond=0;
	}
	//对时钟进行响应
	if (second == 60)
	{
		second = 0;
		minute++;
	}
	if (minute == 60)
	{
		minute = 0;
		hour++;
	}	
	if (hour ==24)
	{
		hour=0;
	}
	if (Chour==24)
	{
		Chour=0;
	}
	if (Cminute==60)
	{
		Cminute=0;
	}
	//接下来对闹钟进行响应
	if (Chour == hour)
	{
		if (Cminute == minute)
		{
			if(Con == 1)
			{
				//设时候闹钟响了;
				Buzzer=1;
				Con=0;//闹钟再响关闭
			}
		}
	}

}

//************************************************
//   驱动显卡显示时钟
//************************************************
void showTime()
{
	Setlocalandchar(7,second%10);
	Setlocalandchar(6,second/10);	
	Setlocalandchar(5,17);
	Setlocalandchar(4,minute%10);
	Setlocalandchar(3,minute/10);
	Setlocalandchar(2,17);
	Setlocalandchar(1,hour%10);
	Setlocalandchar(0,hour/10);
}
//************************************************
//   显示秒表时间 0表示动态,1表示静态
//************************************************
void ShowStopWatch(uchar IsStop)
{
	Setlocalandchar(7,Centisecond%10);
	Setlocalandchar(6,Centisecond/10);	
	Setlocalandchar(5,17);
	if (IsStop == 1)
	{
		Setlocalandchar(4,StopSecond%10);
		Setlocalandchar(3,(StopSecond/10)%10);
		Setlocalandchar(2,StopSecond/100);
	}
	else
	{
		Setlocalandchar(4,Ssecond%10);
		Setlocalandchar(3,(Ssecond/10)%10);
		Setlocalandchar(2,Ssecond/100);
	}
	Setlocalandchar(0,18);
	// 这里是在一秒内显示一个动态图像
	// 分三个阶段进行,为节约资源,比较有进行划分
	if (Centisecond<34)
	{
		Setlocalandchar(0,20);
	}
	if (Centisecond<70)
	{	
		Setlocalandchar(0,21);
	}
	else
	{
		Setlocalandchar(0,22);
	}

}

//************************************************
//   设定时间函数,需美化
//************************************************
void SetTime()
{
	//当按键按下时候
	// 首先应该进行的是01 34 67的位置的设定

	while(1)
	{
		// 一秒显示,一秒隐藏
Sethour:// 首先,先隐藏位置01
		while(1)//这时候会停留在设置时的位置上,下面同理
		{
			FlashTime(0);
			//这时候选择按键,s5为向上,s6为向下
			//s4为跳出这个循环
			if (CathKey() == 5)//只能向上调
			{
				while (CathKey() == 5);
				hour++;
			}
			if (CathKey() == 4)//跳到下一步
			{
				while(CathKey() == 4);
				goto setMinute;
			}
		}

setMinute:// 再者,隐藏位置34
		while(1)//这时候会停留在设置时的位置上,下面同理
		{
			FlashTime(1);
			//这时候选择按键,s5为向上,s6为向下
			//s4为跳出这个循环
			if(CathKey() == 5)
			{
				while (CathKey() == 5);//只能向上调
				minute++;
			}
			if (CathKey() == 4)// 跳出大循环
			{
				while(CathKey() == 4);
				return ;
			}
		}
	}
}

//************************************************
//   闪烁时间,函数对指定位置的数字进行闪烁
//************************************************
void FlashTime(uchar i)
{
	switch (i)
	{
	case 0:// 当光标停留在设定小时
		Setlocalandchar(7,second%10);
		Setlocalandchar(6,second/10);	
		Setlocalandchar(5,17);
		Setlocalandchar(4,minute%10);
		Setlocalandchar(3,minute/10);
		Setlocalandchar(2,17);

		if (second%2 == 0)
		{
			Setlocalandchar(1,18);
			Setlocalandchar(0,18);
		}
		else
		{		
			Setlocalandchar(1,hour%10);
			Setlocalandchar(0,hour/10);
		}
		break;
	case 1:// 当光标停留在设定分钟时候
		Setlocalandchar(7,second%10);
		Setlocalandchar(6,second/10);	
		Setlocalandchar(5,17);
		if (second%2 == 0)
		{		
			Setlocalandchar(4,18);
			Setlocalandchar(3,18);
		} 
		else
		{
			Setlocalandchar(4,minute%10);
			Setlocalandchar(3,minute/10);
		}
		Setlocalandchar(2,17);
		Setlocalandchar(1,hour%10);
		Setlocalandchar(0,hour/10);
		break;
	case 2:	//当光标停留在on和no的时候
		Setlocalandchar(7,Cminute%10);
		Setlocalandchar(6,Cminute/10);
		Setlocalandchar(5,17);
		Setlocalandchar(4,Chour%10);
		Setlocalandchar(3,Chour/10);
		Setlocalandchar(2,17);	
		if (second%2 == 0)
		{		
			Setlocalandchar(1,18);
			Setlocalandchar(0,18);
		} 
		else
		{
			if (Con == 0)//no
			{
				Setlocalandchar(1,0);
				Setlocalandchar(0,19);
			}
			else
			{
				Setlocalandchar(1,19);
				Setlocalandchar(0,0);
			}
		}
		break;
	case 3://当光标停留在设置闹钟小时
		Setlocalandchar(7,Cminute%10);
		Setlocalandchar(6,Cminute/10);
		Setlocalandchar(5,17);
		if (second%2 == 0)
		{		
			Setlocalandchar(4,18);
			Setlocalandchar(3,18);
		} 
		else
		{
			Setlocalandchar(4,Chour%10);
			Setlocalandchar(3,Chour/10);
		}
		Setlocalandchar(2,17);
		if (Con == 0)//no
		{
			Setlocalandchar(1,0);
			Setlocalandchar(0,19);
		}
		else
		{
			Setlocalandchar(1,19);
			Setlocalandchar(0,0);
		}
		break;
	case 4://当光标停留在设置闹钟分钟
		if (second%2 == 0)
		{		
			Setlocalandchar(7,18);
			Setlocalandchar(6,18);
		} 
		else
		{
			Setlocalandchar(7,Cminute%10);
			Setlocalandchar(6,Cminute/10);
		}	
		Setlocalandchar(5,17);
		Setlocalandchar(4,Chour%10);
		Setlocalandchar(3,Chour/10);
		Setlocalandchar(2,17);
		if (Con == 0)//no
		{
			Setlocalandchar(1,0);
			Setlocalandchar(0,19);
		}
		else
		{
			Setlocalandchar(1,19);
			Setlocalandchar(0,0);
		}
		break;
	}
}

//************************************************
//   设置闹钟函数,no,on表示闹钟开启关闭状态
//************************************************
// 闹钟变量
// uchar Csecond=0;
// uchar Cminute=0;
// uchar Con=0;
void SetColock()
{
	while(1)
	{
		//一开始要先显示前面两位
		// 先调教两位
		while (1)
		{	
			FlashTime(2);
			if (CathKey() == 5)// 设定闹钟开启和关闭
			{
				while(CathKey() == 5);
				Con=~Con;

			}
			if (CathKey() == 4)
			{
				while(CathKey() == 4);//调到下一步
				goto SetColockhour;
			}
		}

		// 然后再调教小时
SetColockhour:
		while (1)
		{
			FlashTime(3);
			if (CathKey() == 5)
			{
				while(CathKey() == 5);// 小时++
				Chour++;
			}
			if (CathKey() == 4)
			{
				while(CathKey() == 4);// 跳到下一步
				goto SetColockminute;
			}
		}
		// 最后再调教分钟
SetColockminute:
		while (1)
		{
			FlashTime(4);
			if (CathKey() == 5)// 分钟++
			{
				while(CathKey() == 5);
				Cminute++;
			}
			if (CathKey() == 4)// 跳出该函数
			{
				while(CathKey() == 4);
				return ;
			}
		}
	}
}

//************************************************
//   秒表函数
//************************************************
void stopwatch()
{
	//毫秒用100来显示
	//每次慢100进1
	int tempSscond;
StopWait:
	while(1)//等待,并且数据清零
	{			
		Ssecond=0;
		Centisecond=0;
		ShowStopWatch(0);
		if (p2 == 0xbf)
		{
			goto StopStart;// 开始执行下一步
		}
	}
StopStart:
	while(1)
	{
		Centisecond=num/40;// 显示精度为
		ShowStopWatch(0);
		if (p2 == 0xfb)
		{
			StopSecond = Ssecond;
			goto Stopstop;
		}
	}
Stopstop:
	while(1)
	{
		ShowStopWatch(1);//显示秒表
		if(p2 == 0xef)		// 复位
		{
			goto StopWait;
		}
		if (p2 == 0xfe)		// 退出
		{
			goto Stopexit;
		}
		if(p2 == 0xbf)		//继续
		{
			Ssecond=StopSecond;// 赋予静态函数
			goto StopStart;
		}
	}
Stopexit:
	return ;
}

//************************************************
//   Last Version:2011年5月2日9:29:48
//************************************************

//************************************************
//   Edit by HXH
//************************************************