摘 要
随着社会的进步和发展,电子万年历作为日常计时工具被广泛地应用。此电子万年历在硬件方面主要采用STC89C51单片机作为主控核心,由DS1302时钟芯片提供时钟及1602LCD液晶显示屏显示。STC89C51单片机是由宏晶公司公司生产的,功耗小,电压可选用3.4v~5.5v电压供电;DS1302时钟芯片是美国DALLAS公司推出的低功耗实时时钟芯片,它可以对年、月、日、星期、时、分、秒进行计时,而且DS1302的使用寿命长,误差小;对于数字电子万年历采用直观的数字显示,数字显示是采用的1602LCD液晶显示屏来显示,可以同时显示年、月、日、星期、时、分、秒、温度等信息。此外,该电子万年历在软件方面主要包括日历程序、时间调整程序,显示程序等。所有程序编写完成后,在Keil软件中进行调试,确定没有问题后,烧写到单片机上进行测试。
本次课程设计主要由时钟芯片DS1302和温度传感器DS18B20采集数据到单片机进行处理再通过LCD1602显示出来,本设计主要研究了液晶显示器LCD及时钟芯片DS1302,温度传感器DS18B20与单片机之间的硬件互联及通信,对数种硬件连接方案进行了详尽的比较。
关键词:单片机;DS1302;DS18B20;LCD1602
I
ABSTRACT
With the social progress and development, Electronic calendar is widely used as a daily timing tool. The electronic calendar in hardware using STC89C51 microcontroller as the main control center, provided by the DS1302 clock chip and 1602LCD LCD display. STC89C51 microcontroller is produced by the macro crystal company, small power consumption, the voltage can be choosen among 3.4V ~ 5.5V for power supply; DS1302 clock chip is a low power real-time clock chip produced by DALLAS, it can be a time of years,months,days,weeks,hours,minutes,seconds, and DS1302 has a long service life. The error is small; for the digital electronic calendar using visual digital display, 1602LCD digital display is used to display LCD screen that can display years, months, days, weeks, hours, minutes and seconds, temperature and other information. In addition, the electronic calendar mainly includes calendar program,time to adjust procedures,display program etc in sofeware. After the completion of all the procedures, in the Keil software debugging, determine no problem after, and burning to the microcontroller test.
The curriculum design mainly by the clock chip DS1302 and temperature sensor DS18B20 collecting data to the microcontroller for processing and then through the LCD1602 display, this design mainly studies the liquid crystal display LCD and the clock chip DS1302, the hardware connection and communication between the temperature sensor DS18B20 and the MCU, a number of hardware connection scheme for a detailed comparison.
Key words:SCM,DS1302,DS18B20,LCD1602
II
目 录
第一章 绪 论 ------------------------------------------------------------------------------------------------------------ - 1 -
1.1 单片机的概述 ------------------------------------------------------------------------------------------------- - 1 -
1.1.1 单片机的概念 --------------------------------------------------------------------------------------- - 1 - 1.1.2 单片机的特点 --------------------------------------------------------------------------------------- - 1 - 1.2 课题背景 ------------------------------------------------------------------------------------------------------- - 1 - 1.3 课题内容 ------------------------------------------------------------------------------------------------------- - 2 - 第二章 设计要求和方案 --------------------------------------------------------------------------------------------- - 3 -
2.1 设计要求 ------------------------------------------------------------------------------------------------------- - 3 - 2.2 设计方案 ------------------------------------------------------------------------------------------------------- - 3 -
2.2.1 单片机芯片的选择 --------------------------------------------------------------------------------- - 3 - 2.2.2 各模块方案选择 ------------------------------------------------------------------------------------ - 3 - 2.3 工作原理 ------------------------------------------------------------------------------------------------------- - 4 - 第三章 系统的硬件设计及实现 ------------------------------------------------------------------------------------ - 7 -
3.1 电路设计原理框图 ------------------------------------------------------------------------------------------ - 7 - 3.2 STC89C51单片机的介绍 ----------------------------------------------------------------------------------- - 7 -
3.2.1 主要功能及性能参数 ----------------------------------------------------------------------------- - 7 - 3.2.2单片机的引脚功能说明 --------------------------------------------------------------------------- - 8 - 3.3 各模块电路的设计及原理图 ----------------------------------------------------------------------------- - 9 -
3.3.1 时钟电路模块的设计 ----------------------------------------------------------------------------- - 9 - 3.3.2 温度采集模块的设计及原理图 --------------------------------------------------------------- - 11 - 3.3.3 显示模块的设计及原理 ------------------------------------------------------------------------- - 11 -
第四章 系统的软件设计 -------------------------------------------------------------------------------------------- - 13 -
4.1 程序流程框图 ------------------------------------------------------------------------------------------------ - 13 - 4.2 时间调整程序流程图 -------------------------------------------------------------------------------------- - 14 - 第五章 系统测试 ------------------------------------------------------------------------------------------------------ - 15 -
5.1 硬件测试 ------------------------------------------------------------------------------------------------------ - 15 - 5.2 软件测试 ------------------------------------------------------------------------------------------------------ - 15 - 第六章 总结与致谢 --------------------------------------------------------------------------------------------------- - 17 -
6.1 总结 ------------------------------------------------------------------------------------------------------------- - 17 - 6.2 致谢 ------------------------------------------------------------------------------------------------------------- - 18 - 参考文献 ------------------------------------------------------------------------------------------------------------------- - 19 - 附 录 ------------------------------------------------------------------------------------------------------------------------ - 21 -
附录一:实物图 --------------------------------------------------------------------------------------------------- - 21 - 附录二:源程序 --------------------------------------------------------------------------------------------------- - 23 -
第一章 绪 论
1.1 单片机的概述
1.1.1 单片机的概念
单片机即单片微型计算机,是把中央处理器、存储器、定时/计数器、输入输出接口都集成在一块集成电路芯片上的微型计算机。与应用在个人电脑中的通用型微处理器相比,它更强调自供应和节约成本。单片机也被称为微控制器,是因为它最早被用于工业控制领域。单片机的芯片内仅由CPU的专用处理器发展而来。最早的设计理念是通过将大量外围设备和CPU集成在一个芯片中,使计算机系统更小,更容易集成复杂的而对体积要求严格的控制设备当中。
1.1.2 单片机的特点
单片机以其卓越的性能,得到了广泛的应用,已深入到各个领域。单片机应用在检测、控制领域中,具有如下特点:
1、体积小、控制功能强、成本低。因而可以方便地组装各种智能式控制设备和仪器,做到机、电、仪一体化。
2、易扩展。很容易构成各种规模的应用系统,为应用系统的设计和生产带来极大方便。
3、可靠性好、使用温度范围宽。在各种恶劣的环境下都能可靠的工作,这是其他机种无法比拟的。
4、种类多,型号全。很多单片机厂家逐年扩大适应各种需要,有针对性地推出一系列型号产品,使系统开发工程师有很大的选择余地。大部分产品有较好的兼容性,保证了已开发产品能顺利移植,较容易地使产品进行升级换代。
5、低功耗。现在新型单片机的功耗越来越小,供电电压从5V降低到了3.2V,甚至1V,工作电流从mA降到µA级,工作频率从十几兆可编程到几十千赫兹。 1.2 课题背景
生活中我们无时无刻不在与时间联系,是时间牵引着我们上班不迟到,日常生活都有着一定的规律。随着社会、科技的发展,人们得知时
- 1 -
间,从观太阳、摆钟到现在电子钟的不断研究、创新。为了在观测时间的同时能够了解其它与人类密切相关的信息,比如温度、星期、日期等,所以诞生了电子万年历,它是集时间、日期、星期和温度功能于一身,具有读取方便、显示直观、功能多样、电路简洁等诸多优点,符合电子仪器仪表的发展趋势。伴随着电子技术的迅速发展,特别是随大规模集成电路出现,给人类生活带来了根本性的改变。尤其是单片机技术的应用产品已经走进了千家万户。 1.3 课题内容
单片机以其体积小、功能全、性价比高等诸多优点,在工业控制、家用电器、通信设备、信息处理、尖端武器等各种测控领域的应用中独占霸主,单片机开发技术已成为电子信息、电气、通信、自动化、机电一体化等专业技术人员必须掌握的技术。用最少的芯片就能实现最强大的功能,这是将来电子产品的主流方向,它将无可置疑地一步步取代其它同类产品,其数量之大和应用面之广,是其它任何类型的计算机所无法比拟的。
以基于单片机的万年历作为设计的课题,因为它有很好的开放性和可发挥性,对作者的要求比较高,不仅考察了对单片机的掌握能力而且强调了对单片机扩展的应用。另外液晶显示的万年历已经越来越流行,特别适合在家庭居室、办公室、会议室、车站和广场等地方使用,它具有显示清晰直观、走时准确、可以进行夜视等功能,并且还可以扩展出其它多种功能。所以,电子万年历作为设计课题很有价值。
本电子万年历的设计在硬件方面主要采用STC89C51单片机作为主控核心,由DS1302时钟芯片提供时钟及1602LCD液晶显示屏显示。STC89C51单片机是由宏晶公司公司生产的,功耗小,电压可选用3.4~5.5V电压供电;DS1302时钟芯片是美国DALLAS公司推出的低功耗实时时钟芯片,它可以对年、月、日、星期、时、分、秒进行计时,而且DS1302的使用寿命长,误差小;数字显示是采用的LED液晶显示屏来显示,可以同时显示年、月、日、星期、时、分、秒、温度等信息。所有程序编写完成后,在Keil软件中进行调试,确定没有问题后,烧写到单片机上进行测试。
- 2 -
第二章 设计要求和方案
2.1 设计要求
1、可显示年、月、日、时、分、秒、星期的功能; 2、掉电重启时,无需重新调时;
3、具有温度测定的功能,可准确显示当前的时间和实时温度等信息。 2.2 设计方案
2.2.1 单片机芯片的选择
本设计采用STC89C51芯片作为硬件核心,片内含8k Bytes的可反复擦写1000次的Flash只读程序存储器,器件兼容标准MCS-51指令系统及80C51引脚结构,芯片内集成了通用8位中央处理器和ISP Flash存储单元,具有在系统可编程特性,配合PC端的控制程序即可将用户的程序代码下载进单片机内部,省去了购买通用编程器,而且速度更快。能与5v电压工作,当在对电路进行调试时,由于程序的错误修改或对程序的新增功能需要烧入程序时,避免芯片的多次拔插对芯片造成的损坏。
2.2.2 各模块方案选择
1、显示模块方案选择
采用LCD液晶显示屏,液晶显示屏的显示功能强大,可显示大量文字,图形,显示多样,清晰可见,对于电子万年历而言,一个1602的液晶屏即可,价格也还能接受,需要的接口线较多,但给调试可以带来诸多方便,所以此设计中采用LCD1602液晶显示屏作为显示模块。
2、时钟芯片方案选择
采用DS1302时钟芯片实现时钟,DS1302是美国DALLAS公司推出的一种高性能、低功耗、带RAM的实时时钟电路,它可以对年、月、日、星期、时、分、秒进行计时,工作电压为2.0V~5.5V。采用三线接口与CPU进行同步通信,并可采用突发方式一次传送多个字节的时钟信号或RAM数据。DS1302内部有一个31×8的用于临时性存放数据的RAM寄存器。DS1302是DS1202的升级产品,与DS1202兼容,但增加了主电源/后背电源双电源引脚,同时提供了对后背电源进行涓细电流充电的能力。主要特点是采用串行数据传输,可为掉电保护电源提供可编程的充电功
- 3 -
能,并且可以关闭充电功能。采用普通32.768kHz晶振。因此,本设计中采用DS1302提供时钟。
3、温度传感器方案选择
采用数字式温度传感器DS18B20,此类传感器为数字式传感器而且仅需要一条数据线进行数据传输,易于与单片机连接,可以避免A/D模数转换模块,降低硬件成本,简化系统电路。另外,数字式温度传感器还具有测量精度高、测量范围广等优点。因此,本设计DS18B20温度传感器作为温度采集模块。 2.3 工作原理
1、LCD1602工作原理
1602字符型LCD通常有14条引脚线或16条引脚线的LCD,多出来的2条线是背光电源线。1602液晶模块内部的字符发生存储器已经存储了160个不同的点阵字符;1602通过D0~D7的8位数据端传输数据和指令。
(1)显示模式设置:(初始化)00111000[0x38]设置16×2显示,5×7点阵,8位数据接口;
(2)显示开关及光标设置:(初始化)00001DCBD显示(1有效)、C光标显示(1有效)、B光标闪烁(1有效);
(3)数据指针设置:数据首地址为80H,所以数据地址为80H+地址码(0-27H,40-67H)。
2、DS1302工作原理
(1)DS1302引脚图如下图1所示:
图1 DS1302引脚图
(2)管脚描述
X1、X2:32.768KHz晶振管脚; GND:地;
- 4 -
RST:复位脚;
I/O:数据输入/输出引脚; SCLK:串行时钟;
Vcc1、Vcc2:电源供电管脚; DS1302:串行时钟芯片8脚DIP。 3、DS18B20工作原理 (1)DS18B20的主要特征
最高12位分辨率,精度可达土0.5摄氏度; 12位分辨率时的最大工作周期为750毫秒; 可选择寄生工作方式;
检测温度范围为–55°C~+125°C(–67°F ~+257°F); 内置EEPROM,限温报警功能;
(2)DS18B20芯片的封装结构如下图2所示:
图2 DS18B20封装图
(3)管脚描述 GND:接地; DQ:单数据总线; VDD:电源电压。
- 5 -
- 6 -
第三章 系统的硬件设计及实现
3.1 电路设计原理框图
本设计主要采用STC89C51单片机作为主控核心,由DS1302时钟芯片提供时钟,1602液晶显示屏提供显示,按键开关控制时间,DS18B20进行温度采集。其原理图如图3所示: 片1602液晶显示屏DS1302控 制 时钟芯STC89C51单片机主控制 按键控制 DS18B20温度采集 图3 系统原理图
3.2 STC89C51单片机的介绍
3.2.1 主要功能及性能参数
1、内置标准51内核,机器周期:增强型为6时钟,普通型为12时钟;
2、工作频率范围:0~40MHZ,相当于普通8051的0~80MHZ; 3、STC89C5xRC对应Flash空间:4KB\\8KB\\15KB; 4、内部存储器(RAM):512B; 5、定时器\\计数器:3个16位; 6、通用异步通信口(UART)1个;
- 7 -
7、通用I\\O口:32\\36个; 8、工作电压:3.8~5.5V;
3.2.2单片机的引脚功能说明
STC89C51单片机的引脚图如图4所示:
图4 STC89C51单片机的引脚图
1、VCC:电源电压; 2、GND:地;
3、P0口:P0口是一组8位漏极开路型双向I/O口,也即地址/数据总线复用口。作为输出口用时,每位能吸收电流的方式驱动8个TTL逻辑门电路,对端口P0写“1”时可作为高阻抗输入端用;
4、P1口:P1是一个带内部上拉电阻的8位双向I/O口,P1的输出缓冲级可驱动(吸收或输出电流)4个TTE逻辑门电路。对端口写“1”,通过内部的上拉电阻把端口拉到高电平,此时可作输入口。作输入口使用时,因为内部存在上拉电阻,某个引脚被外部信号拉低时会输出一个电流(ILL);
5、P2口:P2是一个带有内部上拉电阻的8位双向I/O口,P2的输出缓冲级可驱动(吸收或输出电流)4个TTL逻辑门电路。对端口P2写“1”,通过内部的上拉电阻把端口拉到高电平,此时可作输入口,作输入口使用时,因为内部存在上拉电阻,某个引脚被外部信号拉低时会输出一个
- 8 -
电流(ILL);
6、P3口:P3口是一组带有内部上拉电阻的8位双向I/O口。P3口输出缓冲级可驱动(吸收或输出电流)4个TTL逻辑门电路。对P3口写入“1”时,它们被内部上拉电阻拉高并可作为输入端口。此时,被外部拉低的P3口将用上拉电阻输出电流(ILL);
P3口除了作为一般的I/O口线外,更重要的用途是它的第二功能,其第二功能如表一所示:
表一 P3口的第二功能
端口引脚 P3.0 P3.1 P3.2 P3.3 P3.4 P3.5 P3.6 P3.7
第二功能 RXD(串行输入口) TXD(串行输出口) INT0(外中断0) INT1(外中断1) T0(定时/计数0) T1(定时/计数1) WR(外部数据存储器写选通) RD(外部数据存储器读选通) 7、RST:复位输入。当振荡器工作时,RST引脚出现两个机器周期以上高电平将使单片机复位;
8、XTAL1:振荡器反相放大器的及内部时钟发生器的输入端; 9、XTAL2:振荡器反相放大器的输出端。 3.3 各模块电路的设计及原理图
3.3.1 时钟电路模块的设计
1、设计说明及介绍
DS1302是美国DALLAS公司推出的一种高性能、低功耗、带RAM的实时时钟芯片,它可以对年、月、日、周、时、分、秒进行计时,工作电压为2.0V~5.5V。采用三线接口与CPU进行同步通信,并可采用突发方式一次传送多个字节的时钟信号或RAM数据。DS1302内部有一个31×8的用于临时性存放数据的RAM寄存器。
- 9 -
DS1302的引脚排列中Vcc1为后备电源,Vcc2为主电源。在主电源关闭的情况下,也能保持时钟的连续运行。DS1302由Vcc1或Vcc2两者中的较大者供电。当Vcc2大于Vcc1+0.2V时,Vcc2给DS1302供电。当Vcc2小于Vcc1时,DS1302由Vcc1供电。X1和X2是振荡源,外接32.768kHz晶振。RST是复位/片选线,通过把RST输入驱动置高电平来启动所有的数据传送。RST输入有两种功能:首先,RST接通控制逻辑,允许地址/命令序列送入移位寄存器;其次,RST提供终止单字节或多字节数据的传送手段。当RST为高电平时,所有的数据传送被初始化,允许对DS1302进行操作。如果在传送过程中RST置为低电平,则会终止此次数据传送,I/O引脚变为高阻态。上电运行时,在Vcc>2.0V之前,RST必须保持低电平。只有在SCLK为低电平时,才能将RST置为高电平。
2、原理图
时钟电路DS1302芯片的X1和X2接晶振模块电路,VCC2作为电池电路为时钟芯片供电,其原理图如图5所示:
图5 时钟电路原理图
- 10 -
3.3.2 温度采集模块的设计及原理图
1、温度采集模块的设计
采用数字式温度传感器DS18B20,它是数字式温度传感器,具有测量精度高,电路连接简单的特点,此类传感器仅需要一条数据线进行数据传输,使用P3.5与DS18B20的I/O口连接加一个上拉电阻,Vcc接电源,Vss接地。独特的一线接口,只需要一条口线通信多点能力,简化了分布式温度传感应用无需外部元件可用数据总线供电,电压范围为3.4V至5.5V无需备用电源 测量温度范围为-55度至+125度。-10度至+85度范围内精度为±0.5度温度传感器可编程的分辨率为9~12位。
2、原理图
单片机使用P3.0口与DS18B20的2号引脚相接,温度传感器采用外部供电方案,由1、3引脚提供电源。电路图如图6所示:
图6 温度采集电路
3.3.3 显示模块的设计及原理
1、显示模块的设计
采用LCD1602液晶显示器,单片机P0口作为数据输出口,通过10R的上拉电阻连接到VCC,VCC接5V电源,GND接地。GND为液晶显示器对比度调整端,可以通过滑动变阻器RH1调显示器的对比度。RS为寄存器选择,高电平1时选择数据寄存器、低电平0时选择指令寄存器。R/W为读写信号线,高电平(1)时进行读操作,低电平(0)时进行写操作。E(或
- 11 -
EN)端为使能(enable)端,下降沿使能。BLA、BLK分别为显示器背光灯的正、负极。
2、原理图
显示电路由1602液晶接口插槽组成,如下图7所示。使能端EN由单片机P2.2引脚控制,数据/命令选择端由单片机的P0端控制。
图7 LCD显示电路
- 12 -
第四章 系统的软件设计
4.1 程序流程框图
主程序流程图如下图8所示。由于LCD1602,DS18B20,DS1302的数据读取及指令写入函数均已在各自的头文件中完成,在主程序中只须引用即可。
开始 单片机读DS1302数据 单片机送数据到LCD1602 单片机判断按键 单片机处理按键调显示数结束
图8 主程序流程图
- 13 -
4.2 时间调整程序流程图
由于在硬件电路方面上设计了时间调整按键和开关,因此应有对应的时间调整程序。时间调整程序的流程图如下图9所示。
开始 控制键有效,进入月调整程等待按键程序 控制键有效,进入年调整程序 N 等待按键是否执行月N 是否执行年加键有Y Y 减键有加键有减键有月加一 月减一 年加一 年减一 控制键有效,进入日控制键有效,进入星期调整程等待按键程序 等待按键程序 是否执行日是否执行星期调 N Y 加键有效 减键有效 日加一 Y 加键有效 减键有效 日减一 星期加一 星期减一 控制键有效,进入时调整程 - 14 -
N 图9 时间调整程序流程图
第五章 系统测试
5.1 硬件测试
在调试硬件时遇到过很多问题,但只要细心、认真检查这些问题都是可以避免的,主要问题及解决办法如下:
(1)认真检查电路是否有短路及断路的地方,线与线之间,管脚刺破邻近的漆包线之间是否连接在一起,有的话要用刀划开,或者重新焊接。
(2)检查完毕后接通电源后LCD1602没有正确的显示。在不通电状态下用万用表检测电路是否正常连接,在检查回路时发现有的点之间看似连接,但由于虚焊导致其并没有连接,此刻就对焊脚进行在焊接直到解决问题。 5.2 软件测试
由于本系统涉及到多个子程序,多个芯片的编程。首先必须对可编程芯片的控制字即其控制指令要熟记于心。其次,芯片很多都有时钟输入端,需要晶振支持。对芯片的读写都需要在相应的触发沿到来时才能进行。由于DS18B20是串行通信数据,只用一个口线传输,在处理采集的模拟信号时需要一定的时间,会对延时有较高要求。所以在调用温度子程序时,先关闭定时器1中断允许,在温度子程序返回时再打开定时器1中断允许。
- 15 -
- 16 -
第六章 总结与致谢
6.1 总结
在本次课程设计的过程中,我发现很多的问题,刚开始着手做电子万年历时给我的感觉是模糊,拿到复杂的电路图心里有点慌张,但静下心来经过反复的分析和测试,终于对电路的原理及功能有所理解,同时提高了自己对电路的设计能力与分析能力及焊接能力。经过本次课程设计,基本完成了设计任务的要求。在硬件电路方面,详尽解析了各个独立元器件的选择依据,对三种方案进行了全面的比较;在时钟芯片的选择上,若直接采用单片机定时计数器提供秒信号,使用程序实现年、月、日、周、时、分、秒计数,采用此种方案虽然可以减少时钟芯片的使用,节约成本,但是它实现的时间误差较大,因此我们小组采用专业的时钟芯片DS1302,因为它在对年、月、日、周、时、分、秒进行计时时采用串行数据传输,可为掉电保护电源提供可编程的充电功能;在显示模块的选择上,若采用LED数码管动态扫描,LED数码管价格虽适中,对于显示数字也适合,而且采用动态扫描法与单片机连接时,占用的单片机口线少。但是由于数码管动态扫描需要借助74LS164移位寄存器进行移位,该芯片在电路调试时往往会有很多障碍,因此本次课设选择了LCD1602,液晶显示屏的显示功能强大,可显示大量文字,图形,显示多样并且清晰可见;在温度采集模块的选择上,没有采用热敏电阻,因为设计方案需用A/D转换电路,增加硬件成本而且热敏电阻的感温特性曲线并不是严格线性的,会产生较大的测量误差。最后选择了DS18B20,此类传感器为数字式传感器而且仅需要一条数据线进行数据传输,易于与单片机连接,可以避免A/D模数转换模块,降低硬件成本,简化系统电路。另外,数字式温度传感器还具有测量精度高、测量范围广等优点。从元件性能和组装电路后的测试结果来看,硬件电路的设计是比较成功的,各个功能都可以实现。
- 17 -
6.2 致谢
这次课程设计,我一直很努力地去做,过程中得到了老师的悉心指导和同学们的大力支持及热心帮助,并对我的设计提出许多有益的建议,在此对他们表示衷心的感谢。同时也要感谢学校能给我这次机会去尝试自己设计一些东西,使自己所学专业知识与实践能够结合起来,最后也要感谢有关我参考过的文献的作者,是他们为我提供知识的源泉,使我最终能顺利地完成这次课程设计。
在毕业之际,我衷心地祝愿我的同学和朋友们在以后的人生道路上越走越宽广,也深深相信在未来的日子里我们将一路携手前行,会遇到很多的碰撞和交流,我们将始终记得我们曾在兰州交通大学新能源学院同窗学习,这将是我克服困难、不断前进的精神动力。
- 18 -
参考文献
[1]胡乾斌,李光斌,李玲.单片微型计算机原理与应用.华中科技大学出版社,1996 [2]刘勇.数字电路.电子工业出版社,2004
[3]杨子文.单片机原理及应用.西安电子科技大学出版社,2006 [4]王萍.电子技术实验教程.机械工业出版社,2009
[5]沈红卫.单片机应用系统设计实例与分析,北京:北京航空航天大学出版社.2003 [6]李光飞.单片机课程设计实例指导,北京:北京航空航天大学出版社.2004 [7]王法能.单片机原理及应用,科学出版社. 2004
[8]楼然苗,李光飞.51系列单片机设计实例[M].北京航空航天大学出版社,2003 [9]朱定华,戴汝平.单片微机原理与应用[M].清华大学出版社,2003 [10]胡汉才.单片机原理与接口技术[M].清华大学出版社,2004
- 19 -
- 20 -
附 录
附录一:实物图
- 21 -
- 22 -
附录二:源程序
#include #define uint unsigned int #define uchar unsigned char //ds1302IO sbit DSIO=P1^1; sbit RST=P1^2; sbit SCLK=P1^0; #define LCD1602_DATAPINS P0 sbit LCD1602_E=P2^2; sbit LCD1602_RW=P2^1; sbit LCD1602_RS=P2^0; sbit SET_KEY=P3^7; sbit ADD_KEY=P3^6; sbit SUB_KEY=P3^5; sbit DETERMINE_KEY=P3^4; unsigned char Set_Step = 0; #define NormalRun 0 #define SetYear 1 #define SetMon 2 #define SetDay 3 #define SetHour 4 #define SetMin 5 #define SetSec 6 #define SetWeek 7 void Ds1302Write(unsigned char addr,unsigned char dat); unsigned char Ds1302Read(unsigned char addr); void Ds1302Init(); void Ds1302ReadTime(); void Delay1ms(unsigned int ); unsigned char Ds18b20Init(); void Ds18b20WriteByte(unsigned char com); unsigned char Ds18b20ReadByte(); void Ds18b20ChangTemp(); void Ds18b20ReadTempCom(); int Ds18b20ReadTemp(); /*在51单片机12MHZ时钟下的延时函数*/ - 23 - //void Delay1us(uint a); void Delay10us(uint c); //误差 0us /*LCD1602写入8位命令子函数*/ void LcdWriteCom(uchar com); /*LCD1602写入8位数据子函数*/ void LcdWriteData(uchar dat) /*LCD1602初始化子程序*/ void LcdInit(); void LcdDisplay(); void Key_Scan(); //DS1302写入和读取时分秒的地址命令 unsigned char READ_RTC_ADDR[7]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d}; //秒分时日月周年 最低位读写位}; unsigned char WRITE_RTC_ADDR[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c}; //DS1302时钟初始化2013年1月1日星期二12点00分00秒。存储顺序是秒分时日月周年,存储格式是用BCD码 unsigned char TIME[7]={0x0, 0x0, 0x12, 0x30, 0x9, 0x3, 0x15}; unsigned char Time1outNum = 0; int readVal = 0; void Ds1302Write(unsigned char addr,unsigned char dat) { ; unsigned char n; SCLK=0; //先将SCLK置低电平。 _nop_(); RST=1; //然后将RST(CE)置高电平。 _nop_(); for(n=0;n<8;n++) //开始传送八位地址命令 { } for(n=0;n<8;n++) //写入8位数据 { DSIO=dat&0x01; dat>>=1; SCLK=1; //数据在上升沿时,DS1302读取数据 - 24 - DSIO=addr&0x01; //数据从低位开始传送 addr>>=1; SCLK=1; //数据在上升沿时,DS1302读取数据 _nop_(); SCLK=0; _nop_(); } _nop_(); SCLK=0; _nop_(); } RST=0; //传送数据结束 _nop_(); unsigned char Ds1302Read(unsigned char addr) { unsigned char n,dat,dat1; SCLK=0; // _nop_(); RST=1; // _nop_(); for(n=0;n<8;n++) // { DSIO=addr&0x01; // addr>>=1; SCLK=1; // _nop_(); SCLK=0; //DS1302 _nop_(); } _nop_(); for(n=0;n<8;n++) // { dat1=DSIO; // dat=(dat>>1)|(dat1<<7); SCLK =1; _nop_(); SCLK=0; //DS1302 _nop_(); } RST=0; _nop_(); // SCLK=1; _nop_(); DSIO=0; _nop_(); DSIO=1; 先将SCLK置低电平。 然后将RST(CE)置高电平。 开始传送八位地址命令 数据从低位开始传送 数据在上升沿时,DS1302读取数据 下降沿时,放置数据 读取8位数据 从最低位开始接收 下降沿时,放置数据 以下为DS1302复位的稳定时间,必须的。- 25 - } _nop_(); return dat; void Ds1302Init() { } void Ds1302ReadTime() { } void Delay10us(uint c) //误差 0us { unsigned int a,b; for(b=c;b>0;b--) for(a=2;a>0;a--); } void Delay1ms(unsigned int y) { } unsigned char Ds18b20Init() { unsigned char n; Ds1302Write(0x8E,0X00); //禁止写保护,就是关闭写保护功能 for(n=0;n<7;n++) //写入7个字节的时钟信号:分秒时日月周年 { } Ds1302Write(0x8E,0x80); //打开写保护功能 Ds1302Write(WRITE_RTC_ADDR[n],TIME[n]); unsigned char n; for(n=0;n<7;n++) //读取7个字节的时钟信号:分秒时日月周年 { } TIME[n]=Ds1302Read(READ_RTC_ADDR[n]); unsigned int x; for(y;y>0;y--) for(x=110;x>0;x--); unsigned int i; DSPORT=0; //将总线拉低480us~960us i=70; while(i--);//延时642us - 26 - } DSPORT=1; //然后拉高总线,如果DS18B20做出反应会将在i=0; while(DSPORT) //等待DS18B20拉低总线 { } return 1; //初始化成功 i++; if(i>5000) //等待>5MS return 0; //初始化失败 15us~60us后总线拉低 void Ds18b20WriteByte(unsigned char dat) { } unsigned char Ds18b20ReadByte() { unsigned int i,j; for(j=0;j<8;j++) { } DSPORT=0; //每写入一位数据之前先把总线拉低1us i++; DSPORT=dat&0x01; //然后写入一个数据,从最低位开始 i=6; while(i--); //延时68us,持续时间最少60us DSPORT=1; //然后释放总线,至少1us给总线恢复时间才能接着dat>>=1; 写入第二个数值 unsigned char byte,bi; unsigned int i,j; for(j=8;j>0;j--) { DSPORT=0; //先将总线拉低1us i++; DSPORT=1; //然后释放总线 i++; i++; //延时6us等待数据稳定 bi=DSPORT; //读取数据,从最低位开始读取 /*将byte左移一位,然后与上右移7位后的bi,注意移动之后移掉那位补0。*/ byte=(byte>>1)|(bi<<7); - 27 - i=4; //读取完之后等待48us再接着读取下一个数 while(i--); } return byte; } void Ds18b20ChangTemp() { Ds18b20Init(); Delay1ms(1); Ds18b20WriteByte(0xcc); // Ds18b20WriteByte(0x44); // Delay1ms(100); } void Ds18b20ReadTempCom() { Ds18b20Init(); Delay1ms(1); Ds18b20WriteByte(0xcc); // Ds18b20WriteByte(0xbe); //} int Ds18b20ReadTemp() { int temp=0; unsigned char tmh,tml; Ds18b20ChangTemp(); // Ds18b20ReadTempCom(); // tml=Ds18b20ReadByte(); // tmh=Ds18b20ReadByte(); // temp=tmh; temp<<=8; temp|=tml; return temp; } void LcdWriteCom(uchar com) //{ LCD1602_E=0; LCD1602_RS=0; LCD1602_RW=0; LCD1602_DATAPINS=com; Delay10us(1); 跳过ROM操作命令 温度转换命令 跳过ROM操作命令 发送读取温度命令 先写入转换命令 然后等待转换完后发送读取温度命令 读取温度值共16位,先读低字节 再读高字节 写入命令 - 28 - } LCD1602_E=1; Delay10us(1); LCD1602_E=0; void LcdWriteData(uchar dat) //写入数据 { } void LcdInit() //LCD初始化子程序 { LcdWriteCom(0x38); //开显示 } void LcdDisplay() { 点 - 29 - LCD1602_E=0; LCD1602_RS=1; LCD1602_RW=0; LCD1602_DATAPINS=dat; Delay10us(1); LCD1602_E=1; Delay10us(1); LCD1602_E=0; LcdWriteCom(0x0c); //开显示不显示光标 LcdWriteCom(0x06); //写一个指针加1 LcdWriteCom(0x01); //清屏 LcdWriteCom(0x80); //设置数据指针起点 // LcdWriteCom(0x0f); int tmp = 0; char tmpH = 50; char tmpL = 0; unsigned char fh, ge, shi, xs; //定义数组 float tp; tmp = readVal; if(tmp< 0) //当温度值为负数 { //因为读取的温度是实际温度的补码,所以减1,再取反求出原码 tmp=~tmp; tp=tmp; tmp=tp*0.0625*10+0.5; //留一个小数点就*10,+0.5是四舍五入,因为C语言浮点数转换为整型的时候把小数 tmp=tmp-1; 点 } //后面的数自动去掉,不管是否大于0.5,而+0.5之后大于0.5的就是进1了,小于0.5//算加上0.5,还是在小数点后面。 fh = '-'; 的就 else { } shi = tmp % 1000 / 100; //显示温度十位数 tp=tmp;//因为数据处理有小数点所以将温度赋给一个浮点型变量 //如果温度是正的那么,那么正数的原码就是补码它本身 tmp=tp*0.0625*10+0.5; //留一个小数点就*10,+0.5是四舍五入,因为C语言浮点数转换为整型的时候把小数//后面的数自动去掉,不管是否大于0.5,而+0.5之后大于0.5的就是进1了,小于0.5//算加上0.5,还是在小数点后面。 fh = ' '; 的就 ge = tmp % 100 / 10; //显示温度个位数+小数点 xs = tmp % 10; //显示小数一位 LcdWriteCom(0x80+0X40); LcdWriteData('0'+TIME[2]/16); //时 LcdWriteData('0'+((TIME[2]%16)&0x0f)); LcdWriteData(':'); LcdWriteData('0'+TIME[1]/16); //分 LcdWriteData('0'+((TIME[1]%16)&0x0f)); LcdWriteData(':'); LcdWriteData('0'+TIME[0]/16); //秒 LcdWriteData('0'+((TIME[0]%16)&0x0f)); LcdWriteCom(0x80+0X4A); LcdWriteData(fh); LcdWriteData('0'+shi); LcdWriteData('0'+ge); LcdWriteData('.'); LcdWriteData('0'+xs); LcdWriteData('C'); LcdWriteCom(0x80); LcdWriteData('2'); LcdWriteData('0'); LcdWriteData('0'+TIME[6]/16); //年 - 30 - } LcdWriteData('0'+((TIME[6]%16)&0x0f)); LcdWriteData('-'); LcdWriteData('0'+TIME[4]/16); //月 LcdWriteData('0'+((TIME[4]%16)&0x0f)); LcdWriteData('-'); LcdWriteData('0'+TIME[3]/16); //日 LcdWriteData('0'+((TIME[3]%16)&0x0f)); LcdWriteCom(0x8D); LcdWriteData('W'); //星期 LcdWriteData('0'+((TIME[5]-1)&0x07)); //周 void Key_Scan() { if(SET_KEY == 0) { Delay10us(5000); if(SET_KEY == 0) { LcdWriteCom(0x0f); //显示光标 switch(Set_Step) { case NormalRun: LcdWriteCom(0x83); //设置guangbiao Set_Step = SetYear; break; LcdWriteCom(0x86); //设置guangbiao Set_Step = SetMon; break; LcdWriteCom(0x89); //设置guangbiao Set_Step = SetDay; break; LcdWriteCom(0xc1); //设置guangbiao Set_Step = SetHour; break; LcdWriteCom(0xc4); //设置guangbiao Set_Step = SetMin; - 31 - case SetYear: case SetMon: case SetDay: case SetHour: } } } break; LcdWriteCom(0xc7); //设置guangbiao Set_Step = SetSec; break; LcdWriteCom(0x8E); //设置guangbiao Set_Step = SetWeek; break; LcdWriteCom(0x83); //设置guangbiao Set_Step = SetYear; break; case SetMin: case SetSec: case SetWeek: if(Set_Step == NormalRun) { Delay10us(5000); if(ADD_KEY == 0) { if(Set_Step == SetYear) { if(TIME[6] == 0x99) { } LcdDisplay(); LcdWriteCom(0x83); //设置guangbiao TIME[6]=(TIME[6]/16)*10+(TIME[6]%16); TIME[6]=TIME[6]+1; TIME[6]=(TIME[6]/10)*16+(TIME[6]%10); TIME[6] = 0x0; else return ; if(ADD_KEY == 0) } else if(Set_Step == SetMon) { - 32 - } if(TIME[4] == 0x12) { } LcdDisplay(); LcdWriteCom(0x86); //设置guangbiao TIME[4]=(TIME[4]/16)*10+(TIME[4]%16); TIME[4]=TIME[4]+1; TIME[4]=(TIME[4]/10)*16+(TIME[4]%10); TIME[4] = 0x1; else else if(Set_Step == SetDay) { } else if(Set_Step == SetHour) { } else if(Set_Step == SetMin) { if(TIME[1] == 0x59) { TIME[1]=(TIME[1]/16)*10+(TIME[1]%16); - 33 - TIME[3]=(TIME[3]/16)*10+(TIME[3]%16); TIME[3]=TIME[3]+1; TIME[3]=(TIME[3]/10)*16+(TIME[3]%10); LcdDisplay(); LcdWriteCom(0x89); //设置guangbiao if(TIME[2] == 0x23) { } LcdDisplay(); LcdWriteCom(0xc1); //设置guangbiao TIME[2]=(TIME[2]/16)*10+(TIME[2]%16); TIME[2]=TIME[2]+1; TIME[2]=(TIME[2]/10)*16+(TIME[2]%10); TIME[2] = 0x0; else TIME[1] = 0x0; else } } } } TIME[1]=TIME[1]+1; TIME[1]=(TIME[1]/10)*16+(TIME[1]%10); LcdDisplay(); LcdWriteCom(0xc4); //设置guangbiao else if(Set_Step == SetSec) { } else if(Set_Step == SetWeek) { } if(TIME[5] == 7) TIME[5] = 1; TIME[5] = TIME[5]+1; else LcdDisplay(); LcdWriteCom(0x8E); //设置guangbiao if(TIME[0] == 0x59) { } LcdDisplay(); LcdWriteCom(0xc7); //设置guangbiao TIME[0]=(TIME[0]/16)*10+(TIME[0]%16); TIME[0]=TIME[0]+1; TIME[0]=(TIME[0]/10)*16+(TIME[0]%10); TIME[0] = 0x0; else if(SUB_KEY == 0) { Delay10us(5000); if(SUB_KEY == 0) { if(Set_Step == SetYear) { if(TIME[6] == 0x00) TIME[6] = 0x99; else - 34 - { } LcdDisplay(); LcdWriteCom(0x83); //设置guangbiao TIME[6]=(TIME[6]/16)*10+(TIME[6]%16); TIME[6]=TIME[6]-1; TIME[6]=(TIME[6]/10)*16+(TIME[6]%10); } else if(Set_Step == SetMon) { } else if(Set_Step == SetDay) { } else if(Set_Step == SetHour) { if(TIME[2] == 0x00) { } LcdDisplay(); - 35 - if(TIME[4] == 0x01) { } LcdDisplay(); LcdWriteCom(0x86); //设置guangbiao TIME[4]=(TIME[4]/16)*10+(TIME[4]%16); TIME[4]=TIME[4]-1; TIME[4]=(TIME[4]/10)*16+(TIME[4]%10); TIME[4] = 0x12; else TIME[3]=(TIME[3]/16)*10+(TIME[3]%16); TIME[3]=TIME[3]-1; TIME[3]=(TIME[3]/10)*16+(TIME[3]%10); LcdDisplay(); LcdWriteCom(0x89); //设置guangbiao TIME[2] = 0x23; else TIME[2]=(TIME[2]/16)*10+(TIME[2]%16); TIME[2]=TIME[2]-1; TIME[2]=(TIME[2]/10)*16+(TIME[2]%10); } } } LcdWriteCom(0xc1); //设置guangbiao else if(Set_Step == SetMin) { } else if(Set_Step == SetSec) { } else if(Set_Step == SetWeek) { } if(TIME[5] == 1) TIME[5] = 7; TIME[5] = TIME[5]-1; else LcdDisplay(); LcdWriteCom(0x8E); //设置guangbiao if(TIME[0] == 0x00) { } LcdDisplay(); LcdWriteCom(0xc7); //设置guangbiao TIME[0]=(TIME[0]/16)*10+(TIME[0]%16); TIME[0]=TIME[0]-1; TIME[0]=(TIME[0]/10)*16+(TIME[0]%10); TIME[0] = 0x59; else if(TIME[1] == 0x00) { } LcdDisplay(); LcdWriteCom(0xc4); //设置guangbiao TIME[1]=(TIME[1]/16)*10+(TIME[1]%16); TIME[1]=TIME[1]-1; TIME[1]=(TIME[1]/10)*16+(TIME[1]%10); TIME[1] = 0x59; else if(DETERMINE_KEY == 0) - 36 - } { Set_Step = NormalRun; Ds1302Init(); LcdInit(); } void InitTimer1(void) //50ms get temp { TMOD |= 0x10; TH1 = 0x3C; TL1 = 0x0B0; EA = 1; ET1 = 1; TR1 = 1; } void Timer1Interrupt(void) interrupt 3 { } void main() { TH1 = 0x3C; TL1 = 0x0B0; //add your code here! Time1outNum++; if(Time1outNum >= 40)//40*50ms = 2s } Time1outNum = 0; readVal = Ds18b20ReadTemp(); { Set_Step = NormalRun; InitTimer1(); LcdInit(); Ds18b20Init(); while(1) { Key_Scan(); if(Set_Step == NormalRun) { Ds1302ReadTime(); - 37 - } } } LcdDisplay(); - 38 - 因篇幅问题不能全部显示,请点此查看更多更全内容