基于多功能电子时钟设计

1、前期需求

Proteus仿真软件+keil5 51

2、仿真图

3、代码

mian函数

//注意:当前日期不能乱改,DS1302容易报错。
#include <reg52.h>	         //调用单片机头文件
#include <intrins.h>
#include <lcd.h>
#include <ds1302.h>
#include <delay.h>
#include"Ds18b20.h"
#define uchar unsigned char  //无符号字符型 宏定义	变量范围0~255
#define uint  unsigned int	 //无符号整型 宏定义	变量范围0~65535

sbit out=P2^0;			//蜂鸣器   

sbit shijian=P1^1;//下一个
sbit jia=P1^2;//加
sbit jian=P1^3;//减
sbit off=P1^4;//关闭
sbit ok=P1^0;//ok
sbit shang=P3^3;//上一个
sbit next=P2^4;//切换
sbit s1=P2^1;
sbit s2=P2^2;
sbit s3=P2^3;
sbit test=P1^7;
//*****************************************
//定义允许报警的时间段,在该时间段内可以报警
uchar addr=0;		//LCD显示位置追踪0-7,LCD上每个能被修改的位置从0-7编号,以便统一操作
uchar shi;//定时时间:小时
uchar fen;//定时时间:分钟
uchar off0=1;//关闭标志
uchar up=30,down=20;

uchar flag=0,mode=0,start=0;
uchar sec=0,miao=0,fen1=0;//秒表
/********************************************************************
* 名称 : BCD_INT()
* 功能 : 将BCD码转换成十进制
* 输入 : k亮度0-65535
* 输出 : 无
***********************************************************************/
uchar BCD_INT(uchar i)
{
return 10*(i>>4)+(i & 0x0F);
}
/********************************************************************
* 名称 : INT_BCD()
* 功能 : 转换为十进制
* 输入 : k亮度0-65535
* 输出 : 无
***********************************************************************/
uchar INT_BCD(uchar k)
{
	return ((k/10)<<4)+(k % 10);
}
/********************************************************************
* 名称 : addr_set()
* 功能 : addr对应变量+1
* 输入 : 无
* 输出 : 无
***********************************************************************/
void addr_set()
{
	uchar i;
switch(addr)
	{
		case 0:	i=BCD_INT(shi);//定时时间加一不能大于23
						if(i<23)
						{
							i++;
							shi=INT_BCD(i);
						}
						break;
		case 1:	i=BCD_INT(fen);//定时分钟加一,小于60
						if(i<59)
						{
							i++;
							fen=INT_BCD(i);
						}
						break;
		case 2:	i=BCD_INT(TIME[6]);//年,加一
						if(i<99)
						{
							i++;
							TIME[6]=INT_BCD(i);
						}
						break;
						break;
	    case 3: i=BCD_INT(TIME[4]);//月,加一
						if(i<12)
						{
							i++;
							TIME[4]=INT_BCD(i);
						}
						break;
		case 4:	i=BCD_INT(TIME[3]);//日,加一
						if(i<30)
						{
							i++;
							TIME[3]=INT_BCD(i);
						}break;
		case 5:	i=BCD_INT(TIME[2]);//时,加一
						if(i<23)
						{
							i++;
							TIME[2]=INT_BCD(i);
						}break;
		case 6:	i=BCD_INT(TIME[1]);//分,加一
						if(i<59)
						{
							i++;
							TIME[1]=INT_BCD(i);
						}
						break;
		case 7:	i=BCD_INT(TIME[5]);//星期,加一
						if(i<6)
						{
							i++;
							TIME[5]=INT_BCD(i);
						}
						break;
		case 8:	if(up<99)
					up++;
						break;
		case 9:	if(down<up)
					down++;
	}
}
/********************************************************************
* 名称 : addr_clr()
* 功能 : addr对应变量-1
* 输入 : 无
* 输出 : 无
***********************************************************************/
void addr_clr()
{
	uchar i;
switch(addr)
	{
		case 0:	i=BCD_INT(shi);//定时时间减一
						if(i>0)
						{
							i--;
							shi=INT_BCD(i);
						}
						break;
		case 1:	i=BCD_INT(fen);//定时分钟减一
						if(i>0)
						{
							i--;
							fen=INT_BCD(i);
						}
						break;
		case 2:	i=BCD_INT(TIME[6]);//年,减一
						if(i>0)
						{
							i--;
							TIME[6]=INT_BCD(i);
						}
						break;
	    case 3:	i=BCD_INT(TIME[4]);//月,减一
						if(i>1)
						{
							i--;
							TIME[4]=INT_BCD(i);
						}
						break;
		case 4:	i=BCD_INT(TIME[3]);//日,减一
						if(i>0)
						{
							i--;
							TIME[3]=INT_BCD(i);
						}
						break;
		case 5:	i=BCD_INT(TIME[2]);//时,减一
						if(i>0)
						{
							i--;
							TIME[2]=INT_BCD(i);
						}
						break;
		case 6:	i=BCD_INT(TIME[1]);//分,减一
						if(i>0)
						{
							i--;
							TIME[1]=INT_BCD(i);
						}
						break;
		case 7:	i=BCD_INT(TIME[5]);//星期,减一
						if(i>0)
						{
							i--;
							TIME[5]=INT_BCD(i);
						}
						break;
		case 8:	if(up>down)
					up--;
						break;
		case 9:	if(down>0)
					down--;
		}
}
/********************************************************************
* 名称 : addr_guang()
* 功能 : addr对应变量+1
* 输入 : 无
* 输出 : 无
***********************************************************************/
void addr_guang()
{
switch(addr)
	{
		case 0:	write_sfm(1,0);//设置光标到定时,小时
						break;
		case 1:	write_sfm(1,3);//设置光标到定时,分钟
						break;
		case 2:	write_sfm(2,0);//设置光标到年
						break;
		case 3:	write_sfm(2,5);//设置光标到月
						break;
	    case 4:	write_sfm(2,8);//设置光标到日
						break;
		case 5:	write_sfm(1,6);//设置光标到小时
						break;
		case 6:	write_sfm(1,9);//设置光标到分钟
						break;
		case 7:	write_sfm(1,15);//星期
						break;
		case 8:	write_sfm(1,3);//温度上下限
						break;
		case 9:	write_sfm(2,3);
	}
	if(addr<10)
		write_com(0x0e);
	else
		write_com(0x0c);
}
//显示秒表
void disp()
{	
	write_com(0x0c);	 //关光标
	write_string(1,0,"stopwatch:");
	write_sfm(2,4);	 //
	write_data(fen1/10+0x30);
	write_data(fen1%10+0x30);
	write_data(':');
	write_data(miao/10+0x30);				
	write_data(miao%10+0x30);
	write_data(':');
	write_data(sec/10+0x30);				
	write_data(sec%10+0x30);
}
/********************************************************************
* 名称 : xianshi()
* 功能 : 读取日期,显示日期;判断报警 
* 输入 : 无
* 输出 : 无
***********************************************************************/
void xianshi()
{
	if(mode){
		disp();
		return;
	}
	write_com(0x0c);	 //关光标
	write_sfm(2,0);	 //第二行第一列开始显示当前日期
	write_data('2');
	write_data('0');
	write_data((TIME[6]>> 4)+0x30);				//年
	write_data((TIME[6] & 0x0f)+0x30);//9
	write_data('-');
	write_data((TIME[4]>> 4)+0x30);				//月
	write_data((TIME[4] & 0x0f)+0x30);
	write_data('-');
	write_data((TIME[3]>> 4)+0x30);				//日
	write_data((TIME[3] & 0x0f)+0x30);
	write_data(' ');				
	write_data(' ');
	write_data(' ');
	write_data(' ');
	write_data(' ');
	write_sfm(1,6);	
	write_data((TIME[2]>> 4)+0x30);				//时
	write_data((TIME[2] & 0x0f)+0x30);
	write_data(':');
	write_data((TIME[1]>> 4)+0x30);				//分
	write_data((TIME[1] & 0x0f)+0x30);
	write_data(':');
	write_data((TIME[0]>> 4)+0x30);				//秒
	write_data((TIME[0] & 0x0f)+0x30);
	write_data(' ');
	if(TIME[5]>1)
		write_data(TIME[5]+0x2f);				//星期
	else
		write_data('7');
	write_sfm(1,0);							//显示定时时间
	write_data((shi>> 4)+0x30);				
	write_data((shi & 0x0f)+0x30);
	write_data(':');
	write_data((fen>> 4)+0x30);			
	write_data((fen & 0x0f)+0x30);
	write_data(' ');
	write_sfm(2,12);						//显示定时时间
//	write_data(Ds18_temp/10+0x30);				
//	write_data(Ds18_temp%10+0x30);
//	write_data(0xdf);
//	write_data('C');			
	addr_guang();
}
/***************主函数*****************/
void main()
{
	uint time0,time1;//临时变量
	uchar led_time=1;//led点亮,中间变量
	init_1602();			   //1602液晶初始化
	Ds1302ReadTime();//读取7个字节
	xianshi();//调用显示函数初始化LCD
	addr=7;
	shi=0x16;//定时默认6点00分
	fen=0x30;
	
	TMOD|=0X01;//选择为定时器0模式,工作方式1,仅用TR0打开启动。

	TH0=(65536-10000)/256;	//给定时器赋初值,定时10ms
	TL0=(65536-10000)%256;	
	ET0=1;//打开定时器0中断允许
	EA=1;//打开总中断
	while(1)
		{
		delay_uint(20000);
		Ds1302ReadTime();//读取时间
		if(mode==0)
		{
			xianshi();//显示
			TR0=0;
		}
		else
		{
			
			TR0=1;
		}
		if(!next)//切换显示
		{
			mode=!mode;
			write_string(1,0,"                ");
			write_string(2,0,"                ");
			if(mode)
				disp();
			while(!next);
		}
		//秒表控制
		if(TR0)
		{
		if(!s1)
			start=1;
		if(!s2)
			start=0;
		if(!s3)
		{
			sec=0;
			miao=0;
			fen1=0;
			start=0;
			while(!s3);
		}
		}
		time0=600*(TIME[2]>>4)+60*(TIME[2] & 0x0F)+10*(TIME[1]>>4)+(TIME[1] & 0x0F);//将读取的时间转换成分钟,便于计算
		time1=600*(shi>>4)+60*(shi & 0x0F)+10*(fen>>4)+(fen & 0x0F);//将定时时间转换成分钟
	
	if((time0==time1)&&(TIME[0]==0))//时间到
	{
		off0=0;
	}

	if(!off0 && (time0<time1+10) && (time0>time1-1))//如果时间到了,响铃,震动10分钟直到按下关闭按钮
		out=1;
	else
		out=0;
//==========================================================================
	if(!off)//检测关闭按钮
	{
		off0=1;
	}
//=======================================
if(!shijian)//选择下一个要修改的时间
{
	if(addr<7)
		addr++;
	else
		addr=0;
	addr_guang();
	while(!shijian);
}
if(!shang)
{
	if(addr>0)
		addr--;
	else
		addr=7;
	addr_guang();
	while(!shang);
}
//=======================================
if(!ok)//确认
{
	addr=8;
	addr_guang();
	while(!ok);
}
//=======================================
	if(!jia)//加
	{
		addr_set();
		while(!jia);
		if(addr>1)
			Ds1302WriteTime();//写入DS1302
		while(!jia);
	}
//=======================================
	if(!jian)//减
	{
		addr_clr();
		while(!jian);
		if(addr>1)
			Ds1302WriteTime();
		while(!jian);
	}
}
}
//定时器中断
void Timer0() interrupt 1
{
	if(start)
	{
	if(sec<99)
		sec++;
	else
	{
		sec=0;
		if(miao<59)
			miao++;
		else
		{
			miao=0;
			if(fen1<99)
				fen1++;
		}
		
	}
	}
	xianshi();//显示

	TH0=(65536-10000)/256;	//给定时器赋初值,定时10ms
	TL0=(65536-10000)%256;	
}

lcd.c

#include "lcd.h"
#include "delay.h"

/********************************************************************
* 名称 : write_com(uchar com)
* 功能 : 1602命令函数
* 输入 : 输入的命令值
* 输出 : 无
***********************************************************************/
void write_com(uchar com)
{
	e=0;
	rs=0;
	rw=0;
	P0=com;
	delay_uint(3);
	e=1;
	delay_uint(25);
	e=0;
}


/********************************************************************
* 名称 : write_data(uchar dat)
* 功能 : 1602写数据函数
* 输入 : 需要写入1602的数据
* 输出 : 无
***********************************************************************/
void write_data(uchar dat)
{
	e=0;
	rs=1;
	rw=0;
	P0=dat;
	delay_uint(3);
	e=1;
	delay_uint(25);
	e=0;	
}

/********************************************************************
* 名称 : write_sfm(uchar hang,uchar add,uchar date)
* 功能 : 设置当前行和列
* 输入 : 行,列
* 输出 : 无
***********************************************************************/
void write_sfm(uchar hang,uchar add)
{
	if(hang==1)   			   //设置当前行
		write_com(0x80+add);
	else
		write_com(0x80+0x40+add);	
}
/********************************************************************
* 名称 : write_string(uchar hang,uchar add,uchar *p)
* 功能 : 改变液晶中某位的值,如果要让第一行,第五个字符开始显示"ab cd ef" ,调用该函数如下
	 	 write_string(1,5,"ab cd ef;")
* 输入 : 行,列,需要输入1602的数据
* 输出 : 无
***********************************************************************/
void write_string(uchar hang,uchar add,uchar *p)
{
	if(hang==1)   
		write_com(0x80+add);
	else
		write_com(0x80+0x40+add);
		while(1)
		{
			if(*p == '\0')  break;
			write_data(*p);
			p++;
		}	
}


/********************************************************************
* 名称 : init_1602()
* 功能 : 初始化1602液晶 
* 输入 : 无
* 输出 : 无
***********************************************************************/
void init_1602()
{
	write_com(0x38);						//数据总线为8位,显示2行,5x7点阵
	write_com(0x0e);						//开显示,有光标,光标闪烁
	write_com(0x06);						//光标自动右移
	delay_uint(1000);						//等待设置完成
}

lcd.h

#ifndef __LCD_H_
#define __LCD_H_
/**********************************
当使用的是4位数据传输的时候定义,
使用8位取消这个定义
**********************************/
//#define LCD1602_4PINS

/**********************************
包含头文件
**********************************/
#include<reg52.h>

//---重定义关键词---//
#ifndef uchar
#define uchar unsigned char
#endif

#ifndef uint 
#define uint unsigned int
#endif

/**********************************
PIN口定义
**********************************/
sbit rs=P2^6;	 //1602数据/命令选择引脚 H:数据      	L:命令
sbit rw=P2^5;	 //1602读写引脚	         H:数据寄存器  	L:指令寄存器
sbit e =P2^7;	 //1602使能引脚          下降沿触发
sbit rs2=P1^5;	 //1602数据/命令选择引脚 H:数据      	L:命令
sbit rw2=P1^6;	 //1602读写引脚	         H:数据寄存器  	L:指令寄存器
sbit e2 =P1^7;	 //1602使能引脚          下降沿触发
/**********************************
函数声明
**********************************/
void write_com(uchar com);						   //LCD1602写入8位数据子函数
void write_data(uchar dat);						   //1602写数据函数	
void init_1602();								   //LCD1602初始化子程序						  
void write_sfm(uchar hang,uchar add);			   //设置当前行和列
void write_string(uchar hang,uchar add,uchar *p);
#endif

ds1302.c

#include"ds1302.h"


//定义读地址
uchar code READ_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d}; //秒分时日月周年
//定义写地址,秒分时日月周年
uchar code WRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};
//定义时间数组,秒分时日月周年
uchar TIME[7]={0,0,0x12,0x16,0x09,0x01,0x19};
/*******************************************************************************
* 函 数 名         : Ds1302Write
* 函数功能		   : 向DS1302命令(地址+数据)
* 输    入         : addr,dat
* 输    出         : 无
*******************************************************************************/
void Ds1302Write(uchar addr, uchar dat)
{
	uchar n;
	RST = 0;
	_nop_();

	SCLK = 0;//先将SCLK置低电平。
	_nop_();
	RST = 1; //然后将RST(CE)置高电平。
	_nop_();

	for (n=0; n<8; n++)//开始传送八位地址命令
	{
		DSIO = addr & 0x01;//数据从低位开始传送
		addr >>= 1;
		SCLK = 1;//数据在上升沿时,DS1302读取数据
		_nop_();
		SCLK = 0;
		_nop_();
	}
	for (n=0; n<8; n++)//写入8位数据
	{
		DSIO = dat & 0x01;
		dat >>= 1;
		SCLK = 1;//数据在上升沿时,DS1302读取数据
		_nop_();
		SCLK = 0;
		_nop_();	
	}	
		 
	RST = 0;//传送数据结束
	_nop_();
}

/*******************************************************************************
* 函 数 名         : Ds1302Read
* 函数功能		   : 读取一个地址的数据
* 输    入         : addr
* 输    出         : dat
*******************************************************************************/

uchar Ds1302Read(uchar addr)
{
	uchar n,dat,dat1;
	RST = 0;
	_nop_();

	SCLK = 0;//先将SCLK置低电平。
	_nop_();
	RST = 1;//然后将RST(CE)置高电平。
	_nop_();

	for(n=0; n<8; n++)//开始传送八位地址命令
	{
		DSIO = addr & 0x01;//数据从低位开始传送
		addr >>= 1;
		SCLK = 1;//数据在上升沿时,DS1302读取数据
		_nop_();
		SCLK = 0;//DS1302下降沿时,放置数据
		_nop_();
	}
	_nop_();
	for(n=0; n<8; n++)//读取8位数据
	{
		dat1 = DSIO;//从最低位开始接收
		dat = (dat>>1) | (dat1<<7);
		SCLK = 1;
		_nop_();
		SCLK = 0;//DS1302下降沿时,放置数据
		_nop_();
	}

	RST = 0;
	_nop_();	//以下为DS1302复位的稳定时间,必须的。
	SCLK = 1;
	_nop_();
	DSIO = 0;
	_nop_();
	DSIO = 1;
	_nop_();
	return dat;	
}
/*******************************************************************************
* 函 数 名         : Ds1302WriteTime
* 函数功能		   : 写入时钟信息
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void Ds1302WriteTime()
{
	uchar n;
	Ds1302Write(0x8E,0x00);
	for (n=0; n<7; n++)//写入7个字节的时钟信号:秒分时日月周年
	{
		Ds1302Write(WRITE_RTC_ADDR[n],TIME[n]);	
	}
	Ds1302Write(0x8E,0x80);
}

/*******************************************************************************
* 函 数 名         : Ds1302ReadTime
* 函数功能		   : 读取时钟信息
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/

void Ds1302ReadTime()
{
	uchar n;
	for (n=0; n<7; n++)//读取7个字节的时钟信号:分秒时日月周年
	{
		TIME[n] = Ds1302Read(READ_RTC_ADDR[n]);
	}
		
}


ds1302.h

#ifndef __DS1302_H_
#define __DS1302_H_

//---包含头文件---//
#include<reg52.h>
#include<intrins.h>

//---重定义关键词---//
#ifndef uchar
#define uchar unsigned char
#endif

#ifndef uint 
#define uint unsigned int
#endif

//---定义ds1302使用的IO口---//
sbit DSIO=P3^7;
sbit RST=P3^5;
sbit SCLK=P3^6;
//---DS1302时钟初始化2019年9月16日星期一12点00分00秒。---//
//---存储顺序是秒分时日月周年,存储格式是用BCD码---//
extern uchar TIME[7];
extern uchar code READ_RTC_ADDR[7] ;
extern uchar code WRITE_RTC_ADDR[7];
//---定义全局函数---//
void Ds1302Write(uchar addr, uchar dat);     //向DS1302命令(地址+数据)
uchar Ds1302Read(uchar addr);				 //读取一个地址的数据
void Ds1302ReadTime();						 //读取时钟信息
void Ds1302WriteTime();							 //写入时钟信息

#endif

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值