(完整)基于51单片机电子时钟设计

(完整)基于51单片机电子时钟设计
(完整)基于51单片机电子时钟设计

(完整)基于51单片机电子时钟设计

编辑整理:

尊敬的读者朋友们:

这里是精品文档编辑中心,本文档内容是由我和我的同事精心编辑整理后发布的,发布之前我们对文中内容进行仔细校对,但是难免会有疏漏的地方,但是任然希望((完整)基于51单片机电子时钟设计)的内容能够给您的工作和学习带来便利。同时也真诚的希望收到您的建议和反馈,这将是我们进步的源泉,前进的动力。

本文可编辑可修改,如果觉得对您有帮助请收藏以便随时查阅,最后祝您生活愉快业绩进步,以下为(完整)基于51单片机电子时钟设计的全部内容。

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

摘要

本电子时钟以STC89C52单片机作为主控芯片,采用DS12C887时钟芯片,使用1602液晶作为显示输出.该时钟走时精确,具有闹钟设置,以及可同时显示时间、日期等多种功能。本文将详细介绍该电子时钟涉及到的一些基本原理,从硬件和软件两方面进行分析.

【关键词】

STC89C52单片机 DS12C887时钟芯片 1602液晶蜂鸣器

目录

一、绪论 (4)

1.1 电子时钟功能 (4)

1.2设计方案 (4)

二、硬件设计 (4)

2。151单片机部分设计 (4)

2.2 USB供电电路设计 (5)

2.3 串行通信电路设计 (6)

2.4 DS12C887时钟芯片电路的设计 (6)

2。5 1602LCD液晶屏显示电路设计 (7)

2。6蜂鸣器电路设计 (8)

2。7按键调整电路设计 (8)

三、软件设计 (9)

3.1系统程序流程图设计 (9)

3。2程序设计 (11)

四、心得体会 (22)

参考文献 (23)

一、绪论

1。1电子时钟功能

(1)在1602液晶上显示年、月、日、星期、时、分、秒,并且按秒实时更新显示。

(2)具有闹铃设定即到时报警功能,报警响起时按任意键可取消报警。

(3)能够使用实验板上的按键随时调节各个参数,四个有效键分别为功能选择键、数值增大键、数值减小键和闹钟查看键。

(4)每次有键按下时,蜂鸣器都以短“滴”声报警.

(5)利用DS12C887自身掉电可继续走时的特性,该时钟可实现断电时间不停、再次上电时时间仍准确显示在液晶上的功能。

1。2设计方案

DS12C887时钟芯片+1602LCD液晶屏

DS12C887时钟芯片功能丰富、价格适中,能够自动产生世纪、年、月、日、时、分、秒等时间信息,其内部含有世纪寄存器,从而利用硬件电路解决“千年”问题。DS12C887中自带锂电池,外部掉电时,其内部时间信息还能保持10年之久。1602LCD液晶屏可以输出2行,每行显示16个字符。1602LCD液晶屏显示清晰且不会闪烁,由于液晶屏是数字式的,因此和单片机系统的接口简单,操作方便。

以STC89C52为主控芯片,DS12C887为时钟芯片,1602LCD液晶屏作为显示器.程序控制DS12C887时钟芯片实现小时、分、秒和年、月、日的计时,并在1602LCD液晶屏上显示出来。当时间走到程序所设定的时间时,蜂鸣器响起,起到闹钟功能。

二、硬件设计

2.1 51单片机部分设计

单片机部分如图2—1所示:

以STC89C52单片机为核心,选用12MHZ的晶振,由于晶振的频率越高,单片机的运行速度就越快,考虑到单片机的运行速度快会导致对存储器的要求就会变高,因此12MHZ为最佳选择。外接电容的值虽然没有严格的要求,但是外接电容的大小会影响振荡器的频率高低、振荡器的稳定性和起振的快速性 ,因此选用30pF的电容作为起振电容。复位电路为按键高电平复位,当按键按下,RES端为高电平,当高电平持续4us的时间单片机即复位.

2.2 USB供电电路设计

USB供电电路如下图2—2所示:

该电子时钟采用USB端口的方式为单片机供电,LPOW1为电源显示灯,当按键S5按下,电源显示灯LPOW1亮,表示给单片机供+5V电.

2.3 串行通信电路设计

串行通信电路如下图2—3所示:

图中通过MAX232进行RS—232电平与单片机TTL电平之间的转换,从而为单片机和上位机之间通信提供通道。通信电路的目的就是让通信双方的电平匹配,单片机用的是TTL电平,上位机的串口用的是RS—232电平。TTL电平逻辑1的电压范围是+3.3V到+5V,逻辑0的电压范围是0到+3。3V;RS—232电平的逻辑1的电压范围是—15V到-5V,逻辑0的电压范围是+5V 到+15V。MAX232可以把输入的+5V电源电压变换成为RS—232输出电平所需的+10V电压.所以采用此芯片接口的串行通信系统只需单一的+5V电源就可以了。对于没有+12V电源的场合,其适应性更强,

2.4 DS12C887时钟芯片电路的设计

时钟芯片电路如下图2—4所示:

DS12C887时钟芯片共需要13条信号线,分别是并行数据地址复用线AD0~AD7,,AS,R/,DS 和。

MOT —总线操作时序选择端。它有两种工作模式,当MOT 接时,选用Motorola 模式;当MOT 接GND 或悬空时,选用Intel 模式. NC —空引脚。

AD0~AD7—复用地址数据总线。在总线周期的前半部分,出现在AD0~AD7上的是地址信息,可用以选通DS12C887内的RAM,总线周期的后半部分出现在AD0~AD7上的是数据信息. GND ,

—系统电源接入端。当

输入为+5V 时,用户可以访问DS12C887内RAM 中的数据,

并可对其进行读/写操作;当

的输入小于+4.25V

时,禁止用户对内部RAM 进行读/写操作,此

时用户不能正确芯片内的时间信息;当的输入小于+3V 时,DS12C887会自动的将电源切换到内部自带的锂电池上,以保证内部的电路能正常工作。

-芯片片选端。

AS —地址选通输入端。在进行读/写操作时,AS 的上升沿将AD0~AD7上出现的地址信息锁存到DS12C887上,而下一个下降沿清除AD0~AD7上的地址信息,不论CS 是否有效,DS12C887都将执行该操作。

R/—读/写输入端。该引接脚有两种工作模式,当MOT 接

时,R/

工作在Motorola 模式.

此时该引脚的作用是区分读操作还是写操作,R/高电平时为读操作,R/为低电平时为写操作;当MOT 接GND 时,该引脚工作在Intel 模式,此时该引脚为写允许输入,此信号的上升沿锁存数据.

DS-数据选择或读输入脚。该引脚有两种工作模式,当MOT 接时,选用Motorola 模式,此时,每个总线周期后一部分的DS 为高电平,称为数据选通。在读操作中,DS 的上升沿使DS12C887将内部数据送往总线AD0~AD7上,以供外部读取。在写操作中,DS 的下降沿将使总线AD0~AD7上的数据锁存在DS12C887中。当MOT 接GND 时,选用Intel 模式,此时该引脚是读允许输入引脚。

—芯片复位引脚。

—中断请求输出。用作处理器的中断申请输入。只要引起中断的状态位置位,并且相应中断使能位也置位,将一直保持低电平,处理器程序通常读取C 存储器来清除引脚输出,

CS W IRQ V

CC V

CC V

CC V

CC V

CC CS

W V

CC W

W W V

CC RESET IRQ IRQ IRQ

引脚也会清除未处理的中断

.没有中断发生时,为高阻状态,可将多个中断器件接到

一条

总线上,只要它们均为漏极开路输出即可。引脚为漏极开路输出,需要使用一个外

接上拉电阻与

相连。

SQW —方波输出引脚。当供电电压

大于4。25V 时,SQW 引脚可输出方波。

2。5 1602LCD 液晶屏显示电路设计

1602LCD 液晶屏显示电路如下图2—5所示:

1602液晶为5V 电压驱动,带背光,可显示2行,每行16个字符,不能显示汉字,内置含128个字符的ASCII 字符集字库,只有并行接口,无串行接口。 接口说明如下:

(1)液晶1,2端为电源;15,16为背光电源;为防止直接加5V 电压烧坏背光灯,在15脚串接一个1K 电阻用于限流.

(2)液晶3端为液晶对比度调节端,通过一个10K 电位器接地来调节液晶显示对比度。首次使用时,在液晶上电状态下,调节至液晶上面一行显示出黑色小格为止。

(3)液晶4端为向液晶控制器写数据/写命令选择端,接单片机的P3。5口。

(4)液晶5端为读/写选择端,因为我们不从液晶读取任何数据,只向其写入命令和显示数据,因此此端始终选择为写状态,即低电平接地。

(5)液晶6端为使能信号,是操作时必须的信号,接单片机的P3。4口。

2.6 蜂鸣器电路设计

蜂鸣器电路如下图2—6所示:

蜂鸣器电路接在单片机的P2.3引脚上,当该引脚一个低电平,三极管导通,蜂鸣器发出声音作为闹铃.

2.7 按键调整电路设计

按键调整电路如下图2—7所示:

RESET IRQ

IRQ IRQ V

CC V

CC ΩΩ

四个独立键盘均采用查询方式,将按键的一端接地,另一端各接一根输入线直接与STC89C52的I/O口相连.当按键闭合时,相当于该I/O口通过按键与地相连,变成低电平,单片机通过检测I/O口的电平状态,即可识别出按下的键.通过四个键实现参数的调节,S1为功能选择键,S2为数值增大键,S3为数值减小键,S4为闹钟查看键。

三、软件设计

3.1 系统程序流程图设计

流程图1:实验主程序流程图

流程图2:定时中断程序流程图

流程图3:调时功能流程图

3。2 程序设计

#include

#include

void delay(uint z) //延时函数

{

uint x,y;

for(x=z;x〉0;x——)

for(y=110;y〉0;y—-);

}

void di( ) //蜂鸣器报警声音

beep=0;

delay(100);

beep=1;

void write_com(uchar com) //写液晶命令函数{

rs=0;

lcden=0;

P0=com;

delay(3);

lcden=1;

delay(3);

lcden=0;

void write_data(uchar data) //写液晶数据函数

rs=1;

lcden=0;

P0=data;

delay(3);

lcden=1;

delay(3);

lcden=0;

}

void init( ) //初始化函数

uchar num;

EA=1; //打开总中断

EX1=1; //开外部中断1

IT1=1; //设置负跳变沿触发中断

flag1=0; //变量初始化

t0_num=0;

s1num=0;

week=1;

dula=0; //关闭数码管显示

wela=0;

lcden=0;

rd=0;

/*以下几行在首次设置DS12C887时使用,以后不必再写入

write_ds(0x0A,0x20); //打开振荡器

write_ds(0x0B,0x26); //设置24小时模式,数据二进制格式,开启闹铃中断 set_time( ); //设置上电默认时间

--——--——-—-—-————--—-—-———-—----———--—-—-———-——-——--——-——-—--—--——-----———--—*/

write_com(0x38); //1602液晶初始化

write_com(0x0c);

write_com(0x06);

write_com(0x01);

write_com(0x80);

for(num=0;num〈15;num++) //写入液晶固定部分显示

write_data(table[num]);

delay(1);

write_com(0x80+0x40);

for(num=0;num<11;num++)

write_data(table1[num]);

delay(1);

}

void write_sfm(uchar add,char data)

{ //1602液晶刷新时分秒函数,4为时,7为分,10为秒 char shi,ge;

shi=data/10;

ge=data%10;

write_com(0x80+0x40+add);

write_data(0x30+shi);

write_data(0x30+ge);

}

void write_nyr(uchar add,char data)

{ //1602液晶刷新年月日函数,3为年,6为月,9为日

char shi,ge;

shi=data/10;

ge=data%10;

write_com(0x80+add);

write_data(0x30+shi);

write_data(0x30+ge);

void write_week(char we) //写液晶星期显示函数{

write_com(0x80+12);

switch(we)

{

case 1: write_data('M’);delay(5);

write_data(’O');delay(5);

write_data(’N’);

break;

case 2: write_data(’T');delay(5);

write_data(’U’);delay(5);

write_data(’E');

break;

case 3: write_data('W');delay(5);

write_data('E');delay(5);

write_data(’D’);

break;

case 4: write_data('T');delay(5);

write_data(’H');delay(5);

write_data(’U’);

break;

case 5: write_data(’F');delay(5);

write_data('R');delay(5);

write_data('I');

break;

case 6: write_data('S’);delay(5);

write_data(’A’);delay(5);

write_data('T’);

break;

case 7: write_data('S’);delay(5);

write_data(’U’);delay(5);

write_data(’N');

break;

void keyscan( )

{

if(flag_ri==1)

{ //这里用来取消闹钟报警,按任意键取消报警

if((s1==0)||(s2==0)||(s3==0)||(s4==0)){

delay(5);

if((s1==0)||(s2==0)||(s3==0)||(s4==0)) {

while(!(s1&&s2&&s3&s&s4));di( );

flag_ri=0; //清除报警标志

if(s1==0) //检测s1

delay(5);

if(s1==0)

{

s1num++; //记录按下次数

if(flag1==1)

if(s1num==4)

s1num=1;

flag=1;

while(!s1);di( );

switch(s1num)

{ //光标闪烁点定位

case 1: write_com(0x80+0x40+10);

write_com(0x0f);

break;

case 2: write_com(0x80+0x40+7);

break;

case 3: write_com(0x80+0x40+4);

break;

case 4: write_com(0x80+12);

break;

case 5: write_com(0x80+9);

break;

case 6: write_com(0x80+6);

break;

case 7: write_com(0x80+3);

break;

case 8: s1num=0;

write_com(0x0c);

flag=0;

write_ds(0,miao);

write_de(2,fen);

write_ds(4,shi);

write_ds(6,week);

write_ds(7,day);

write_ds(8,month);

write_ds(9,year);

break;

}

if(s1num!=0) //只有当s1按下后,才检测s2和s3 {

if(s2==0)

{

delay(1);

if(s2==0)

while(!s2);di( );

switch(s1num)

{ //根据功能键次数调节相应数值

case 1: miao++;

if(miao==60)

miao=0;

write_sfm(10,miao);

write_com(0x80+0x40+10);

break;

case 2: fen++;

if(fen==60)

fen=0;

write_sfm(7,fen);

write_com(0x80+0x40+7); break;

case 3: shi++;

if(shi==24)

shi=0;

write_sfm(4,shi);

write_com(0x80+0x40+4); break;

case 4: week++;

if(week==8)

week=1;

write_week(week);

write_com(0x80+12);

break;

case 5: day++;

if(day==32)

day=1;

write_nyr(9,day);

write_com(0x80+9);

break;

case 6: month++;

if(month==13)

month=1;

write_nyr(6,month); write_com(0x80+6);

break;

case 7: year++;

if(year==100)

year=0;

write_nyr(3,year);

write_com(0x80+3);

break;

}

}

if(s3==0)

delay(1);

if(s3==0)

while(!s3);di();

switch(s1num)

{ //根据功能键次数调节相应数值

case 1: miao——;

if(miao==—1)

miao=59;

write_sfm(10,miao);

write_com(0x80+0x40+10); break;

case 2: fen—-;

if(fen==—1)

fen=59;

write_sfm(7,fen);

write_com(0x80+0x40+7);

break;

case 3: shi—-;

if(shi==—1)

shi=23;

write_sfm(4,shi);

write_com(0x80+0x40+4); break;

case 4: week--;

if(week==0)

week=7;

write_week(week);

write_com(0x80+12);

break;

case 5: day——;

if(day==0)

day=31;

write_nyr(9,day);

write_com(0x80+9);

break;

case 6: month--;

if(month==0)

month=12;

write_nyr(6,month);

write_com(0x80+6);

break;

case 7: year—-;

if(year==—1)

year=99;

write_nyr(3,year);

write_com(0x80+3);

break;

}

if(s4==0) //检测s4

delay(5);

if(s4==0)

flag1=~flag1;

while(!s4);di( );

if(flag1==0)

{ //退出闹钟设置时保存数值

flag=0;

write_com(0x80+0x40);

write_data(' ’);

write_data(’ ’);

write_com(0x0c);

write_ds(1,miao);

write_ds(3,fen);

write_ds(5,shi);

else

{ //进入闹钟设置

read_alarm(); //读取原始数据

miao=amiao; //重新赋值用以按键调节

fen=afen;

shi=ashi;

write_com(0x80+0x40);

write_data('R'); //显示标志

write_data('i');

write_com(0x80+0x40+3);

write_sfm(4,ashi); //送液晶显示闹钟时间 write_sfm(7,afen);

write_sfm(10,amiao);

}

void write_ds(uchar add,uchar data)

{ //写12C887函数

dscs=0;

dsas=1;

dsds=1;

dsrw=1;

P0=add; //先写地址

dsas=0;

dsrw=0;

P0=data; //再写数据

dsrw=1;

dsas=1;

dscs=1;

uchar read_ds(uchar add)

{ //读12C887函数

uchar ds_data;

dsas=1;

dsds=1;

dsrw=1;

dscs=0;

P0=add; //先写地址

dsas=0;

dsds=0;

P0=0xff ;

ds_data=P0; //再读数据

dsds=1;

dsas=1;

dscs=1;

return ds_data;

}

/*——-首次操作12C887时给予寄存器初始化--—-—

void set_time( )

{ //首次上电初始化时间函数

write_ds(0,0);

write_ds(1,0);

write_ds(2,0);

write_ds(3,0);

write_ds(4,0);

write_ds(5,0);

write_ds(6,0);

write_ds(7,0);

write_ds(8,0);

write_ds(9,0);

}

--—--—-——-—-—---—--———-—--—--——-——----—-—---—-——————-*/ void read—alarm()

{ //读取12C887闹钟值

amiao=read_ds(1);

afen=read_ds(3);

ashi=read_ds(5);

void main( ) //主函数

{

init( ); //调用初始化函数

while(1)

{

keyscan( ); //按键扫描

if(flag_ri==1) //当闹钟中断时进入这里

{

di( );

delay(100);

di( );

delay(500);

}

if(flag==0&&flag1==0) //正常工作时进入这里

keyscan( ); //按键扫描

year=read_ds(9); //读取12C887数据

month=read_ds(8);

day=read_ds(7);

week=read_ds(6);

shi=read_ds(4);

fen=read_ds(2);

miao=read_ds(0);

write_sfm(10,miao); //送液晶显示

write_sfm(7,fen);

write_sfm(4,shi);

write_week(week);

write_nyr(3,year);

write_nyr(6,month);

write_nyr(9,day);

}

void exter( ) interrupt 2 //外部中断1服务程序

{ uchar c; //进入中断表示闹钟时间到

flag_ri=1; //设置标志位,用于大程序中报警提示

c=read_ds(0x0c); //读取12C887的C寄存器表示响应了中断

_______________________________________________________________________________以下为define.h源代码:

_______________________________________________________________________________

#define uchar unsigned char

#define uint unsigned int

sbit dula=P2^6;

sbit wela=P2^7;

sbit rs=P3^5;

sbit lcden=P3^4;

sbit s1=P3^0; //功能键

sbit s2=P3^1; //增大键

sbit s3=P3^2; //减小键

sbit s4=P3^6; //闹钟查看键

sbit rd=P3^7;

sbit beep=P2^3; //蜂鸣器

sbit dscs=P1^4;

sbit dsas=P1^5;

sbit dsrw=P1^6;

sbit dsds=P1^7;

sbit dsirq=P3^3;

bit flag1,flag_ri; //定义两个位变量

uchar count,s1num,flag,t0_num; //其他变量定义

char miao,shi,fen,year,month,day,week,amiao,afen,ashi;

uchar code table[]="201- ”; //液晶固定显示内容

uchar code table1[]=” :: ”;

void write_ds(uchar,uchar); //函数申明

void set_alarm(uchar,uchar,uchar);

void read_alarm( );

uchar read_ds(uchar);

void set_time( );

四、心得体会

在本次电子时钟设计中对单片机的内部结构有了一定的了解,熟悉了各个引脚的功能,同时熟知了1602LCD液晶、DS12C887时钟芯片的使用,以及各种电路的功能.

相关主题
相关文档
最新文档