首页 热点专区 小学知识 中学知识 出国留学 考研考公
您的当前位置:首页正文

基于51单片机的电子万年历与温度检测报警系统

2024-03-19 来源:要发发知识网
序号: 编码:

重庆理工大学

第十八届“开拓杯”学生课外学术科技作品竞赛

参赛作品

作品名称:基于单片机的万年历与温度检测报警系统

作品类别:B

类别:

A自然科学类学术论文 B 科技发明制作

C哲学社会科学类学术论文与社会调查报告

目录

摘要······················································· 1

一、 设计要求与方案论证

1.1设计要求··········································· 2 1.2系统方案选择和论证································· 2 1.3电路最终方案确定··································· 4

二、电子万年历与温度采集报警硬件设计和实现

2.1系统设计··········································· 4

2.1.1系统设计框图································ 4 2.1.2系统硬件需求介绍····························· 4 2.2系统硬件各模块作用································· 5

2.2.1单片机核心控制模块··························· 5 2.2.2实时时钟电路模块····························· 6 2.2.3数字温度传感器模块··························· 13 2.2.4液晶显示电路模块····························· 17 2.2.5蜂鸣器电路模块(2个)··························22 2.2.6 USB和外部电源供电模块························ 23 2.3系统电路图设计·······································23

2.3.1系统电路原理框图和原理图······················23

三、软件设计与分析

3.1系统软件流程图·······································25

3.1.1DS12C87程序流程图······························25

3.1.2DS18B20程序流程图·······························26 3.1.3键盘扫描程序流程图······························27 3.1.4主程序流程图····································28

四、系统测试

4.1测试工具·············································29 4.2软件测试·············································29 4.3硬件测试·············································30

五、设计总结和心得

4.1设计总结与心得·······································31 参考文献·····················································32 附录一:程序清单·············································33 附录三:实物图片·············································48

基于单片机的万年历与温度检测报警系统

摘要

随着社会发展需求的改变,电子万年历是一个应用非常广泛的实用日常计

时工具,带有显示世纪,年,月,日,星期,时,分,秒和按键可调时间及其按键设置闹钟的功能,同时具有月末自动更新,闰年补偿功能等多种功能。温度检测报警系统也是在日常生活和工业应用非常广泛的工具,能实时采集周围的温度信息进行显示,程序内部设定有报警上下限,根据应用环境不同可设定不同的报警上下限。

此系统是基于STC89C52单片机设计的,包含液晶显示模块,DS12C887实时时钟模块,DS18B20温度采集模块,键盘扫描模块,报警模块。STC89C52作为控制核心,具有功耗低,功能强等特点,电压可选3到5V电源供电。显示模块采用1602液晶动态显示,相对数码管而言经济实用,占用空间小,对于显示数字、字母最为合适,而且与单片机连线简单,占用IO口相对较少。实时时钟芯片DS12C887是一款与DS12C885实时时钟兼容的替代产品,该器件提供RTC/日历、定时闹钟等功能,如果检测到主电源故障,该器件可自动切换到备用电源供电,DS12C887将石英晶体与电池集成在一起,在断电后仍可精确走10年。温度检测报警模块采用数字式温度传感器DS18B20,该芯片具有精度高,测量范围广等优点,易与单片机连接,模块电路组成简单并同时具有温度报警功能。

关键词:STC89C52,DS12C887,DS18B20,1602液晶显示,电子万年历,采集周围设备温度、温度报警

一、设计要求与方案论证

1.1.1设计要求

设计一个能够实现世纪,年,月,日,星期,小时,分,秒显示附带温

度检测显示的实时时钟电子万年历,同时具有时间调节和闹钟设置功能,以及时间预设报警、温度报警、报警解除等功能。

该产品共设有四个按键,每个按键具有多种功能,充分利用各个按键。在温度报警的同时还有发光二极管做相应的指示。并且通过编程还可以控制继电器的开闭,从而控制外部设备的运行,通过对闹钟和温度报警的设置可进行定时对设备进行自动化控制,也体现了产品的智能化。

1.1.3系统方案选择和论证

STC89C52单片机作为核心控制体,该单片机具有高可靠,超低价,低功耗,无法解密等优点。该单片机属于双列直插式封装的PDI40口管脚。具有4个输入输出端口,分别为PORT0,PROT1,PROT2,PROT3,其中P0口是一组8位漏极开路型双向IO口,校验时,要求接上拉电阻。其他三个内部有30K的电阻,所以不用再外接电阻。此单片机具有6个中断,其中包括三个定时器中断,二个外部中断,一个串口中断,为全双工通信口。内部有静态非易失EEPROM和看门狗。片内含8Kbbytes的可反复檫写的只读程序存储器(PEROM)和256bytes的随机存取数据存储器(RAM),功能强大,适合许多较为复杂的控制应用场合。相比较其他芯片来说比较适合学生试验所用,故采用此单片机作为核心控制芯片。

DS12C887为实时时钟芯片,功能丰富,可以用来直接代替IBMPC上的时钟日历芯片DS12887,同时,它的管脚也和MC146818B、DS12887相兼容。由于DS12C887能够自动产生世纪、年、月、日、时、分、秒等时间信息,其内部又增加世纪寄存器,从而利用硬件电路解决子“千年”问题:DS12C887中自带有锂电池,外部掉电时,其内部信息还能够保持10年之久;对于一天内

的时间记录,有12小时制和24小时制两种模式。在12小时制模式中,用AM和PM区分上午和下午;时间表示方法也有两种,一种用二进制数表示,一种用BCD码表示;DS12C887中带有128字节RAM,其中有11字节RAM用来储存时间信息,4字节RAM用来储存DS12C887的控制信息,称为控制寄存器,113字节通用RAM使用户使用;此外用户还可以对DS12C887进行编程以实现多种方波输出,并对其内部的三路中断进行屏蔽。芯片内部石英晶体与充电电池,具有三个可单独屏蔽中断标志位的中断输出,闰年补偿至2100年。+5V或+3.3V工作电源,工业级温度范围,自动电源故障检测和切换电路,故此芯片适合应用于工业生产和家庭应用中。

DS18B20是数字式温度传感器,采用单总线通信协议。DS18B20具有体积小,硬件开销低,抗干扰能力强,精度高附加功能强,封装形式多样等特点。适合各种狭小空间内设备的数字测温和控制。同时单线可挂接多个元件,因为每个元件都有唯一的一个64位光刻ROM编码,家族码为28H,可以多个也可单个操作。电压测量范围是3.0V到5.5V。内部含有EEPROM,其报警上、下限温度值和设定的分辨率倍数在芯片掉电的情况不丢失。并且内部带有AD转换电路,技术较为成熟,所以采用此芯片最为合适。1602液晶应用非常广泛,操作简单,功能强大,

采用1602液晶显示各种数字信息最为合适,通过对单片机的编程来控制DS12C887和DS18B20芯片的读写操作来获取相应的信息,再通过对液晶的编程控制将获取到的信息通过一系列转换从而显示到1602液晶上。最后达到有电子万年历和温度采集报警等功能。系统论证时通过在单片机学习板上的试验操作,能够达到预期的效果!

1.2最终方案确定

核心控制体:STC89C52单片机 实时时钟芯片:DS12C887 数字式温度传感器:DS18B20

总共设有四个按键,为节约资源考虑,每个按键都有多种功能。每个按键分别标号为A,B,C,D.第一次按下B,C,D都没有反应,首先按下A键可选择指针位置,B,C键为加减键,D键为闹钟设置键。B同时又是闹钟报警消除键。操作简单,按键灵活。两个报警模块,分为温度报警和闹钟报警两种。

二、电子万年历与温度采集报警硬件设计和实现

2.。1系统设计框图

1602显示模块 主 控 时钟模块 键盘扫描模块 模 块 温度检测模块 报警模块 图1 系统组成框图

2.1.2系统硬件需求介绍

STC89C52单片机一片,DS12C887实时时钟芯片一个,DS18B20数字式温度传感器一个,+5V无源蜂鸣器二个,12MHZ晶振一个,多个按键和开关,常用电容电阻,连接线,三极管,二极管若干,滑动变阻器一个,USB母口一个。

2.2系统硬件各模块作用

2.2.1单片机核心控制模块

核心控制器件选用STC89C52单片机。STC89C52单片机为40管脚双列直插芯片,它是一种高性能,低功耗的8位CMOS微处理器芯片,市场应用最多。而且价格便宜,控制方便,便于应用有4个I/O口分别为P1,P2,P3,P4。其中每一个管脚都能做独立的输入输出管脚,它的第9脚位复位管脚,接上电容和上拉电阻再带个开关构成复位电路。18,19管脚接外部晶振和两个微调电容构成外部晶振电路。单片机,复位电路,晶振,5V电源构成单片机最小系统。其中与AT89S52单片机管脚容。

图2 单片机最小电路

图2为单片机最小电路,其中晶振频率可以根据自己需要进行选择,范围在0-24MHZ,常用12MHZ。复位电路得电容一般用10UF,但并不唯一,只要RC所得时间大于两个机器周期即可。还有其P0内部无上拉电阻,所以在

执行输出功能时,外部必须接上拉电阻(一般10K即可)。

P0口有两个作用,一个接上DS12C887的AD0-AD7(双向地址/数据复用总线),控制着DS12C887的8位并行数据的地址和数据的传输,另接上液晶的DB0-DB7(数据总线)控制着向液晶发送8位并行数据。P1^7接上DS18B20的单数据线,发送并接受数据,地址的操作。P3^0到P3^3作为独立按键口。P2^4口为液晶的数据/命令选择端,1为数据,二为命令,P2^5口控制液晶读/写选择端,1为读命令,0为写操作,P2^6口控制液晶使能信号。对DS12C887:P2^0口控制DS1`2C887的片选信号的输入(CS),P2^1口控制地址选通输入(AS),P2^2口为读写输入(R/W),P2^3控制着数据选通或读输入(DS)。P3^2(外部中断0)接reset管脚,当闹钟时间到时便由此触发外部中断0,进入到外部中断0程序中。P1^0和P1^1口分别控制着蜂鸣器的报警,当温度、时间到达限定值时会发出高低电平脉冲,以至发出报警声音。

2.2.2实时时钟电路模块

时钟模块选用DS12C887芯片,DS12C887芯片能够自动产生世纪,年,月,日,星期,时,分,秒信息,闰年补偿至2100年,具有闹钟功能。内部自带锂电池,在外部掉电时信息不丢失,并且能精确走10年之久。同时DS12C887能自动检测电源故障和切换电路,有工业级温度范围。此芯片可以广泛应用于对环境要求严格的控制系统中。如嵌入式系统,电表,安全系统,网络集线器,网桥,路由器。

图3 DS12C887硬件连接图 D12C887电路图,工作电源采用5V。

第一管脚(MOT)是Motorola或Intel总线时序选择端,利用此引脚选择两种总线类型中的一种,连接到Vcc时选择Motoroal总线时序,接GND或悬空选择Intel总线时序。该引脚内部有一个下拉电阻。

D0到D7为双向地址/数据复用总线。地址于总线周期的开始发送到总线上。并由AS信号的下降沿锁存到DS12C887中。所写的数据由DS信号的下降沿(Motoroal时序)或R/W信号的上升沿(Intel时序)锁存。读周期中,DS12C887于DS信号的后期(Motoroal时序中DS和R/W均为高,Intel时序中DS为低、R/W为高)将数据发送到总线上。读周期结束后,总线恢复到高阻状态,同时DS在Motoroal时序中变低,在Intel时序中变高。12脚为GND。 13脚叫CS-片选信号输入,片选信号低电平有效,在访问DS12C887的总线周期内必须保持低电平Intel时序中的DS和R/W信号工作期间,CS必须保持有效,在CS信号无效情况下,总线操作将锁存地址,不能访问芯片。当

Vcc低于Vpf电压时,DS12C887内部通过禁止CS输入来拒绝访问,此举旨在断电时保护RTC数据和RAM数据。所以在访问期间CS片选信号应保持低电平。 14管脚AS-地址选通输入。有低变为高的地址选通脉冲用来分离总线信号。在AS信号的下降沿,地址锁存到DS12C887内,无论CS信号是否有效,AS的下一个上升沿都将清除地址,地址选通信号必须先于每个读或写访问。如果在CS信号无效的情况下执行了读或写操作,则必须在CS信号有效时且在读或写访问之前,从新发送一次地址选通信号。

15管脚R/W读/写输入。R/W引脚有两种操作模式,在MOT引脚接Vcc的Motoroal时序中,R/W电平用来指示当前周期是读还是写。DS为高时,R/W为高电平表示读周期,R/W为低电平则表示写周期,在MOT引脚接GND的Intel时序中,R/W为低电平有效,在此模式下,R/W引脚与普通RAM的写时能信号(WE)工作方式类似,在信号的上升沿锁存数据。

17管脚DS-数据选通或读输入,DS引脚根据MOT引脚电平有两种模式,MOT引脚接Vcc时,选择Motorola总线时序,此模式下,总线周期的后期DS为正脉冲,称作数据选通脉冲,在读周期中,DS表明DS12C887将要驱动双向总线,在写周期,DS信号的下降沿使使DS12C887锁存所写的数据,当MOT接GND时,选择Intel总线时序,DS表示读取DS12C887数据驱动总线的时间周期,此模式下,DS引脚与普通RAM的输出使能信号(OE)工作方式类似。 18管脚RESET-复位输入,低电平有效RESET引脚对时钟、日历或RAM不起作用,上电时可将RESET引脚首先保持低电平,以等待电源稳定下来,保持低电平时间可根据应用需要而定,但是,如果上电时使用RESET信号,RESET

保持低电平时间应当超过200ms,以保证控制DS12C887上电时的内部定时器结束,当RESET为低电平,而且Vcc大于Vpf时,将产生以下操作: A周期性中断使能(PIE)位清0;B闹钟中断使能(AIE)位清0; C更新结束中断使能(UIE)位清0;D周期中断标志(PF)位清0; E闹钟中断标志(AF)位清0;F更新结束中断标志(UF)位清0; G中断请求状态标志(IRQF)位清0;H IRQ引脚置为高阻状态; I直到RESET恢复为高电平才能访问器件;J方波使能(SQWE)位清0。 在典型应用中,将RESET与Vcc连接。使得DS12C887在进入或退出电源失效状态时不影响任何控制寄存器的值。

19管脚IRQ-中断请求输出。DS12V887的IRQ引脚低电平有效,可用作处理器的中断请求输入,只要引起中断的状态位置位,并且相应中断使能位也置位,IRQ将一直保持低电平。处理器程序通常读取C寄存器来清除IRQ引脚输出,RESET引脚也会清除未处理的中断,没有中断发生时IRQ为高阻状态,可将多个中断器件接到一条IRQ总线上,只要他们均为漏极开路输出,IRQ引脚为漏极开路输出,需要使用一个上拉电阻与Vcc相连。 23脚SQW-方波输出,因为我们此实验中不需要方波输出,故不接。 VCC主电源的DC电源引脚。VCC在正常范围时,可访问器件的所有功能,并能进行数据读写,如果VCC低于VPF,则禁止读和写。

DS12C887采用的是并行通信协议,8位同时传递,对应到D0到D7八位端口。D0到D7接P0口,作为地址/数据选通复用总线。并行通信控制简单,传输速度快,适合近距离传输。

图4 Intel总线写时序图

图5 Intel读时序图

Intel总线如上图所示,编写程序如图时序图所示。因为其时序延时都为纳秒级的,软件执行一句简单语句为微秒级。所以在编写程序是可直接跳过,不用做软件延时。对此相对降低了软件编写的难度。

DS12C887有4个控制寄存器,在任何时间都可以进行访问,即使处于更新周期。

寄存器A字节的内容如下。

MSB LSB UIP DV2 DV1 DV0 RS3 RS2 RS1 RS0 UIP: 更新标志位。为只读位且不受复位操作的影响,为1时,表示即将发生的数据更新;为0时,表示至少244US不会更新数据。当UIP为0时,可以获得所有时钟、日历、闹钟信息。将寄存器B中的SET位置1可以限制任何数据更新操作,并且清除UIP位。

DV2、DV1、DV0:此3位为010时将打开晶振,并开始计时。RES3、RES2、RES1、RES0:用于设置周期性中断产生的时间周期和输出方波的频率。 寄存器B字节的内容如下。

MSB LSB SET PIE AIE UIE SQWE DM 24/12 DSE SET:设置位,可读写,不受复位操作影响。为0时,不处于设置状态,芯片进行正常时间数据更新;为1时,抑制数据更新,可以通过程序设定时间和日历信息。

PIE:周期性中断使能位,可读写,复位时清除此位。为1时,允许寄存器C中的周期中断标志位PF,驱动/IRQ引脚为低产生中断信号输出,中断信号产生的周期由RS3~RE0决定。

AIE:闹钟中断使能位,可读写。为1时,允许寄存器C中的闹钟中断标志位AF、闹钟发生时就会通过/IRQ引脚产生中断输出。

UIE:数据更新结束中断使能位,可读写。复位或者SET位为1时清除此位。为1时允许寄存器C中的更新结束标志UF,更新结束时就会通过/IRQ引脚产生

中断输出。

SQWE:方波使能位,可读写,复位时清除此位。为0时,SQW引脚保持低电平;为1时,SQW引脚输出方波信号,其频率由RS3~RS0决定。

DM:数据模式位,可读写,不受复位操作影响。为0时,设置时间、日历信息为二进制数据;为1时,设置为BCD码数据。

24/12:时间模式设置为,可读写,不受复位操作影响。为0时,设置为12小时模式;为1时,设置为24小时模式。

DSE:为1时,会引起两次特殊的时间更新;4月的第一个星期日凌晨1:59:59会直接更新到3:00:00,10月的最后一个星期日凌晨1:59:59会直接更新到1:00:00;为0时,时间信息正常更新,此位可读写,不受复位操作影响。

寄存器C字节内容如下。

MSB LSB IRQF PF AF UF 0 0 0 0 IQRF:中断申请标志位。为1时,/IRQ引脚为低,产生中断申请。当PF、PIE为1时或者AF、ATE为1或者UF、UIE为1时,此位为1,否则置0.

PF:中期中断标志位。为1时,它是只读位,和PIE位状态无关,由复位操作或者寄存器C操作清除。

AF:闹钟中断标志位。为1时,表示当前时间和闹钟设定时间一至,由复位操作或读寄存器C操作清除。

UF:数据更新结束中断标志位。每个更新周期后此位都会置1,当UIE位位置1时,UF若为1就会引起IRQF置1,将驱动/IRQ引脚为低电平,申请中断。

此位由复位操作或读寄存器C操作清除。

寄存器D字节的内容如下。

MSB LSB 0 0 0 0 0 0 0 0 VRT;RAM和时间有效位。用于指示和VBAT引脚连接的电池状态。此位不可写,也不受操作为影响,正常情况下读取时总去为1,如果出现读取为0的情况,则表示电池耗尽,时间数据和RAM中的数据就会出现问题。

芯片DS12CR887的113字节普通RAM空间为非易失性RAM空间,他不专门用于某些特别功能,而是可以在未处理器程序中作为非易失性内存空间使用。如write_ds(0x0a,0x20);write_ds(0x0b,0x26);分别表示向A,B寄存器发送0X20,0X26命令。0X20表示RAM中时钟、日历和闹钟信息都可以访问;启动振荡器使能中断和SQW输出都禁止。0X26表示更新传输功能正常进行;阻止周期性中断输出;开闹钟中断使能;选择二进制格式;24小时格式;关闭夏令时使能。Read_ds(0x0c)意义为读取C寄存器的地址。

芯片DS12CR887的113字节普通RAM空间为非易失性RAM空间,他不专门用于某些特别功能,而是可以在未处理器程序中作为非易失性内存空间使用。 通过软件编程将读到的信息显示到1602液晶中,显示世纪,年,月,日,星期,小时,分,秒。通过设置按键可以进行时间调节,在调节时间时时钟暂时停止走,再通过功能键回到正常工作状态中,并且具有闹钟设定功能,但在设定闹钟时期内部时间仍然在走。当时,分,秒,相符时通过蜂宁器进行报警,再设置按键关闭闹钟。实现随意控制闹钟的开启和关闭。

2.2.3数字温度传感器模块

数字温度传感器选用DS18B20,采用单总线通信协议。 DS18B20主要特性有:

1、适应电压范围更宽,电压范围:3.0~5.5V,在寄生电源方式下可由数据线供电。

2、独特的单线接口方式,DS18B20在与微处理器连接时仅需要一条口线即可实现微处理器与DS18B20的双向通讯。

3、DS18B20支持多点组网功能,多个DS18B20可以并联在唯一的三线上,实现组网多点测温

4、DS18B20在使用中不需要任何外围元件,全部传感元件及转换电路集成在形如一只三极管的集成电路内。

5、温范围-55℃~+125℃,在-10~+85℃时精度为0.5℃。

6、可编程的分辨率为9~12位,对应的可分辨温度分别为0.5℃、0.25℃、0.125℃和0.0625℃,可实现高精度测温。

7、在9位分辨率时最多在93.75ms内把温度转换为数字,12位分辨率时最多在750ms内把温度值转换为数字,速度更快。

8、测量结果直接输出数字温度信号,以\"一线总线\"串行传送给CPU,同时可传送CRC校验码,具有极强的抗干扰纠错能力。

9、负压特性:电源极性接反时,芯片不会因发热而烧毁,但不能正常工作。 DS1820的操作指令分为ROM操作命令和存储器操作命令: (1)、ROM操作命令及其含义

Skip ROM指令代码(CCh):此命令执行后的存储器操作将针对在线的所有DS1820。

Alarm Search指令代码(ECh):当温度值高于TH或低于TL中的数值时,此命令可以读出报警的DS1820。 (2)、存储器操作指令代码及其含义

Read Scratchpad指令代码(BEh):读取温度寄存器的温度值。 Copy Scratchpad指令代码(48h):将温度寄存器的数值拷贝到EERAM中,保证温度值不丢失。

Convert T指令代码(44h):启动在线DS1280做温度A/D转换。 Recall E2指令代码(B8h):将EERAM中的数值拷贝到温度寄存器中。 温度测量步骤如下:

(1).Read ROM(33 h),每次对DS1820进行操作之前都要对它进行初始化,主要目的在于确定传感器已经连接到单总线上。

(2).Search ROM(F0h),这条指令使处理器用排除的方法去辨别总线上的DS1820。

(3).Match ROM(55h),只有准确的符合64位ROM序列的DS1820才能响应其后的指令,当然,单点测温时可以使用Skip ROM(CCh)指令来跳过这一步。

(4).Convert T(44h),发完指令后应查询总线上的电平,当电平位高时温度转换完成。

(5).Read Scratchpad(BEh),将读指令发出后,就可从总线上读得表示温度的2字节二进制数

由于采用单总线数据传输方式,DS18B20的数据I/O均由同一条线完成,因此,对读写的操作时序要求严格。为了保证DS18B20的严格I/O时序。需

要做较精确的延时。它的各种时序如下图所示:

DS18B20初始化时序

图6 DS18B20温度传感器

DS18B20采用+5V电源供电

2.2.4液晶显示模块

字符型液晶显示模块是一种专门用于显示字母、数字、符号等点阵式LCD,本设计采用16列*2行的字符型LCD1602带背光的液晶显示屏。 各引脚接口说明如表1-1所示: 编号 符号 引脚说明 1 2 3 4 5 6 7 8 VSS VDD VL RS R/W E D0 D1 电源地 电源正极 编号 符号 引脚说明 9 D2 10 D3 D4 D5 D6 D7 BLA BLK 数据 数据 数据 数据 数据 数据 背光源正极 背光源负极 液晶显示偏压 11 数据/命令选择 12 读/写选择 使能信号 数据 数据 13 14 15 16 引脚接口说明: 第1脚:VSS为地电源。 第2脚:VDD接5V正电源。

第3脚:VL为液晶显示器对比度调整端,接正电源时对比度最弱,接地时对比度最高,对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度。

第4脚:RS为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。

第5脚:R/W为读写信号线,高电平时进行读操作,低电平时进行写操作。当RS和R/W共同为低电平时可以写入指令或者显示地址,当RS为低电平R/W为高电平时可以读忙信号,当RS为高电平R/W为低电平时可以写入数据。 第6脚:E端为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。 第7~14脚:D0~D7为8位双向数据线。 第15脚:背光源正极。 第16脚:背光源负极。

1602LCD的指令说明及时序:

1602液晶模块内部的控制器共有11条控制指令,如表1-2所示: 序号 指令 1 2 3 4 清显示 光标返回 置输入模式 显示开/关控制 RS R/W D7 D6 D5 D4 D3 D2 D1 D0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 * 0 0 0 0 0 0 1 I/D S 0 0 0 0 0 1 D C B 5 6 7 光标或字符移位 置功能 置字符发生存贮器0 0 0 0 0 0 0 1 S/C R/L * * 0 0 0 1 DL N F * * 字符发生存贮器地址 0 0 1 0 1 显示数据存贮器地址 1 BF 计数器地址 要写的数据内容 0 读出的数据内容 地址 8 9 10 DDRAM) 从CGRAM或DDRAM读11 数 字符控制命令说明:

1602液晶模块的读写操作、屏幕和光标的操作都是通过指令编程来实现的。(说明:1为高电平、0为低电平)

指令1:清显示,指令码01H,光标复位到地址00H位置。 指令2:光标复位,光标返回到地址00H。

指令3:光标和显示模式设置 I/D:光标移动方向,高电平右移,低电平左移

S:屏幕上所有文字是否左移或者右移。高电平表示有效,低电平则无效。

指令4:显示开关控制。 D:控制整体显示的开与关,高电平表示开显示,低

电平表示关显示 C:控制光标的开与关,高电平表示有光标,低电平表示无光标 B:控制光标是否闪烁,高电平闪烁,低电平不闪烁。 指令5:光标或显示移位 S/C:高电平时移动显示的文字,低电平时移动光标。

1 1 置数据存贮器地址 0 读忙标志或地址 写数到CGRAM或1 0 指令6:功能设置命令 DL:高电平时为4位总线,低电平时为8位总线 N:低

电平时为单行显示,高电平时双行显示 F: 低电平时显示5x7的点阵字符,高电平时显示5x10的点阵字符。 指令7:字符发生器RAM地址设置。 指令8:DDRAM地址设置。

指令9:读忙信号和光标地址 BF:为忙标志位,高电平表示忙,此时模块不

能接收命令或者数据,如果为低电平表示不忙。 指令10:写数据。 指令11:读数据。

基本操作时序表,读写操作时序如图所示:

图7 读操作时序

图8 写操作时序

图9 液晶部分电路连接图

2.2.5蜂鸣器电路模块(2个)

图10 温度报警

图11 闹钟报警

蜂鸣器用CS9013三极管驱动,蜂鸣器用5V的无源蜂鸣器,并接一个发光二极管作为指示灯,同时在发光二极管前串接个限流电阻,数据端口分别接

P1^0,P1^1(由单片机的P1^0,P1^1直接输出驱动)。设置两个报警时为了防止闹钟和温度报警发生重叠,影响判断!

2.2.6 USB和外部电源供电电路

图12 电源部分电路

如图可接插USB口,从而获取电源,也可外部供给+5V电源。此电路图最大优点就是可以连接多个VCC和GND,方便电路连接。有发光二极管做电源指示灯,方便操作。

2.3系统电路图设计

2.3.1系统原理框图和原理图

通过对实时时钟的读写操作,将读取到时间信息显示到1602液晶上,通过按键可对时间和闹钟进行调节,为方便调节考虑,在调节时间不读取温度值。调节完成后再读取温度值。 STC89C52 单 片 温度传感器进行温度采集,经过A/D转换(DS18B20内部完成此操作),送入单片机存储,通过定时器0进行定时读取。 液晶显示,开机时显示welcome have a nice day字样,过几秒钟后显示时间和温度值, 键盘扫描,按键进行时间调节,闹钟设定闹钟设定,关闭蜂宁器报警声。 机 蜂宁器报警,在温度达到相应设定的温度值和闹钟时间到时,触发蜂宁器发出响声,进行报警。再通过相应按键进行消除报警声。(设置两个报警时为了防止两个报警发生重叠) 图8 系统原理框图

下面是系统硬件电路连线图(原理图)

三、软件测试与分析

3.1系统软件流程图

3.1.1DS12C887程序流程图

开始 初始化,写地址、数据,读地址。将相应地址和数据写入控制寄存器A、B中 读取秒闹钟,分闹钟,时闹钟寄存器到相应的存储变量中(read-alarm()函数),调用write-ds()函数将时分秒闹钟的地读取C控制寄存器的地址 读取年,月,日,星期,时,分,秒寄存器的相应地址 当flag,flag1标志位允许时,通过调用时分秒,年月日显示函数将相应信息显示到液晶确定的位置上去。

3.1.2 DS18B20程序流程图

开始 初始化DS18B20 检测DS18B20序列号(单个挂接不需要) 主机发出复位脉冲以检测从机是否有应答 NO YES 发送跳过读ROM的操作 启动温度转换 稍微延时,给硬件一点反应时间 主机再次发出复位脉冲以检测从机是否有NO YES 发送跳过读ROM的操作 读取温度寄存器的值,并经过温度转换,返回温度值。当flag-di,keyxuan标志位允许时将数字温度数据送到1602液晶上显示。 3.1.3 键盘扫描程序模块

进入键盘扫描 闹钟时间已到?否则不进YES A键按下,延时去抖。此时设定flag=1,keyxuan=0时间停止走,温度将暂不进行动态显示(为液晶稳定性考虑)。A每按下一次S1num++一次,指针落在不同位置上(利用switch(S1num),case语句来实现是需要调节时间,日期,还是星期)。最后一次按下S1num=8时,将各位数据送到液晶上显示,同时将flag=0,keyxuan=1,即正常显示时间,动态扫描温度,S1num=0. 按下B键消除闹钟报警 在A键还没有退出时。B,C键根据功能键A选择指针位置switch(S1num),case,然后每按B一次加一,按下C减一,直到调节到准确时间为止(其中每按下一次按键都进行一次显示刷新)。 另外需要调节闹钟时就在按下A后再按下D闹钟键flag1=1,标志位无效(即暂不显示万年历信息)。延时去抖后调用在字符显示函数(SET ALARM字样),再利用B,C键将时分秒加加或减减(每按下一次按键都会有刷新显示)。调用read-alarm()函数。将调节好的时间送入相应时分秒寄存器中。再次按下D键时,将读取到的时分秒信息送到set-alarm()函数中,并发出清屏命令。标志位(flag,flag1,keyxuan)为有效。从而正常显示时间和动态显示温度值。 当调节好时间后,再按A键,直至将S1num++到8为止,即退出了键盘扫描程序,此时将调节好的各个时间信息读取到相应的寄存器中,调用write-ds()函数,读取相应的时分秒等信息的地址和数据,最后发出清屏命令,将flag,flag1,keyxuan标志位改为有效位。从而正常显示时间信息和实现温度动态扫描。

3.1.6 主程序流程图

开始 各个IO端口的设定,各个变量初始化 液晶初始化,DS12C887,DS18B20,定时器0初始化 显示welcome! Heve a nice day !字样 简单延时30S,然后发出清屏命令 无键按下,全部标志位允许,调用读取DS12C887时间函数DS18B20函数,并调用其1602显示各数据的函数,调用星期显示函数,其他字符函数 进入主循环体 键盘扫描 有键按下,调用键盘扫描程序 定时器时间到(即flag-di=1用定时器0实现),温度标志位有效,通过定时器0实现 读取温度值,再将此标志位设为无效,以便显示。 闹钟时间已到?(通过外部中断0将温度的各位显示到液晶上,并设定温度报警上下限 设置标志位,从而调用蜂宁器报高于上限或低于下限? 读取C寄存器表示响应了中断 实现中断)触发进入外部中断扫描 NO 警程序,发出的声音可以根据自己喜好设定。 YES 按下B键可以解除闹钟报警 蜂鸣器发出报警声,并伴有发光二极管闪烁 返回到主循环体 四、系统测试

4.1测试工具 52单片机学习板 4.2软件测试

电子万年历与数字式温度传感器功能强大,芯片简化了硬件电路设计的同时也无形加大了软件编写的复杂程度,为方便程序的调试和提高效率,故将软件编写分模块进行,先将实时时钟模块一步步调试,按照时序图将读写函数写好后,会显示秒部分,并准时走,但液晶屏不稳定,有一些乱码和光标乱闪。经检查发现有些发生地址重叠的冲突,写按键部分程序是发现调节好后在最后刷新屏幕时调节好的时间没有读取到,还有闹钟不能实现闹钟报警功能,不断调节,不断烧写进学习板,然后看结果,最终发现时没有将调节好的时间读取到寄存器中。加上温度传感器部分后发现在调节时间时出现乱码和不稳定现象,光标乱跳的现象。经过不断检查软件,发现在按键调节时软件读取温度值的标志位是允许的,也就是说它在调节时间时又在动态显示周围环境中的温度值,这样会导致光标不稳定的现象。经过再添加keyxuan标志允许位时,这个问题得到很好的解决。在软件编写的过程中遇到非常多的问题,远远不止这些,在暑假期间也花费了大量的时间去不断修改,以上只是列举些有代表性的问题作为反映。

4.3硬件测试

首先单片机最小系统的设计几乎都是统一的,DS12C887,DS18B20接线灵活,IO口的设置具有多样性,开始我想温度用数码管显示,万年历用液晶显示。后来经过何老师的提醒,将数码管撤去,统一用液晶显示数据,这样节约了硬件的开销,用杜邦线将芯片与单片机学习板按照电路原理图连接好,

经过不断的软件,硬件的反复修改,最终实现了软件编写的目标功能!

五、设计总结与心得

大一下学期利用课余时间学习了单片机,并买了块52单片机学习板,在期间学习到了单片机的简单部分,算是有点入门,在暑假期间决定做个作品出来,便一边学习,一边动手实践做,利用52单片机学习板自己写些程序,下载到学习板中看试验结果,一步步的感觉到了学习单片机的乐趣所在,便决定做个电子万年历和温度报警系统,开始一头雾水,觉得无从下手,但我相信事在人为,别人可以的,我一样可以做到!因为在家里,无法向学长和老师请教些技术性问题。唯一可以利用的就是郭天祥老师的视频,走了不少弯路。第一步便是学习如何看懂芯片时序图,对此,英语阅读能力对我也是个挑战。一边参照视频里的指点,一边也开始了编写程序。许多东西以前都没有概念,需要一一开始建立,所以花费的时间也相对较长。每天的时间都花在了这个实验上,程序写一点,烧一点,一点点看试验结果,有时候一段小程序需要调试几天,但我还是一步步的坚持了下去。就这样,思路也逐渐清晰起来,找到了问题的方向。通过在学习板上用杜邦线外接其他芯片构造成所要达到的目标电路,即电子万年历和温度报警系统。电路连接好后,接下来便是复杂的调程序步骤,一点点的改进,修改,一直花了整整两个星期,最终达到了预期的效果。对此,感到了些许欣慰吧!

通过这么久的学习单片机的过程,自己也感受颇多,很多东西有想法只是一小部分,关键在于自己肯不肯实际动手去做。大一上学期觉得自己很迷茫,不知道该干什么,通过自己不断对本专业的了解,发现专业技能的学习才是我的方向,记得大一上学期有位大三的学长为我们做新生交流时说到专

业方向的问题,他说大三的专业课非常多,要想每门学好几乎不可能,必须要有自己的侧重点,我想在大一多学点东西为大三节约时间。后来发现了学习单片机的乐趣和重要性所在。便决定提前自学单片机,开始很多东西都没有概念,需要一步步建立,为此也花费了大量的时间,一遍遍的看书,加上有硬件支持,最终做出了这个成品。相信在今后的不断学习中,会收获更多!同时也很感谢学校能够提供这样一个学习平台,让我们能够在学习之余参加这类实做的比赛,对我们对知识的掌握有很大的帮助!

参考资料

一、 例说51单片机(C语言版),人民邮电出版社。

二、全国大学生电子设计竞赛单片机应用技能精解,电子工业出版社。 三、快速精通Altium Designer6电路图和PCB设计,化学工业出版社。 四、郭天祥视频讲解《十天征服单片机》,与配套资料。

附录一:程序清单

#include #include #include

#define uchar unsigned char #define uint unsigned int //各个IO口的初始化

sbit dscs=P2^0;sbit dsas=P2^1;sbit dsrw=P2^2;sbit dsds=P2^3;sbit irq=P3^2; sbit s1=P3^0;sbit s2=P3^1;sbit s3=P3^2;sbit s4=P3^3;sbit beep=P1^0; sbit beep1=P1^1;sbit rs=P2^4;sbit rw=P2^5;sbit e=P2^6;sbit DQ=P1^7; int i,tt=0;

uchar table0[]={\"WELCOME !\

uchar table1[]={\"HAVE A NICE DAY!\uchar table2[]={\"SET ALARM\

int miao,fen,shi,nian,yue,ri,week,s1num=0,num=0,

num2=1,flag,flag_di,flag1,amiao,afen,ashi; uchar flag_get,num1,TZ=0;TX=0;keyxuan=1;

uchar baiwei,shiwei,gewei,shifen,baifen,qianfen,wanfen; uint wd;

void write_temperture(uchar TZ,uchar TX); void ReadTemperature(); void DS18B20();

unsigned char ReadOneChar();

void WriteOneChar(unsigned char dat); void ddelay(unsigned int i); void dididi();

void delay(uint z){

uint x,y;for(x=z;x>0;x--)for(y=110;y>0;y--);} //液晶写数据与命令函数 void write_com(uchar com)

{rs=0;rw=0;e=0;P0=com;delay(5);e=1;delay(5);e=0;} void write_date(uchar date)

{rs=1;rw=0;e=0;P0=date;delay(5);e=1;delay(5);e=0;} void init(){

rw=0;write_com(0x38);write_com(0x0c);write_com(0x06);write_com(0x01); write_com(0x80);EA=1;EX0=1;IT0=1;TMOD=0x01;TH0=(65536-50000)/256; TL0=(65536-50000)%256;ET0=1;TR0=1;flag1=0;flag=0;flag_di=1;} DS12C887//读写数据与地址命令

void write_ds(uchar add,uchar date){

dscs=0;dsas=1;dsds=1;dsrw=1;P0=add;dsas=0;dsrw=0; P0=date;dsrw=1;dsas=1;dscs=1;} uchar read_ds(uchar add)

{uchar ds_date;dsas=1;dsds=1;dsrw=1;dscs=0;P0=add;dsas=0;dsds=0;P0=0xff; ds_date=P0;dsds=1;dsas=1;dscs=1;return ds_date; } void write_sfm(uchar add,uchar date)显示时分秒函数 {uchar

shi,ge;shi=date/10;ge=date%10;write_com(0x80+0x40+add);write_date(0x30+shi); write_date(0x30+ge);}

void write_nyr(uchar add,uchar date)显示年月日函数

{uchar shi,ge;shi=date/10;ge=date%10;write_com(0x80+add); write_date(0x30+shi);write_date(0x30+ge);} void didi()//闹钟报警程序

{beep=0;delay(100);beep=1;delay(100);beep=0;delay(100);beep=1;} void init_ds12c887()//DS12C887的初始化 {write_ds(0x0a,0x20);write_ds(0x0b,0x26);}

void read_alarm()//读取闹钟寄存器地址到相应的变量中{ amiao=read_ds(1);afen=read_ds(3);ashi=read_ds(5);} void set_alarm(ashi,afen,amiao)//设置闹钟

{write_ds(1,amiao);write_ds(3,afen);write_ds(5,ashi);}

void showsign()//显示其他字符

{ write_com(0x80);write_date('2');write_com(0x80+1);write_date('0'); write_com(0x80+4);write_date('-');write_com(0x80+7);write_date('-'); write_com(0x80+0x40+2);write_date(':');write_com(0x80+0x40+5); write_date(':');}

void show_week()//显示星期函数 {switch(week){

case 1:write_com(0x80+11);write_date('M');write_date('O'); write_date('N');write_date('D');write_date('A');break;

case 2:write_com(0x80+11);write_date('T');write_date('U'); write_date('E');write_date('S');write_date('D');break; case 3:write_com(0x80+11);write_date('W');write_date('E'); write_date('N');write_date('D');write_date('N');break;

case 4:write_com(0x80+11);write_date('T');write_date('H'); write_date('U');write_date('R');write_date('S');break;

case 5:write_com(0x80+11);write_date('F');write_date('R'); write_date('I');write_date('D');write_date('A');break;

case 6:write_com(0x80+11);write_date('S');write_date('A'); write_date('T');write_date('T');write_date('U');break;

case 7:write_com(0x80+11);write_date('S');write_date('U');

write_date('N');write_date('D');write_date('A');break;}} void keyscan()//键盘扫描{

if(s1==0){delay(4);if(s1==0){s1num++;if(flag1==1){ if(s1num==8){s1num=1;}} keyxuan=0; flag=1;// 温度扫描和时钟显示标志位设为无效while(!s1); switch(s1num)//选择液晶光标位置{

case 1:write_com(0x80+0x40+7);write_com(0x0f);break; case 2:write_com(0x80+0x40+4);write_com(0x0f);break; case 3:write_com(0x80+0x40+1);write_com(0x0f);break; case 4:write_com(0x80+15);write_com(0x0f);break; case 5:write_com(0x80+9);write_com(0x0f);break; case 6:write_com(0x80+6);write_com(0x0f);break; case 7:write_com(0x80+3);write_com(0x0f);break;

case 8:write_ds(0x00,miao);delay(5);//最后一次将修改后的数据读取到相应的寄存器中

write_ds(0x02,fen);delay(5);write_ds(0x04,shi);delay(5); write_ds(0x06,week);delay(5);write_ds(0x07,ri);delay(5); write_ds(0x08,yue);delay(5);write_ds(0x09,nian);delay(5);

flag=0;keyxuan=1;write_com(0x0c);s1num=0;break;}}}//在推出键盘扫描程序前将相应标志位设置为有效,并发出清屏命令 if(s1num!=0){if(s2==0){

delay(4);if(s2==0){while(!s2);switch(s1num){ case 1:miao++;if(miao==60)

miao=0;write_sfm(6,miao);write_com(0x80+0x40+7);break;

case 2:fen++;if(fen==60)

fen=0;write_sfm(3,fen);write_com(0x80+0x40+4);break; case 3:shi++;if(shi==24)

shi=0;write_sfm(0,shi);write_com(0x80+0x40+1);break; case 4:week++;if(week==8) week=1;show_week();break; case 5:ri++;if(ri==32) ri=1;

write_nyr(8,ri);write_com(0x80+9);break; case 6:yue++;if(yue==13)

yue=1;write_nyr(5,yue);write_com(0x80+6);break; case 7:nian++;if(nian==100)

nian=0;write_nyr(2,nian);write_com(0x80+3);break;}}}} if(s1num!=0){if(s3==0){delay(4);if(s3==0){ while(!s3);switch(s1num){

case 1:miao--;if(miao==-1)miao=59;

write_sfm(6,miao);write_com(0x80+0x40+7);break; case 2:fen--;if(fen==-1)fen=59;

write_sfm(3,fen);write_com(0x80+0x40+4);break;case 3:shi--;if(shi==-1) shi=23;write_sfm(0,shi);write_com(0x80+0x40+1);break; case 4:week--;if(week==0)week=7; show_week();break;

case 5:ri--;if(ri==-1)ri=31;write_nyr(8,ri);write_com(0x80+9);break; case 6:yue--;if(yue==0)yue=12;

write_nyr(5,yue);write_com(0x80+6);break;

case 7:nian--;if(nian==-1)nian=99;write_nyr(2,nian);write_com(0x80+3); break;}}}}

if(s1num!=0){if(s4==0){delay(4);if(s4==0)//进入闹钟设置程序 {num++;while(!s4);keyxuan=0;if(num==1) {flag1=1;write_com(0x80);for(i=0;i<16;i++) {write_date(' ');delay(5);}

write_com(0x0f);write_com(0x80+3);for(i=0;i<10;i++) {write_date(table2[i]);delay(2);} read_alarm(); miao=amiao;fen=afen;shi=ashi;

write_sfm(0,ashi);write_com(0x80+0x40+1); write_sfm(3,afen);write_com(0x80+0x40+4);

write_sfm(6,amiao);write_com(0x80+0x40+7);} if(num==2)

{num=0;s1num=0;write_com(0x80+3);for(i=0;i<10;i++) {write_date(' ');delay(5);}

amiao=miao;afen=fen;ashi=shi;set_alarm(ashi,afen,amiao);flag=0;

flag1=0;write_com(0x0c);keyxuan=1;}}}}}//推出闹钟设置程序,将修改后的数据读取到相应寄存器中,并将相应标志位设置为有效,发出清屏命令。 void main()//主程序

{init();write_com(0x80+4);for(i=0;i<9;i++) {write_date(table0[i]);delay(2);}

write_com(0x80+0x40);for(i=0;i<16;i++){write_date(table1[i]);delay(2);} delay(2000); write_com(0x01);init_ds12c887();read_alarm(); set_alarm(ashi,afen,amiao);read_ds(0x0c); while(1)//进入主循环体

{keyscan();if(flag_di==0)didi();if(flag_di==0) {if(s2==0){

delay(4);if(s2==0)

{while(!s2);flag_di=1;}}}

if((flag==0)&&(flag1==0))//两个时钟标志允许为有效

{showsign();miao=read_ds(0);write_sfm(6,miao);fen=read_ds(2);write_sfm(3,fen);shi=read_ds(4);write_sfm(0,shi);nian=read_ds(0x09);write_nyr(2,nian); yue=read_ds(0x08);write_nyr(5,yue);ri=read_ds(0x07);write_nyr(8,ri); week=read_ds(0x06);show_week();}

void exter0() interrupt 0//外部中断0程序 {uchar c;flag_di=0;//进入后将标志位设置为有效 c=read_ds(0x0c);}

void tim(void) interrupt 1 using 1//定时器0程序

{TH0=(65536-50000)/256;TL0=(65536-50000)%256;num1++; if (num1==20){ num1=0;flag_get=1;//标志位有效,读取温度 }}

void ddelay(unsigned int i) { while(i--);}

void DS18B20(void)//DS18B20的初始化

{ unsigned char x=0;DQ = 1; ddelay(8); DQ = 0; ddelay(80); DQ = 1; ddelay(10); x=DQ; ddelay(5);}

unsigned char ReadOneChar(void)//读字节函数

{nsigned char i=0;unsigned char dat = 0;for (i=8;i>0;i--) { DQ = 0; dat>>=1;DQ = 1; if(DQ) dat|=0x80; ddelay(5); } return(dat);}

void WriteOneChar(unsigned char dat)//写字节函数 { unsigned char i=0; for (i=8; i>0; i--) {

DQ = 0;DQ = dat&0x01;ddelay(5);DQ = 1;dat>>=1; }ddelay(5);}

void ReadTemperature()//读取温度值

{unsigned char a=0;unsigned char b=0;DS18B20();WriteOneChar(0xCC); WriteOneChar(0x44);ddelay(200);DS18B20();WriteOneChar(0xCC);

WriteOneChar(0xBE); a=ReadOneChar();b=ReadOneChar();TZ=(a>>4)|(b<<4)&0x3f; TX=a<<4;}

void write_temperture(uchar TZ,uchar TX)//启动温度温度转换函数

{baiwei=TZ/100;shiwei=TZ/10;gewei=TZ%10;wd=0; if(TX&0x80) wd=wd+5000;

if(TX&0x40) wd=wd+2500;if(TX&0x20) wd=wd+1250; shifen=wd/1000; baifen=(wd%1000)/100;qianfen=(wd%100)/10;}

附件三:实物图片

实物全图

因篇幅问题不能全部显示,请点此查看更多更全内容