89C51单片机时钟程序

2024-05-27

89C51单片机时钟程序(精选2篇)

89C51单片机时钟程序 篇1

SECOND EQU 40H

;给内存RAM空间中40H单元起名SECOND MINUTE EQU 41H

;给内存RAM空间中41H单元起名MINUTE HOUR EQU 42H

;给内存RAM空间中42H单元起名HOUR SECONDGEWEI EQU 43H

;给43H单元起名SECONDGEWEI存秒的个位 SECONDSHIWEI EQU 44H

;给44H单元起名SECONDSHIWEI存秒的十位 MINUTEGEWEI EQU 45H

;给45H单元起名MINUTEGEWEI存分的个位 MINUTESHIWEI EQU 46H

;给46H单元起名MINUTESHIWEI存分的十位 HOURGEWEI EQU 47H

;给47H单元起名HOURGEWEI存小时的个位 HOURSHIWEI EQU 48H

;给48H单元起名HOURSHIWEI存小时的十位 ORG 0000H

;复位时程序从此开始 SJMP START

;跳到START进行初始化 ORG 000BH

;定时器 0中断入口 AJMP TIMER0

;跳转到TIMER0处

ORG 0030H

;初始化程序从30H开始;---------------初始化START------------------------------START:

MOV SECOND, #0

;给秒存储单元SECOND赋初始值0 MOV MINUTE, #0

;给分存储单元MINUTE赋初始值0 MOV HOUR , #12

;给小时存储单元HOUR赋初始值12 MOV DPTR , #TAB

;给数据指针赋值,将DPTR指向TAB数据表头处 MOV 30H, #0

;给30H单元赋初始值0(用于计20次的50ms中断)MOV TH0,#3CH

;给计数容器的高8位TH0赋初始值3CH MOV TL0,#0B0H

;给计数容器的低8位TL0赋初始值B0H MOV TMOD,#00000001B

;C/T位设置为0,M1M0设置位10,即模式1定时 MOV TCON,#00010000B

;TR0设置为1,即启动定时器0开始工作 SETB ET0

;IE中的ET0位设置为1,开定制器中断0 SETB EA

;IE中的EA位设置为1,开总中断;-----------------------主程序MAIN-----------------------------MAIN:CALL KEY

;调按键子程序KEY CALL PROCESS

;调数据处理子程序PROCESS CALL DISPLAY

;调显示子程序DISPLAY SJMP MAIN

;跳转到MAIN标号处;------------------------------按键子程序KEY调时-------------------KEY:MOV P1,#0FEH

;行扫描 LCALL DELAY

;JNB P1.4,HOURJIA

;P1.4引脚如果是低电平就跳到HOURJIA处

JNB P1.5,HOURJIAN

;P1.5引脚如果是低电平就跳到HOURJIAN处 JNB P1.6,MINUTEJIA

;P1.6引脚如果是低电平就跳到MIMUTEJIA处 JNB P1.7,MINUTEJIAN

;P1.7引脚如果是低电平就跳到MIMUTEJIAN处 FANHUI:RET

;子程序返回(如果没有按键按下)

HOURJIA:CALL DELAY

;调延时程序目的是跳过按键抖动期(去抖)JB P1.4,FANHUI

;P1.4如果是高电平就跳到FANHUI处(没键按)JNB P1.4,$

;如果P1.4是低电平就停在当前位置等键释放 MOV R4,HOUR CJNE R4,#23,A1

;判断时数字是否为23 AJMP A2

A1:INC HOUR

;把小时位加1 MOV SECOND, #0

;小时进位,秒归0

RET

A2:MOV HOUR,#0

;小时数为23时加一为0

MOV SECOND, #0

;小时进位,秒归0

RET

;子程序返回

HOURJIAN:CALL DELAY

;调延时程序目的是跳过按键抖动期(去抖)JB P1.5,FANHUI

JNB P1.5,$

MOV R5,HOUR CJNE R5,#0,A3

AJMP A4 A3:DEC HOUR

MOV SECOND, #0

RET A4:MOV HOUR,#23

MOV SECOND, #0 RET

MINUTEJIA:CALL DELAY

JB P1.6,FANHUI

JNB P1.6,$

MOV R6,MINUTE

CJNE R6,#59,A5

AJMP A6 A5:INC MINUTE

MOV SECOND, #0

RET A6:MOV SECOND, #0

MOV MINUTE, #0

MOV R4,HOUR CJNE R4,#23,A10

MOV HOUR,#0

RET A10:INC HOUR

RET

MINUTEJIAN:CALL DELAY

JB P1.7,FANHUI

JNB P1.7,$

MOV R7,MINUTE CJNE R7,#0,A7

AJMP A8 A7:DEC MINUTE

;P1.5如果是高电平就跳到FANHUI处(没键按)

;如果P1.5是低电平就停在当前位置等键释放

;判断时数字是否为23

;把小时位减1

;小时数为0时减一为23

;子程序返回

;调延时程序目的是跳过按键抖动期(去抖)

;P1.6如果是高电平就跳到FANHUI处(没键按)

;如果P1.6是低电平就停在当前位置等键释放

;判断分钟数是否为59

;把分钟位加1

;给秒存储单元SECOND赋初始值0

;分钟数为59则分钟归0

;判断时数字是否为23

;23时增1归0

;分钟数为59 自增1后小时增1

;子程序返回

;调延时程序目的是跳过按键抖动期(去抖)

;P1.7如果是高电平就跳到FANHUI处(没键按)

;如果P1.7是低电平就停在当前位置等键释放

;判断分钟数是否为0

;分钟不为0把分钟位减1

MOV SECOND, #0

RET

A8:MOV MINUTE, #59

;分钟数为0时减一为59 MOV R4,HOUR CJNE R4,#0,A9

;判断时钟数是否为0 MOV HOUR,#23

;时钟数为0减1为23 MOV SECOND, #0 RET

A9:DEC HOUR

;时钟数不为0则减1 MOV SECOND, #0

RET

;子程序返回;-------------------处理子程序PROCESS-----------------------PROCESS:MOV A, SECOND

;把SECOND中的秒值拷贝给A MOV B, #10

;给寄存器B赋值10 DIV AB

;A除以B,结果存入A中,余数存入B中 MOV SECONDSHIWEI , A

;结果即秒的十位数拷贝给SECONDSHIWEI MOV SECONDGEWEI , B

;余数即秒的个位拷贝给SECONDGEWEI MOV A, MINUTE

;把MINUTE中的分值拷贝给A MOV B, #10

;给寄存器B赋值10 DIV AB

;A除以B,结果存入A中,余数存入B中 MOV MINUTESHIWEI , A

;结果即分的十位拷贝给MINUTESHIWEI MOV MINUTEGEWEI , B

;余数即分的个位拷贝给MINUTEGEWEI MOV A, HOUR

;把HOUR中的小时值拷贝给A MOV B, #10

;给寄存器B赋值10 DIV AB

;A除以B,结果存入A中,余数存入B中 MOV HOURSHIWEI , A

;结果即小时的十位拷贝给HOURSHIWEI MOV HOURGEWEI , B

;余数即小时的个位拷贝给HOURGEWEI RET

;子程序结束返回到主程序;-----------------显示子程序DISPLAY--------------DISPLAY:MOV A, HOURSHIWEI

;小时的十位拷贝给A MOVC A, @A+DPTR

;到A+DPRT这个数对应的地方找显示段码拷贝给A MOV P0, A

;把显示段码(小时的十位)送到P0 CLR P2.0

;将P2.0置低电平,对应的三极管导通 CALL DELAY

;调延时(让显示小时十位的数码管持续亮一段时间)SETB P2.0

;将P2.0置高电平,对应三极管截止,对应数码管灭 MOV A, HOURGEWEI

;小时的个位拷贝给A MOVC A,@A+DPTR

;到A+DPRT这个数对应的地方找显示段码拷贝给A MOV P0, A

;把显示段码(小时的个位)送到P0 CLR P2.1

;将P2.1置低电平,对应的三极管导通

CALL DELAY

;调延时(让显示小时个位的数码管持续亮一段时间)SETB P2.1 MOV P0,#7FH CLR P2.1 CALL DELAY SETB P2.1

;将P2.1置高电平,对应三极管截止,对应数码管灭 MOV A, MINUTESHIWEI

;分钟的十位拷贝给A MOVC A,@A+DPTR

;到A+DPRT这个数对应的地方找显示段码拷贝给A MOV P0, A

;把显示段码(分钟的十位)送到P0 CLR P2.2

;将P2.2置低电平,对应的三极管导通 CALL DELAY

;调延时(让显示分钟十位的数码管持续亮一段时间)SETB P2.2

;将P2.2置高电平,对应三极管截止,对应数码管灭 MOV A, MINUTEGEWEI

;分钟的个位拷贝给A MOVC A,@A+DPTR

;到A+DPRT这个数对应的地方找显示段码拷贝给A MOV P0, A

;把显示段码(分钟的个位)送到P0 CLR P2.3

;将P2.3置低电平,对应的三极管导通

CALL DELAY

;调延时(让显示分钟个位的数码管持续亮一段时间)SETB P2.3

;将P2.3置高电平,对应三极管截止,对应数码管灭

MOV P0,#7FH CLR P2.3 CALL DELAY SETB P2.3

MOV A, SECONDSHIWEI

;秒的十位拷贝给A MOVC A,@A+DPTR

;到A+DPRT这个数对应的地方找显示段码拷贝给A MOV P0, A

;把显示段码(秒钟的十位)送到P0 CLR P2.4

;将P2.4置低电平,对应的三极管导通 CALL DELAY

;调延时(让显示秒钟十位的数码管持续亮一段时间)SETB P2.4

;将P2.4置高电平,对应三极管截止,对应数码管灭 MOV A, SECONDGEWEI

;秒的个位拷贝给A MOVC A,@A+DPTR

;到A+DPRT这个数对应的地方找显示段码拷贝给A MOV P0, A

;把显示段码(秒钟的个位)送到P0 CLR P2.5

;将P2.5置低电平,对应的三极管导通

CALL DELAY

;调延时(让显示秒钟个位的数码管持续亮一段时间)SETB P2.5

;将P2.5置高电平,对应三极管截止,对应数码管灭 RET

;显示子程序结束返回主程序;--------------------中断服务子程序----------------------------TIMER0:MOV R3, A

;把A中的数据送入R3保护起来 INC 30H

;30H单元中的数加1 MOV A, 30H

;30H单元中的数据拷贝给A CJNE A,#20,JIXU

;A中的数据与20比较不相等就跳转到JIXU处 MOV 30H,#0

;(如果30H单元计满20了)给30H赋值0 INC SECOND

;把SECOND中的秒钟数加1 MOV A,SECOND

;把SECOND中的数据拷贝给A CJNE A, #60, JIXU

;A中的数据与60比较不相等就跳转到JIXU处 MOV SECOND, #0

;给秒SECOND赋值0 INC MINUTE

;把MINUTE中的分钟数加1 MOV A, MINUTE

;把MINUTE中的数据拷贝给A CJNE A, #60, JIXU

;A中的数据与60比较不相等就跳转到JIXU处 MOV MINUTE, #0

;给分钟MINUTE赋值0 INC HOUR

;把HOUR中的小时数据加1 MOV A, HOUR

;把HOUR中的数据拷贝给A CJNE A, #24, JIXU

;A中的数据与24比较不相等就跳转到JIXU处 MOV HOUR, #0

;给小时HOUR赋值0 JIXU: MOV A,R3

;把刚才送入R3中的数据还给A MOV TH0,#3CH

;给计数容器的高8位TH0赋初始值3CH MOV TL0,#0B0H

;给计数容器的低8位TL0赋初始值B0H RETI

;中断子程序返回主程序;---------------------------延时子程序----------------------------DELAY:MOV R0, #50

;给R0赋值50 D2:MOV R1, #10

;给R1赋值10 D1:DJNZ R1, D1

;R1减1不等于0跳到D1处 DJNZ R0, D2

;R0减1不等于0跳到D2处

RET

;延时子程序结束返回调用该程序的下一条;---------------下面的数据表中存储的是显示段码(共阳)-------------------TAB:DB 0C0H,0F9H,0A4H,0B0H,99H

;从TAB处开始存储0、1、2、3、4

DB 92H ,82H ,0F8H,80H ,90H

;5、6、7、8、9对应的显示段码 END

;程序结束

89C51单片机时钟程序 篇2

单片机课程设计

题目:用51单片机实现电子时钟

院 部 物理与电子信息工程学院 专 业 名 称 电子信息科学与技术 班 级 1111 姓 名 杨庆月 学 号 2011111136 指 导 教 师 李刚

2013年12月09日

目录

摘要------------------------------1 1 单片机的相关知识------------1 1.1 单片机的简介--------------------1 1.2 单片机的特点--------------------1 1.3 89C52单片机的基本特点------------2 2 电子时钟--------------------3 2.1电子时钟的基本特点----------------3 2.2电子时钟的原理-------------------4 控制系统的硬件设计---------4 3.1单片机型号的选择-----------------4 3.2 lcd1602工作的原理---------------4 3.3 键盘电路的设计------------------6 3.4 复位电路设计-------------------------6

3.5 时钟电路设计-------------------7 3.6 整体电路原理图-----------------7 控制系统的软件的设计------8 4.1程序的设计----------------------8 4.2程序源代码----------------------8 5 仿真结果和实物图---------------19 5.1仿真结果------------------------------19 5.2实物图-19 6 总结--20

参考文献------------------------21

摘要:单片计算机即单片微型计算机。由 RAM ,ROM,CPU构成,定时,计数和多种接口于一体的微控制器。它体积小,成本低,功能强,广泛应用于智能产业和工业自动化上。而 51系列单片机是各单片机中最为典型和最有代表性的一种。这次课程设计通过对它的学习,应用,从而达到学习、设计、开发软、硬的能力。

本设计主要设计了一个基于 AT89C52单片机的电子时钟。并在 1602上显示相应的时间。并通过一个控制键用来实现时间的调节和是否进入省电模式的转换。

具有时钟和日历的功能,年限显示范围是2013-2099(可修改),且具有闰年自动修正功能

关键字:单片机;子时钟;键盘控制;LCD1602。单片机识的相关知识 1.1 单片机简介

MCS-51是 INTEL公司在成功推广的 MCS-48单片机基础上加以改进而成的 8位单片机。

这种单片机大约是上世纪 70年代末推出的,内部程序可重写的为 8751,外扩程序的是 8031,一次性生产,不可改变程序的是 8051。外形一般为 DIP40封装。不久又推出了增强型的 8052,其资源更加丰富。以后又采用 CHMOS技术推出了 80c51,耗电大大降低。到了 90年代,INTEL公司把精力放到更赚钱的计算机上,将 51单片机技术转让给了一此其它公司,如 ATMEL Philips等半导体制造公司,使 51系列单片机的市场份额不断扩大。

尽管十多年前就有人认为 51单片机会很快淘汰,但事实证明 51单片机经过不断的改进后,由于技术成熟,使用方便,至今在 8位单片机市场仍然拥有庞大的用户。特别是 MCS-51技术的 20年专利期限到期后,大量的兼容型号不断推出。从上世纪 90年代后期开始,美国 ATMEL公司在掌握快速擦写的存储器后,推出了 AT89C系列,此系列在中国获得了广泛的应用。

在此之前,由于可擦写的 8751价格昂贵,国内长时间采用 8031+27C64这样的外扩存程序储器方式。

51单片机最初只有 DIP40这种很古老的封装,后来推出了 CHMOS工艺的80C51后开始有了 PLCC44这种相对较小的方形封装。AT89C系列中开始有 20脚的 DIP20的精简型封装,这极大方便了在一些相对简单的单片机应用,缩小了 PCB的体积。20脚的有 AT89C1051、AT89C1051、AT89C1051,对应程序存储器分别为 1K、2K、4K。

标准的 51为 4K程序空间,128字节的 RAM,32条端口,5个中断,2个定时/计数器,12个时钟周期执行一条基本指令,最长的除法为 48个周期。52为 8K程序空间,256字节的 RAM,32条端口,6个中断,3个定时/计数器。AT89S51是可在板上直接下载程序的改进型号,并增加了看门狗功能,AT89C51只能在编程器下写入程序,所以经常会有人在 PCB上安装 IC插座,以便取下来编程更新程序。

AT的 51系列后来也推出了单周期的 51,但价格没什么优势,国内很少使用。最近几年宏晶在国内大量推广 STC51系列单片机,最近又推出不少所谓 1T的单

片机,价格较低

STC采用串口直接下载程序,写入程序很方便。

1.2 单片机的特点.单片机的存储器ROM 和RAM 时严格区分的。ROM 称为程序存储器,只存放 程序,固定常数,及数据表格。RAM 则为数据存储器,用作工作区及存放用户数 据。2.采用面向控制的指令系统。为满足控制需要,单片机有更强的逻辑控制能力,特别是单片机具有很强的位处理能力。.单片机的I/O 口通常时多功能的。由于单片机芯片上引脚数目有限,为了 解决实际引脚数和需要的信号线的矛盾,采用了引脚功能复用的方法,引脚处于 何种功能,可由指令来设置或由机器状态来区分。.单片机的外部扩展能力很强。在内部的各种功能部件不能满足应用的需求 时,均可在外部进行扩展,与许多通用的微机接口芯片兼容,给应用系统设计带 来了很大的方便。

1.3 89C52单片机介绍

P0 口:P0 口为一个8 位漏级开路双向I/O 口,每脚可吸收8TTL 门电流。当 P1 口的管脚第一次写1 时,被定义为高阻输入。P0 能够用于外部程序数据存储 器,它可以被定义为数据/地址的第八位。在FIASH 编程时,P0 口作为原码输入 口,当FIASH 进行校验时,P0 输出原码,此时P0 外部必须被拉高。

P1 口:P1 口是一个内部提供上拉电阻的8 位双向I/O 口,P1 口缓冲器能接 收输出4TTL 门电流。P1 口管脚写入1 后,被内部上拉为高,可用作输入,P1 口被外部下拉为低电平时,将输出电流,这是由于内部上拉的缘故。在FLASH 编程和校验时,P1 口作为第八位地址接收。

P2 口:P2 口为一个内部上拉电阻的8 位双向I/O 口,P2 口缓冲器可接收,输出4 个TTL 门电流,当P2 口被写“1”时,其管脚被内部上拉电阻拉高,且 作为输入。并因此作为输入时,P2 口的管脚被外部拉低,将输出电流。这是由 于内部上拉的缘故。P2 口当用于外部程序存储器或16 位地址外部数据存储器 进行存取时,P2 口输出地址的高八位。在给出地址“1”时,它利用内部上拉优 势,当对外部八位地址数据存储器进行读写时,P2 口输出其特殊功能寄存器的 内容。P2 口在FLASH 编程和校验时接收高八位地址信号和控制信号。

P3 口:P3 口管脚是8 个带内部上拉电阻的双向I/O 口,可接收输出4 个TTL 门电流。当P3 口写入“1”后,它们被内部上拉为高电平,并用作输入。作为输 入,由于外部下拉为低电平,P3 口将输出电流(ILL)这是由于上拉的缘故。P3 口也可作为AT89C52 的一些特殊功能口,如下表所示: 口管脚备选功能

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(外部数据存储器读选通)P3 口同时为闪烁编程和编程校验接收一些控制信号。

RST:复位输入。当振荡器复位器件时,要保持RST 脚两个机器周期的高电平时 间。

ALE/PROG:当访问外部存储器时,地址锁存允许的输出电平用于锁存地址的 地位字节。在FLASH 编程期间,此引脚用于输入编程脉冲。在平时,ALE 端以不

变的频率周期输出正脉冲信号,此频率为振荡器频率的1/6。因此它可用作对外

部输出的脉冲或用于定时目的。然而要注意的是:每当用作外部数据存储器时,将跳过一个ALE 脉冲。如想禁止ALE 的输出可在SFR8EH 地址上置0。此时,ALE 只有在执行MOVX,MOVC 指令是ALE 才起作用。另外,该引脚被略微拉高。

如果微处理器在外部执行状态ALE 禁止,置位无效。PSEN:外部程序存储器的选通信号。在由外部程序存储器取指期间,每个机 器周期两次/PSEN 有效。但在访问外部数据存储器时,这两次有效的/PSEN 信号

将不出现。

EA/VPP:当/EA 保持低电平时,则在此期间外部程序存储(0000H-FFFFH),不

管是否有内部程序存储器。注意加密方式1 时,/EA 将内部锁定为RESET;当/EA 端保持高电平时,此间内部程序存储器。在FLASH 编程期间,此引脚也用于施加 12V 编程电源(VPP)。电子时钟

2.1 电子时钟的基本特点

现在高精度的计时工具大多数都使用了石英晶体振荡器,由于电子钟、石英 钟、石英表都采用了石英技术,因此走时精度高,稳定性好,使用方便,不需要 经常调试,数字式电子钟用集成电路计时时,译码代替机械式传动,用用液晶显 示器代替指针显示进而显示时间,减小了计时误差,这种表具有时、分、秒显示 时间的功能,还可以进行时和分的校对,片选的灵活性好。

2.2 电子时钟的原理

该电子时钟由89C52,1602 液晶等构成,采用晶振电路作为驱动电路,由延时程序和循环程序达到时分秒的计时,六十秒为一分钟,六十分钟为一小时,满二十四小时为一天。而电路中有四个控制按键,一个是选择,一个进行加数,一个进行减数,还有一个保存。例如按下选择键,然后1602显示光标,此时可以用加或减来进行调节,在按下选择键,光标移到不同的单位上,同理进行调节,最后待日期时间调节好后,按下保存键,时钟开始计时。控制系统的硬件设计 3.1 单片机型号的选择

通过对51单片机的学习,认为STC89C52 是最理想的电子时钟开发芯片。STC89C52,最终认为89C52是一种带8K 字节闪烁可编程可擦除只读存储器的低电压,高性能CMOS8位微处理器,器件采用高密度非易失存储器制造技术制造,与工业标准的MCS-52指令集和输出引脚相兼容。还有一点重要原因,就是采用AT89C52时不能用开发板进行程序的下载,所以最终选用STC89C52进行设计。

3.2 1602 工作原理及显示电路

字符型LCD 通常有14 条引脚线或16 条引脚线的LCD,多出来的2 条线是背 光电源线VCC(15 脚)和地线GND(16 脚),其控制原理与14 脚的LCD 完全一样 1602液晶的基本的操作分为以下四种:

状态字读操作:输入RS=低、RW=高、EP=高; 输出:DB0~7 读出为状态字; 数据读出操作:输入RS=高、RW=高、EP=高; 输出:DB0~7 读出为数据; 指令写入操作:输入RS=低、RW=低、EP=上升沿; 输出:无; 数据写入操作:输入RS=高、RW=低、EP=上升沿; 输出:无。

如图 1602模块的引脚

LCD1602正面

LCD1602背面

1602与单片机连接图 3.3 键盘电路设计

本时钟采用四个按键控制,一个(实物图蓝色线24号引脚)是选择,一个进行加数(实物图紫色线25号引脚),一个进行减数(实物图灰色线26号引脚),还有一个保存(实物图白色线27号引脚)。例如按下选择键,然后1602显示光标,此时可以用加或减来进行调节,在按下选择键,光标移到不同的单位上,同理进行调节,最后待日期时间调节好后,按下保存键,时钟开始计时。

3.4 复位电路设计

单片机复位有上电复位和手动复位两种方式,上电复位是接通电源后利用RC充电来实现复位。手动复位是通过人为干预,强制系统复位。

连接至9号复位引脚

复位电路如图所示,可以实现上电复位和手动复位功能。

3.5 时钟电路设计

系统时钟源由内部时钟方式产生,时钟电路由12MH晶振和两个30PF瓷片电容组成,构成自激振荡,形成振荡源提供给单片机。电容可在5PF到30PF之间选择,电容的大小对振荡频率有微小影响,可起频率微调作用。

3.6整体电路原理图 控制系统的软件设计 4.1 程序设计

由于C 语言程序设计较汇编可读性强,可移植性,且可以大大降低编程的难 度和缩短开发周期,本系统程序采用c 语言设计。

4.2 程序源代码

#include

//包含单片机寄存器的头文件 #include //包含_nop_()函数定义的头文件

#define uchar unsigned char #define uint unsigned int

sbit RS=P2^0;

//寄存器选择位,将RS位定义为P2.0引脚 sbit RW=P2^1;

//读写选择位,将RW位定义为P2.1引脚 sbit E=P2^2;

//使能信号位,将E位定义为P2.2引脚 sbit BF=P0^7;

//忙碌标志位,将BF位定义为P0.7引脚

uchar code table[]=“2013-12-07 WEEK6”;

//初始化液晶显示 16 uchar code table1[]=“TIME: 19-27-50”;

//14

uchar count,s1num;char second,minute,hour,day,month,year,week;

sbit s1=P2^3;

//功能键

sbit s2=P2^4;

//加键 sbit s3=P2^5;

//减键

sbit s4=P2^6;

//保存并退出

/*

延时若干毫秒

*/ void delay(uchar n){ uchar i,a,b;for(i=0;i

for(b=199;b>0;b--)

for(a=1;a>0;a--);}

/*********************************************** 函数功能:判断液晶模块的忙碌状态

返回值:result。result=1,忙碌;result=0,不忙

************************************************/ uchar BusyTest(void){ bit result;RS=0;//根据规定,RS为低电平,RW为高电平时,可以读状态

RW=1;E=1;

//E=1,才允许读写

_nop_();

//空操作

_nop_();_nop_();_nop_();

//空操作四个机器周期,给硬件反应时间

result=BF;//将忙碌标志电平赋给result E=0;

//将E恢复低电平

return result;}

/******************************************** 函数功能:写指令 入口参数:dictate *********************************************/ void WriteInstruction(uchar dictate){ while(BusyTest()==1);

//如果忙就等待

RS=0;//根据规定,RS和R/W同时为低电平时,可以写入指令

RW=0;E=0;

//E置低电平(根据表8-6,写指令时,E为高脉冲,//就是让E从0到1发生正跳变,所以应先置“0” _nop_();

_nop_();

//空操作两个机器周期,给硬件反应时间

P0=dictate;

//将数据送入P0口,即写入指令或地址

_nop_();_nop_();_nop_();_nop_();

//空操作四个机器周期,给硬件反应时间

E=1;

//E置高电平

_nop_();_nop_();_nop_();_nop_();

//空操作四个机器周期,给硬件反应时间

E=0;

//当E由高电平跳变成低电平时,液晶模块开始执行命令 }

/********************************************* 函数功能:写数据

入口参数:y(为字符常量)**********************************************/ void WriteData(uchar y){ while(BusyTest()==1);RS=1;

//RS为高电平,RW为低电平时,可以写入数据

RW=0;E=0;

//E置低电平(根据表8-6,写指令时,E为高脉冲,//就是让E从0到1发生正跳变,所以应先置“0” P0=y;//将数据送入P0口,即将数据写入液晶模块

_nop_();_nop_();_nop_();_nop_();

//空操作四个机器周期,给硬件反应时间

E=1;

//E置高电平

_nop_();_nop_();_nop_();_nop_();

//空操作四个机器周期,给硬件反应时间

E=0;

//当E由高电平跳变成低电平时,液晶模块开始执行命令 }

/****************************************** 函数功能:对LCD的显示模式进行初始化设置 *******************************************/ void LcdInitiate(void){ uchar num;

second=50;minute=27;hour=19;week=6;day=7;month=12;year=13;count=0;s1num=0;E=0;delay(15);//延时15ms,首次写指令时应给LCD一段较长的反应时间 WriteInstruction(0x38);//显示模式设置:16×2显示,//5×7点阵,8位数据接口 delay(5);//延时5ms?,给硬件一点反应时间 WriteInstruction(0x38);delay(5);WriteInstruction(0x38);//连续三次,确保初始化成功 delay(5);WriteInstruction(0x0c);//显示模式设置:显示开,无光标,//光标不闪烁 delay(5);WriteInstruction(0x06);//显示模式设置:光标右移,字符不移 delay(5);WriteInstruction(0x01);//清屏幕指令,将以前的显示内容清除 delay(5);WriteInstruction(0x80);for(num=0;num<16;num++)//让液晶显示日期 { WriteData(table[num]);delay(5);} WriteInstruction(0x80+0x40);for(num=0;num<14;num++)//让液晶显示时间 { WriteData(table1[num]);delay(5);} TMOD=0x01;

//定时器中断初始化 TH0=(65536-50000)/256;TL0=(65536-50000)%256;EA=1;

ET0=1;TR0=1;}

//-------写年月日---------------void write_nyr(uchar add,uchar date){ uchar i,j;i=date/10;j=date%10;WriteInstruction(0x80+add);WriteData(0x30+i);WriteData(0x30+j);}

//--------写时分秒---------------void write_sfm(uchar add,uchar date){ uchar i,j;i=date/10;j=date%10;WriteInstruction(0x80+0x40+add);WriteData(0x30+i);WriteData(0x30+j);}

//-------------写星期-------------void write_week(uchar add,uchar date){ WriteInstruction(0x80+add);WriteData(0x30+date);}

//---------该年是否是闰年-------------bit leap_year(){ int leap;if((year%4==0&&year%100!=0)||year%400==0)

leap=1;

//是闰年

else

leap=0;

//非闰年

return leap;}

//----------键盘扫描--------------------void keyscan(){ if(s1==0)

//第一个键是否按下

{

delay(5);

if(s1==0)

{

while(!s1);

s1num++;

if(s1num>7)

s1num=1;

if(s1num==1)

//第一个键被按一次

{

TR0=0;

WriteInstruction(0x80+0x40+13);

WriteInstruction(0x0f);

}

if(s1num==2)

{

WriteInstruction(0x80+0x40+10);

}

if(s1num==3)

{

WriteInstruction(0x80+0x40+7);

}

if(s1num==4)

{

WriteInstruction(0x80+9);

}

if(s1num==5)

{

WriteInstruction(0x80+6);

}

if(s1num==6)

{

WriteInstruction(0x80+3);

}

if(s1num==7)

{

WriteInstruction(0x80+15);

}

} }

if(s1num!=0)

//如果功能键被按下 { if(s2==0)//第二个按下

{

delay(5);

if(s2==0)

{

while(!s2);

if(s1num==1)

//第一个键被按一次,秒钟加一

{

second++;

if(second==60)

second=0;

write_sfm(12,second);

WriteInstruction(0x80+0x40+13);

}

if(s1num==2)

//第一个键被按二次,分钟加一

{

minute++;

if(minute==60)

minute=0;

write_sfm(9,minute);

WriteInstruction(0x80+0x40+10);

}

if(s1num==3)

//第一个键被按三次,时钟加一

{

hour++;

if(hour==24)

hour=0;

write_sfm(6,hour);

WriteInstruction(0x80+0x40+7);

}

if(s1num==4)

//日期加一

{

day++;

if(day==32)

day=1;

write_nyr(8,day);

WriteInstruction(0x80+9);

}

if(s1num==5)

//月加一

{

month++;

if(month==13)

month=1;

write_nyr(5,month);

WriteInstruction(0x80+6);

}

if(s1num==6)

//年加一

{

year++;

if(year==99)

year=0;

write_nyr(2,year);

WriteInstruction(0x80+3);

}

if(s1num==7)

//星期加一

{

week++;

if(week==8)

week=1;

write_week(15,week);

WriteInstruction(0x80+15);

} } } if(s3==0)

//第三个键被按下 { delay(5);if(s3==0){

while(!s3);

if(s1num==1)

//秒减一

{

second--;

if(second==-1)

second=59;

write_sfm(12,second);

WriteInstruction(0x80+0x40+13);

}

if(s1num==2)

//分减一

{

minute--;

if(minute==-1)

minute=59;

write_sfm(9,minute);

WriteInstruction(0x80+0x40+10);

}

if(s1num==3)

//时减一

{

hour--;

if(hour==-1)

hour=23;

write_sfm(6,hour);

WriteInstruction(0x80+0x40+7);} if(s1num==4)

//日减一

{

day--;

if(day==0)

day=31;

write_nyr(8,day);

WriteInstruction(0x80+9);} if(s1num==5)

//月减一

{

month--;

if(month==0)

month=12;

write_nyr(5,month);

WriteInstruction(0x80+6);} if(s1num==6)

//年减一

{

year--;

if(year==-1)

year=99;

write_nyr(2,year);

WriteInstruction(0x80+3);} if(s1num==7)

//日期减一

{

week--;

if(week==0)

week=7;

write_week(15,week);

WriteInstruction(0x80+15);

} } } if(s4==0)

//保存并退出 {

s1num=0;

WriteInstruction(0x0c);

TR0=1;

} } }

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

main function *******************************************/ void main(void){ uchar k=0;LcdInitiate();

//调用LCD初始化函数

while(1){

keyscan();

k=1;} }

/***************************************** 函数功能:定时器T0的中断服务函数

******************************************/ void timer0()interrupt 1 { count++;if(count==13){

count=0;

second++;

if(second==60)

//秒计满60,秒归0,分+1

{

second=0;

minute++;

if(minute==60)//分计满60,分归0,时+1

{

minute=0;

hour++;

if(hour==24)//时计满24,时归0,星期+1,日+1

{

hour=0;

week++;

day++;

if(week==8)

week=1;//星期计满7,星期归1

if(month==1||month==3||month==5||month==7||month==8||month==10||month==12)//大月三十一天

{

if(day==32)

//大月天数计满31,日归1,月+1

{

day=1;

month++;

}

}

if(month==4||month==6||month==9||month==11)//小月三十天

{

if(day==31)

{ //小月天数计满30,日归1,月+1

day=1;

month++;

}

}

if(month==2)

{

if(leap_year())

{

if(day==30)//闰年二月29天??计满,日归1,月+1

{

day=1;

month++;

}

}

else

{

if(day==29)//非闰年二月28天 计满,日归1,月+1

{

day=1;

month++;

}

}

}

if(month==13)//月计满12,月归1,年+1

{

month=1;

year++;

}

if(year==99)//年计满99,年归0

{

year=0;

}

write_nyr(2,year);

}

write_nyr(5,month);

}

write_nyr(8,day);

write_week(15,week);

}

write_sfm(6,hour);

} write_sfm(9,minute);} write_sfm(12,second);5 仿真结果和实物图 5.1 仿真结果

5.2 实物图 总结:

说句实话,这个时钟在硬件上没有什么太多的技术含量,只有一个单片机的最小系统和一个显示电路,其实它们可以结合在一起,但是为了以后的方便,我还是将它们设计了两个部分,方便以后最小系统的其他方面的应用。还有就是程序,这个时钟程序如果让我自己写的话那我肯定不能再规定时间内完成,所以还是靠外界力量的帮忙。也正是如此,我找到我学习单片机的弱点,那就是程序的编写,记得室友百度开玩笑说:“程序是单片机的灵魂”,想想当时很搞笑,但仔

细一想,那还真是个恰当的比喻,如果说单片机没有程序的输入,那么它不能完成任何事情。虽然本学期的单片机课程即将结束,但是我学习单片机的过程还没有结束,以后还是要在程序的编写上多多下工夫。

此次的电子时钟设计给我奠定了一个实践基础,我会在以后的学习、生活中磨练自己,使自己适应于以后的竞争。当遇到不会或是设计不出来的地方,我们就会在QQ 群里讨论或者是同学之间相互帮助。团结就是力量,无论在现在的学习中还是在以后的工作中,团结都是至关重要的,有了团结会有更多的理念、更多的思维、更多的情感。

参考文献

上一篇:护肤品总结下一篇:如何进行小学生的德育