单片机万年历时钟_单片机万年历程序设计 - CSDN
精华内容
参与话题
  • 51单片机项目设计:时钟万年历、闹钟(lcd1602显示)

    千次阅读 多人点赞 2020-08-29 12:00:32
    利用STC89C52RC单片机作为主控芯片,DS1302提供日期时间信息,DS18B20作为温度传感器,利用纽扣电池提供DS1302掉电走时电源,利用单片机内部eeprom存储闹钟数据信息。用户输入电路采用4个按键,输出电路一个蜂鸣器。...

    基于51单片机的时钟万年历项目设计

    哔哩哔哩项目展示视频:https://www.bilibili.com/video/BV1VQ4y1M79K
    资料下载链接:51单片机时钟设计.rar

    一、项目功能:
    1、能够显示年、月、日、星期、时间、实时温度。
    2、能够按键实现修改当前时间与日期。
    3、能够同时设定闹钟,在指定时间蜂鸣器发出滴滴声响。
    4、掉电走时,掉电闹钟设置数据不丢失,断开电源再上电依然是上一次设置的闹钟状态

    二、项目思路:
    利用STC89C52RC单片机作为主控芯片,LCD1602显示数据,DS1302提供日期时间信息,DS18B20作为温度传感器,利用纽扣电池提供DS1302掉电走时电源,利用单片机内部eeprom存储闹钟数据信息。用户输入电路采用4个按键,输出电路采用一个蜂鸣器。

    三、主要的芯片与传感器介绍:
    STC89C52RC:是STC公司生产的一种低功耗、高性能CMOS8位微控制器,具有8K字节系统可编程Flash存储器。STC89C52使用经典的MCS-51内核,但是做了很多的改进使得芯片具有传统51单片机不具备的功能。在单芯片上,拥有灵巧的8 位CPU 和在系统可编程Flash,使得STC89C52为众多嵌入式控制应用系统提供高灵活、超有效的解决方案。
    在这里插入图片描述
    LCD1602: 是一种工业字符型液晶,能够同时显示16x02即32个字符。LCD1602液晶显示的原理是利用液晶的物理特性,通过电压对其显示区域进行控制,即可以显示出图形
    在这里插入图片描述
    DS1302: 是由美国DALLAS公司推出的具有涓细电流充电能力的低功耗实时时钟芯片。它可以对年、月、日、周、时、分、秒进行计时,且具有闰年补偿等多种功能。
    在这里插入图片描述
    DS18B20: 是常用的数字温度传感器,其输出的是数字信号,具有体积小,硬件开销低,抗干扰能力强,精度高的特点。 DS18B20数字温度传感器接线方便,封装成后可应用于多种场合,如管道式,螺纹式,磁铁吸附式,不锈钢封装式,型号多种多样,有LTM8877,LTM8874等等。
    在这里插入图片描述
    在这里插入图片描述
    四、准备材料
    STC89C52RC、DS18B20、DS1302、LCD1602、洞洞板、三极管、电容、电阻、晶振、纽扣电池、蜂鸣器、按键、开关、LED、电位器、排座、芯片底座、电源插座、电源线等。

    五、用proteus绘制仿真电路
    由于纽扣电池掉电保存等功能不能仿真,这里没有画出,实物连接图参考下面DXP绘制的原理图为准
    在这里插入图片描述
    六、DXP原理图绘制
    在这里插入图片描述
    七、编写代码
    由于代码过长只提供部分核心代码:

    /********显示日期、时间、星期***********/
    void display_data(void)
    {
    	LcdWriteCom(0x80);
    	LcdWritestr("20");	
    	LcdWriteData(TIME[6]/16+0x30);	  //年
    	LcdWriteData(TIME[6]%16+0x30);
    	LcdWriteData('-');
    	LcdWriteData(TIME[4]/16+0x30);	  //月
    	LcdWriteData(TIME[4]%16+0x30);
    	LcdWriteData('-');
    	LcdWriteData(TIME[3]/16+0x30);	  //日
    	LcdWriteData(TIME[3]%16+0x30);
    
    	LcdWritestr("  ");
    	switch(TIME[5])					   //显示星期
    	{		
    		case 0:LcdWritestr("Mon"); break;
    		case 1:LcdWritestr("Tue"); break;
    		case 2:LcdWritestr("Wed"); break;
    		case 3:LcdWritestr("Thu"); break;
    		case 4:LcdWritestr("Fri"); break;
    		case 5:LcdWritestr("Sat"); break;
    		case 6:LcdWritestr("Sun"); break;
    	}
    	if(alarmswitch==ON)LcdWriteData('.');
    	else LcdWriteData(' ');
    
    	LcdWriteCom(0xC0);
    	LcdWriteData(' ');
    	LcdWriteData(TIME[2]/16+0x30);	  //时
    	LcdWriteData(TIME[2]%16+0x30);
    	LcdWriteData(':');
    	LcdWriteData(TIME[1]/16+0x30);	  //分
    	LcdWriteData(TIME[1]%16+0x30);
    	LcdWriteData(':');
    	LcdWriteData(TIME[0]/16+0x30);	  //秒
    	LcdWriteData(TIME[0]%16+0x30);
    	LcdWritestr(" ");
    }
    
    /**************main函数**************/
    void main(void)
    {
    	LcdInit();	 		//lcd初始化
    	//Ds1302Init();		  //时钟初始化
    	Ds18b20Init();		  //温度传感器初始化
    	SectorErase(0x2001);  //擦除扇区
    
    	alarm_hour=byte_read(0x2601);//获取上一次保存的闹钟数据
    	alarm_min=byte_read(0x2201);
    	alarmswitch=byte_read(0x2401);
    	while(1)		
    	{
    		switch(mode)	//模式选择
    		{
    			case DISPLAYDATA:		//时间显示模式
    				Ds1302ReadTime(); //更新时间
    				display_data();		  //显示时间 	 秒分时日月周年
    				displaytemp(Ds18b20ReadTemp());//显示温度
    	   			keypros(); 				//按键检测
    				if(alarmswitch==ON && alarm_hour==TIME[2] && alarm_min==TIME[1])  //闹钟
    				{
    					mode = ALARMCLOCK; 
    				}
    				break;
    			case MODIFYDATA:			  //时间修改模式
    				modify();
    				break;
    			case SETALARMCLOCK:			   //设置闹钟模式
    				setalarmclock();
    				break;
    			case ALARMCLOCK:			   //闹钟模式
    				alarmclock();
    				break;
    		}
    		
    	}				
    }
    

    八、实物展览
    做了一两天,总算做好了,由于博主性子急,不想浪费时间和焊锡,就用了许多跳线,稍微有点不美观,但不影响使用
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    资料下载链接:51单片机时钟设计.rar

    在这里插入图片描述
    代码文件:
    在这里插入图片描述
    原理图文件:
    在这里插入图片描述
    仿真文件:
    在这里插入图片描述
    博主能力有限,不到之处还请批评指正。
    求支持。

    END…

    展开全文
  • 基于51单片机的万年历(包含闹钟,秒表)实现

    万次阅读 多人点赞 2019-04-29 16:48:43
    开头唠一唠: 趁着寒假的时间,也趁着课程设计正好是做一个万年历。就打算好好从头到尾来一遍。涨涨知识。首先说的是本人也是小白一颗,大神们能帮忙指正错误的话,不胜感激。写博客只是为了总结经验,要是帮到一...

     

    开头唠一唠:

              趁着寒假的时间,也趁着课程设计正好是做一个万年历。就打算好好从头到尾来一遍。涨涨知识。首先说的是本人也是小白一颗,大神们能帮忙指正错误的话,不胜感激。写博客只是为了总结经验,要是帮到一部分人就更好了。我想是从硬件到软件都介绍的详细一点,还想说一说自己遇到的一些问题,可能要写的长一点。代码的话我会在后面上传。好,闲话不多说。进入正题。

    概述:

             首先说一下我用到的东西,硬件方面(电路都是自己拿万能板焊的):一片51单片机,一块12864液晶,一片ds1302时钟芯片,四个按键。还有些电容、电阻、晶振什么的,下面讲到的时候再说吧。主要的就这么多吧。再简单说一下按键的功能吧,假设按键分别是k1,k2,k3,k4。首先lcd主界面是显示的当前的日期时间和四路闹钟的时间。附图。k1,k2,k3,k4最开始被按下时分别对应的功能是k1:进入时间设定模式;k2:进入日期设定模式;k3:进入闹钟设定模式;k4:进入秒表计数模式。进入不同的模式后,四个按键有都有了新的功能,首先k4一直是退出,就是退出到最开始的选四种模式。k1,k2,k3对于日期和时间设定模式是一样的功能k1:数值加1,k2:数值减1,k3:更换调的是小时还是分钟抑或年份还是月份。对于闹钟模式,k1:数值加1,k2:更换调的是小时还是分钟,k3:更换调的是第几个闹钟。对于秒表模式,k1:第一次按是开始计数,然后再按就是记录一下当前是多少秒,最多可以记录9次。k2:暂停/开始,k3:重新计数。有点绕得慌,简单的的说就是有两重循环。要是还没理解,可以看后面的代码。

     一:硬件电路

           这部分怎么说,说简单也挺简单的。但其中有个梗我现在还没过去。就是最开始我打算自己焊个下载电路在上面的,结果总是下不进去程序。这部分算是题外话了,但还是想简单说一说。最开始打算用CH340芯片直接usb转uart的,结果芯片买回来发现好像没有直插的。自己腐板子什么的又嫌太麻烦。最后打算先用usb转九针串口转成rs232电平,再用max232转成uart电平的。照着电路图一顿焊,结果果然不出我所料,不可能一下就成功下进去程序。就找问题啊,找啊找,找啊找。好像是找到了一个,就是51下程序不是有一个断电在上电的过程吗?我是这样做的,但其中好像有问题,断的这个电应该只是单片机的电,而不包括max232的电。于是又改电路,改完还是不行。算了,这个我以后搞明白了再来说说吧。

           其余的应该就不算什么难的了,找一个51最小系统原理图照着焊呗,没什么太大的问题的。法

           对了,还有几个小的点,提一提吧。51的P0口是相当于集电极开路的门电路的,记得接上拉电阻。LCD屏导完程序时,最开始如果什么也不显示的话,记得调一下3脚接的电位器调一下背光。

     

    二.软件设计

        1.按键检测

            这一部分在我最开始看来是没有什么大文章的,也没有什么可以值得写的,有点基础的人几分钟就可以把程序写出了。可是当自己正真写的时候,才知道自己不懂得太多,要学的也太多。单片机的IO口最普通的两种功能,输入和输出嘛。记得自己学stm32时,IO口的输入输出是要在最开始初始化的是定义的。也就是IO口在同一时刻只能有一种功能吧,总不能又输入有输出吧。可是51呢?让我懵逼,在任何地方,包括启动文件里都没有定义IO口是输入还是输出。这让我很郁闷,总不会我让一个IO口输出一个高电平后,还可以从IO口读输入吧,那样不一直应该读到的就是我输出的高电平吗。直到我好好研究了一波51IO口的内部电路,才明白其中的玄机。

    这里是最简单的P1口的内部结构图。有点数电基础的人大概可以看明白。具体我就不讲了。你可以参考这里http://www.eeworld.com.cn/mcu/article_2017120236473_2.html

    由上图可见,要正确地从引脚上读入外部信息,必须先使场效应管关断,以便由外部输入的信息确定引脚的状态。为此,在作引脚读入前,必须先对该端口写入l。具有这种操作特点的输入/输出端口,称为准双向I/O口。8051单片机的P1、P2、P3都是准双向口。P0端口由于输出有三态功能,输入前,端口线已处于高阻态,无需先写入l后再作读操作。弄懂IO口的内部结构之后。我就直接上程序了,慢慢研究吧。注释的和没有用到的部分大家就不要纠结了。

    /*************************************************************************************************
    程序说明:按键的检测程序(基于51单片机),现在只有独立按键检测函数
    Author:	xingcheng
    IO说明:按键接的
    **************************************************************************************************/
    
    #include"key.h"
    sbit KeyPort2=P1^5;
    sbit KeyPort0=P1^7;						
    sbit KeyPort1=P1^6;
    sbit KeyPort3=P1^4;	//自己焊的按键接的单片机引脚
    //sbit KeyPort2=P1^2;
    //sbit KeyPort0=P1^0;						
    //sbit KeyPort1=P1^1;
    //sbit KeyPort3=P1^3;
    
    /************************************************************************
    函数名称:key_scan()
    函数功能:4个独立按键检测
    输入参数:无
    返回值:KeyV		通过返回值的不同来确定哪个按键被按下
    *************************************************************************/ 
    uchar key_scan()
    {
    	uchar KeyV;
    	KEYPORT=0xff;		//从51IO口读数据,一般要先给锁存器写1,
    						//具体请参考51IO口内部结构						
    	if(KeyPort0==0||KeyPort1==0||KeyPort2==0||KeyPort3==0)		//判断是否有按键按下
    	//这里改成if((P3&0xf0)!=0xf0)总是错,原因可能是P3读数据不是从引脚读的
    	//而是从锁存器读的,一直是0xff
    	{
    		delay_ms(10);		//防止抖动(拿板子实验时,发现这里延不延时并无影响)
    		 if(KeyPort0==0)		//判断哪个按键被按下//
    		{	
    			KeyV=K1;
    		}
    		else if(KeyPort1==0)
    		{
    			KeyV= K2;
    		}
    		else if(KeyPort2==0)
    		{	
    			KeyV=K3;
    		}
    		else if(KeyPort3==0)
    		{
    			KeyV=K4;
    		}
    		else 
    		{
    			KeyV= 0;
    		}		  			//判断哪个按键被按下//
    		
    		if(KeyV != 0)		//有按键按下时,进行松手检测
                  while(KeyPort0==0||KeyPort1==0||KeyPort2==0||KeyPort3==0);
    		delay_ms(10);		//延时消抖(拿板子实验,这里延时非常必要)
       }
    
        return KeyV;			//返回KeyV来标识哪一个按键被按下
    }
    
    /*****************************有时间再完善连按,长按等功能************************/
    
    /*		while((KEYPORT&0Xf0)!=NO_KEY)
    		{
    			delay_ms(15);
    			PressCnt--;
    			if(PressCnt==0)
    				{
    					PressCnt=SHORTCNT;
    					return KeyV;
    				}
    		}
    	}
    	delay_ms(15);
    	if((KEYPORT&0Xf0)==NO_KEY)
    	{
    		ReleaseCon=0;
    		return KeyV;
    	}
      */
    #ifndef __KEY_H#define _KEY_H
    
    #include<reg52.h>#include"delay.h"
    
    #ifndef uchar #define uchar  unsigned char#endif
    
    #define KEYPORT P3  //   四个按键接在了P3口的四个引脚#define NO_KEY   0xf0#define K1    0X01#define K2    0X02#define K3    0X03#define K4   0X04#define KEYSUB    0X02#define KEYADD    0X01#define KEYSET    0X04#define KEYNEXT   0X03 //K1,2,3,4,和这些是一样的,只是写.c文件时#define LONGCNT  150#define SHORTCNT 12
    
     
    
          uchar key_scan();
    
    #endif


     

      2.lcd12864

         这个就是真的没什么好说的了。就是记得调电位器调背光。对了,还有一个 好坑的地方,不知道各位有没有解决方法,就是那个光标(一闪一闪的那个)每次移动都是两个字两个字的移。上程序。

    /***********************************************************************
    程序功能:12864液晶驱动程序
    其他:   只包括基本的字符串显示功能
    *************************************************************************/
     
    
    #include <LCD12864.h>
    #define uchar unsigned char
    #define uint  unsigned int
    #define LCD_data  P0             //数据口
    
     
    /*******************************************************************
    函数名称:delay(int ms)
    函数功能:延时
    输入参数:ms  要延时的ms数                                                                                                                                                                      
    返回值:  无
     *******************************************************************/
     void delay(int ms)
     {
         while(ms--)
     {
           uchar i;
      for(i=0;i<250;i++)  
       {
        ; ; ; ;
       }
     }
     } 
    
     /*******************************************************************
    函数名称:lcd_busy()
    函数功能:检测LCD忙状态。
    输入参数:无
    返回值:  result result为1时,忙等待;result为0时,闲,可写指令数据
    
     *******************************************************************/
    bit lcd_busy()
      {                          
         bit result;
         LCD_RS = 0;
         LCD_RW = 1;
         LCD_EN = 1;
          delay_ms(1);
         result = (bit)(LCD_data&0x80);
         LCD_EN = 0;
         return(result); 
      }
     /*******************************************************************/                                                               
     /*写指令数据到LCD                                                  */
     /*RS=L,RW=L,E=高脉冲,D0-D7=指令码。                             */                                                                
     /*******************************************************************/
     void lcd_wcmd(uchar cmd)
     {                          
        while(lcd_busy());
         LCD_RS = 0;
         LCD_RW = 0;
         LCD_EN = 0;
         delay_ms(1);
         LCD_data = cmd;
        delay_ms(1);
         LCD_EN = 1;
        delay_ms(1);
         LCD_EN = 0;  
     }
     /*******************************************************************/
     /*写显示数据到LCD                                                  */
     /*RS=H,RW=L,E=高脉冲,D0-D7=数据。                               */
     /*******************************************************************/
     void lcd_wdat(uchar dat)
     {                          
        while(lcd_busy());
         LCD_RS = 1;
         LCD_RW = 0;
         LCD_EN = 0;
         LCD_data = dat;
        delay_ms(1);
         LCD_EN = 1;
       delay_ms(1);
         LCD_EN = 0; 
     }
     /*******************************************************************/
     /*  LCD初始化设定                                                  */
     /*******************************************************************/
     void lcd_init()
     { 
     
    
        LCD_PSB = 1;         //并口方式
         
         lcd_wcmd(0x34);      //扩充指令操作
         delay_ms(5);
         lcd_wcmd(0x30);      //基本指令操作
         delay_ms(5);
         lcd_wcmd(0x0C);      //显示开,关光标
         delay(5);
         lcd_wcmd(0x01);      //清除LCD的显示内容
         delay(5);
     }
     
    
    /*********************************************************/
     /* 设定显示位置       X:行数                Y:列数                                   */
     /*********************************************************/
     void lcd_pos(uchar X,uchar Y)
     {                          
        uchar  pos;
        if (X==0)
          {X=0x80;}
        else if (X==1)
          {X=0x90;}
        else if (X==2)
          {X=0x88;}
        else if (X==3)
          {X=0x98;}
        pos = X+Y ;  
        lcd_wcmd(pos);     //显示地址
     }
     
    /*********************************************************/
     /* 在设定位置显示字符(串)                                         */
     /*********************************************************/
     void zifu_dis (uchar X,uchar Y,uchar *dis)
     {
          uchar i;
      lcd_pos(X,Y);   
          i = 0;
         while(dis[i] != '\0')
          {                         //显示字符
            lcd_wdat(dis[i]);
            i++;
          }
     }
    
    
    /**************dis_12864.h***************/#ifndef __LCD12864_H__#define __LCD12864_H__
    
    #include"delay.h" #include <reg52.h>#define uchar unsigned char #define uint  unsigned int /*12864端口定义*/ #define LCD_data  P0             //数据口 sbit LCD_RS  =  P2^3;            //寄存器选择输入  sbit LCD_RW  =  P2^4;            //液晶读/写控制 sbit LCD_EN  =  P2^5;            //液晶使能控制 sbit LCD_PSB =  P3^3;            //串/并方式控制 
    
    /*函数声明*/ void delay(int ms); void lcd_init();  void beep(); void  dataconv(); void lcd_pos(uchar X,uchar Y);  //确定显示位置 void zifu_dis (uchar X,uchar Y,uchar *dis); #endif


     

    3.ds1302时钟

      直接给程序,相应的资料大家可以网上搜的。   

     

    /**************************************************************************
      
                       		THE REAL TIMER DS1302 DRIVER LIB
      
                 		COPYRIGHT (c)   2005 BY JJJ.
                           		--  ALL RIGHTS RESERVED  --
      
       File Name:       DS1302.h
       Author:          Jiang Jian Jun
       Created:         2003/7/21
       Modified:		NO
       Revision: 		1.0
       re
    ***************************************************************************/
    #include"ds1302.h"
    
    /***************************************************************************
    函数名称:DS1302InputByte(unsigned char d)
    函数功能:实时时钟写入一个字节(内部函数)
    输入参数:d			要写入的数据
    返回值:无
    ***************************************************************************/
    void DS1302InputByte(unsigned char d) 	
    { 
        unsigned char i;
        ACC = d;
        for(i=8; i>0; i--)
        {
            DS1302_IO = ACC0;           	//相当于汇编中的 RRC
            DS1302_CLK = 1;
            DS1302_CLK = 0;
            ACC = ACC >> 1; 
        } 
    }
    
    /***************************************************************************
    函数名称:DS1302OutputByte(void)
    函数功能:实时时钟读取一个字节(内部函数)
    输入参数:无
    返回值:ACC			读到的数据
    ***************************************************************************/
    unsigned char DS1302OutputByte(void) 	
    { 
        unsigned char i;
        for(i=8; i>0; i--)
        {
            ACC = ACC >>1;         			//相当于汇编中的 RRC
            ACC7 = DS1302_IO;
            DS1302_CLK = 1;
            DS1302_CLK = 0;
        } 
        return(ACC); 
    }
    
    /***************************************************************************
    函数名称:Write1302(unsigned char ucAddr, unsigned char ucDa)	
    函数功能:往实时时钟指定地址写数据
    输入参数:ucAddr		要写数据的地址
    		  ucDa			要写入的数据
    返回值:无
    ***************************************************************************/
    void Write1302(unsigned char ucAddr, unsigned char ucDa)	
    {
        DS1302_RST = 0;
        DS1302_CLK = 0;
        DS1302_RST = 1;
        DS1302InputByte(ucAddr);       	// 地址,命令
        DS1302InputByte(ucDa);       	// 写1Byte数据
    //    DS1302_CLK = 1;
        DS1302_RST = 0;
    } 
    
    /***************************************************************************
    函数名称:Read1302(unsigned char ucAddr)	
    函数功能:读取ds1302某地址的数据
    输入参数:ucAddr		要读数据的地址
    返回值:  ucData		读出的数据
    ***************************************************************************/
    unsigned char Read1302(unsigned char ucAddr)	//读取ds1302某地址的数据
    {
        unsigned char ucData;
        DS1302_RST = 0;
        DS1302_CLK = 0;
        DS1302_RST = 1;
        DS1302InputByte(ucAddr|0x01);        // 地址,命令 
        ucData = DS1302OutputByte();         // 读1Byte数据
    //    DS1302_CLK = 1;
        DS1302_RST = 0;
        return(ucData);
    }
    
    /***************************************************************************
    函数名称:DS1302_SetProtect(bit flag)        
    函数功能:是否写保护
    输入参数:flag		
    返回值:  无 
    其他:flag为1时,0x8E对应的control register最高位为1,写保护开启
    ***************************************************************************/
    void DS1302_SetProtect(bit flag)        //是否写保护
    {
    	if(flag)
    		Write1302(0x8E,0x80);
    	else
    		Write1302(0x8E,0x00);
    }
    
    /***************************************************************************
    函数名称:DS1302_SetTime(unsigned char Address, unsigned char Value)        
    函数功能:向指定寄存器写时间
    输入参数:Address		寄存器地址
    		  Value			要写入的时间(hex码)
    返回值:  无 
    其他:可以先用宏定义定义好year,month,hour等的地址
    ***************************************************************************/
    void DS1302_SetTime(unsigned char Address, unsigned char Value)        // 设置时间函数
    {
    	DS1302_SetProtect(0);
    	Write1302(Address, ((Value/10)<<4 | (Value%10))); 		//将hex码转化为BCD码
    }
    
    /***************************************************************************
    函数名称:DS1302_GetTime(SYSTEMTIME *Time)
    函数功能:读出日期和时间,将它们存入Time这个结构体中
    输入参数:*Time		要存日期和时间的结构体的地址
    返回值:  无 
    ***************************************************************************/
    void DS1302_GetTime(SYSTEMTIME *Time)
    {
    	unsigned char ReadValue;
    	ReadValue = Read1302(DS1302_SECOND);
    	Time->Second = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);	//八进制转为十进制
    	ReadValue = Read1302(DS1302_MINUTE);
    	Time->Minute = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
    	ReadValue = Read1302(DS1302_HOUR);
    	Time->Hour = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
    	ReadValue = Read1302(DS1302_DAY);
    	Time->Day = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);	
    	ReadValue = Read1302(DS1302_WEEK);
    	Time->Week = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
    	ReadValue = Read1302(DS1302_MONTH);
    	Time->Month = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
    	ReadValue = Read1302(DS1302_YEAR);
    	Time->Year = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);	
    }
    
    /***************************************************************************
    函数名称:DateToStr(SYSTEMTIME *Time)	 
    函数功能:将读出的日期变成便于显示的字符形式
    输入参数:*Time		要存字符的结构体
    返回值:无 
    ***************************************************************************/
    void DateToStr(SYSTEMTIME *Time)	 
    {
    	Time->DateString[0] = Time->Year/10+0x30 ;	 //·分离个位和十位
    	Time->DateString[1] = Time->Year%10+0x30 ;
    	Time->DateString[2] = '-';
    	Time->DateString[3] = Time->Month/10+0x30;
    	Time->DateString[4] = Time->Month%10+0x30 ;
    	Time->DateString[5] = '-';
    	Time->DateString[6] = Time->Day/10+0x30 ;
    	Time->DateString[7] = Time->Day%10+0x30 ;  //用LCD显示,要变成ascii码所以加了0x30,用数码管显示的话就不用加了
    	Time->DateString[8] = '\0';
    }
    
    /***************************************************************************
    函数名称:TimeToStr(SYSTEMTIME *Time)
    函数功能:将读出的时间变成便于显示的字符形式
    输入参数:*Time		要存字符的结构体
    返回值:无 
    ***************************************************************************/
    void TimeToStr(SYSTEMTIME *Time)
    {
    	Time->TimeString[0] = Time->Hour/10+0x30 ;
    	Time->TimeString[1] = Time->Hour%10+0x30 ;
    	Time->TimeString[2] = ':';
    	Time->TimeString[3] = Time->Minute/10+0x30 ;
    	Time->TimeString[4] = Time->Minute%10+0x30 ;
    	Time->TimeString[5] = ':';
    	Time->TimeString[6] = Time->Second/10+0x30;
    	Time->TimeString[7] = Time->Second%10+0x30 ;//用LCD显示,要变成ascii码所以加了0x30,用数码管显示的话就不用加了
    	Time->DateString[8] = '\0';
    }
    
    /***************************************************************************
    函数名称:Initial_DS1302(void)
    函数功能:初始化ds1302
    输入参数:无
    返回值:无 
    ***************************************************************************/
    void Initial_DS1302(void)
    {
    	unsigned char Second=Read1302(DS1302_SECOND);
    	if(Second&0x80)		  
    		DS1302_SetTime(DS1302_SECOND,0);
    }
    				   
    /********************************************************************************
    void BurstWrite1302(unsigned char *pWClock)	//往ds1302写入时钟数据(多字节方式)
    {
        unsigned char i;
        Write1302(0x8e,0x00);         	// 控制命令,WP=0,写操作
        DS1302_RST = 0;
        DS1302_CLK = 0;
        DS1302_RST = 1;
        DS1302InputByte(0xbe);        	// 0xbe:时钟多字节写命令
        for (i = 8; i>0; i--)     		//8Byte = 7Byte 时钟数据 + 1Byte 控制
        {
            DS1302InputByte(*pWClock); 	// 写1Byte数据
            pWClock++;
        }
        DS1302_CLK = 1;
        DS1302_RST = 0;
    } 
    
    void BurstRead1302(unsigned char *pRClock)	//读取ds1302时钟数据(时钟多字节方式)
    {
        unsigned char i;
        DS1302_RST = 0;
        DS1302_CLK = 0;
        DS1302_RST = 1;
        DS1302InputByte(0xbf);             	// 0xbf:时钟多字节读命令 
        for (i=8; i>0; i--) 
        {
           *pRClock = DS1302OutputByte();   // 读1Byte数据 
           pRClock++;
        }
        DS1302_CLK = 1;
        DS1302_RST = 0;
    }
    
    void DS1302_TimeStop(bit flag)           // 是否将时钟停止
    {
    	unsigned char Data;
    	Data=Read1302(DS1302_SECOND);
    	DS1302_SetProtect(0);
    	if(flag)
    		Write1302(DS1302_SECOND, Data|0x80);
    	else
    		Write1302(DS1302_SECOND, Data&0x7F);
    }
    ********************************************************************************/
    
    
     
    #ifndef _DS1302_H#define _DS1302_H
    
    #include<reg52.h>#include"delay.h"#include<intrins.h>
    
    #ifndef uchar #define uchar unsigned char#endifsbit  DS1302_CLK = P3^6;            //实时时钟时钟线引脚sbit  DS1302_IO  = P3^5;              //实时时钟数据线引脚sbit  DS1302_RST = P3^4;              //实时时钟复位线引脚//sbit  DS1302_CLK = P3^6;            //实时时钟时钟线引脚//sbit  DS1302_IO  = P3^4;              //实时时钟数据线引脚//sbit  DS1302_RST = P3^5;              //实时时钟复位线引脚
    
    sbit  ACC0 = ACC^0;sbit  ACC7 = ACC^7;
    
    typedef struct __SYSTEMTIME__{ unsigned int Second; unsigned char Minute; unsigned char Hour; unsigned char Week; unsigned char Day; unsigned char Month; unsigned char  Year; unsigned char DateString[9]; unsigned char TimeString[9];
    
    }SYSTEMTIME; //定义的时间类型
    
    #define AM(X) X#define PM(X) (X+12)                      // 转成24小时制#define DS1302_SECOND 0x80#define DS1302_MINUTE 0x82#define DS1302_HOUR  0x84 #define DS1302_WEEK  0x8A#define DS1302_DAY  0x86#define DS1302_MONTH 0x88#define DS1302_YEAR  0x8C#define DS1302_RAM(X) (0xC0+(X)*2)    //用于计算ds1302RAM地址的宏
    
    void DS1302InputByte(unsigned char d) ;unsigned char DS1302OutputByte(void)  ;void Write1302(unsigned char ucAddr, unsigned char ucDa);void DS1302_SetProtect(bit flag);unsigned char Read1302(unsigned char ucAddr);void DS1302_SetTime(unsigned char Address, unsigned char Value);void DS1302_GetTime(SYSTEMTIME *Time);void DateToStr(SYSTEMTIME *Time);void TimeToStr(SYSTEMTIME *Time);void Initial_DS1302(void);#end

     

       主要的程序模块到这里基本上就算准备好了。完整的程序我压缩一下上传到资源吧,(没办法想赚点积分,理解理解),其实到这步,大家应该把完整的程序写出来也不是问题了。

       再来说说其他的吧。在使用keil软件时,总是报这样的错误*** ERROR L107: ADDRESS SPACE OVERFLOW。也是多方查找才找到问题所在。就是我们所定义变量是定义在51的RAM里的,而且供变量存储的只有256或者128个字节(看型号吧),这里看网上说在变量前面加idata,然而并不管用。还是尽量节省RAM吧。只读的数组定义前面加上code,全局变量尽量少点。不行就只能换单片机了毕竟51是一个资源很少 的单片机,不适合一些大工程。最后加上张效果图

     

    算了,我还是把,所有的程序也贴上来吧,也不在乎那几个积分啦 。

    下面的是按键处理程序(这个才是核心程序),和主函数。我从KEIL上复制过来的时候改了一下把edit configuration里的Encode in ANSI 改成了Chinese GB2312.要不然复制过来时中文是乱码。你复制到自己的工程里时应该要改回来吧。

    #include"keyProcess.h"
    void array2show(ARRAY2SHOW *arrayshow0,uchar wch);	 //函数声明//
    void sec2show(SYSTEMTIME *secshow);
    SYSTEMTIME showtime;  
    extern SYSTEMTIME CurrentTime;
    extern ARRAY2SHOW  Alarmandshow;
    /****************************************************************************************************
    函数名称:key_process(uchar mode)
    函数功能:按键处理函数(调节日期,时间,秒表,闹钟)
    输入参数:mode		用来选择模式,是修改日期,时间还是闹钟
    返回值:无
    ****************************************************************************************************/
    void key_process(uchar mode)
    {	
    	
    	uchar Wch=0;
    	uchar flag=0;
    	uchar AlarmWch=0;
    	uchar HourSecWch=0;
    	uchar temp=0;
    	switch(mode)		//在最外层循环中检测按键,确定要设置什么
    	{
    		DS1302_GetTime(&CurrentTime);
    		case MODE0:			//设置时间
    			showtime=CurrentTime;
    			while(1)
    			{	 				
    				DateToStr(&CurrentTime);
    				zifu_dis(1,0,&CurrentTime.DateString[0]); 		//修改时间不影响从1302读日期显示
    				//(麻烦的思想)TArray3=show2array3(&CurrentTime.TimeString[0]);	//将显示的字符形式变成可以直接加1的形式
    				if(key_scan()==K1||key_scan()==K2||key_scan()==K3||key_scan()==K4)//检测有没有按键按下,有按键按下才执行操作
    				{
    					switch(key_scan())			//再次检测按键
    					{	  
    						case K3:				//K3按下,选择时间的哪一位被更改
    								 
    								Wch++;
    								if(Wch==3)
    									Wch=0;
    								break;						
    						case K1:			   //K1按下,数字加一
    							   //(麻烦的思想)TArray3[TimeWch]++;			//转化成单个字符形式显示 
    								if(Wch==0)
    								{
    									showtime.Hour++;
    									if(showtime.Hour==24)
    										showtime.Hour=0;
    								}
    								else if(Wch==1)
    								{
    									showtime.Minute++;
    									if(showtime.Minute==60)
    										showtime.Minute=0;
    								}
    								else if(Wch==2)
    								{
    									showtime.Second++;
    								 	if(showtime.Second==60)
    										showtime.Second=0;
    								}
    								TimeToStr(&showtime);
    								zifu_dis(0,0,&showtime.TimeString[0]); 
    								break;
    	
    						case K2:			   //K2按下,数字减一
    								//(麻烦的思想)TArray3[TimeWch]--;
    								//(麻烦的思想)zifu_dis(1,0,array32show(TArray3)); 
    								if(Wch==0)
    								{
    									showtime.Hour--;
    									if(showtime.Hour==0xff)
    										showtime.Hour=0;
    								}
    								else if(Wch==1)
    								{
    									showtime.Minute--;
    									if(showtime.Minute==0xff)
    										showtime.Minute=0;
    								}
    								else if(Wch==2)
    								{
    									showtime.Second--;
    									if(showtime.Second==0xff)
    										showtime.Second=0;
    								}
    								TimeToStr(&showtime);
    								zifu_dis(0,0,&showtime.TimeString[0]); 
    								break;
    	
    						case K4:  			  //K4按下,确定修改,
    								flag=1;break;
    					 }	 	
    			
    				}
    				 if(flag==1)		 //flag为1时,确定修改,将1302里的时间重置,并退到最初的模式检测
    				 {		
    					DS1302_SetTime(DS1302_HOUR,showtime.Hour);	
    					DS1302_SetTime(DS1302_MINUTE,showtime.Minute);
    					DS1302_SetTime(DS1302_SECOND,showtime.Second);
    					Wch=0;
    					flag=0;
    				 	break;
    				 } 	
    			}
    			 break;
    		case MODE1:			//设置日期
    			showtime=CurrentTime;
    			while(1)
    			{
    				DS1302_GetTime(&CurrentTime);
    				TimeToStr(&CurrentTime);
    				zifu_dis(0,0,&CurrentTime.TimeString[0]); 		   //修改日期,不影响从1302读时间显示
    				//(麻烦的思想)DArray3=show2array3(&CurrentTime.DateString);	   //将显示的字符形式变成可以直接加1的形式
    				if(key_scan()==K1||key_scan()==K2||key_scan()==K3||key_scan()==K4)//检测有没有按键按下,有按键按下才执行操作
    				{
    					switch(key_scan())	//再次检测按键
    					{
    						case K3:			    //K3按下,选择日期的哪一位被更改
    								Wch++;
    								if(Wch==3)
    									Wch=0;
    								break;
    						case K1:			   //K1按下,数字加一
    							    //(麻烦的思想)DArray3[DateWch]=DArray3[DateWch]+1;
    								//(麻烦的思想)zifu_dis(0,0,array32show(DArray3)); 
    								if(Wch==0)
    									showtime.Year++;
    								else if(Wch==1)
    								{
    									showtime.Month++;
    									if(showtime.Month==13)
    										showtime.Month=1;
    								}		
    								else if(Wch==2)
    								{
    									showtime.Day++;
    									if(showtime.Month==1||showtime.Month==3||showtime.Month==5||showtime.Month==7||showtime.Month==8||showtime.Month==10||showtime.Month==12)
    										if(showtime.Day==32)
    											showtime.Day=0;
    									else if(showtime.Month==2)
    										if(showtime.Day=30)
    											showtime.Day=0;
    									else
    										if(showtime.Day==31)
    											showtime.Day=0;	
    								}
    								DateToStr(&showtime);
    								zifu_dis(1,0,&showtime.DateString[0]); 
    								break;
    						case K2:			   //K2按下,数字减一
    								//(麻烦的思想)DArray3[DateWch]--;
    								//(麻烦的思想)zifu_dis(0,0,array32show(DArray3)); 
    								if(Wch==0)
    									showtime.Year--;
    								else if(Wch==1)
    									showtime.Month--;
    								else if(Wch==2)
    									showtime.Day--;
    								DateToStr(&showtime);
    								zifu_dis(1,0,&showtime.DateString[0]); 
    								break;
    						case K4: 
    											   //K4按下退出此循环,回到模式检测循环
    								flag=1;
    								break;
    					 }
    				}
    				 if(flag==1)	//flag为1时,确定修改,将1302里的日期重置,并退到最初的模式检测
    				 {
    				 	DS1302_SetTime(DS1302_YEAR,showtime.Year);	
    					DS1302_SetTime(DS1302_MONTH,showtime.Month);
    					DS1302_SetTime(DS1302_DAY,showtime.Day);
    					flag=0;
    					Wch=0;
    				 	break;
    					
    				 }
    			}
    			 break;
    		case MODE2:			//设置闹钟
    			while(1)
    			{	
    				DS1302_GetTime(&CurrentTime);
    				DateToStr(&CurrentTime);
    				TimeToStr(&CurrentTime);
    				zifu_dis(0,0,&CurrentTime.TimeString[0]); 	 //在设置闹钟时不让时间的显示停下
    				if(key_scan()==K1||key_scan()==K2||key_scan()==K3||key_scan()==K4)//检测有没有按键按下,有按键按下才执行操作
    				{
    					switch(key_scan())	//再次检测按键
    					{
    						case K3:			    //K1按下,选择哪一个闹钟被更改
    								AlarmWch++;
    								if(AlarmWch==4)
    									AlarmWch=0;
    								break;
    						case K2:			   //K2按下,选择闹钟的小时还是秒被更改
    							    HourSecWch++;
    								if(HourSecWch==2)
    									HourSecWch=0;
    								break;							   
    						case K1:			   //K3按下,数字加1
    								Alarmandshow.Alarm[AlarmWch][HourSecWch]++;
    								if(Alarmandshow.Alarm[AlarmWch][HourSecWch]==60)
    									Alarmandshow.Alarm[AlarmWch][HourSecWch]=0;
    								array2show(&Alarmandshow,AlarmWch);
    					
    								zifu_dis(2+AlarmWch%2,2+AlarmWch/2*3,&Alarmandshow.showstring[0]);
    								break;
    						case K4: 			   //K4按下退出此循环,回到模式检测循环
    								flag=1;break;
    					 }
    				}
    				 if(flag==1)
    				 {
    				 	AlarmWch=0;
    					HourSecWch=0;		//最好要将AlarmWch,HourSecWch清零,后面要用
    				 	flag=0;
    				 	break;
    					
    				 }
    			}	
    			break;	
    		case MODE3:					 //秒表
    				
    				while(1)	//此层循环用来显示秒表的初始界面	  	
    				{
    					temp=0;
    					showtime.Second=0;
    					lcd_init();		
    					zifu_dis(0,3,"00.0");
    					if(key_scan()==K1)		//K1按下,秒表开始计时
    					{
    						while(1)	//此层循环是秒表开始后的循环
    							{		 
    								delay_ms(73);		//再算上程序执行的时间,一共为100ms				 
    								sec2show(&showtime);
    								zifu_dis(0,3,&showtime.TimeString[0]);	
    								if(flag==0)
    								showtime.Second++;		//每过100ms,Second++,
    								switch(key_scan())
    								{
    									case K1:
    										zifu_dis(temp/3+1,temp*3%9,&showtime.TimeString[0]);			
    										temp++;		//读一下秒表,记录下
    										if(temp==9)
    											temp=0;
    										break;
    									case K2:
    										flag=~flag;
    										break;
    									case K3:
    										flag=2;
    										break;
    									case K4:
    										flag=1;
    										break;
    								}	
    								if(flag==2||flag==1)
    								{
    									if(flag==2)
    										flag=0;
    									break;	
    								}
    							}
    					}
    					if(flag==1)
    					{
    						flag=0;
    						break;
    					}
    				}
    			lcd_init();
    			for(;AlarmWch<4;AlarmWch++)
    			{
    				//arrayshow.array2[AlarmWch][HourSecWch]=0;
    				array2show(&Alarmandshow,AlarmWch);
    				zifu_dis(AlarmWch/2+2,AlarmWch%2*3+2,&Alarmandshow.showstring[0]);
    			}
    			zifu_dis(2,0,"闹钟");
    			AlarmWch=0;
    			HourSecWch=0;
    			break;				
    	}
    }
     
    /***********************************************************************************************
    函数名称:array32show(uchar *array3)
    函数功能:将存在array[3]里的小时,分钟,秒转换成可以直接显示的形式
    输入参数:*array3 		array[3]的首地址
    返回值:  show			show[9]的首地址,可以直接用来显示
    *************************************************************************************************/
    /*uchar *array32show(uchar *array3)
    {
    	uchar show[5];
    	show[0] = *array3/10+0x30 ;
    	show[1] = *array3++%10+0x30 ;
    	show[2] = ':';
    	show[3] = *array3/10+0x30 ;
    	show[4] = *array3%10+0x30 ;//用LCD显示,要变成ascii码所以加了0x30,用数码管显示的话就不用加了
    	show[5] = '\0';
    	return show;	
    } *///没有用到
    
    /***********************************************************************************************
    函数名称:show2array3(uchar *show)
    函数功能:将存在show[]里的可直接显示的字符转换成可以直接加一的array[3]
    输入参数:*show 		show数组的首地址
    返回值:  array3		array数组的首地址,可以直接用来做加一操作
    *************************************************************************************************/
    /*uchar *show2array3(uchar *show)
    {
    	uchar array3[3];
    	array3[0]=(show[0]-0x30)*10+(show[1]-0x30);
    	array3[1]=(show[3]-0x30)*10+(show[4]-0x30);		
    	array3[2]=(show[6]-0x30)*10+(show[7]-0x30);
    	return array3;	
    }*/ 
    
    void array2show(ARRAY2SHOW *arrayshow0,uchar wch)
    {
    	arrayshow0->showstring[0] = arrayshow0->Alarm[wch][0]/10+0x30 ;
    	arrayshow0->showstring[1] = arrayshow0->Alarm[wch][0]%10+0x30 ;
    	arrayshow0->showstring[2] =':';
    	arrayshow0->showstring[3] = arrayshow0->Alarm[wch][1]/10+0x30 ;
    	arrayshow0->showstring[4] = arrayshow0->Alarm[wch][1]%10+0x30 ;
    	//用LCD显示,要变成ascii码所以加了0x30,用数码管显示的话就不用加了
    	arrayshow0->showstring[5] = '\0';
    }
    
    void sec2show(SYSTEMTIME *secshow)
    {
    	secshow->TimeString[0]=secshow->Second/100+0x30;
    	secshow->TimeString[1]=secshow->Second%100/10+0x30;
    	secshow->TimeString[2]='.';
    	secshow->TimeString[3]=secshow->Second%10+0x30;
    	secshow->TimeString[4]='\0';
    }
     
    #ifndef __KEYPROCESS_H
    #define _KEYPROCESS_H
    
    #include<reg52.h>
    #include<stdio.h>
    #include"delay.h"
    #include"key.h"
    #include"ds1302.h"
    #include"LCD12864.h"
    
    
    #ifndef uchar
    	#define uchar 	unsigned char
    #endif
    
    typedef struct _ARRAYSHOW_
    {
    	unsigned char   showstring[6];
    	unsigned char  Alarm[4][2];
    }ARRAY2SHOW;
    
    typedef struct _SHOW_
    {
    	unsigned char   showstring[6];
    	unsigned char  array2[4][2];
    }show;
    
    #define MODE0 		0X00
    #define MODE1		0X01
    #define MODE2 		0X02
    #define MODE3		0X03
    #define TIMESET		MODE0	
    #define DATESET		MODE1
    #define ALARMSET	MODE2
    #define SECCON		MODE3
    
    void key_process(uchar mode);
    
    #endif
    

    /***********************************************************************************
    程序说明:利用12864液晶和ds1302配合按键实现 万年历,四路可调闹钟,秒表(基于51单片机)
    作者:哈尔滨工程大学  黄子炫
    ***********************************************************************************/
    #include <reg52.h>
    #include<stdio.h>
    #include"delay.h"
    #include"ds1302.h"
    #include"LCD12864.h"
    #include"key.h"
    #include"buzzer.h"
    #include"keyProcess.h"
    SYSTEMTIME  CurrentTime;	//存储当前从ds1302中读到的时间日期等
    ARRAY2SHOW  Alarmandshow;	//存储闹钟的时间,和用于闹钟显示的字符串
    char code table[7][20]={{"星期壹"},{"星期贰"},{"星期叁"},{"星期肆"},{"星期伍"},{"星期陆"},{"星期日"}};
    sbit led=P1^7;
    void main()
    {	
    	uchar mode;
    	Initial_DS1302();				//ds1302初始化
    //	DS1302_SetTime(DS1302_HOUR,10);	
    //	DS1302_SetTime(DS1302_MINUTE,0);
    //	DS1302_SetTime(DS1302_SECOND,0);//向ds1302中写初始时间
    //	DS1302_SetTime(DS1302_YEAR,17);	
    //	DS1302_SetTime(DS1302_MONTH,1);
    //	DS1302_SetTime(DS1302_DAY,16);	//向ds1302中写初始日期
    	DS1302_SetTime(DS1302_WEEK,3);
    	
    	lcd_init();						//lcd12864初始化
    	zifu_dis(2,0,"闹钟");
    	zifu_dis(2,2,"00:00");
    	zifu_dis(2,5,"00:00");
    	zifu_dis(3,2,"00:00");
    	zifu_dis(3,5,"00:00");			 //设置闹钟的初始显示
      	
    	while(1)
    	{
    		if(key_scan()==K1||key_scan()==K2||key_scan()==K3||key_scan()==K4)
    		{				
    			switch (key_scan())
    			{	
    				case K1: mode=MODE0;break;		//MODE0设置时间
    				case K2: mode=MODE1;break;		//MODE0设置日期
    				case K3: mode=MODE2;break;		//MODE0设置闹钟
    				case K4: mode=MODE3;break;		//MODE0设置秒表
    			}
    			key_process(mode);				   //按键处理函数
    		}		
    		DS1302_GetTime(&CurrentTime);
    		DateToStr(&CurrentTime);
    		TimeToStr(&CurrentTime);
    		zifu_dis(0,0,&CurrentTime.TimeString[0]); 
    		zifu_dis(1,0,&CurrentTime.DateString[0]); 		 //读出ds1302里的时间,在lcd上显示
    		zifu_dis(1,4,table[CurrentTime.Week]);
    		
    		if((CurrentTime.Hour==Alarmandshow.Alarm[0][0]&&CurrentTime.Minute==Alarmandshow.Alarm[0][1])||
    		   (CurrentTime.Hour==Alarmandshow.Alarm[1][0]&&CurrentTime.Minute==Alarmandshow.Alarm[1][1])||
    		   (CurrentTime.Hour==Alarmandshow.Alarm[2][0]&&CurrentTime.Minute==Alarmandshow.Alarm[2][1])||
    		   (CurrentTime.Hour==Alarmandshow.Alarm[3][0]&&CurrentTime.Minute==Alarmandshow.Alarm[3][1]))
    		   //检查所设的闹钟时间和现在的时间是否一致,是则响蜂鸣器。
    		   
    				buzzer_delay();
    	}		
    }
    												
    这个是蜂鸣器要用到的,就是一个IO口拉高拉低。
     
    #include"buzzer.h"
    
    void buzzer_on(void)
    {
    		BuzzerPort=0;
    }
    
    void buzzer_off(void)
    {
    		BuzzerPort=1;
    }
    
    void buzzer_delay(void)
    {
    		BuzzerPort=0;
    		delay_ms(400);
    		BuzzerPort=1;
    		delay_ms(400);
    }
    #ifndef __BUZZER_H
    #define _BUZZER_H
    
    #include<reg52.h>
    #include"delay.h"
    
    #ifndef uchar
    	#define uchar 	unsigned char
    #endif
    
    sbit BuzzerPort=P2^2;
    
    void buzzer_on(void);
    void buzzer_off(void);
    void buzzer_delay(void);
    
    #endif
    

     完工~

     

     

     

     

     

     

     

     

     

     

       

     

     

     

     

         

     

     

             

     

     

    搜索

    展开全文
  • 单片机+时钟+万年历

    2020-07-21 09:59:17
    单片机课程答辩,内含时钟+万年历代码 仿真图+加文档+加ppt+实物代码+实物教程
  • 本设计包括四个按键,单片机复位按键,设置键,加键,减键,闹钟设置键。 按下复位键后程序将复位。 开始运行后程序默认进入时钟显示,显示为时分秒星期当前温度。当闹钟时间到时候会有蜂鸣器报警。没有按键按下情况...

    演示视频:https://v.youku.com/v_show/id_XNDQ1OTM5NzA1Mg==.html?spm=a2hzp.8244740.0.0
    将链接复制至IE浏览器打开!!!
    功能操作说明:
    本设计包括四个按键,单片机复位按键,设置键,加键,减键,闹钟设置键。
    按下复位键后程序将复位。
    开始运行后程序默认进入时钟显示,显示为时分秒星期当前温度。当闹钟时间到时候会有蜂鸣器报警。没有按键按下情况显示。
    按下设置键后可以设置年月日时分秒参数
    按下闹钟设置键可以设置闹钟时间。

    展开全文
  • 基于51单片机的LCD1602电子时钟

    千次阅读 2018-12-16 20:01:11
    51系列单片机是各单片机中最为典型和最有代表性的一种。由RAM ,ROM,CPU构成,定时,计数和多种接口于一体的微控制器。本次设计的数字电子时钟采用了STC89C52芯片进行控制,使用DS1302时钟芯片产生时钟数据,通过LCD...

    摘要:
    51系列单片机是各单片机中最为典型和最有代表性的一种。由RAM ,ROM,CPU构成,定时,计数和多种接口于一体的微控制器。本次设计的数字电子时钟采用了STC89C52芯片进行控制,使用DS1302时钟芯片产生时钟数据,通过LCD1602液晶显示屏进行刷新显示。同时,使用4*4矩阵键盘,可以进行日期和时间的调整,且操作简单,计时误差小,显示亮度高,具有良好的实用价值。

    一.电子时钟的功能及原理
    1.本设计采用时钟芯片,通过单片机对其输出的时间数据进行年、月、日、时、分、秒的解码,并将解码后的数据送到显示屏进行显示。单片机使用定时器T0,每定时2ms后,单片机便产生一个的计时溢出中断,在中断服务函数对矩阵按键进行动态扫描,这样既避免了按键消抖,又减轻了CPU的工作载荷。
    2.此外,为了提高电子时钟的实用性,本课题还添加了一个矩阵键盘和蜂鸣器,通过矩阵键盘来调整时间,16个按键分别为‘0~9数字键’、‘设置键’、‘esc键’、‘增加键’、‘减少键’、‘向左键’、‘向右键’。 单片机确定有按键按下,在蜂鸣器控制脚产生一个高电平,使蜂鸣器发出“嘀”的一声,以此来说明按下的动作被执行了。
    3.同时电子时钟具有报时的功能,当时间到了整点,比如到了10点钟时,蜂鸣器会连续发出10个响声,表示现在是10点正;当时间到了某点30分时,蜂鸣器会响一声,表示现在是某时半点。

    二.电子时钟的硬件设计
    1.总体硬件框图
    在这里插入图片描述
    2 电子时钟硬件系统主要模块功能简要介绍
    (1)单片机:本次设计采用AT89C52芯片,低功耗、高性能CMOS8位微控制器,具有 8K 在系统可编程Flash 存储器。256字节RAM, 32 位I/O 口线,与工业80C51 产品指令和引脚完全兼容。价格较低,能满足本次设计的要求
    在这里插入图片描述
    (2) 电源和复位模块:AT89C52需5V电压,所以可以采用USB接口的5V电源对其供电,复位电路可采用上电复位、按键电平复位、按键脉冲复位3种,本次采用按键电平复位。
    (3)显示模块:该模块由LCD1602液晶显示屏组成,共有16个引脚,其中有11个需与单片机相接,工作控制引脚分别接于单片机的P2.4-P2.6脚,数据引脚接于单片机的P0.0-P0.7口上,使用可调电阻实现对显示屏文字清析度的调节。
    在这里插入图片描述
    (4)矩阵键盘模块:键盘由16个按键组成,行脚分别接在单片机的P1.0-P1.3口,列脚分别接在单片机P1.4-P1.7口上。
    在这里插入图片描述
    (5)DS1302时钟模块:为了保证同步工作方式的思想,单片机必须有时钟信号,以使其系统在时钟信号的控制下按时序协调工作。
    在这里插入图片描述
    (6)总体实物图
    在这里插入图片描述
    3. 电子时钟元器件清单
    在这里插入图片描述
    三.电子时钟软件系统的设计

    1 电子时钟软件系统主要模块功能简要介绍
    (1) 主程序:主程序的主要功能是进行定时器/计数器,显示缓冲区的初始化,显示,以及判断是否有功能键按下,判断按下的键并调相应的键功能程序。
    (2) 键功能程序:键功能程序的主要功能是执行对应的功能,主要对16个按键进行编码,当单片机得到按下的键的编码,单片机便会跳转到相应的子程序执行相应的功能。
    (3) 中断服务程序:中断服务程序的主要功能是进行计时操作和按键扫描,程序开始进行按键检测,然后判断计数溢出是否满了100次,若不满100次则表明没有到达最小的刷新时间,则中断结束;若满100次表明已到达了刷新时间,则将刷新时间标志位置1,进行时间的刷新。

    2 电子时钟软件系统程序流程框图
    在这里插入图片描述
    3.主程序代码

    void main()
    {
        InitLCD1602(); //初始化 lcd1602
        InitDS1302(); //初始化 DS1302
        ConfgiTimer0(2); //初始化定时器,并定时 2ms
        Delay_nms(10);
        buz = 0;
        LcdShowStr(0,0,"Date:20 - - ");
        LcdShowStr(0,1,"Time: : : ");
        while(1)
        {
            KeyDriver();//检测按键动作
            if (flag200ms == 1 && (setTimeIndex == 0)) //每 200ms 且 setTimeIndex==0 处于非设定时间状态时刷新一次时间显示
            {
                flag200ms = 0;
                GetTimeFromDS1302(&timeBuf); //从 DS1302 中获取时间到 timeBuf 结构体指针变量的成员中
                if(timeBuf.sec != psec) //当前秒值和上一次的秒值不相等
                {
                    RefreshLcdShowTime();//刷新时间显示
                    psec = timeBuf.sec;//备份当前的秒值(秒寄存器值)
                    On_Timr_Alarm();
                }
            }
        }
    }
    

    源码下载:关注公众号,首页回复“电子时钟”获取电子时钟的源码工程
    在这里插入图片描述

    展开全文
  • 安徽界首原创农历干支纪年、生肖、节日、纪念日、51MCU+12864串口万年历时钟 安徽界首马
  • 功能说明: LCD1602液晶显示年、月、日、时、分、秒、星期、温度,三个按键控制时间日期调整以及闹钟设定。   三个按键: 1、“校时”键,每次按下分别对应调整秒、调整分钟、调整小时、调整星期、调整日、调整...
  • 要求在液晶上显示AD转换信号,年月日,时间。 单片机:STM32f103rbt6 3.2V液晶,型号qc12864b
  • 我设计了一块PCB,走线非常细,万年历时钟芯片离五一单片机很远。 发送数据读取异常,读取出来的字往往不对,而且数据还乱跳。 下面这个图就是我的电路,没加上拉电阻。 另外,其他可能原因: 芯片被焊坏了; 晶振不...
  • 程序开发环境为IAR FOR STM8 1.40 主控MCU为STM8S103F3P6 温度采集芯片为TMP275,采用IIC接口 时钟芯片位高精度的DS3231,采用IIC接口 显示采用2个6位LED数码管显示,每个数码管均采用数码管驱动芯片TM1620控制,TM...
  • 引脚说明 GND ------ 地线  VCC ------ 电源(5V or 3.3v 电源不同显示效果有点差别) SDA ------ I2C 数据线 SCL ------ I2C 时钟线   接线方法 LCD1602 i2c模块 Ardunio Uno   ...-...
  • 1.硬件﹑软件方案的设计说明。 2.用PROTEL工具软件画出系统电路原理图,系统元件布局﹑布线图。 3.系统的元器件清单。 4.提供程序流程图。 5.提供源程序清单(带中文注释)。 6.提供系统的使用和操作说明。...
  • 基于PCF8563的电子时钟设计,原理图
  • 个人经过调试 可以实现,选用PCF8563芯片,C51单片机来实现
  • 一、方案确定 今天要实现手表的万年历功能。实现万年历功能有三种方式 1.新建一个1秒定时的APP_TIMER。...APP_TIMER采用轮询执行而非抢占的方式,假如其它APP_TIMER耗时较长,例如有一个APP_TIMER在采集心率,...
  • 一个74HC595和两个74LS138的16位数码管显示,加个光敏电阻可以自动调节数码管亮度。实现电子的基本功能,时间,农历,日期,星期等显示及修改功能
  • 设计一个智能化万年历时钟电路,LED数码管作为电路的显示部分,按钮开关作为调时部分,通过与单片机连接数码管动态显示年、月、日、时、分、秒、星期、温度。并能准确计算闰年闰月的显示。
  • 万年历—proteus仿真

    2020-07-24 23:31:33
    基于proteus的万年历仿真,可供单片机初学者设计万年历时参考。
  • 课程涉及如何使用STM32的硬件SPI和IIC快速驱动OLED屏幕,如何驱动温湿度模块DTH11,如何使用STM32的外部中断和捕获来解码红外遥控器,以及使用STM32的RTC资源,打造一个集温湿度测量于一体的万年历时钟项目。
  • 基于51单片机的半导体制冷小冰箱

    千次阅读 2016-11-28 20:09:44
    基于51单片机的半导体制冷小冰箱 1、设计目的 温度控制系统广泛应用于社会生活的各个领域,比如温室、水池、发酵缸、电源等场所的控制。对于课程设计来说,选题用51单片机来进行半导体制冷小冰箱的设计...
1 2
收藏数 29
精华内容 11
关键字:

单片机万年历时钟