可设置时间的日历

完整电路图:

完整代码:

#include <reg51.h>
#include <intrins.h>			//包含_nop_( )空函数指令的头文件

#define uchar unsigned char
#define uint unsigned int
#define out P2
sbit RS=P3^0; 					
sbit RW=P3^1;				
sbit E=P3^2; 
sbit RST=P1^7 ;
sbit SCLK =P1^6;
sbit DSIO=P1^5;	
sbit set=P1^0;	//设置时间按钮
sbit up=P1^1;	// 增加时间
sbit down=P1^2;	//	减小时间		

void lcd1602_initial(void);			//lcd1602初始化函数
void lcd1602_write_command(uchar com); 	//lcd1602写命令函数
void lcd1602_write_data(uchar dat);		//lcd1602写数据函数
void lcd1602_string(uchar ad ,uchar *s);//lcd1602写字符串
void delay(uint);						//延时函数
void Ds1302Write(uchar add,uchar dat);
uchar Ds1302Read(uchar add);
void Ds1302Readtime_data();
uchar bcd_decimal(uchar bcd);
void write_time(uchar add,uchar date);
void xinshi_time();	
uchar key_bcd(uchar key_decimal);
void key_set();
void key_process();
void key_up_down();

uchar code table1[]={"2021-01-24"};
uchar code table2[]={"23:59:50"};
uchar nian,zhou,yue,ri,shi,fen,miao;
uchar count=0,done=0,flag=1,flag_up=0,flag_down=0;
//---DS1302写入和读取时分秒的地址命令---//
//---秒分时日月周年 最低位读写位;-------//
uchar code read_add[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d}; 
uchar code write_add[7]= {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};

//---DS1302时钟初始化2013年1月1日星期二12点00分00秒。---//
//---存储顺序是秒分时日月周年,存储格式是用BCD码---//
uchar code time_data[7]= {0x58, 0x40, 0x14, 0x29, 0x01, 0x01, 0x21};
uchar code     xingqi1[]={"MON"};
uchar code     xingqi2[]={"TUE"};
uchar code     xingqi3[]={"WED"};
uchar code     xingqi4[]={"THU"};
uchar code     xingqi5[]={"FRI"};
uchar code     xingqi6[]={"SAT"};
uchar code     xingqi7[]={"SUN"};	 

/**************************************************************
*函数名		:delay
*函数功能	:延时函数
*函数参数	:需要延时的毫秒数:uint j
*函数返回值	:无
****************************************************************/
void delay(uint j){	 //1ms延时子程序
	uchar i=250;
	for(;j>0;j--){
		while(--i);
		i=249;
		while(--i);
		i=250;
	}
}
/**************************************************************
*函数名		:key_set
*函数功能	:按键设置
*函数参数	:无
*函数返回值	:无
****************************************************************/
void key_set(){
    if(set==0){
	    delay(5);		
		while(!set);
		    count++;  //计数,按了几次
			lcd1602_write_command(0x0f);
			if(flag==1){
			   done=1;
			   flag=0;
			   Ds1302Write(0x8e,0x00);
			   Ds1302Write(0x80,key_bcd(miao)|0x80);
			   Ds1302Write(0x8e,0x80);
			 }
			
		
	 }
}
/**************************************************************
*函数名		:key_up_down
*函数功能	:按键增加时间或者减少时间
*函数参数	:无
*函数返回值	:无
****************************************************************/
void key_up_down(){
	if(up==0){
		delay(5);
		flag_up=1;
		while(!up);
		switch(count){
			case 1: miao++;
					if(miao>59) miao =0;break;
			case 2: fen++;
					if(fen>59) fen =0;break;
			case 3: shi++;
					if(shi>23) shi =0;break;
			case 4: ri++;
					if(ri>31) ri =1;break;
			case 5: yue++;
					if(yue>12) yue =1;break;
			case 6: zhou++;
					if(zhou>7) zhou =1;break;
			case 7: nian++;
					if(nian>99) miao =0;break;

		}
	}
	if(down==0){
		delay(5);
		flag_down=1;
		while(!down);
		switch(count){
			case 1: miao--;
					if(miao==255) miao =59;break;
			case 2: fen--;
					if(fen==255) fen =59;break;
			case 3: shi--;
					if(shi==255) shi =23;break;
			case 4: ri--;
					if(ri<1) ri =31;break;
			case 5: yue--;
					if(yue<1) yue =12;break;
			case 6: zhou--;
					if(zhou<1) zhou =7;break;
			case 7: nian--;
					if(nian==255) miao =99;break;
					

		}
	}
}
 /**************************************************************
*函数名		:key_bcd
*函数功能	:可以将十进制数转换成bcd类型数据
*函数参数	:十进制数:uchar key_decimal
*函数返回值	:返回bcd类型数据:uchar temp
****************************************************************/
 uchar key_bcd(uchar key_decimal){
 	uchar temp;
	temp=(((key_decimal/10)&0x0f)<<4 )|(key_decimal%10);
	return temp;
 }
/**************************************************************
*函数名		:key_process
*函数功能	:案件处理函数
*函数参数	:无
*函数返回值	:无
****************************************************************/
void key_process(){
	   key_set();
	   if(count!=0){
	   		 switch(count){
			 	 case 1: do{
					 	lcd1602_write_command(0xc0+7);
						key_up_down();
						if(flag_up|flag_down){
						   flag_up=0;flag_down=0;
						   Ds1302Write(0x8e,0x00);
						   Ds1302Write(0x80,key_bcd(miao)|0x80);
						   Ds1302Write(0x8e,0x80);
						   write_time(0x40+6,miao);
						   lcd1602_write_command(0xc0+7);
				       	}
				        }while(count==2);
				        break;

				  case 2: do{
					 	lcd1602_write_command(0x80+0x40+4);
						key_up_down();
						if(flag_up|flag_down){
						   flag_up=0;flag_down=0;
						   Ds1302Write(0x8e,0x80);
						   Ds1302Write(0x82,key_bcd(fen));
						   Ds1302Write(0x8e,0x80);
						   write_time(0x40+3,fen);
						   lcd1602_write_command(0xc0+4);
					}
				 }while(count==3);
				 break;

				 case 3: do{
				 	lcd1602_write_command(0x80+0x40+1);
					key_up_down();
					if(flag_up|flag_down){
					       flag_up=0;flag_down=0;
					 	   Ds1302Write(0x8e,0x80);
					       Ds1302Write(0x84,key_bcd(shi));
					  	   Ds1302Write(0x8e,0x80);
					        write_time(0x40+0,shi);
					       lcd1602_write_command(0xc0+1);
					}
				 }while(count==4);
				 break;


				  case 4: do{
				 	lcd1602_write_command(0x80+7);
					key_up_down();
					if(flag_up|flag_down){
					      flag_up=0;flag_down=0;
					      Ds1302Write(0x8e,0x00);
					      Ds1302Write(0x86,key_bcd(ri));
					      Ds1302Write(0x8e,0x80);
					      write_time(6,ri);
					      lcd1602_write_command(0x80+7);
					}
				 }while(count==5);
				 break;

				  case 5: do{
				 	lcd1602_write_command(0x80+4);
					key_up_down();
					if(flag_up|flag_down){
					      flag_up=0;flag_down=0;
					      Ds1302Write(0x8e,0x00);
					      Ds1302Write(0x88,key_bcd(yue));
					      Ds1302Write(0x8e,0x80);
					      write_time(3,yue);
					      lcd1602_write_command(0x80+4);
					}
				 }while(count==6);
				 break;

				  case 6: do{
				 	lcd1602_write_command(0x80+15);
					key_up_down();
					if(flag_up|flag_down){
					     flag_up=0;flag_down=0;
					     Ds1302Write(0x8e,0x00);
					     Ds1302Write(0x8a,key_bcd(zhou));
					     Ds1302Write(0x8e,0x80);
					     write_time(13,zhou);
					     lcd1602_write_command(0x80+15);
					}
				 }while(count==7);
				 break;

				  case 7: do{
				 	lcd1602_write_command(0x80+1);
					key_up_down();
					if(flag_up|flag_down){
					     flag_up=0;flag_down=0;
					     Ds1302Write(0x8e,0x00);
					     Ds1302Write(0x8c,key_bcd(nian));
					     Ds1302Write(0x8e,0x80);
					     write_time(0,nian);
					     lcd1602_write_command(0x80+1);
					}
				 }while(count==8);
				 break;

				 case 8:
				 	lcd1602_write_command(0x0c);
					flag=1;
					done=0;
					count =0;
					   Ds1302Write(0x8e,0x00);
					   Ds1302Write(0x80,key_bcd(miao)&0x7f);
					   Ds1302Write(0x8e,0x80);
					   break;

				default:break;
			 }
	   }
}



/**************************** ds1302的驱动程序*********************************/

/*******************************************************************************
*函数名     :Ds1302Read
*函数功能   :读取ds1302中的数据
*函数参数   :所需写入的地址:ucahr addr
*函数返回值 :返回写入的数据:ucahr 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;	
}
/*******************************************************************************
*函数名     : Ds1302Write
*函数功能   : 写入设置的时间
*函数参数   : 地址:ucahr addr,数据:ucahr 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_();
}
/*******************************************************************************
*函数名     :Ds1302Init
*函数功能   :ds1302的初始化
*函数参数   :无
*函数返回值 :无
*******************************************************************************/
void Ds1302Init(){
	uchar n;
	Ds1302Write(0x8E,0X00);		 //禁止写保护,就是关闭写保护功能
	for (n=0; n<7; n++)//写入7个字节的时钟信号:分秒时日月周年
	{
		Ds1302Write(write_add[n],time_data[n]);	
	}
	Ds1302Write(0x8E,0x80);		 //打开写保护功能
}


/*******************************************************************************
*函数名     :bcd_decimal
*函数功能   :将BCD吗转成10进制数
*函数参数   :需要转化的bcd:ucahr bcd
*函数返回值 : 转化完成的十进制数:ucahr decimal
*******************************************************************************/
uchar bcd_decimal(uchar bcd){
	uchar decimal;
	decimal = bcd>>4;
	decimal = decimal*10+(bcd&=0x0f);
	return decimal;
}

/*******************************************************************************
*函数名     :write_time 
*函数功能   :将时间显示在lcd上
*函数参数   :地址:ucahr add, 时间:uchar date
*函数返回值 :无
*******************************************************************************/
void write_time(uchar add,uchar date){
	 uchar shi,ge;
	 shi = date/10;
	 ge = date%10;
	 lcd1602_write_command(0x80+add);
	 lcd1602_write_data(0x30+shi);
	 lcd1602_write_data(0x30+ge);
}

/*******************************************************************************
*函数名     :write_week 
*函数功能   :将星期显示在lcd上
*函数参数   :星期的表示值:0-6,分别对应周一到周日:uchar dat
*函数返回值 :无
*******************************************************************************/
void write_week(uchar dat){
	
	 switch(dat){
	 	 case 1:  lcd1602_string(0x80+13,xingqi1); break;
		 case 2:  lcd1602_string(0x80+13,xingqi2); break;
		 case 3:  lcd1602_string(0x80+13,xingqi3); break;
		 case 4:  lcd1602_string(0x80+13,xingqi4); break;
		 case 5:  lcd1602_string(0x80+13,xingqi5); break;
		 case 6:  lcd1602_string(0x80+13,xingqi6); break;
		 case 7:  lcd1602_string(0x80+13,xingqi7); break;
	 }
	
}

/*******************************************************************************
*函数名     : xianshi_time
*函数功能   : 显示时间
*函数参数   : 无
*函数返回值 : 无
*******************************************************************************/
void xianshi_time(){
	  //Ds1302Readtime_data();
	  miao = bcd_decimal(Ds1302Read(0x81));
	  fen =  bcd_decimal(Ds1302Read(0x83));
	  shi =  bcd_decimal(Ds1302Read(0x85));
	  ri =   bcd_decimal(Ds1302Read(0x87));
	  yue =  bcd_decimal(Ds1302Read(0x89));
	  zhou = bcd_decimal(Ds1302Read(0x8b));
	  nian = bcd_decimal(Ds1302Read(0x8d));

	  write_time(0,nian);
	  lcd1602_write_command(0x80+2);
	  lcd1602_write_data(0x2d);
	  write_time(3,yue);
	  lcd1602_write_command(0x80+5);
	  lcd1602_write_data(0x2d);
      write_time(6,ri);
	 
	  write_week(zhou);

      write_time(0x40+0,shi);
	  lcd1602_write_command(0xc0+2);
	  lcd1602_write_data(0x3a);
      write_time(0x40+3,fen);
	  lcd1602_write_command(0xc0+5);
	  lcd1602_write_data(0x3a);
	  write_time(0x40+6,miao);	
}


/**************************** lcd1602的驱动程序**********************/

/**************************************************************
*函数名		:lcd1602_write_command
*函数功能	:lcd1602的写命令函数
*函数参数	:所要设置的命令:uchar command
*函数返回值	:无
****************************************************************/
void lcd1602_write_command(uchar command) 	{
	E=0;
	RS=0;
	RW=0;
	out=command;
	E=1;
	_nop_( );
	E=0;
	delay(1);
}
/**************************************************************
*函数名		:lcd1602_write_data
*函数功能	:lcd1602的写数据函数
*函数参数	:要写入的数据:uchar dat
*函数返回值	:无
****************************************************************/
void lcd1602_write_data(uchar dat){   
	E=0;
	RS=1;
	RW=0;
	out=dat;
	E=1;
	_nop_();
	E=0;
	delay(1);	
}
/**************************************************************
*函数名		: lcd1602_initial
*函数功能	: lcd1602的初始化
*函数参数	: 无
*函数返回值	: 无
****************************************************************/
void lcd1602_initial(void){
    lcd1602_write_command(0x38);	       //写入命令0x38:8位两行显示,5×7点阵字符
    lcd1602_write_command(0x0C);	       //写入命令0x0C:开整体显示,光标关,无黑块
    lcd1602_write_command(0x06);	       //写入命令0x06:光标右移
    lcd1602_write_command(0x01); 	       //写入命令0x01:清屏
    delay(1);
}
/**************************************************************
*函数名		:lcd1602_string
*函数功能	:将字符串写入对应的地址上
*函数参数	:地址:uchar ad 字符串:uchar *s
*函数返回值	:无
****************************************************************/
void lcd1602_string(uchar ad,uchar *s){
    lcd1602_write_command(ad);
    while(*s>0)
   {
       lcd1602_write_data(*s++);		//输出字符串,且指针增1
       delay(100);
   }
}


/*********************************主函数************************/
/**************************************************************
*函数名    : 主函数
*函数功能  : 驱动程序
*函数参数  : 无
*函数返回值: 无
****************************************************************/
void main(void){
	uchar ch;
   lcd1602_initial( );			//调用对LCD初始化函数  

   ch = Ds1302Read(0x81)>>7;
   if(ch){
   		Ds1302Init();
   }
   while(1)
   {
//		lcd1602_string(0x80,table1);		//显示的第1行数据
//		lcd1602_string(0x80+0x40,table2);	//显示第2行数据
	if(done==1)	{
	    key_process();
	}
	if(done==0){
		xianshi_time();	
		key_set();

	}
		
		
	}
}

效果展示:

猜你喜欢

转载自blog.csdn.net/fw1035/article/details/113437531