最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 正文

基于单片机的万年历设计

来源:动视网 责编:小OO 时间:2025-09-23 18:37:36
文档

基于单片机的万年历设计

实现功能:(1)显示年月日,时分秒,星期与温度(2)年月日,时分秒均可调,具备自动调节闰年的功能(3)具有闹钟功能,且开关控制闹钟的开启与关闭(4)具有整点报时功能一、概述、设计思路该设计方案是以ATC51单片机为核心,采用LCD1602液晶屏幕显示系统,辅以时钟模块,温度采集模块、日期提醒、键盘时间调整预设置等模块,所构建的数字时钟系统,能动态显示实时时钟的时、分、秒,数据显示(误差在30每天),对闹铃方式与温度调节模块进行了重点设计实现SB0、SB1、SB2、SB3四个键实现时钟正
推荐度:
导读实现功能:(1)显示年月日,时分秒,星期与温度(2)年月日,时分秒均可调,具备自动调节闰年的功能(3)具有闹钟功能,且开关控制闹钟的开启与关闭(4)具有整点报时功能一、概述、设计思路该设计方案是以ATC51单片机为核心,采用LCD1602液晶屏幕显示系统,辅以时钟模块,温度采集模块、日期提醒、键盘时间调整预设置等模块,所构建的数字时钟系统,能动态显示实时时钟的时、分、秒,数据显示(误差在30每天),对闹铃方式与温度调节模块进行了重点设计实现SB0、SB1、SB2、SB3四个键实现时钟正
实现功能:

(1)显示年月日,时分秒,星期与温度

(2)年月日,时分秒均可调,具备自动调节闰年的功能

(3)具有闹钟功能,且开关控制闹钟的开启与关闭

(4)具有整点报时功能

一、概述、设计思路

该设计方案是以ATC51单片机为核心,采用LCD1602液晶屏幕显示系统,辅以时钟模块,温度采集模块、日期提醒、键盘时间调整预设置等模块,所构建的数字时钟系统,能动态显示实时时钟的时、分、秒,数据显示(误差在30每天),对闹铃方式与温度调节模块进行了重点设计 实现SB0、SB1、SB2、SB3四个键实现时钟正常显示,调时,及闹钟时间设置。本系统设计大部分功能有软件来实现,使电路简单明了,系统稳定性也得大大提高。

二、系统组成与工作原理

1、工作原理:

   本设计采用STCC51单片机作为本次课程设计的控制模块。单片机可把由DS18B20、DS1302、AT24C02中的数据利用软件来进行处理,从而把数据传输到显示模块,实现温度、日历和闹铃的显示。以LCD液晶显示器为显示模块,把单片机传来的的数据显示出来,并且显示多样化,在显示电路中,主要靠按键来实现各种显示要求的选择与切换。

2、总是设计框架图:

3、系统硬件概述:

该电路是由单片机STCC52为核心,具有在线编程功能,低功耗,时钟电路采用芯片1302,它是一款高性能、低功耗、自带RAM的实时时钟芯片,具有掉电自动保存功能。可自动对秒、分、时、日、周、月、年进行计数,具有闰年补偿功能,而且精度高位的RAM做为数据暂存区,工作电压2.5V~5.5V范围内,2.5V时耗电小于300nA。显示模块采用LCD1602显示屏,它内置192种字符,可显示32个符号或数字,清晰可见,而且功率消耗小寿命长抗干扰能力强。其工作电压为5v。温度采集模块采用温度传感器18b20。

三、单元电路的设计与分析

    整个电子时钟系统电路可分为六大部分:处理单元(CPU)、复位电路部分、显示部分、键盘输入部分、温度采集部分。

1、MCS-51单片机

S51各引脚功能介绍:

VCC:

S51 电源正端输入,接+5V。

VSS:

电源地端。

XTAL1:

单芯片系统时钟的反相放大器输入端。

XTAL2:

系统时钟的反相放大器输出端,一般在设计上只要在 XTAL1 和 XTAL2 上接上一只石英振荡晶体系统就可以动作了,此外可以在两引脚与地之间加入一 20PF 的小电容,可以使系统更稳定,避免噪声干扰而死机。

RESET:

S51的重置引脚,高电平动作,当要对晶片重置时,只要对此引脚电平提升至高电平并保持两个机器周期以上的时间,ATS51便能完成系统重置的各项动作,使得内部特殊功能寄存器之内容均被设成已知状态,并且至地址0000H处开始读入程序代码而执行程序。

EA/Vpp:

"EA"为英文"External Access"的缩写,表示存取外部程序代码之意,低电平动作,也就是说当此引脚接低电平后,系统会取用外部的程序代码(存于外部EPROM中)来执行程序。因此在8031及8032中,EA引脚必须接低电平,因为其内部无程序存储器空间。如果是使用 8751 内部程序空间时,此引脚要接成高电平。此外,在将程序代码烧录至8751内部EPROM时,可以利用此引脚来输入21V的烧录高压(Vpp)。

ALE/PROG:

端口3的管脚设置:

P3.0:RXD,串行通信输入。

P3.1:TXD,串行通信输出。

P3.2:INT0,外部中断0输入。

P3.3:INT1,外部中断1输入。

P3.4:T0,计时计数器0输入。

P3.5:T1,计时计数器1输入。

P3.6:WR:外部数据存储器的写入信号。

P3.7:RD,外部数据存储器的读取信号。

2、复位电路

电路图如下:

上电自动复位是通过外部复位电路的电容充电来实现的。只要Vcc的上升时间不超过1ms,就可以实现自动上电复位。

     

3、时钟电路

时钟是单片机的心脏,单片机各功能部件的运行都是以时钟频率为基准,有条不紊的一拍一拍地工作。因此,时钟频率直接影响单片机的速度,时钟电路的质量也直接影响单片机系统的稳定性。常用的时钟电路有两种方式:一种是内部时钟方式,另一种为外部时钟方式。本文用的是内部时钟方式。

电路图如下:

3.2 时钟电路模块设计

DS1302内含有一个实时时钟/日历和31字节静态RAM,通过简单的串行接口与单片机进行通信。图中VCC1为后备电源,VCC2为主电源。DS1302由VCC1或VCC2两者中的较大者供电。所以在主电源关闭的情况下,也能保持时钟的连续运行。X1和X2是振荡源,外接32.768KHz晶振用来为芯片提供计时脉冲。RST是复位/片选线,通过把RST输入驱动置高电平来启动所有的数据传送。DS1302

的硬件接线图如图所示:

                   

3.3 温度传感采集模块设计

如图所示。采用数字式温度传感器DS18B20,它是数字式温度传感器,具有测量精度高,电路连接简单特点。

                   

3.4 按键设计

电路由三个按键开关组成,分别与单片机的I/O相连,控制调整电路的加、减以及确定。

按键的开关状态通过一定的电路转换为高、低电平状态。按键闭合过程在相应的I/O端口形成一个负脉冲。闭合和释放过程都要经过一定的过程才能达到稳定,这一过程是处于高、低电平之间的一种不稳定状态,称为抖动。抖动持续时间的常长短与开关的机械特性有关,一般在5-10ms之间。为了避免CPU多次处理按键的一次闭合,应采用措施消除抖动。本文采用的是式按键,直接用I/O口线构成单个按键电路,每个按键占用一条I/O口线,每个按键的工作状态不会产生互相影响。

P1.0口表示功能移位键,按键选择要调整的时十位、时个位、分十位或分个位。 

    P1.1口表示数字“+“键,按一下则对应的数字加1。

    P1.2口表示数字“-”键,按一下则对应的数字减1。

    P1.3口表示时间表的切换,程序默认为日常时间表,当按下该开关,使输入为低电平时,表示当前执行的是考试时间表,并有绿发光二极管显示。再按键,使键抬起,输入维高电平时,表示当前执行的是日常作息时间表,用红发光二级管显示。

4、显示电路

采用LCD显示,LCD显示具有丰富多样性,灵活性,电路简单、易于控制而且功耗小,对于信息量多的系统,是比较适合的,LCD液晶显示模块采用LCD1602型号,具有很低的功耗,正常工作室电流仅2.0mA/5.0V。通过编程实现总动关闭屏幕能够更有效地降低功耗。LCD1602分两行显示,每行可现实多达16个字符,其内部的字符发生器已经存储了160个不同的点阵字符图形,通过内部指令可实现对其显示多样的控制。

        

四、程序设计

#include

#include"DS18B20_3.H"

#define uint unsigned int

#define uchar unsigned char

uchar a,b,miao,shi,fen,ri,yue,nian,week,flag,key1n,temp,miao1,shi1=12,fen1=1,miao1=0,clock=0 ;

//flag用于读取头文件中的温度值,和显示温度值

#define yh 0x80 //LCD第一行的初始位置,因为LCD1602字符地址首位D7恒定为1(100000000=80)

#define er 0x80+0x40 //LCD第二行初始位置(因为第二行第一个字符位置地址是0x40)

//液晶屏的与C51之间的引脚连接定义(显示数据线接C51的P0口)

sbit rs=P2^0;

sbit en=P2^2;

sbit rw=P2^1; //如果硬件上rw接地,就不用写这句和后面的rw=0了

sbit led=P2^6; //LCD背光开关

//DS1302时钟芯片与C51之间的引脚连接定义

sbit IO=P1^1;

sbit SCLK=P1^0;

sbit RST=P1^2;

sbit CLO=P1^4;

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代表的是累加器的地址。 

***************************************************************/

//校时按键与C51的引脚连接定义

sbit key1=P1^5;  //设置键

sbit key2=P1^6;  //加键

sbit key3=P1^7;  //减键

sbit buzzer=P1^3;//蜂鸣器,通过三极管9012驱动,端口低电平响

/**************************************************************/

uchar code tab1[]={"20  -  -   "}; //年显示的固定字符

uchar code tab2[]={"  :  :  "};//时间显示的固定字符

uchar code tab3[]={"   Congratulation!The New World is coming! "};//开机动画

//延时函数,后面经常调用

void delay(uint xms)//延时函数,有参函数

{uint x,y;

for(x=xms;x>0;x--)

for(y=110;y>0;y--);}

void delay1ms(int i)//1毫秒延时

{   int j,k;

   while(i--)

for(j=76;j>1;j--);

for(k=29;k>1;k--);     }

/********液晶写入指令函数与写入数据函数,以后可调用**************/

/*在这个程序中,液晶写入有关函数会在DS1302的函数中调用,所以液晶程序要放在前面*/

write_1602com(uchar com)//****液晶写入指令函数****

{    rs=0;//数据/指令选择置为指令

    rw=0; //读写选择置为写

    P0=com;//送入数据

    delay(1);

    en=1;//拉高使能端,为制造有效的下降沿做准备

    delay(1);

    en=0;//en由高变低,产生下降沿,液晶执行命令}

write_1602dat(uchar dat)//***液晶写入数据函数****

{    rs=1;//数据/指令选择置为数据

    rw=0; //读写选择置为写

    P0=dat;//送入数据

    delay(1);

    en=1; //en置高电平,为制造下降沿做准备

    delay(1);

    en=0; //en由高变低,产生下降沿,液晶执行命令}

lcd_init()//***液晶初始化函数****

{    uchar j;

    write_1602com(0x0f|0x08);  

for(a=0;a<42;a++)

       write_1602dat(tab3[a]);

      j=42;

    while(j--)

    {    write_1602com(0x1a);//循环左移

        delay(700);    } 

    write_1602com(0x01);

    delay(10);

    write_1602com(0x38);//设置液晶工作模式,意思:16*2行显示,5*7点阵,8位数据

    write_1602com(0x0c);//开显示不显示光标

    write_1602com(0x06);//整屏不移动,光标自动右移

    write_1602com(0x01);//清显示

    /***开机动画显示hello welcome dianzizhong****/

    write_1602com(yh+1);//日历显示固定符号从第一行第1个位置之后开始显示

for(a=0;a<14;a++)

    {write_1602dat(tab1[a]);//向液晶屏写日历显示的固定符号部分

    //delay(3);

    }write_1602com(er+1);//时间显示固定符号写入位置,从第1个位置后开始显示

for(a=0;a<8;a++){write_1602dat(tab2[a]);//写显示时间固定符号,两个冒号

    //delay(3);

    }

    write_1602com(er+0);

    write_1602dat(0x20);

}

/***************DS1302有关子函数********************/

void write_byte(uchar dat)//写一个字节

{    ACC=dat;

    RST=1;

for(a=8;a>0;a--)

    {    IO=ACC0;

        SCLK=0;

        SCLK=1;

     ACC=ACC>>1;

    }

}

uchar read_byte()//读一个字节

{RST=1;

for(a=8;a>0;a--)

    {

        ACC7=IO;

        SCLK=1;

        SCLK=0;

     ACC=ACC>>1;    }

    return (ACC);

}

//----------------------------------------

void write_1302(uchar add,uchar dat)//向1302芯片写函数,指定写入地址,数据

{   RST=0;

    SCLK=0;

    RST=1;

    write_byte(add);

    write_byte(dat);

    SCLK=1;

    RST=0;

}

uchar read_1302(uchar add)//从1302读数据函数,指定读取数据来源地址

{    uchar temp;

    RST=0;

    SCLK=0;

    RST=1;

    write_byte(add);

    temp=read_byte();

    SCLK=1;

    RST=0;

    return(temp);

}uchar BCD_Decimal(uchar bcd)//BCD码转十进制函数,输入BCD,返回十进制

{ uchar Decimal;

Decimal=bcd>>4;

 return(Decimal=Decimal*10+(bcd&=0x0F));}

//--------------------------------------

void ds1302_init() //1302芯片初始化子函数(2012-12-22,00:00:00,week6)

{RST=0;

SCLK=0;

write_1302(0x8e,0x00); //允许写,禁止写保护 

write_1302(0x80,0x00); //向DS1302内写秒寄存器80H写入初始秒数据00

write_1302(0x82,0x00);//向DS1302内写分寄存器82H写入初始分数据00

write_1302(0x84,0x00);//向DS1302内写小时寄存器84H写入初始小时数据00

write_1302(0x8a,0x06);//向DS1302内写周寄存器8aH写入初始周数据6

write_1302(0x86,0x22);//向DS1302内写日期寄存器86H写入初始日期数据22

write_1302(0x88,0x12);//向DS1302内写月份寄存器88H写入初始月份数据12

write_1302(0x8c,0x12);//向DS1302内写年份寄存器8cH写入初始年份数据12

write_1302(0x8e,0x80); //打开写保护

}//------------------------------------

//温度显示子函数

void write_temp(uchar add,uchar dat)//向LCD写温度数据,并指定显示位置

{uchar gw,sw,bw;

if(dat>=0&&dat<=128)

    {gw=dat%10;//取得个位数字

    sw=dat%100/10;//取得十位数字

    bw=-5    ;//取得百位数字

    }

    else

    {

    dat=256-dat;

    gw=dat%10;//取得个位数字

    sw=dat%100/10;//取得十位数字

    bw=-3;         //0x30-3表示为负号

    }

    write_1602com(er+add);//er是头文件规定的值0x80+0x40

    write_1602dat(0x30+bw);//数字+30得到该数字的LCD1602显示码

    write_1602dat(0x30+sw);//数字+30得到该数字的LCD1602显示码

    write_1602dat(0x30+gw);//数字+30得到该数字的LCD1602显示码

    write_1602dat(0xdf);//显示温度的小圆圈符号,0xdf是液晶屏字符库的该符号地址码

      write_1602dat(0x43);    //显示"C"符号,0x43是液晶屏字符库里大写C的地址码            

}//------------------------------------

//时分秒显示子函数

void write_sfm(uchar add,uchar dat)//向LCD写时分秒,有显示位置加、现示数据,两个参数

{   uchar gw,sw;

    gw=dat%10;//取得个位数字

    sw=dat/10;//取得十位数字

    write_1602com(er+add);//er是头文件规定的值0x80+0x40

    write_1602dat(0x30+sw);//数字+30得到该数字的LCD1602显示码

    write_1602dat(0x30+gw);//数字+30得到该数字的LCD1602显示码

}

//-------------------------------------

//年月日显示子函数

void write_nyr(uchar add,uchar dat)//向LCD写年月日,有显示位置加数、显示数据,两个参数

{    uchar gw,sw;

    gw=dat%10;//取得个位数字

    sw=dat/10;//取得十位数字

    write_1602com(yh+add);//设定显示位置为第一个位置+add

    write_1602dat(0x30+sw);//数字+30得到该数字的LCD1602显示码

    write_1602dat(0x30+gw);//数字+30得到该数字的LCD1602显示码

    }

//-------------------------------------------

void write_week(uchar week)//写星期函数

{    write_1602com(yh+0x0c);//星期字符的显示位置

    switch(week)

    {        case 1:write_1602dat('M');//星期数为1时,显示

               write_1602dat('O');

               write_1602dat('N');

               break;

             case 2:write_1602dat('T');//星期数据为2时显示

               write_1602dat('U');

               write_1602dat('E');

               break;

            case 3:write_1602dat('W');//星期数据为3时显示

               write_1602dat('E');

               write_1602dat('D');

               break;

            case 4:write_1602dat('T');//星期数据为4是显示

               write_1602dat('H');

               write_1602dat('U');

               break;

            case 5:write_1602dat('F');//星期数据为5时显示

               write_1602dat('R');

               write_1602dat('I');

               break;

            case 6:write_1602dat('S');//星期数据为6时显示

               write_1602dat('T');

               write_1602dat('A');

               break;

        

        case 7:write_1602dat('S');//星期数据为7时显示

               write_1602dat('U');

               write_1602dat('N');

               break;}}

//****************键盘扫描有关函数**********************

void keyscan()

{    if(key1==0)//---------------key1为功能键(设置键)--------------------

    {    delay(9);//延时,用于消抖动

    if(key1==0)//延时后再次确认按键按下

    {    buzzer=1;//蜂鸣器短响一次

    delay(20);

    buzzer=0;

    while(!key1);

    key1n++;

    if(key1n==12)

        key1n=1;//设置按键共有秒、分、时、星期、日、月、年、返回,8个功能循环

    switch(key1n)

    {    case 1: TR0=0;//关闭定时器

            //TR1=0;

            write_1602com(er+0x08);//设置按键按动一次,秒位置显示光标

               write_1602com(0x0f);//设置光标为闪烁

               temp=(miao)/10*16+(miao)%10;//秒数据写入DS1302

               write_1302(0x8e,0x00);

               write_1302(0x80,0x80|temp);//miao

              write_1302(0x8e,0x80);

               break;

    case 2:  write_1602com(er+5);//按2次fen位置显示光标

        //write_1602com(0x0f);

            break;

    case 3: write_1602com(er+2);//按动3次,shi

             //write_1602com(0x0f);

            break;

    case 4: write_1602com(yh+0x0e);//按动4次,week

             //write_1602com(0x0f);

            break;

    case 5: write_1602com(yh+0x0a);//按动5次,ri

             //write_1602com(0x0f);

            break;

    case 6: write_1602com(yh+0x07);//按动6次,yue

             //write_1602com(0x0f);

            break;

    case 7: write_1602com(yh+0x04);//按动7次,nian

             //write_1602com(0x0f);

            break;

    case 8: write_1602com(er+0);

            write_1602dat(0x53);

            write_1602com(er+0);

            break;

    case 9: write_1602com(er+0);

            write_1602dat(0x4d);

            write_1602com(er+0);

            break;

    case 10:write_1602com(er+0);

            write_1602dat(0x48);

            write_1602com(er+0);

            break;

    case 11:write_1602com(er+0);

            write_1602dat(0x20);

            write_1602com(0x0c);//按动到第8次,设置光标不闪烁

            TR0=1;//打开定时器

         temp=(miao)/10*16+(miao)%10;

           write_1302(0x8e,0x00);

           write_1302(0x80,0x00|temp);//miao数据写入DS1302

           write_1302(0x8e,0x80);

            break;                                                                

    }}}

//------------------------------加键key2----------------------------        

    if(key1n!=0)//当key1按下以下。再按以下键才有效(按键次数不等于零)

    {if(key2==0)  //上调键

{    delay(10);

    if(key2==0)

    {   buzzer=1;//蜂鸣器短响一次

    delay(20);

    buzzer=0;

    while(!key2);

    switch(key1n)

    {    case 1:miao++;//设置键按动1次,调秒

            if(miao==60)

                miao=0;//秒超过59,再加1,就归零

            write_sfm(0x07,miao);//令LCD在正确位置显示"加"设定好的秒数

            temp=(miao)/10*16+(miao)%10;//十进制转换成DS1302要求的DCB码

               write_1302(0x8e,0x00); //允许写,禁止写保护 

               write_1302(0x80,temp); //向DS1302内写秒寄存器80H写入调整后的秒数据BCD码

               write_1302(0x8e,0x80); //打开写保护

            write_1602com(er+0x08);//因为设置液晶的模式是写入数据后,光标自动右移,所以要指定返回

    //write_1602com(0x0b);

            break;

    case 2:fen++;

            if(fen==60)

                fen=0;

            write_sfm(0x04,fen);//令LCD在正确位置显示"加"设定好的分数据

            temp=(fen)/10*16+(fen)%10;//十进制转换成DS1302要求的DCB码

               write_1302(0x8e,0x00);//允许写,禁止写保护 

               write_1302(0x82,temp);//向DS1302内写分寄存器82H写入调整后的分数据BCD码

               write_1302(0x8e,0x80);//打开写保护

            write_1602com(er+5);//因为设置液晶的模式是写入数据后,指针自动加一,在这里是写回原来的位置

            break;

    case 3:shi++;

            if(shi==24)

                shi=0;

            write_sfm(1,shi);//令LCD在正确的位置显示"加"设定好的小时数据

            temp=(shi)/10*16+(shi)%10;//十进制转换成DS1302要求的DCB码

               write_1302(0x8e,0x00);//允许写,禁止写保护 

               write_1302(0x84,temp);//向DS1302内写小时寄存器84H写入调整后的小时数据BCD码

               write_1302(0x8e,0x80);//打开写保护

            write_1602com(er+2);//因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位

            break;

    case 4:week++;

            if(week==8)

                week=1;

            write_1602com(yh+0x0C);//指定'加'后的周数据显示位置

                write_week(week);//指定周数据显示内容

            temp=(week)/10*16+(week)%10;//十进制转换成DS1302要求的DCB码

               write_1302(0x8e,0x00);//允许写,禁止写保护 

               write_1302(0x8a,temp);//向DS1302内写周寄存器8aH写入调整后的周数据BCD码

               write_1302(0x8e,0x80);//打开写保护

               write_1602com(yh+0x0e);//因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位

            break;

    case 5:ri++;

                switch(yue)

            {   case 1:case 3:case 5:case 7:case 8:case 10:case 12:

             if(ri>31) ri=1;

                break;

                case 2: 

                if(nian%4==0||nian%400==0)

           { if(ri>29) ri=1; } else

                  { if(ri>28) ri=1;}break;

               case 4:case 6:case 9:case 11:

              ri++;

if(ri>30) ri=1;

 break;

 }         

            write_nyr(9,ri);//令LCD在正确的位置显示"加"设定好的日期数据

            temp=(ri)/10*16+(ri)%10;//十进制转换成DS1302要求的DCB码

               write_1302(0x8e,0x00);//允许写,禁止写保护

               write_1302(0x86,temp);//向DS1302内写日期寄存器86H写入调整后的日期数据BCD码

               write_1302(0x8e,0x80);//打开写保护

            write_1602com(yh+10);//因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位

            break;

    case 6:yue++;

        switch(ri)

            {   case 31:

                if(yue==2|yue==4|yue==6|yue==9|yue==11)    {yue++;}

                else 

             {if(yue>=13) yue=1;}

                

                break;

               case 30:

                if(yue==2){yue++;}

                else  

             {if(yue>=13) yue=1;}

                case 29:

                if(nian%4==0||nian%400==0)

             {if(yue>=13) {yue=1;}}

                else{if(yue==2){yue++;}

             else if(yue>=13) {yue=1;}}

                break;

              }

         if(yue>=13) yue=1;        

            write_nyr(6,yue);//令LCD在正确的位置显示"加"设定好的月份数据

            temp=(yue)/10*16+(yue)%10;//十进制转换成DS1302要求的DCB码

               write_1302(0x8e,0x00);//允许写,禁止写保护

               write_1302(0x88,temp);//向DS1302内写月份寄存器88H写入调整后的月份数据BCD码

               write_1302(0x8e,0x80);//打开写保护

            write_1602com(yh+7);//因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位

            break;

    case 7:nian++;

         if(nian==100)

            nian=0;

            write_nyr(3,nian);//令LCD在正确的位置显示"加"设定好的年份数据

            temp=(nian)/10*16+(nian)%10;//十进制转换成DS1302要求的DCB码

               write_1302(0x8e,0x00);//允许写,禁止写保护

               write_1302(0x8c,temp);//向DS1302内写年份寄存器8cH写入调整后的年份数据BCD码

               write_1302(0x8e,0x80);//打开写保护

            write_1602com(yh+4);//因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位

            break;

    case 8:    write_1602com(er+8); //设置闹钟的秒定时

            miao1++;

            if(miao1==60)

               miao1=0;

            write_sfm(0x07,miao1);//令LCD在正确位置显示"加"设定好秒的数据

            write_1602com(er+8);//因为设置液晶的模式是写入数据后,指针自动加一,在这里是写回原来的位置

            break;

    case 9:    write_1602com(er+5); //设置闹钟的分钟定时

            fen1++;

            if(fen1==60)

            fen1=0;

            write_sfm(0x04,fen1);//令LCD在正确位置显示"加"设定好的分数据

            write_1602com(er+5);//因为设置液晶的模式是写入数据后,指针自动加一,在这里是写回原来的位置

            break;

    case 10:    write_1602com(er+2); //设置闹钟的小时定时

            shi1++;

            if(shi1==24)

            shi1=0;

            write_sfm(0x01,shi1);//令LCD在正确的位置显示"加"设定好的小时数据

            write_1602com(er+2);//因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位

            break;

    }

    }

    }

    //------------------减键key3,各句功能参照'加键'注释---------------

    if(key3==0)

    {

    delay(10);//调延时,消抖动

    if(key3==0)

    {

    buzzer=1;//蜂鸣器短响一次

    delay(20);

    buzzer=0;

    while(!key3);

    switch(key1n)

    {

        case 1:miao--;

                if(miao==-1)

                    miao=59;//秒数据减到-1时自动变成59

            write_sfm(0x07,miao);//在LCD的正确位置显示改变后新的秒数

            temp=(miao)/10*16+(miao)%10;//十进制转换成DS1302要求的DCB码

               write_1302(0x8e,0x00); //允许写,禁止写保护 

               write_1302(0x80,temp); //向DS1302内写秒寄存器80H写入调整后的秒数据BCD码

               write_1302(0x8e,0x80); //打开写保护

            write_1602com(er+0x08);//因为设置液晶的模式是写入数据后,指针自动加一,在这里是写回原来的位置

            //write_1602com(0x0b);

            break;

        case 2:fen--;

                if(fen==-1)

                    fen=59;

            write_sfm(4,fen);

            temp=(fen)/10*16+(fen)%10;//十进制转换成DS1302要求的DCB码

               write_1302(0x8e,0x00);//允许写,禁止写保护 

               write_1302(0x82,temp);//向DS1302内写分寄存器82H写入调整后的分数据BCD码

               write_1302(0x8e,0x80);//打开写保护

            write_1602com(er+5);//因为设置液晶的模式是写入数据后,指针自动加一,在这里是写回原来的位置

            break;

        case 3:shi--;

               if(shi==-1)

                    shi=23;

            write_sfm(1,shi);

            temp=(shi)/10*16+(shi)%10;//十进制转换成DS1302要求的DCB码

               write_1302(0x8e,0x00);//允许写,禁止写保护 

               write_1302(0x84,temp);//向DS1302内写小时寄存器84H写入调整后的小时数据BCD码

               write_1302(0x8e,0x80);//打开写保护

            write_1602com(er+2);//因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位

            break;

        case 4:week--;

                if(week==0)

                    week=7;

            write_1602com(yh+0x0C);//指定'加'后的周数据显示位置

                write_week(week);//指定周数据显示内容

               temp=(week)/10*16+(week)%10;//十进制转换成DS1302要求的DCB码

               write_1302(0x8e,0x00);//允许写,禁止写保护 

               write_1302(0x8a,temp);//向DS1302内写周寄存器8aH写入调整后的周数据BCD码

               write_1302(0x8e,0x80);//打开写保护

               write_1602com(yh+0x0e);//因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位

            break;

        case 5:ri--;

                switch(yue)

            { 

                  case 1:case 3:case 5:case 7:case 8:case 10:case 12:

                   

                 if(ri==0) ri=31;

                 break;

                  case 2: if(nian%4==0||nian%400==0)

                     { if(ri==0) ri=29;     }

                   else { if(ri==0) ri=28;     }break;

                 case 4:case 6:case 9:case 11:

                  if(ri==0) ri=30;

                     break;}

            write_nyr(9,ri);

            temp=(ri)/10*16+(ri)%10;//十进制转换成DS1302要求的DCB码

               write_1302(0x8e,0x00);//允许写,禁止写保护

               write_1302(0x86,temp);//向DS1302内写日期寄存器86H写入调整后的日期数据BCD码

               write_1302(0x8e,0x80);//打开写保护

            write_1602com(yh+10);//因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位

            break;

        case 6:yue--;

                switch(ri)

            {  case 31:

                if(yue==2|yue==4|yue==6|yue==9|yue==11)    {yue--;}

                else 

                 {if(yue==0) yue=12;}

                break;

               case 30:

                if(yue==2){yue--;}

                else  

                {if(yue==0) yue=12;}

                case 29:

                if(nian%4==0||nian%400==0)

                {if(yue==0) {yue=12;}}

                else{if(yue==2){yue--;}

                      else if(yue==0) {yue=12;}}

                break;

              }

              if(yue==0) yue=12;

            write_nyr(6,yue);

            temp=(yue)/10*16+(yue)%10;//十进制转换成DS1302要求的DCB码

               write_1302(0x8e,0x00);//允许写,禁止写保护

               write_1302(0x88,temp);//向DS1302内写月份寄存器88H写入调整后的月份数据BCD码

               write_1302(0x8e,0x80);//打开写保护

            write_1602com(yh+7);//因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位

            break;    

        case 7:nian--;

         if(nian==-1)

            nian=99;

            write_nyr(3,nian);

         temp=(nian)/10*16+(nian)%10;//十进制转换成DS1302要求的DCB码

               write_1302(0x8e,0x00);//允许写,禁止写保护

               write_1302(0x8c,temp);//向DS1302内写年份寄存器8cH写入调整后的年份数据BCD码

               write_1302(0x8e,0x80);//打开写保护

            write_1602com(yh+4);//因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位

            break;

        case 8:    write_1602com(er+8); //设置闹钟的秒定时

            miao1--;

            if(miao1==-1)

               miao1=59;

            write_sfm(0x07,miao1);//令LCD在正确位置显示"加"设定好秒的数据

            write_1602com(er+8);//因为设置液晶的模式是写入数据后,指针自动加一,在这里是写回原来的位置

            break;

        case 9:    write_1602com(er+5); //设置闹钟的分钟定时

            fen1--;

            if(fen1==-1)

            fen1=59;

            write_sfm(0x04,fen1);//令LCD在正确位置显示"加"设定好的分数据

            write_1602com(er+5);//因为设置液晶的模式是写入数据后,指针自动加一,在这里是写回原来的位置

            break;

        case 10:    write_1602com(er+2); //设置闹钟的小时定时

            shi1--;

            if(shi1==-1)

            shi1=23;

            write_sfm(0x01,shi1);//令LCD在正确的位置显示"加"设定好的小时数据

            write_1602com(er+2);//因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位

            break;        

    }

    }

    }

    }

}

//定时器0初始化程序

void init() //定时器、计数器设置函数

{

    TMOD=0x11; //指定定时/计数器的工作方式为1

    TH0=0;  //定时器T0的高四位=0

    TL0=0;  //定时器T0的低四位=0

    EA=1;  //系统允许有开放的中断

    ET0=1; //允许T0中断

    TR0=1; //开启中断,启动定时器

}

//*******************主函数**************************

//***************************************************

void main()

{    buzzer=0;

    lcd_init();      //调用液晶屏初始化子函数

    ds1302_init();   //调用DS1302时钟的初始化子函数

    init();          //调用定时计数器的设置子函数

    led=0;           //打开LCD的背光电源

    buzzer=1;//蜂鸣器长响一次

    delay(80);

    buzzer=0;

    while(1)  //无限循环下面的语句:

    {    

    keyscan();      //调用键盘扫描子函数 }

}

/*************通过定时中断实现定是独处并显示数据******************/

void timer0() interrupt 1  //取得并显示日历和时间

{  //Init_DS18B20();//温度传感器DS18b2初始化子函数,在头文件中

   flag=ReadTemperature();//将18b2头文件运行返回的函数结果送到变量FLAG中,用于显示

  //读取秒时分周日月年七个数据(DS1302的读寄存器与写寄存器不一样):

 miao = BCD_Decimal(read_1302(0x81));

    fen = BCD_Decimal(read_1302(0x83));

    shi  = BCD_Decimal(read_1302(0x85));

    ri  = BCD_Decimal(read_1302(0x87));

    yue = BCD_Decimal(read_1302(0x));

    nian=BCD_Decimal(read_1302(0x8d));

    week=BCD_Decimal(read_1302(0x8b));

//显示温度、秒、时、分数据:

      write_temp(11,flag);//显示温度,从第二行第12个字符后开始显示

   write_sfm(7,miao);//秒,从第二行第8个字后开始显示(调用时分秒显示子函数)

    write_sfm(4,fen);//分,从第二行第5个字符后开始显示

    write_sfm(1,shi);//小时,从第二行第2个字符后开始显示

//显示日、月、年数据:

    write_nyr(9,ri);//日期,从第二行第9个字符后开始显示

   write_nyr(6,yue);//月份,从第二行第6个字符后开始显示

    write_nyr(3,nian);//年,从第二行第3个字符后开始显示

    write_week(week);

/***********整点报时程序************/

    if(fen==0&&miao==0)

if(shi<22&&shi>6 )

          {    buzzer=1;//蜂鸣器短响一次

        delay(20);

        buzzer=0;}

/**************闹钟程序: 将暂停键按下停止蜂鸣********************/

     if(CLO==0)        /*按下p1.3停止蜂鸣*/

     { clock=0; return;}    

     if(shi1==shi&&fen1==fen&&miao1==miao)

        {    clock=1; }    

    if(clock==1)

       {buzzer=1;//蜂鸣器短响一次

        delay(20);

        buzzer=0;  }}

5、测试结果分析与结论

Protel总电路图:

设计电路的PROTEU仿真图:

整体PCB版图如下:

六、调试所需的仪器设备

基本测试仪器:万用电表、秒表、电源、温度表

七、设计的难点和可能出现的问题

1、设计难点:

   (1):温度设计模块的设计,

   (2):LCD显示模块的设计

   (3):闹铃设计模块的实现设计

   (4):单片机个功能模块的综合设计

   (5):电路总体设计,元器件选择及焊接,调试

2、可能出现的问题:

   (1):温度显示,与实际偏差大

   (2):LCD显示模块的功能显示不正常

   (3):闹铃设计与其他时间功能设计冲突

   (4):软件程序设计功能不完善,系统无法正常运转

八、预期达到的性能指标

1、预期达到的性能指标:

能动态显示实时时钟的时、分、秒,数据显示(误差在30每天),对闹铃方式与温度调节模块进行了重点设计 实现SB0、SB1、SB2、SB3四个键实现时钟正常显示,调时,及闹钟时间设置。

2、多功能数字时钟使用说明:

A:(调整切换键)进行时间、闹铃以及生日的设置,调整内容切换。

B: (调整加减/生日的设定)在时间显示界面中按A键后,进入时间调整。按B键对应闪烁内容加1;在时间显示界面中长按改建进入圣体信息设定,按A键选择调整内容,按B键加1,C键减1,D减退出设定,当设定生日到时,当日七点整第一次响铃提醒,以后每隔一小时整点提醒,直至当日晚上22点后最后一次提醒。

C:(调整减/日期提醒)在时间显示界面中按A键后,进入时间调整。按C键对应闪烁内同加1;在时间显示界面中常按A键后,进入日期提醒查看。

D (退出键/闹铃设定)在各种设定模式(时间、生日、闹铃)下,按该键退出设定;若在时间显示界面中短按键后,则进入闹铃、生日信息查看;长按则进行闹铃设定。

E:(屏幕背光键):按下该键不放则屏幕背光。调整左上方的蓝色变阻器课调整LCD显示灰度;调整右上方的蓝色编著器可调整LCD背光的亮度。(注:系统再不进行日和操作时,10秒后自动关闭屏幕,按任意键返回)

F:(复位键)按下该键系统复位,系统从头开始执行程序,如果与长按可按下改嫁进行系统复位,复位不会造成时间、生日、和闹铃等细细的丢失。

文档

基于单片机的万年历设计

实现功能:(1)显示年月日,时分秒,星期与温度(2)年月日,时分秒均可调,具备自动调节闰年的功能(3)具有闹钟功能,且开关控制闹钟的开启与关闭(4)具有整点报时功能一、概述、设计思路该设计方案是以ATC51单片机为核心,采用LCD1602液晶屏幕显示系统,辅以时钟模块,温度采集模块、日期提醒、键盘时间调整预设置等模块,所构建的数字时钟系统,能动态显示实时时钟的时、分、秒,数据显示(误差在30每天),对闹铃方式与温度调节模块进行了重点设计实现SB0、SB1、SB2、SB3四个键实现时钟正
推荐度:
  • 热门焦点

最新推荐

猜你喜欢

热门推荐

专题
Top