基于proteus的数字电子钟

零、设计要求
1.时钟可以显示小时、分钟以及秒
2.,四个按键可以实现时间的手动调节
3.加入AT24C02,存储关机之前的时间,并且下次开机后可以通过某一按键将存储的时间读取出来

一、硬件仿真

二、程序设计

二、程序部分

1.IIC
#include <I2C.h>

/*
	开始信号
*/ 
void I2C_Star()
{
	SDA = 1;
	SCL = 1;
	delay();
	SDA = 0;
	delay();
	SCL = 0;	
}
/*
	停止信号
*/
void I2C_Stop()
{
	SCL = 0;
	SDA = 0;
	delay();
	SCL = 1;
	delay();
	SDA = 1;
	delay();
}
/*
	写操作
*/
bit I2C_Write(uchar date)
{
	bit ack;//应答位
	uchar mask;
	for(mask=0x80;mask!=0;mask>>=1)
	{
		if((date&mask)==0)
			SDA = 0;
		else
			SDA = 1;
		delay();
		SCL = 1;//拉高让从机读信号
		delay();
		SCL = 0;//拉低准备写下一位
	}
	SDA = 1;//释放数据线,以检测从机应答
	delay();
	SCL = 1;
	ack  = SDA;
	delay();
	SCL = 0;
	return (~ack);//返回1--应答    返回0--非应答
}
/*
	读操作 + 应答
*/
uchar I2C_Read_Ack()
{
	uchar date;//读到的一个字节
	uchar mask;
	SDA = 1;//确保数据线释放
	for(mask=0x80;mask!=0;mask>>=1)
	{
		delay();
		SCL = 1;//拉高时钟线准备读
		if(SDA==1)
			date |= mask;
		else
			date &= ~mask;
		delay();
		SCL = 0;
	}	
	//读完给从机发送应答
	SDA = 0;
	delay();
	SCL = 1;//从机读走应答位
	delay();
	SCL = 0;

	return date;//返回读到的一字节
}
/*
	读操作 + 非应答
*/
uchar I2C_Read_NAck()
{
	uchar date;//读到的一个字节
	uchar mask;
	SDA = 1;//确保数据线释放
	for(mask=0x80;mask!=0;mask>>=1)
	{
		delay();
		SCL = 1;//拉高时钟线准备读
		if(SDA==1)
			date |= mask;
		else
			date &= ~mask;
		delay();
		SCL = 0;
	}	
	//读完给从机发送非应答
	SDA = 1;
	delay();
	SCL = 1;//从机读走非应答位
	delay();
	SCL = 0;

	return date;//返回读到的一字节
}
2. 按键
#include "key.h"

/*
	毫秒级延时
*/
void delay_ms(uint z)
{
	uint x,y;
	for(x=z;x>0;x--)
		for(y=125;y>0;y--);
}
/*
	按键扫描
*/
uint key_scan()
{
	if(sec_up==0)
	{
		delay_ms(10);
		while(!sec_up);
		return 1;
	}
	if(sec_down==0)
	{
		delay_ms(10);
		while(!sec_down);
		return 2;
	}
	if(min_up==0)
	{
		delay_ms(10);
		while(!min_up);
		return 3;
	}
	if(min_down==0)
	{
		delay_ms(10);
		while(!min_down);
		return 4;
	}
	if(read_e2==0)
	{
		delay_ms(10);
		while(!read_e2);
		return 5;		
	}
	return 0;
}
3.液晶显示
#include "LCD1602.h"

/*
	微秒级延时
*/
void delay_us(uint x)
{
	for(;x>0;x--)
		_nop_();	
}
/*
	写命令
*/
void write_com(uchar com)
{
	P0 = com;
	rs = 0;
	lcd_en = 0;
	delay_us(100);
	lcd_en = 1;
	delay_us(100);
	lcd_en = 0;
}
/*
	写数据
*/
void write_date(uchar date)
{
	P0 = date;
	rs = 1;
	lcd_en = 0;
	delay_us(100);
	lcd_en = 1;
	delay_us(100);
	lcd_en = 0;
}
/*
	初始化
*/
void Init_lcd()
{
	uchar i=0;
	rw = 0;//写入数据或指令
	write_com(0x38);//显示模式16X2
	delay_us(100);
	write_com(0x0c);//开显示,不显示光标
	delay_us(100);
	write_com(0x06); //写入新数据光标右移
	delay_us(100);
	write_com(0x01);//清屏
	delay_us(100);
}
/*	
	显示位置设置	
*/
void lcd_location(uchar location)
{
	write_com(0x80 | location);
}
4.主函数
#include<reg52.h>
#include "LCD1602.h"
#include "key.h"
#include "I2C.h"
/**接口定义**/
sbit START = P3^5;
/**变量定义**/
uchar sec,min,hour;
uchar count = 0;
uchar KeyCount = 0;
/**数组定义**/
uchar code lcd_date_1[]={"  Design-By-WHH "};
uchar code lcd_date_2[]={"    00:00:00    "}; 
uchar display[6];
uchar buf[3];//24C02缓存
/**函数声明**/
void display_lcd();
void Display_Init();
void Timer0_Config();
void key_action();
void E2PROM_Write(uchar *buf,uchar address,uchar len);
void E2PROM_Read(uchar *buf,uchar address,uchar len);
void Init_E2Data_Write();
void Init_E2Data_Read();
/*****/
/*
	主函数
*/
void main()
{
	Timer0_Config();
	Init_lcd();
	Display_Init();
	while(1)
	{
		if(START==0)
		{
			if(!START)
			{
					KeyCount++;
					switch(KeyCount%2)
					{
						case 1:
							EA = 1;
							break;
						case 0:
							EA = 0;
							break;
					}
			}
		}	
		key_action();
		display_lcd();
	}
}
/*
	掉电写数据包
*/
void Init_E2Data_Write()
{
	buf[0] = hour;
	buf[1] = min;
	buf[2] = sec;
}
/*
	上电读数据包
*/
void Init_E2Data_Read()
{
	hour = buf[0];
	min = buf[1];
	sec = buf[2];
}
/*
	显示函数
*/
void display_lcd()
{
	display[0] = hour/10+0x30;
	display[1] = hour%10+0x30;
	display[2] = min/10+0x30;
	display[3] = min%10+0x30;
	display[4] = sec/10+0x30;
	display[5] = sec%10+0x30;

	lcd_location(0x44);//第二行第五个位置
	write_date(display[0]);
	write_date(display[1]);
	write_date(0x3a);//显示':'

	write_date(display[2]);
	write_date(display[3]);
	write_date(0x3a);//显示':'

	write_date(display[4]);
	write_date(display[5]);
}
/*
	显示初始化
*/
void Display_Init()
{
	uchar i;
	lcd_location(0x00);
	for(i=0;i<16;i++)
	{
		write_date(lcd_date_1[i]);
	}
	lcd_location(0x40);//第二行初始位置	
	for(i=0;i<16;i++)
	{
		write_date(lcd_date_2[i]);
	}
}
/*
	定时器配置
*/
void Timer0_Config()
{
	TMOD &= 0xF0;
	TMOD |= 0x01;
	TH0 = 0x4c;//定时50ms
	TL0 = 0X00;
	ET0 = 1;
	TR0 = 1;
}
/*
	按键动作操作
*/
void key_action()
{
	uint key_value = 0;
	key_value = key_scan();
	if(key_value==1)
	{
		min++;
	}
	if(key_value==2)
	{
		min--;
	}
	if(key_value==3)
	{
		sec++;
	}
	if(key_value==4)
	{
		sec--;
	}
	if(key_value==5)
	{
		Init_E2Data_Read();
		E2PROM_Read(buf,0x3a,sizeof(buf));
	}
}
/*
	E2PROM写多个字节
*/
void E2PROM_Write(uchar *buf,uchar address,uchar len)
{
	while(len--)
	{
		do
		{
	 		I2C_Star();
			if(I2C_Write(0xa0))
				break;//如果允许写入则退出检测循环
			I2C_Stop();
		}while(1);
		I2C_Write(address++);
		I2C_Write(*buf++);
		I2C_Stop();
	}
}
/*
	E2PROM读多个字节
*/
void E2PROM_Read(uchar *buf,uchar address,uchar len)
{
	do
	{
	 	I2C_Star();
		if(I2C_Write(0xa0))
			break;//如果允许写入则退出检测循环
		I2C_Stop();	
	}while(1);
	I2C_Write(address);//写入要读取的地址
	I2C_Star();
	I2C_Write(0xa1);//选择读
	while(len>1)//读取字节数-1
	{
		*buf++ = I2C_Read_Ack();//给应答以继续读
		len--;	
	}
	*buf = I2C_Read_NAck();//给非应答不继续读了
	I2C_Stop();
}
/*
	定时器0中断服务函数
*/
void Time0() interrupt 1
{
	TH0 = 0x4c;//定时50ms
	TL0 = 0X00;
	count++;
	if(count==20)//1s
	{
		Init_E2Data_Write();
		E2PROM_Write(buf,0x3a,sizeof(buf));//1s时间写一次数据到E2
		count=0;
		sec++;
	}
	if(sec==60)//1min
	{
		sec = 0;
   	min++;
	}
	if(min==60)//1h
	{
		min=0;
		hour++;
	}
}
posted @ 2021-05-11 10:18  是小魏啊  阅读(1466)  评论(0编辑  收藏  举报