首页 范文1(请套用格式)

范文1(请套用格式)

举报
开通vip

范文1(请套用格式) 广东海洋大学寸金学院 《单片机》期末考查(论文设计) 论文题目: 高精度大屏幕LED日历时钟设计 A high precision and large screen LED calendar clock design 系 别: 信息技术系 专 业: 计算机科学与技术 班 级: 计算机科学与技术1班 姓 名: 陈创胜 学 号: 200816704101 ...

范文1(请套用格式)
广东海洋大学寸金学院 《单片机》期末考查( 论文 政研论文下载论文大学下载论文大学下载关于长拳的论文浙大论文封面下载 设计) 论文题目: 高精度大屏幕LED日历时钟设计 A high precision and large screen LED calendar clock design 系 别: 信息技术系 专 业: 计算机科学与技术 班 级: 计算机科学与技术1班 姓 名: 陈创胜 学 号: 200816704101 指导老师: 叶伟慧 职 称: 讲师 日 期: 2012年5月5日 广东海洋大学寸金学院教务处制 目 录 I目 录 II摘 要 4第1章 引言 41.1背景与意义 41.2论文设计 41.2.1 系统设计实现的目标 41.2.2 系统的总体设计 5第2章 需求 分析 定性数据统计分析pdf销售业绩分析模板建筑结构震害分析销售进度分析表京东商城竞争战略分析 52.1需求分析 52.2 可行性分析 52.3开发及运行环境 5第3章 硬件电路设计 53.1单片机最小系统 53.2时钟芯片设计 53.2.1时钟芯片引脚介绍 53.2.2 4个控制寄存器介绍 53.3按键调整电路 53.4电源模块 5第4章 软件设计 54.1主程序流程 54.2 时间设置子流程 54.3闹钟设置子程序流程 54.4程序设计问题 54.4.1 按键抖动问题 54.4.2 蜂鸣器设置 54.4.3 液晶显示器设置 54.4.4中断设置 5第5章 测试 55.1测试软件介绍 55.2软件调试 5结束语 5致 谢 5参考文献 5附录 5程序代码: 摘 要 在51单片机应用的系统中,常常需要 记录 混凝土 养护记录下载土方回填监理旁站记录免费下载集备记录下载集备记录下载集备记录下载 实时的时间信息并长期保存。比如,在数据采集时,对某些重要的信息不仅需要几路车其内容,还需要记录下改事件发生的准确时间;在银行营业大厅中使用的利率或汇率显示屏,上面除了需要显示利率或汇率等数据以外,还需要显示实时的时间信息,如年、月、日、星期、时间等。本文用51单片机以及DS1302日历时钟芯片实现日历时钟的设计。 论文研究了DS1302日历时钟芯片的相关功能。设计结果表明本文设计的基于DS1302的实时日历时钟显示系统完全能够满足设计要求 关键词: DS1302,51单片机, LCD1062显示器 Abstract 51 SCM application system , often need to record real-time information and long-term preservation. For example, when data collection for some important information not only need to record the content, but also record the exact time of the incident; the banking hall in the use of interest rate or exchange rate display, shown above in addition to the interest rate or exchange rate such data, it also needs to show real-time information, such as year, month, date, day and time. In this paper,51MCU and the calendar clock chip DS1302 calendar clock design. Thesis of the calendar clock chip DS1302-related functions.Design results show that the DS1302-based design of real-time calendar clock display system can completely meet the design requirements. Key Word :DS1302,51Microcontroller, LCD1062 display 第1章 引言 1.1背景与意义 LED显示屏作为信息传播的一种重要手段,具有高亮度、工作电压低、功耗小、小型化、寿命长、耐冲击和性能稳定等优点,再加上集成电路的使用,LED显示屏的外围电路变得越来越简单,性价比不断攀升,使得LED显示屏广泛用于各行各业以及公共场所,成为了信息化时代发布工具。现在的LED大屏幕一般应用于汽车站、银行、机场、高速公路可变报版、体育场馆比赛等人多去关注的地方,所以这就要求LED大屏幕要设计得鲜明、显眼、耐用、三防能力强。 本次设计将LED大屏幕和电子日历时钟的结合起来,打破传统电子时钟只适用于个人的局限,将日历时钟推广到公共场合,更方便人们。本次设计将采用51单片机、DS1302日历时钟芯片和1062显示器(代替LED大屏幕,因为两者都差不多)。 1.2论文设计 1.2.1 系统设计实现的目标 本文是以实时时钟芯片DS1302和AT89C52单片机为主要研究对象,着重进行51单片机如何读取DS1302内部时钟信息的研究。 主要内容包括: 1) 实时温度显示; 2) 年月日星期时分秒显示; 3) 年月日星期时分秒调整; 4) 闹钟定时小时分钟和秒; 1.2.2 系统的总体设计 采用AT89C52作为主控单片机,时钟模块选用DS1302作为时钟芯片,显示模块选用LCD1062,设置部分选用按键电路。 AT89C52与MCS-51单片机产品兼容 、8K字节在系统可编程Flash存储器、 1000次擦写周期、 全静态操作:0Hz~33Hz 、 三级加密程序存储器 、 32个可编程I/O口线 、三个16位定时器/计数器 八个中断源 、全双工UART串行通道、 低功耗空闲和掉电模式 、掉电后中断可唤醒 、看门狗定时器 、双数据指针 、掉电标识符 。 DS1302 实时时钟芯片功能丰富,可以用来直接代替IBM PC 上的时钟日历芯片DS12887,同时,它的管脚也和MC146818B、DS12887 相兼容。由于DS1302 能够自动产生世纪、年、月、日、时、分、秒等时间信息,其内部又增加了世纪寄存器,从而利用硬件电路解决子“千年”问题;DS1302 中自带有锂电池,外部掉电时,其内部时间信息还能够保持10 年之久;对于一天内的时间记录,有12 小时制和24 小时制两种模式。用户还可对DS1302 进行编程以实现多种方波输出,并可对其内部的三路中断通过软件进行屏蔽。 该系统的系统框图如图1.1示: 图1-1系统框图 第2章 需求分析 2.1需求分析 数字电子钟一个无处不在的电子产品,经过多年的发展技术已经相当成熟了。 随着电子技术的产业结构调整,生产工艺的飞速发展,市场对智能电子时钟的需求也越来越大,而现今市场上多采用的普通电子表,不具备报时和闹钟的双重功能。 日前应用广泛的数字钟大多用DS1302时钟芯片,以51单片机为核心控制部件制作的。可以实现对年、月、日、周、时、分、秒精确计时,闰年补偿,可计时至2100年。DS1302内嵌一个锂电池,可以保证在没有电源系统的情况下做到非易挥发性计时。通过对相应管脚电平的简单设置,就可以轻松地适应Intel处理器或Motorola处理器的总线时序。通过扩展还可以实现对电子钟所在地点的温度显示和智能闹钟功能,广泛用于车站、医院、机场、厕所等公共场所的时间显示。该电子钟运用单片机进行设计制作,通过软件编程完成实时时间显示、按键调节时间,与数字电路电子钟相比具有设计电路简单、成本低的优点。与机械钟表和3V电源半机械表相比,数字电子钟具有时间精确度高、停电不用校准、较少汞的使用等优点。 2.2 可行性分析 通过可行性分析对所开发的高精度时钟从适应性、经济效益以及开发成本进行研究。通过调查和高精度时钟设计目标分析,对要开发的硬件、软件从技术、经济、资源和管理进行可行性的分析。以保证资源合理使用、避免失误和浪费。 · 技术可行性: 通过51单片机来设计电子时钟,采用K软件来进行编程,可以实现小时、分、秒和年、月、日的显示的功能。本次设计的电子时钟系统由时钟电路、显示电路、按键调整电路、定时报警电路四个部分组成。 本次报告需要介绍51单片机的基本原理,分析时钟芯片DS1302各个管脚的功能及它在设计电路中的作用工作原理及其软件设计过程以及1062显示屏在设计电路中的作用。 · 经济可行性: 本次设计使用的单片机是51单片机,是集CPU、RAM/ROM,计数和多种接口于一体的微控制器。自从单片机在20世纪70年代问世,以其极高的性能价格比,受到人们的重视和关注。它体积小、重量轻、抗干扰能力强、环境要求不高、价格相对比较低廉、可靠性高、灵活性好、开发较为容易,广泛应用于智能生产和工业自动化上。 DS1302时钟芯片设计了一种具有校时和闹钟功能的高精度电子钟,DS1302可精确计时到2100年。其价格一般为几元到几十元,性价比比较高。 · 操作可行性: 51单片机通过软件编程,在1062显示屏上实现时、分、秒和年、月、日,并且按秒实时更新显示,利用时钟芯片DS1302来实现计时,定时功能,通过四个按键开关:一个用于功能选择、一个用于闹钟查看、另外两个为数值增多和减少,来实现参数设置和调节功能,到达设置的闹钟时间,由蜂鸣器发声,起报警作用。本次设计的电子时钟,走时精度较高,可满足多种场合的应用需求。 2.3开发及运行环境 本次设计包括51单片机、DS1302时钟芯片、1062显示屏、K软件。下图为原理图 图2-1原理图 第3章 硬件电路设计 3.1单片机最小系统 本系统以AT89C52单片机为核心,本系统选用11.0592MHZ的晶振,,使得单片机有合理的运行速度。起振电容30pF对振荡器的频率高低、振荡器的稳定性和起振的快速性影响较合适,复位电路为按键高电平复位。 AT89C52单片机最小系统电路设计如图3-1所示。 图3-1单片机最小系统 3.2时钟芯片设计 3.2.1时钟芯片引脚介绍 1) 时钟芯片DS1302,其引脚分布图如下所示 图3-2时钟引脚分布 MOT (1脚) :总线时序模式选择脚。接高电平,选择MOTOROLA总线时;序;接低电平或悬空,择选择INTEL总线时序。 NC (2,3,16,20,21,22脚):悬空脚。 AD0~AD7(4~11脚):地址/地址数据复用总线引脚。 CS(13脚):片选脚,低电平有效。 AS(14脚):地址锁存输入脚。下降沿时,地址被锁存,紧接着的上升沿来时地址被清除。 R/W(15脚):读/写输入脚。在选择MOTOROLA总线时序模式时,此引脚用于指示当前的读写周期,高电平指示当前为读周期,低电平指示当前为写周期;选择INTEL中线时序模式时,此引脚为低电平有效的输入脚,相当于通用RAM的写使能信号(/WE) DS(17脚):选择MOTOROLA总线时序模式时,此引脚为数据锁存脚;选择INTEL总线时序模式时,此引脚为读输入脚,低电平有效,相当于典型的内存的输出使能信号(/OE) RESET(18脚):复位脚,低电平有效,复位不会影响到时钟、日历和RAM。 IRQ(19脚):中断申请输出脚,低电平有效,可作为微处理器的中断输入。 SQW(23脚):方波信号输出脚。可通过设置寄存器位SQWE关断此信号输出,此信号的输出频率也可通过对芯片内部的寄存器编程予以改变。 VCC(24脚):+5v电源端。 3.2.2 4个控制寄存器介绍 DS1302有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空间,他不专门用于某些特别功能,而是可以在未处理器程序中作为非易失性内存空间使用。 3.3按键调整电路 系统四个独立键盘均采用查询方式,S2用于设置年、月、日、时、分、秒、星期的数值加,以及闹钟开,S3用于设置年、月、日、时、分、秒、星期的数值减以及闹钟关,s1用于具体设置时钟位的切换,s4键用于设置闹钟。其电路图如3-3所示: 图3-3按键电路连接 3.4电源模块 电子钟的电源为5伏直流电源,本设计中我使用的是5V的充电模块,电源模块的原理图如图3-4所示: 图3-4电源模块 第4章 软件设计 4.1主程序流程 主程序开始初始化,并打开中断,然后执行扫描闹钟、键盘及读取18B20值。当有S1键按下时,执行时钟设置,当有S4键按下时,则进入闹钟设置,无论是时钟还是闹钟,设置完后退出,温度、时钟恢复实时显示。主程序流程图如图4-1所示: SHAPE \* MERGEFORMAT 图4-1主程序流程图 4.2 时间设置子流程 通过单片机判断S1按下的次数来设置,由s1num标志位来记录次数,用if语句判断执行命令。系统程序不断扫面键盘,当s1键按下后产生一个低电平,即s1num加一。在调节时间之前首先进行各个变量初始化,及设置起始时间,同时为读取数据作准备。当s1=1时进入秒的设置,地址指针指向miao显示位置处,通过两个if语句分别循环控制显示秒数的加和减。当s1=2时,地址指针指向fen显示位置处,变量最大值为59。当s1=3时,地址指针指向shi显示位置处,变量最大值设为23。当s1=4时,地址指针指向week显示位置处,最大值设为7,1至7分别用MON、TUE、WED、THU 、FRI、SAT、SUN字符串显示。随着s2、s3值的的变化显示不同的字符串。当s1=5时,地址指针指向day显示位置,变量最大值为31。当s1=6时,地址指针指向month显示位置,变量最大值为12。 当s1=7时,地址指针指向year显示位置,最大值为99。 SHAPE \* MERGEFORMAT 图4-2时间设置流程图 4.3闹钟设置子程序流程 时间设置程序流程图如图4-3所示。在开始时间设置之前程序会关闭全局中断,直至设置结束,中断又会重新开启,进入计时状态。 闹钟的设置时通过S1键的按下次数来判断的。当单片机检测到S4键按下一次时则进入闹钟设置界面,光标并自动跳到秒设置位置,可以对秒进行设置,当S1键依次按下1、2、3次时,则分别进入闹钟的秒、分、时关的设置。: SHAPE \* MERGEFORMAT 图4-3闹钟设置流程图 4.4程序设计问题 4.4.1 按键抖动问题 按键在按下时因为机械原因会产生抖动,抖动的后果就是当按下一次按键时因为抖动的原因让系统读取到多次的按键按下的次数,由此导致设置时出现错误。解决的方法如下:当按键按下时读取按键键值,若5ms后键值和按下是相等,则确认为有效按键,以此消除按键抖动带来的问题。 4.4.2 蜂鸣器设置 蜂鸣器报警时,设置响100毫秒,停100毫秒,循环响应,产生滴滴的声音。 4.4.3 液晶显示器设置 初始化设置 显示模式设置 写入指令码write_com(0x38),设置功能16*2显示,5*7点阵,8位数据接口 显示/开关及光标设置 8) 写入指令码write_com(0x0c),设置开显示,不显示光标,光标不闪烁。 16) 写入指令码write_com(0x06),设置当读或写一个字符后地址指针加一,且光标加一。当写一个字符,整屏显示不移动。 显示清屏,写入指令码write_com(0x01)。 写入指令码函数write_com()写指令过程 :输入:rs=0,D0-D7=指令码,E=高脉冲 写入数据函数 write_date() 写指令过程: 输入:rs=1,D0-D7=数据,E=高脉冲 写入指令和数据时rw端已经接地。 数据指针设置 指令码80H+地址码(0-27H)显示第一行的字符 指令码80H+地址码(40H-67H)显示的第二行字符 4.4.4中断设置 EA=1;//打开总中断 EX1=1;//打开外部中断 IT1=1;//设置负跳变沿触发中断 当闹钟到点时响应外部中1 时间到时IRQ端从高阻态转为低电平,此时读一次c寄存器清除IRQ端的输出,等待下一次定时。 void exter() interrupt 2 //外部中断1服务程序 { uchar c;//进入中断表示闹钟时间到 flag_ri=1; //设置标志位,用以大程序中报警 c=read_ds(0x0c);//读取12c887c寄存器表示响应了中端 } 第5章 测试 5.1测试软件介绍 Keil C51是美国Keil Software公司出品的51系列兼容单片机C语言软件开发系统,与汇编相比,C语言在功能上、结构性、可读性、可维护性上有明显的优势,因而易学易用。用过汇编语言后再使用C来开发,体会更加深刻。Keil C51软件提供丰富的库函数和功能强大的集成开发调试工具,全Windows界面。另外重要的一点,只要看一下编译后生成的汇编代码,就能体会到Keil C51生成的目标代码效率非常之高,多数语句生成的汇编代码很紧凑,容易理解。在开发大型软件时更能体现高级语言的优势。Keil C51软件是一个基于32位Windows环境的应用程序,支持C语言和汇编语言编程,其6.0以上的版本将编译和仿真软件统一为μVision(通常称为μV2)。Keil提供包括C编译器、宏汇编、连接器、库管理和一个功能强大的仿真调试器等在内的完整开发 方案 气瓶 现场处置方案 .pdf气瓶 现场处置方案 .doc见习基地管理方案.doc关于群访事件的化解方案建筑工地扬尘治理专项方案下载 ,由以下几部分组成:μVision IDE集成开发环境C51编译器、A51汇编器、LIB51库管理器、BL51连接/定位器、OH51目标文件生成器以及 Monitor-51、RTX51实时操作系统。 5.2软件调试 应用Keil进行软件仿真开发的主要步骤为:编写源程序并保存—建立工程并添加源文件—设置工程—编译/汇编、连接,产生目标文件—程序调试。Keil使用“工程”(Project)的概念,对工程(而不能对单一的源程序)进行编译/汇编、连接等操作。工程的建立、设置、编译/汇编及连接产生目标文件的方法非常易于掌握。首先选择菜单File-New…,在源程序编辑器中输入汇编语言或C语言源程序(或选择File-Open…,直接打开已用其它编辑器编辑好的源程序文档)并保存,注意保存时必须在文件名后加上扩展名.asm(.a51)或.c;然后选择菜单Project-New Project…,建立新工程并保存(保存时无需加扩展名,也可加上扩展名.uv2);工程保存后会立即弹出一个设备选择对话框,选择CPU后点确定返回主界面。这时工程管理窗口的文件页(Files)会出现“Target1”,将其前面+号展开,接着选择Source Group1,右击鼠标弹出快捷菜单,选择“Add File to Group ‘Source Group1’”,出现一个对话框,要求寻找并加入源文件(在加入一个源文件后,该对话框不会消失,而是等待继续加入其它文件)。加入文件后点close返回主界面,展开“Source Group1”前面+号,就会看到所加入的文件,双击文件名,即可打开该源程序文件。紧接着对工程进行设置,选择工程管理窗口的Target1,再选择Project-Option for Target‘Target1’(或点右键弹出快捷菜单再选择该选项),打开工程属性设置对话框,共有8个选项卡,主要设置工作包括在Target选项卡中设置晶振频率、在Debug选项卡中设置实验仿真板等,如要写片,还必须在Output选项卡中选中“Creat Hex Fi”;其它选项卡内容一般可取默认值。工程设置后按F7键(或点击编译工具栏上相应图标)进行编译/汇编、连接以及产生目标文件。  成功编译/汇编、连接后,选择菜单Debug-Start/Stop Debug Session(或按Ctrl+F5键)进入程序调试状态,Keil提供对程序的模拟调试功能,内建一个功能强大的仿真CPU以模拟执行程序。Keil能以单步执行(按F11或选择Debug-Step)、过程单步执行(按F10或选择Debug-Step Over)、全速执行等多种运行方式进行程序调试。如果发现程序有错,可采用在线汇编功能对程序进行在线修改(Debug-Inline Assambly…),不必执行先退出调试环境、修改源程序、对工程重新进行编译/汇编和连接、然后再次进入调试状态的步骤。对于一些必须满足一定条件(如按键被按下等)才能被执行的、难以用单步执行方式进行调试的程序行,可采用断点设置的方法处理(Debug-Insert/Remove Breakpoint或Debug-Breakpoints…等)。在模拟调试程序后,还须通过编程器将.hex目标文件烧写入单片机中才能观察目标样机真实的运行状况。 结束语 本文是一篇关于用单片机实现高精度日历时钟论文,设计中使用到了AT89C52和1602液晶显示屏。在设计过程中我通过在网上和图书馆查阅资料,收集了关于单片机和液晶显示方面的资料,通过对这些资料的学习,我了解了单片机的基本结构,使用和单片机在生活和生产中所发挥的作用;液晶显示的原理和使用。本次毕业设计除了让我回顾以前学过的知识外,也使我学习到了新的东西。这次毕业设计可以说是对四年的大学学习的总结。 本次毕业设计完成的主要工作和任务如下:对设计方案的理论研究,单片机的合理选型,硬件电路的设计,电路板的制作,元器件的焊接,软件的编写和调试以及 毕业论文 毕业论文答辩ppt模板下载毕业论文ppt模板下载毕业论文ppt下载关于药学专业毕业论文临床本科毕业论文下载 的制作。 通过对本课题的研究我有以下几个方面的收获: (1)学习与掌握了单片机的基本原理及其各种应用,对它的各种硬件接口与软件设计方法有较深入的认识。 (2)对液晶显示有了一定的认识,能够初步掌握液晶显示的原理。 (3)通过对电路原理图、pcb图的绘制,电路板的制作掌握了对Altium Designer Winter 09 (4)本设计重点在于软件的设计,因此在设计过程中使自己在大学学到的C语言知识得到了巩固,同时提高了解决实际问题的能力。 由于时间仓促,再加上作者水平有限,本文不免有很多错误,恳请各位读者批评指正。 致 谢 在我的毕业设计与论文完成过程中,得到了很多人的帮助与支持。首先,最感谢的是我的指导老师叶伟慧老师,他以严谨的治学态度、做研究全力以赴的精神,对我毕业设计和论文的写作给予悉心指导,提出了许多批评建议,使个人的毕业设计和论文得以如期完成,在此致上最真挚的谢意。 也谢谢大学所有教导过我的老师,谢谢你们四年来的悉心教导与关心爱护。感谢培养教育我的母校—广东海洋大学寸金学院! 最后,感谢我亲爱的家人,感谢他们在生活及情感上的容忍及包容,在我完成论文的学习生活中,默默的支持着我。 参考文献 [1] 余锡存,曹国华,单片机原理及接口技术. 西安:西安电子科技大学出版社,2000 [2] 郭天祥,新概念51单片机c语言教程。北京:电子工业出版社,2009 [3] 杨拴科, 模拟电子技术基础. 北京:高等教育出版社, 2003。 [4] 李光才,楼然笛.单片机课程设计实例指导. 北京:北京航空航天大学出版社,2004。 [6] 杨立民,单片机技术及应用.西安:西安电子科技大学出版社,1997.9~12。 [7] 马忠梅,单片机的C语言应用程序设计.北京:北京航空航天大学出版社,1997。 [8]王天曦 ,李洪儒.电子技术工艺基础.北京:清华大学出版社,2000。 [9] 弘道工作室,融会贯通 Protel99电路设计.北京: 人民交通出版设,2000。 [10] 张伟,王力,赵晶,ProtelDXP 入门与提高.北京:人民邮电出版社, 2003.2。 [11] 李广弟,朱月秀,王秀山.单片机基础[M]. 北京:北京航空航天大学出版社, 2001.7。 [12] 谭浩强,C程序设计(第二版)[M].北京:清华大学出版社,2003。 [13] 付家才,单片机控制工程实践技术[M]. 北京:化学工业出版社,2004.3。 [14] W.Simpson,Editor,The Point-to-Point Protocol, RFC1661 [EB/OL]. July 1994。 [15] WAVECOM,AT Commands Interface Guide, Revision 002[EB/OL].6th November 2003。 附录 程序代码 #include //#include"DS18B20_3.H" #include #include #define uint unsigned int #define uchar unsigned char #define wd 1 //定义是否有温度功能 =0时无温度,=1时有温度 #define yh 0x80 //LCD第一行的初始位置,因为LCD1602字符地址首位D7恒定为1(100000000=80) #define er 0x80+0x40 //LCD第二行初始位置(因为第二行第一个字符位置地址是0x40) //液晶屏的与C51之间的引脚连接定义(显示数据线接C51的P0口) sbit en=P2^7; //sbit rw=P2^6; //如果硬件上rw接地,就不用写这句和后面的rw=0了 sbit rs=P2^6; //校时按键与C51的引脚连接定义 sbit menu=P3^0; //菜单键 sbit set=P3^1; //设置键 sbit add=P3^2; //加键 sbit dec=P3^3; //减键 sbit ensure=P3^4; //确认键 sbit DQ=P2^0; // sbit buzzer=P1^4; //蜂鸣器,通过三极管8550驱动,端口低电平响 sbit led=P2^4; //LCD背光开关 bit led1=1; unsigned char temp_miao; unsigned char bltime; //背光亮的时间 //DS1302时钟芯片与C51之间的引脚连接定义 sbit IO=P1^1; sbit SCLK=P1^2; sbit RST=P1^0; uchar a,miao,shi,fen,ri,yue,nian,week,setn,temp; uint flag; //flag用于读取头文件中的温度值,和显示温度值 bit c_moon; uchar nz_shi=12,nz_fen=0,nz_miao=0,setNZn; //定义闹钟变量 uchar shangyimiao,bsn,temp_hour; //记录上一秒时间 uchar T_NL_NZ; //计数器 bit timerOn=0; //闹钟启用标志位 bit baoshi=0; //整点报时标志位 bit p_r=0; //平年/润年 =0表示平年,=1表示润年 data uchar year_moon,month_moon,day_moon,week; sbit ACC0=ACC^0; sbit ACC7=ACC^7; code uchar year_code[597]={ 0x04,0xAe,0x53, //1901 0 0x0A,0x57,0x48, //1902 3 0x55,0x26,0xBd, //1903 6 0x0d,0x26,0x50, //1904 9 0x0d,0x95,0x44, //1905 12 0x46,0xAA,0xB9, //1906 15 0x05,0x6A,0x4d, //1907 18 0x09,0xAd,0x42, //1908 21 0x24,0xAe,0xB6, //1909 0x04,0xAe,0x4A, //1910 0x6A,0x4d,0xBe, //1911 0x0A,0x4d,0x52, //1912 0x0d,0x25,0x46, //1913 0x5d,0x52,0xBA, //1914 0x0B,0x54,0x4e, //1915 0x0d,0x6A,0x43, //1916 0x29,0x6d,0x37, //1917 0x09,0x5B,0x4B, //1918 0x74,0x9B,0xC1, //1919 0x04,0x97,0x54, //1920 0x0A,0x4B,0x48, //1921 0x5B,0x25,0xBC, //1922 0x06,0xA5,0x50, //1923 0x06,0xd4,0x45, //1924 0x4A,0xdA,0xB8, //1925 0x02,0xB6,0x4d, //1926 0x09,0x57,0x42, //1927 0x24,0x97,0xB7, //1928 0x04,0x97,0x4A, //1929 0x66,0x4B,0x3e, //1930 0x0d,0x4A,0x51, //1931 0x0e,0xA5,0x46, //1932 0x56,0xd4,0xBA, //1933 0x05,0xAd,0x4e, //1934 0x02,0xB6,0x44, //1935 0x39,0x37,0x38, //1936 0x09,0x2e,0x4B, //1937 0x7C,0x96,0xBf, //1938 0x0C,0x95,0x53, //1939 0x0d,0x4A,0x48, //1940 0x6d,0xA5,0x3B, //1941 0x0B,0x55,0x4f, //1942 0x05,0x6A,0x45, //1943 0x4A,0xAd,0xB9, //1944 0x02,0x5d,0x4d, //1945 0x09,0x2d,0x42, //1946 0x2C,0x95,0xB6, //1947 0x0A,0x95,0x4A, //1948 0x7B,0x4A,0xBd, //1949 0x06,0xCA,0x51, //1950 0x0B,0x55,0x46, //1951 0x55,0x5A,0xBB, //1952 0x04,0xdA,0x4e, //1953 0x0A,0x5B,0x43, //1954 0x35,0x2B,0xB8, //1955 0x05,0x2B,0x4C, //1956 0x8A,0x95,0x3f, //1957 0x0e,0x95,0x52, //1958 0x06,0xAA,0x48, //1959 0x7A,0xd5,0x3C, //1960 0x0A,0xB5,0x4f, //1961 0x04,0xB6,0x45, //1962 0x4A,0x57,0x39, //1963 0x0A,0x57,0x4d, //1964 0x05,0x26,0x42, //1965 0x3e,0x93,0x35, //1966 0x0d,0x95,0x49, //1967 0x75,0xAA,0xBe, //1968 0x05,0x6A,0x51, //1969 0x09,0x6d,0x46, //1970 0x54,0xAe,0xBB, //1971 0x04,0xAd,0x4f, //1972 0x0A,0x4d,0x43, //1973 0x4d,0x26,0xB7, //1974 0x0d,0x25,0x4B, //1975 0x8d,0x52,0xBf, //1976 0x0B,0x54,0x52, //1977 0x0B,0x6A,0x47, //1978 0x69,0x6d,0x3C, //1979 0x09,0x5B,0x50, //1980 0x04,0x9B,0x45, //1981 0x4A,0x4B,0xB9, //1982 0x0A,0x4B,0x4d, //1983 0xAB,0x25,0xC2, //1984 0x06,0xA5,0x54, //1985 0x06,0xd4,0x49, //1986 0x6A,0xdA,0x3d, //1987 0x0A,0xB6,0x51, //1988 0x09,0x37,0x46, //1989 0x54,0x97,0xBB, //1990 0x04,0x97,0x4f, //1991 0x06,0x4B,0x44, //1992 0x36,0xA5,0x37, //1993 0x0e,0xA5,0x4A, //1994 0x86,0xB2,0xBf, //1995 0x05,0xAC,0x53, //1996 0x0A,0xB6,0x47, //1997 0x59,0x36,0xBC, //1998 0x09,0x2e,0x50, //1999 294 0x0C,0x96,0x45, //2000 297 0x4d,0x4A,0xB8, //2001 0x0d,0x4A,0x4C, //2002 0x0d,0xA5,0x41, //2003 0x25,0xAA,0xB6, //2004 0x05,0x6A,0x49, //2005 0x7A,0xAd,0xBd, //2006 0x02,0x5d,0x52, //2007 0x09,0x2d,0x47, //2008 0x5C,0x95,0xBA, //2009 0x0A,0x95,0x4e, //2010 0x0B,0x4A,0x43, //2011 0x4B,0x55,0x37, //2012 0x0A,0xd5,0x4A, //2013 0x95,0x5A,0xBf, //2014 0x04,0xBA,0x53, //2015 0x0A,0x5B,0x48, //2016 0x65,0x2B,0xBC, //2017 0x05,0x2B,0x50, //2018 0x0A,0x93,0x45, //2019 0x47,0x4A,0xB9, //2020 0x06,0xAA,0x4C, //2021 0x0A,0xd5,0x41, //2022 0x24,0xdA,0xB6, //2023 0x04,0xB6,0x4A, //2024 0x69,0x57,0x3d, //2025 0x0A,0x4e,0x51, //2026 0x0d,0x26,0x46, //2027 0x5e,0x93,0x3A, //2028 0x0d,0x53,0x4d, //2029 0x05,0xAA,0x43, //2030 0x36,0xB5,0x37, //2031 0x09,0x6d,0x4B, //2032 0xB4,0xAe,0xBf, //2033 0x04,0xAd,0x53, //2034 0x0A,0x4d,0x48, //2035 0x6d,0x25,0xBC, //2036 0x0d,0x25,0x4f, //2037 0x0d,0x52,0x44, //2038 0x5d,0xAA,0x38, //2039 0x0B,0x5A,0x4C, //2040 0x05,0x6d,0x41, //2041 0x24,0xAd,0xB6, //2042 0x04,0x9B,0x4A, //2043 0x7A,0x4B,0xBe, //2044 0x0A,0x4B,0x51, //2045 0x0A,0xA5,0x46, //2046 0x5B,0x52,0xBA, //2047 0x06,0xd2,0x4e, //2048 0x0A,0xdA,0x42, //2049 0x35,0x5B,0x37, //2050 0x09,0x37,0x4B, //2051 0x84,0x97,0xC1, //2052 0x04,0x97,0x53, //2053 0x06,0x4B,0x48, //2054 0x66,0xA5,0x3C, //2055 0x0e,0xA5,0x4f, //2056 0x06,0xB2,0x44, //2057 0x4A,0xB6,0x38, //2058 0x0A,0xAe,0x4C, //2059 0x09,0x2e,0x42, //2060 0x3C,0x97,0x35, //2061 0x0C,0x96,0x49, //2062 0x7d,0x4A,0xBd, //2063 0x0d,0x4A,0x51, //2064 0x0d,0xA5,0x45, //2065 0x55,0xAA,0xBA, //2066 0x05,0x6A,0x4e, //2067 0x0A,0x6d,0x43, //2068 0x45,0x2e,0xB7, //2069 0x05,0x2d,0x4B, //2070 0x8A,0x95,0xBf, //2071 0x0A,0x95,0x53, //2072 0x0B,0x4A,0x47, //2073 0x6B,0x55,0x3B, //2074 0x0A,0xd5,0x4f, //2075 0x05,0x5A,0x45, //2076 0x4A,0x5d,0x38, //2077 0x0A,0x5B,0x4C, //2078 0x05,0x2B,0x42, //2079 0x3A,0x93,0xB6, //2080 0x06,0x93,0x49, //2081 0x77,0x29,0xBd, //2082 0x06,0xAA,0x51, //2083 0x0A,0xd5,0x46, //2084 0x54,0xdA,0xBA, //2085 0x04,0xB6,0x4e, //2086 0x0A,0x57,0x43, //2087 0x45,0x27,0x38, //2088 0x0d,0x26,0x4A, //2089 0x8e,0x93,0x3e, //2090 0x0d,0x52,0x52, //2091 0x0d,0xAA,0x47, //2092 0x66,0xB5,0x3B, //2093 0x05,0x6d,0x4f, //2094 0x04,0xAe,0x45, //2095 0x4A,0x4e,0xB9, //2096 0x0A,0x4d,0x4C, //2097 0x0d,0x15,0x41, //2098 0x2d,0x92,0xB5, //2099 }; ///月份数据表 code uchar day_code1[9]={0x0,0x1f,0x3b,0x5a,0x78,0x97,0xb5,0xd4,0xf3}; code uint day_code2[3]={0x111,0x130,0x14e}; bit c_moon; data uchar year_moon,month_moon,day_moon,week; //子函数,用于读取数据表中农历月的大月或小月,如果该月为大返回1,为小返回0 bit get_moon_day(uchar month_p,uint table_addr) { uchar temp; switch (month_p){ case 1:{temp=year_code[table_addr]&0x08; if (temp==0)return(0);else return(1);} case 2:{temp=year_code[table_addr]&0x04; if (temp==0)return(0);else return(1);} case 3:{temp=year_code[table_addr]&0x02; if (temp==0)return(0);else return(1);} case 4:{temp=year_code[table_addr]&0x01; if (temp==0)return(0);else return(1);} case 5:{temp=year_code[table_addr+1]&0x80; if (temp==0) return(0);else return(1);} case 6:{temp=year_code[table_addr+1]&0x40; if (temp==0)return(0);else return(1);} case 7:{temp=year_code[table_addr+1]&0x20; if (temp==0)return(0);else return(1);} case 8:{temp=year_code[table_addr+1]&0x10; if (temp==0)return(0);else return(1);} case 9:{temp=year_code[table_addr+1]&0x08; if (temp==0)return(0);else return(1);} case 10:{temp=year_code[table_addr+1]&0x04; if (temp==0)return(0);else return(1);} case 11:{temp=year_code[table_addr+1]&0x02; if (temp==0)return(0);else return(1);} case 12:{temp=year_code[table_addr+1]&0x01; if (temp==0)return(0);else return(1);} case 13:{temp=year_code[table_addr+2]&0x80; if (temp==0)return(0);else return(1);} } } void Conversion(bit c,uchar year,uchar month,uchar day) { //c=0 为21世纪,c=1 为19世纪 输入输出数据均为BCD数据 uchar temp1,temp2,temp3,month_p; uint temp4,table_addr; bit flag2,flag_y; temp1=year/16; //BCD->hex 先把数据转换为十六进制 temp2=year%16; // year=temp1*10+temp2; year=temp1*16+temp2; temp1=month/16; temp2=month%16; //month=temp1*10+temp2; month=temp1*16+temp2; temp1=day/16; temp2=day%16; //day=temp1*10+temp2; day=temp1*16+temp2; //定位数据表地址 if(c==0){ table_addr=(year+0x64-1)*0x3; } else { table_addr=(year-1)*0x3; } //定位数据表地址完成 //取当年春节所在的公历月份 temp1=year_code[table_addr+2]&0x60; temp1=_cror_(temp1,5); //取当年春节所在的公历月份完成 //取当年春节所在的公历日 temp2=year_code[table_addr+2]&0x1f; //取当年春节所在的公历日完成 // 计算当年春年离当年元旦的天数,春节只会在公历1月或2月 if(temp1==0x1){ temp3=temp2-1; } else{ temp3=temp2+0x1f-1; } // 计算当年春年离当年元旦的天数完成 //计算公历日离当年元旦的天数,为了减少运算,用了两个表 //day_code1[9],day_code2[3] //如果公历月在九月或前,天数会少于0xff,用表day_code1[9], //在九月后,天数大于0xff,用表day_code2[3] //如输入公历日为8月10日,则公历日离元旦天数为day_code1[8-1]+10-1 //如输入公历日为11月10日,则公历日离元旦天数为day_code2[11-10]+10-1 if (month<10){ temp4=day_code1[month-1]+day-1; } else{ temp4=day_code2[month-10]+day-1; } if ((month>0x2)&&(year%0x4==0)){ //如果公历月大于2月并且该年的2月为闰月,天数加1 temp4+=1; } //计算公历日离当年元旦的天数完成 //判断公历日在春节前还是春节后 if (temp4>=temp3){ //公历日在春节后或就是春节当日使用下面代码进行运算 temp4-=temp3; month=0x1; month_p=0x1; //month_p为月份指向,公历日在春节前或就是春节当日month_p指向首月 flag2=get_moon_day(month_p,table_addr); //检查该农历月为大小还是小月,大月返回1,小月返回0 flag_y=0; if(flag2==0)temp1=0x1d; //小月29天 else temp1=0x1e; //大小30天 temp2=year_code[table_addr]&0xf0; temp2=_cror_(temp2,4); //从数据表中取该年的闰月月份,如为0则该年无闰月 while(temp4>=temp1){ temp4-=temp1; month_p+=1; if(month==temp2){ flag_y=~flag_y; if(flag_y==0)month+=1; } else month+=1; flag2=get_moon_day(month_p,table_addr); if(flag2==0)temp1=0x1d; else temp1=0x1e; } day=temp4+1; } else{ //公历日在春节前使用下面代码进行运算 temp3-=temp4; if (year==0x0){year=0x63;c=1;} else year-=1; table_addr-=0x3; month=0xc; temp2=year_code[table_addr]&0xf0; temp2=_cror_(temp2,4); if (temp2==0) month_p=0xc; else month_p=0xd; // //month_p为月份指向,如果当年有闰月,一年有十三个月,月指向13,无闰月指向12 flag_y=0; flag2=get_moon_day(month_p,table_addr); if(flag2==0)temp1=0x1d; else temp1=0x1e; while(temp3>temp1){ temp3-=temp1; month_p-=1; if(flag_y==0)month-=1; if(month==temp2)flag_y=~flag_y; flag2=get_moon_day(month_p,table_addr); if(flag2==0)temp1=0x1d; else temp1=0x1e; } day=temp1-temp3+1; } c_moon=c; //HEX->BCD ,运算结束后,把数据转换为BCD数据 temp1=year/10; temp1=_crol_(temp1,4); temp2=year%10; year_moon=temp1|temp2; temp1=month/10; temp1=_crol_(temp1,4); temp2=month%10; month_moon=temp1|temp2; temp1=day/10; temp1=_crol_(temp1,4); temp2=day%10; day_moon=temp1|temp2; } void Conver_week(uchar year,uchar month,uchar day) {//c=0 为21世纪,c=1 为19世纪 输入输出数据均为BCD数据 uchar p1,p2; year+=0x64; //如果为21世纪,年份数加100 p1=year/0x4; //所过闰年数只算1900年之后的 p2=year+p1; p2=p2%0x7; //为节省资源,先进行一次取余,避免数大于0xff,避免使用整型数据 p2=p2+day+table_week[month-1]; if (year%0x4==0&&month<3)p2-=1; week=p2%0x7; } uchar code tab1[]={"20 - - "}; //年显示的固定字符 uchar code tab2[]={" : : "}; //时间显示的固定字符 uchar code nlp[]={"NL: - - PING"}; //农历平年显示 uchar code nlr[]={"NL: - - RUN "}; //农历润年显示 uchar code NZd[]={"timer: - - "}; //显示闹钟固定点 uchar code qk[]= {" "}; //清空显示 uchar code tm[]= {"time"}; //=====================DS18B20============================================= void Init_DS18B20(void)//初始化ds1820 { unsigned char x=0; DQ = 1; //DQ复位 Delayns(8); //稍做延时 DQ = 0; //单片机将DQ拉低 Delayns(80); //精确延时 大于 480us DQ = 1; //拉高总线 Delayns(14); x=DQ; //稍做延时后 如果x=0则初始化成功 x=1则初始化失败 Delayns(20); } //****************************************************************************** unsigned char ReadOneChar(void)//读一个字节 { unsigned char i=0; unsigned char dat = 0; for (i=8;i>0;i--) { DQ = 0; // 给脉冲信号 dat>>=1; DQ = 1; // 给脉冲信号 if(DQ) dat|=0x80; Delayns(4); } return(dat); } //****************************************************************************** void WriteOneChar(unsigned char dat)//写一个字节 { unsigned char i=0; for (i=8; i>0; i--) { DQ = 0; DQ = dat&0x01; Delayns(5); DQ = 1; dat>>=1; } } //延时函数,后面经常调用 void delay(uint xms)//延时函数,有参函数 { uint x,y; for(x=xms;x>0;x--) for(y=110;y>0;y--); } /********液晶写入指令函数与写入数据函数,以后可调用**************/ /*在这个程序中,液晶写入有关函数会在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()//***液晶初始化函数**** { write_1602com(0x38);//设置液晶工作模式,意思:16*2行显示,5*7点阵,8位数据 write_1602com(0x0c);//开显示不显示光标 write_1602com(0x06);//整屏不移动,光标自动右移 write_1602com(0x01);//清显示 write_1602com(yh+1);//日历显示固定符号从第一行第1个位置之后开始显示 for(a=0;a<14;a++) { write_1602dat(tab1[a]);//向液晶屏写日历显示的固定符号部分 //delay(3); } write_1602com(er);//时间显示固定符号写入位置,从第2个位置后开始显示 for(a=0;a<8;a++) { write_1602dat(tab2[a]);//写显示时间固定符号,两个冒号 //delay(3); } } /*********************over***********************/ /***************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芯片初始化子函数(2010-01-07,12:00:00,week4) { 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,0x12);//向DS1302内写小时寄存器84H写入初始小时数据12 //write_1302(0x8a,0x04);//向DS1302内写周寄存器8aH写入初始周数据4 //write_1302(0x86,0x07);//向DS1302内写日期寄存器86H写入初始日期数据07 //write_1302(0x88,0x01);//向DS1302内写月份寄存器88H写入初始月份数据01 //write_1302(0x8c,0x10);//向DS1302内写年份寄存器8cH写入初始年份数据10 write_1302(0x8e,0x80); //打开写保护 } //------------------------------------ //温度显示子函数 void write_temp(uchar add,uint dat)//向LCD写温度数据,并指定显示位置 { uint gw,sw,bw; bw=dat/100;//取得百位 sw=dat%100/10;//取得十位数字 gw=dat%10;//取得个位数字 write_1602com(er+add);//er是头文件规定的值0x80+0x40 write_1602dat(0x30+bw); write_1602dat(0x30+sw);//数字+30得到该数字的LCD1602显示码 write_1602dat('.'); 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_nl(uchar add,uchar dat)//向LCD写时分秒,有显示位置加、现示数据,两个参数 { uchar gw,sw; //gw=dat%10;//取得个位数字 //sw=dat/10;//取得十位数字 gw=dat%16;//取得个位数字 sw=dat/16;//取得十位数字 write_1602com(er+add);//er是头文件规定的值0x80+0x40 // write_1602dat(0x30+sw);//数字+30得到该数字的LCD1602显示码 // write_1602dat(0x30+gw);//数字+30得到该数字的LCD1602显示码 write_1602dat('0'+sw);//数字+30得到该数字的LCD1602显示码 write_1602dat('0'+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 0:write_1602dat('S');//星期数据为7时显示 write_1602dat('U'); write_1602dat('N'); break; } write_1602dat(' '); } //****************键盘扫描有关函数********************** void keyscan() { if(ensure==0) { delay(9); if(ensure==0) { buzzer=0;//蜂鸣器短响一次 delay(20); buzzer=1; led1=1; //背光灭 setn=0; //退出任何当前的设置 setNZn=0; T_NL_NZ=0; write_1602com(0x0c); //设置光标不闪烁 TR0=1; //打开定时器 temp=(miao)/10*16+(miao)%10; write_1302(0x8e,0x00); write_1302(0x80,0x00|temp); //miao数据写入DS1302 write_1302(0x8e,0x80); } } if(menu==0) { delay(9); if(menu==0) { led1=0; bltime=0; if((setn==0)&&(setNZn==0)) //在没有进入调时模式时才可按动 { buzzer=0;//蜂鸣器短响一次 delay(20); buzzer=1; if(TR1==1) { TR1=0; } else { T_NL_NZ++; if(T_NL_NZ==3) { setn=0; setNZn=0; T_NL_NZ=0; } } } while(menu==0); } } if(set==0)//---------------set为功能键(设置键)-------------------- { delay(9);//延时,用于消抖动 if(set==0)//延时后再次确认按键按下 { led1=0; bltime=0; buzzer=0;//蜂鸣器短响一次 delay(20); buzzer=1; while(!set); if(T_NL_NZ==0x02) //证明是对闹钟进行设置 { setNZn++; if(setNZn==4) //闹钟设定成功,退回到正常显示并开启闹钟 { setNZn=0; setn=0; timerOn=1; } switch(setNZn) { case 0: //正常显示日期时间 write_1602com(0x0c); //置光标不闪? write_1602com(er); //时间显示固定符号写入位置? for(a=0;a<16;a++) write_1602dat(NZd[a]); //写显示时间固定符号,两个冒号 write_sfm(8,nz_shi); //闹钟 时 write_sfm(11,nz_fen); //闹钟 分 write_sfm(14,nz_miao); //闹钟 秒 break; case 1: //闹钟秒光标闪烁 write_1602com(er+15); //设置按键按动一次,秒位置显示光标 //er+0x09; write_1602com(0x0f); //设置光标为闪烁 break; case 2: //闹钟分光标闪烁 write_1602com(er+12); //设置按键按动一次,秒位置显示光标 //er+0x09; write_1602com(0x0f); //设置光标为闪烁 break; case 3: //闹钟时光标闪烁 write_1602com(er+9); //设置按键按动一次,秒位置显示光标 //er+0x09; write_1602com(0x0f); //设置光标为闪烁 break; } } else //证明是对时间及日期进行设置 { if(T_NL_NZ==0) { setn++; if(setn==7) setn=0; //设置按键共有秒、分、时、星期、日、月、年、返回,8个功能循环 switch(setn) { case 1: TR0=0;//关闭定时器 //TR1=0; write_1602com(er+7);//设置按键按动一次,秒位置显示光标 //er+0x09; 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+4); //按2次fen位置显示光标 //er+0x06 //write_1602com(0x0f); break; case 3: write_1602com(er+1); //按动3次,shi //write_1602com(0x0f); break; // case 4: write_1602com(yh+0x0e);//按动4次,week //write_1602com(0x0f); // break; case 4: write_1602com(yh+0x0a);//按动4次,ri //write_1602com(0x0f); break; case 5: write_1602com(yh+0x07);//按动5次,yue //write_1602com(0x0f); break; case 6: write_1602com(yh+0x04);//按动6次,nian //write_1602com(0x0f); break; case 0: write_1602com(0x0c);//按动到第7次,设置光标不闪烁 TR0=1;//打开定时器 temp=(miao)/10*16+(miao)%10; write_1302(0x8e,0x00); write_1302(0x80,0x00|temp);//miao数据写入DS1302 write_1302(0x8e,0x80); break; } } } } } //------------------------------加键add---------------------------- if((setn!=0)&&(setNZn==0))//当set按下以下。再按以下键才有效(按键次数不等于零) { if(add==0) //上调键 { delay(10); if(add==0) { led1=0; bltime=0; buzzer=0;//蜂鸣器短响一次 delay(20); buzzer=1; while(!add); switch(setn) { case 1:miao++;//设置键按动1次,调秒 if(miao==60) miao=0;//秒超过59,再加1,就归零 write_sfm(0x06,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+7);//因为设置液晶的模式是写入数据后,光标自动右移,所以要指定返回 //write_1602com(0x0b); break; case 2:fen++; if(fen==60) fen=0; write_sfm(0x03,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+4);//因为设置液晶的模式是写入数据后,指针自动加一,在这里是写回原来的位置 break; case 3:shi++; if(shi==24) shi=0; write_sfm(0x00,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+1);//因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位 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 4:ri++; if(ri==32) ri=1; Conver_week(nian,yue,ri); write_week(week); 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 5:yue++; if(yue==13) yue=1; Conver_week(nian,yue,ri); write_week(week); 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 6:nian++; if(nian==100) nian=0; Conver_week(nian,yue,ri); write_week(week); 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; } } } //------------------减键dec,各句功能参照'加键'注释--------------- if(dec==0) { delay(10);//调延时,消抖动 if(dec==0) { led1=0; bltime=0; buzzer=0;//蜂鸣器短响一次 delay(20); buzzer=1; while(!dec); switch(setn) { case 1: miao--; if(miao==-1) miao=59;//秒数据减到-1时自动变成59 write_sfm(0x06,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+7);//因为设置液晶的模式是写入数据后,指针自动加一,在这里是写回原来的位置 //write_1602com(0x0b); break; case 2: fen--; if(fen==-1) fen=59; write_sfm(3,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+4);//因为设置液晶的模式是写入数据后,指针自动加一,在这里是写回原来的位置 break; case 3: shi--; if(shi==-1) shi=23; write_sfm(0,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+1);//因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位 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 4: ri--; if(ri==0) ri=31; Conver_week(nian,yue,ri); write_week(week); 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 5: yue--; if(yue==0) yue=12; Conver_week(nian,yue,ri); write_week(week); 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 6: nian--; if(nian==-1) nian=99; Conver_week(nian,yue,ri); write_week(week); 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; } } } } if((setNZn!=0)&&(setn==0)) { if(add==0) //上调键 { delay(10); if(add==0) { led1=0; bltime=0; buzzer=0;//蜂鸣器短响一次 delay(20); buzzer=1; while(!add); switch(setNZn) { case 1: nz_miao++; //设置键按动1次,调秒 if(nz_miao==60) nz_miao=0;//秒超过59,再加1,就归零 write_sfm(14,nz_miao);//令LCD在正确位置显示"加"设定好的秒数 write_1602com(er+15);//因为设置液晶的模式是写入数据后,光标自动右移,所以要指定返回 break; case 2: nz_fen++; if(nz_fen==60) nz_fen=0; write_sfm(11,nz_fen);//令LCD在正确位置显示"加"设定好的分数据 write_1602com(er+12);//因为设置液晶的模式是写入数据后,指针自动加一,在这里是写回原来的位置 break; case 3: nz_shi++; if(nz_shi==24) nz_shi=0; write_sfm(8,nz_shi);//令LCD在正确的位置显示"加"设定好的小时数据 write_1602com(er+9);//因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位 break; } } } //------------------减键dec,各句功能参照'加键'注释--------------- if(dec==0) { delay(10);//调延时,消抖动 if(dec==0) { led1=0; bltime=0; buzzer=0;//蜂鸣器短响一次 delay(20); buzzer=1; while(!dec); switch(setNZn) { case 1: nz_miao--; if(nz_miao==-1) nz_miao=59;//秒数据减到-1时自动变成59 write_sfm(14,nz_miao);//在LCD的正确位置显示改变后新的秒数 write_1602com(er+15); break; case 2: nz_fen--; if(nz_fen==-1) nz_fen=59; write_sfm(11,nz_fen); write_1602com(er+12);//因为设置液晶的模式是写入数据后,指针自动加一,在这里是写回原来的位置 break; case 3: nz_shi--; if(nz_shi==-1) nz_shi=23; write_sfm(8,nz_shi); write_1602com(er+9);//因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位 break; } } } } } //------------------------------- void init(void) //定时器、计数器设置函数 { TMOD=0x11; //指定定时/计数器的工作方式为3 TH0=0; //定时器T0的高四位=0 TL0=0; //定时器T0的低四位=0 TH1=0x3C; TL1=0xB0; EA=1; //系统允许有开放的中断 ET0=1; //允许T0中断 ET1=1; IT1=1; IT0=0; TR0=1; //开启中断,启动定时器 TR1=0; } void alarm(void) { if((shi==nz_shi)&&(fen==nz_fen)&&(miao==0)) { TR1=1; } if((shi==nz_shi)&&(fen==(nz_fen+1))) { TR1=0; buzzer=1; } } void ZD_baoshi(void) { buzzer=0; delay(5); buzzer=1; bsn++; if(bsn==temp_hour) { baoshi=0; } } //*******************主函数************************** //*************************************************** void main() { P1=0xff; lcd_init(); //调用液晶屏初始化子函数 ds1302_init(); //调用DS1302时钟的初始化子函数 init(); //调用定时计数器的设置子函数 led=1; //打开LCD的背光电源 buzzer=0; //蜂鸣器长响一次 delay(80); buzzer=1; while(1) //无限循环下面的语句: { keyscan(); //调用键盘扫描子函数 led=led1; if(timerOn==1) alarm(); //闹钟输出 if((fen==0)&&(miao==0)) { if(shi>12) temp_hour=shi-12; else { if(shi==0) temp_hour=12; else temp_hour=shi; } shangyimiao=miao; baoshi=1; } if(baoshi==1) { ZD_baoshi(); do keyscan(); while(shangyimiao==miao); shangyimiao=miao; } } } 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(0x89)); nian=BCD_Decimal(read_1302(0x8d)); //week=BCD_Decimal(read_1302(0x8b)); //不读取,直接通过日期计算得到 if((led1==0)) { if(temp_miao!=miao) { temp_miao=miao; bltime++; } if(bltime==10) { led1=1; bltime=0; } } if(T_NL_NZ==1) //显示农历 { uint nian_temp,temp; temp=nian; nian_temp=2000+(temp&0xF0)*10+temp&0x0F; if((nian_temp%400==0)||((nian_temp%100!=0)&&(nian_temp%4==0))) //判断是否为闰年 p_r=1; else p_r=0; Conversion(0,nian,yue,ri); write_1602com(er);//时间显示固定符号写入位置? for(a=0;a<16;a++) { if(p_r==0) write_1602dat(nlp[a]);//写显示时间固定符号,两个冒号 else write_1602dat(nlr[a]); } write_nl(3,year_moon);//农历 年 write_nl(6,month_moon);//农历 月 write_nl(9,day_moon);//农历 日 do keyscan(); while(T_NL_NZ==1); write_1602com(er);//时间显示固定符号写入位置,从第2个位置后开始显示 for(a=0;a<16;a++) { write_1602dat(qk[a]);//写显示时间固定符号,两个冒号 } write_1602com(er);//时间显示固定符号写入位置,从第2个位置后开始显示 for(a=0;a<8;a++) { write_1602dat(tab2[a]);//写显示时间固定符号,两个冒号 } } if(T_NL_NZ==2) //显示闹钟时间, { write_1602com(er);//时间显示固定符号写入位置? for(a=0;a<16;a++) write_1602dat(NZd[a]);//写显示时间固定符号,两个冒号 write_sfm(8,nz_shi);//农历 年 write_sfm(11,nz_fen);//农历 月 write_sfm(14,nz_miao);//农历 日 do keyscan(); while(T_NL_NZ==2); write_1602com(er);//时间显示固定符号写入位置,从第2个位置后开始显示 for(a=0;a<16;a++) { write_1602dat(qk[a]);//写显示时间固定符号,两个冒号 } write_1602com(er);//时间显示固定符号写入位置,从第2个位置后开始显示 for(a=0;a<8;a++) { write_1602dat(tab2[a]);//写显示时间固定符号,两个冒号 } } else { //显示温度、秒、时、分数据: if(wd) { flag=ReadTemperature()-5; write_temp(10,flag);//显示温度,从第二行第12个字符后开始显示 } else { write_1602com(er+12); for(a=0;a<4;a++) { write_1602dat(tm[a]); } } write_sfm(6,miao);//秒,从第二行第8个字后开始显示(调用时分秒显示子函数) write_sfm(3,fen);//分,从第二行第5个字符后开始显示 write_sfm(0,shi);//小时,从第二行第2个字符后开始显示 } //显示日、月、年数据: write_nyr(9,ri);//日期,从第二行第9个字符后开始显示 write_nyr(6,yue);//月份,从第二行第6个字符后开始显示 write_nyr(3,nian);//年,从第二行第3个字符后开始显示 Conver_week(nian,yue,ri); write_week(week); } unsigned char count1; void timer1() interrupt 3 //取得并显示日历和时间 { TH1=0x3C; TL1=0xB0; TR1=1; count1++; if(count1==10) { count1=0; buzzer=!buzzer; } } 初始化开中断 读18b20 S1或S2是否按下 扫描闹钟 显示温度 设置闹钟 显示温度 设置时间 S1=1秒 S1=2分 S1=7月 S1=8退出 S2调加秒 S3调减秒 S3调减年 S2调加年 S4=1设置闹钟 S4=2退出设置 S1=1调节秒 S1=2调节分 S1=3调节时 S1=4退出 PAGE 1
本文档为【范文1(请套用格式)】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_221542
暂无简介~
格式:doc
大小:1MB
软件:Word
页数:0
分类:工学
上传时间:2018-09-10
浏览量:21