硬件设计

本设计由数据显示模块、温度采集模块、时间处理模块和调整设置模块四个模块组成。系统以AT89S52单片机为控制器,以串行时钟日历芯片DS1302记录日历和时间,它可以对年、月、日、时、分、秒进行计时,还具有闰年补偿等多种功能。温度采集选用DS18B20芯片,万年历采用直观的数字显示,数据显示采用1602A液晶显示模块,可以在LCD上同时显示年、月、日、星期、时、分、秒,还具有时间校准等功能。此万年历具有读取方便、显示直观、功能多样、电路简洁。
硬件框图:

(1)用4个按键实现所有功能,计时准确。
(2)可以设定闹钟功能。
(3)有阴历功能,平年闰年准确无误。
(4)液晶能显示年、月、日、星期、时、分、秒、温度。

仿真图:

农历:

程序设计

#include<reg52.h>
//#include"DS18B20_3.H"
#include <string.h>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char
#define wd 1                //定义是否有温度功能  =0时无温度,=1时有温度
#include "eeprom52.h"#define yh 0x80 //LCD第一行的初始位置,因为LCD1602字符地址首位D7恒定为1(100000000=80)
#define er 0x80+0x40 //LCD第二行初始位置(因为第二行第一个字符位置地址是0x40)//液晶屏的与C51之间的引脚连接定义(显示数据线接C51的P0口)
sbit en=P2^7;
sbit rw=P2^6;   //如果硬件上rw接地,就不用写这句和后面的rw=0了
sbit rs=P2^5;//校时按键与C51的引脚连接定义sbit set=P3^0;      //设置键
sbit add=P3^1;     //加键
sbit dec=P3^2;     //减键
sbit seeNL_NZ=P3^3;    //查看农历/闹钟sbit DQ=P3^7;     //
sbit buzzer=P2^0;  //蜂鸣器,通过三极管8550驱动,端口低电平响sbit led=P2^4;       //LCD背光开关
bit  led1=1;
bit NZ_sdgb=1;
unsigned char temp_miao;
unsigned char bltime;  //背光亮的时间//DS1302时钟芯片与C51之间的引脚连接定义
sbit IO=P1^1;
sbit SCLK=P1^0;
sbit RST=P1^2;char a,miao,shi,fen,ri,yue,nian,week,setn,temp;
uint flag;
//flag用于读取头文件中的温度值,和显示温度值
bit c_moon;char nz_shi,nz_fen,setNZn;       //定义闹钟变量
uchar shangyimiao,bsn,temp_hour;            //记录上一秒时间
uchar T_NL_NZ;                          //计数器
bit timerOn=0;                         //闹钟启用标志位
bit baoshi=0;                          //整点报时标志位
bit  p_r=0;                                //平年/润年  =0表示平年,=1表示润年
data uchar year_moon,month_moon,day_moon;sbit ACC0=ACC^0;
sbit ACC7=ACC^7;
/************************************************************
ACC累加器=A
ACC.0=E0H ACC.0就是ACC的第0位。Acc可以位寻址。累加器ACC是一个8位的存储单元,是用来放数据的。但是,这个存储单元有其特殊的地位,
是单片机中一个非常关键的单元,很多运算都要通过ACC来进行。以后在学习指令时,
常用A来表示累加器。但有一些地方例外,比如在PUSH指令中,就必须用ACC这样的名字。
一般的说法,A代表了累加器中的内容、而ACC代表的是累加器的地址。
***************************************************************//******************把数据保存到单片机内部eeprom中******************/
void write_eeprom()
{SectorErase(0x2000);byte_write(0x2000, nz_shi);byte_write(0x2001, nz_fen);byte_write(0x2002, timerOn);byte_write(0x2060, a_a);
}/******************把数据从单片机内部eeprom中读出来*****************/
void read_eeprom()
{nz_shi   = byte_read(0x2000);nz_fen = byte_read(0x2001);timerOn = byte_read(0x2002);a_a      = byte_read(0x2060);
}/**************开机自检eeprom初始化*****************/
void init_eeprom()
{read_eeprom();     //先读if(a_a != 1)       //新的单片机初始单片机内问eeprom{nz_shi   = 12;nz_fen = 30;timerOn=0;a_a = 1;write_eeprom();       //保存数据}
}///月份数据表
code uchar day_code1[9]={0x0,0x1f,0x3b,0x5a,0x78,0x97,0xb5,0xd4,0xf3};
code uint day_code2[3]={0x111,0x130,0x14e};/*
函数功能:输入BCD阳历数据,输出BCD阴历数据(只允许1901-2099年)
调用函数示例:Conversion(c_sun,year_sun,month_sun,day_sun)
如:计算2004年10月16日Conversion(0,0x4,0x10,0x16);
c_sun,year_sun,month_sun,day_sun均为BCD数据,c_sun为世纪标志位,c_sun=0为21世
纪,c_sun=1为19世纪
调用函数后,原有数据不变,读c_moon,year_moon,month_moon,day_moon得出阴历BCD数据
*/bit c_moon;
//子函数,用于读取数据表中农历月的大月或小月,如果该月为大返回1,为小返回0
bit get_moon_day(uchar month_p,uint table_addr)
{uchar temp10;switch (month_p){case 1:{temp10=year_code[table_addr]&0x08;if (temp10==0)return(0);else return(1);}case 2:{temp10=year_code[table_addr]&0x04;if (temp10==0)return(0);else return(1);}case 3:{temp10=year_code[table_addr]&0x02;if (temp10==0)return(0);else return(1);}case 4:{temp10=year_code[table_addr]&0x01;if (temp10==0)return(0);else return(1);}case 5:{temp10=year_code[table_addr+1]&0x80;if (temp10==0) return(0);else return(1);}case 6:{temp10=year_code[table_addr+1]&0x40;if (temp10==0)return(0);else return(1);}case 7:{temp10=year_code[table_addr+1]&0x20;if (temp10==0)return(0);else return(1);}case 8:{temp10=year_code[table_addr+1]&0x10;if (temp10==0)return(0);else return(1);}case 9:{temp10=year_code[table_addr+1]&0x08;if (temp10==0)return(0);else return(1);}case 10:{temp10=year_code[table_addr+1]&0x04;if (temp10==0)return(0);else return(1);}case 11:{temp10=year_code[table_addr+1]&0x02;if (temp10==0)return(0);else return(1);}case 12:{temp10=year_code[table_addr+1]&0x01;if (temp10==0)return(0);else return(1);}case 13:{temp10=year_code[table_addr+2]&0x80;if (temp10==0)return(0);else return(1);}default:return(2);}
}/*
函数功能:输入BCD阳历数据,输出BCD阴历数据(只允许1901-2099年)
调用函数示例:Conversion(c_sun,year_sun,month_sun,day_sun)
如:计算2004年10月16日Conversion(0,0x4,0x10,0x16);
c_sun,year_sun,month_sun,day_sun均为BCD数据,c_sun为世纪标志位,c_sun=0为21世
纪,c_sun=1为19世纪
调用函数后,原有数据不变,读c_moon,year_moon,month_moon,day_moon得出阴历BCD数据
*/void Conversion(bit c,uchar year,uchar month,uchar day)
{                         //c=0 为21世纪,c=1 为19世纪 输入输出数据均为BCD数据uchar temp1,temp2,temp3,month_p;uint temp4,table_addr;bit flag2,flag_y;temp1=year/16;   //BCD->hex 先把数据转换为十六进制temp2=year%16;// year=temp1*10+temp2;year=temp1*16+temp2;temp1=month/16;temp2=month%16;//month=temp1*10+temp2;month=temp1*16+temp2;temp1=day/16;temp2=day%16;//day=temp1*10+temp2;day=temp1*16+temp2;//定位数据表地址if(c==0){                   table_addr=(year+0x64-1)*0x3;}else {table_addr=(year-1)*0x3;}//定位数据表地址完成//取当年春节所在的公历月份temp1=year_code[table_addr+2]&0x60; temp1=_cror_(temp1,5);//取当年春节所在的公历月份完成//取当年春节所在的公历日temp2=year_code[table_addr+2]&0x1f; //取当年春节所在的公历日完成// 计算当年春年离当年元旦的天数,春节只会在公历1月或2月if(temp1==0x1){  temp3=temp2-1;  }  else{temp3=temp2+0x1f-1;        }// 计算当年春年离当年元旦的天数完成//计算公历日离当年元旦的天数,为了减少运算,用了两个表//day_code1[9],day_code2[3]//如果公历月在九月或前,天数会少于0xff,用表day_code1[9],//在九月后,天数大于0xff,用表day_code2[3]//如输入公历日为8月10日,则公历日离元旦天数为day_code1[8-1]+10-1//如输入公历日为11月10日,则公历日离元旦天数为day_code2[11-10]+10-1if (month<10){ temp4=day_code1[month-1]+day-1;}else{temp4=day_code2[month-10]+day-1;}if ((month>0x2)&&(year%0x4==0)){  //如果公历月大于2月并且该年的2月为闰月,天数加1temp4+=1;}//计算公历日离当年元旦的天数完成//判断公历日在春节前还是春节后if (temp4>=temp3){ //公历日在春节后或就是春节当日使用下面代码进行运算temp4-=temp3;month=0x1;month_p=0x1;  //month_p为月份指向,公历日在春节前或就是春节当日month_p指向首月flag2=get_moon_day(month_p,table_addr); //检查该农历月为大小还是小月,大月返回1,小月返回0flag_y=0;if(flag2==0)temp1=0x1d; //小月29天else temp1=0x1e; //大小30天temp2=year_code[table_addr]&0xf0;temp2=_cror_(temp2,4);  //从数据表中取该年的闰月月份,如为0则该年无闰月while(temp4>=temp1){temp4-=temp1;month_p+=1;if(month==temp2){flag_y=~flag_y;if(flag_y==0)month+=1;}else month+=1;flag2=get_moon_day(month_p,table_addr);if(flag2==0)temp1=0x1d;else temp1=0x1e;}day=temp4+1;}else{  //公历日在春节前使用下面代码进行运算temp3-=temp4;if (year==0x0){year=0x63;c=1;}else year-=1;table_addr-=0x3;month=0xc;temp2=year_code[table_addr]&0xf0;temp2=_cror_(temp2,4);if (temp2==0)month_p=0xc; elsemonth_p=0xd; ////month_p为月份指向,如果当年有闰月,一年有十三个月,月指向13,无闰月指向12flag_y=0;flag2=get_moon_day(month_p,table_addr);if(flag2==0)temp1=0x1d;else temp1=0x1e;while(temp3>temp1){temp3-=temp1;month_p-=1;if(flag_y==0)month-=1;if(month==temp2)flag_y=~flag_y;flag2=get_moon_day(month_p,table_addr);if(flag2==0)temp1=0x1d;else temp1=0x1e;}day=temp1-temp3+1;}c_moon=c;                 //HEX->BCD ,运算结束后,把数据转换为BCD数据temp1=year/10;temp1=_crol_(temp1,4);temp2=year%10;year_moon=temp1|temp2;temp1=month/10;temp1=_crol_(temp1,4);temp2=month%10;month_moon=temp1|temp2;temp1=day/10;temp1=_crol_(temp1,4);temp2=day%10;day_moon=temp1|temp2;
}

附:http://www.jh-tec.cn/archives/7125

基于51单片机的电子时钟万年历带农历温度proteus仿真相关推荐

  1. 基于51单片机的DS12C887电子钟万年历带农历温度

    基于51单片机的DS12C887电子钟万年历( proteus仿真+程序+讲解视频) 仿真图proteus 7.8及以上 程序编译器:keil 4/keil 5 编程语言:C语言 设计编号:S0028 ...

  2. 基于51单片机的电子时钟万年历温度仿真数码管显示

    硬件设计 仿真图1: A. 由数码管作为显示器,三个按键可以设置时间. 仿真图2: A 由数码管作为显示器,可通过开关设置年月日星期等时间: 程序设计1 #include <reg51.h> ...

  3. c51单片机时钟c语言程序设计,基于51单片机的电子时钟设计..doc

    -- I -- - - I -- 设计题目: 基于 51 单片机的电子时钟设计 摘要 单片机,是集 CPU ,RAM ,ROM ,定时器,计数器和多种接口于一体的微控制器.自 20 世纪 70 年代问 ...

  4. 基于51单片机LCD1602电子时钟实物制作

    之前写了51单片机的LCD1602的程序,现在画了电路图,焊接了电路板,做出了基于51单片机LCD1602电子时钟的实物. 注意事项: 焊接过程中,注意提前布局电路. 对应好端口(避免接线错误),我由 ...

  5. 基于51单片机的电子时钟设计

    基于51单片机的电子时钟设计 0 功能介绍 1.从DS1302中读取时间显示 2.一共4个按键,按键1按下进入修改时间模式,再按下切换修改的时间变量,这个时候第2和3个按键就是修改时间变量的按键,修改 ...

  6. 【036】基于51单片机的电子时钟与秒表Proteus仿真设计

    一.压缩包资料内容 (1).基于51单片机的电子时钟与秒表proteus仿真设计一份: (2).基于51单片机的电子时钟与秒表proteus仿真设计keli源代码一份: (3).基于51单片机的电子时 ...

  7. 【033】基于51单片机的步进电机角度测量与速度设定Proteus仿真设计

    一.压缩包资料内容 (1).基于51单片机的步进电机角度测量与速度设定proteus仿真设计一份: (2).基于51单片机的步进电机角度测量与速度设定proteus仿真设计keli源代码一份: (3) ...

  8. 1430基于51单片机的管道压力检测及泄漏检测Proteus仿真

    [前言] hello 大家好,今天给大家讲一讲基于51单片机的管道压力检测及泄漏检测Proteus仿真. 该项目的功能如下: 1.LCD1602液晶实时显示当前始端和末端压力,压力阈值 2.按键启动/ ...

  9. 基于51单片机CO一氧化碳可燃气体浓度检测超限报警Proteus仿真

    资料编号:160   下面是相关功能视频演示: 160-基于51单片机CO一氧化碳可燃气体浓度检测超限报警Proteus仿真(源码+仿真+全套资料) 功能介绍: 采用51单片机作为CPU,ADC083 ...

最新文章

  1. 计算机count的功能是,全国计算机二级Access每日练习4
  2. 在Windows下编译FFmpeg详细说明
  3. python连接kafka-python连接kafka生产者,消费者脚本
  4. cuda nsight 调试和性能分析
  5. hdu-5707-Combine String
  6. Eclipse安装aptana
  7. php打印订单,WooCommerce: 打印订单
  8. 3-6 字符和字符串处理
  9. Linux下编写简单的程序
  10. c++中的c_str()函数
  11. atitit.基于bat cli的插件管理系统.doc
  12. HCP数据的下载,以及头动文件和CSF文件的所在位置
  13. Android常用对话框
  14. 前端最新2022面试题(JS)
  15. Semi迎来重要试驾客户,特斯拉致力于将其推向市场
  16. 假如举行一场世界功夫大赛,这33位动作片明星谁可跻身前十?
  17. August Rush
  18. 将二维数组中最大值的 行和列的下标打印出来
  19. java方法声明无效_Java错误 - “无效的方法声明;需要返回类型”
  20. knife4j:快速入门

热门文章

  1. 计算机软件安装检查工具,正版软件检查工具部署应用培训.pptx
  2. ASP技巧:让Len,Left,Right函数识别中文
  3. 智能公路发展现状与关键技术
  4. Python数据类型,if语句
  5. NetCore中带图片的word转html (NPOI.Word2Html)
  6. 【factoryio】虚拟仓储实现(入仓出仓)
  7. 如何防止短信验证码接口、登录注册入口被恶意调用攻击?
  8. JAVA改变图片大小,将图片改为Jpg格式
  9. 洛谷 P2336 [SCOI2012]喵星球上的点名
  10. 任正非再露面!三天去了三所高校,传递两个重要信号