摘 要
目前,家庭居住环境的采光及避光问题主要采用的是手动开闭窗帘,手动开闭不仅费力而且很多方面不够人性化,会对用户造成一定的困扰,本文设计的智能窗帘控制系统可以解决这些问题。
本文主要阐述了智能窗帘控制器的设计过程。本设计采用STC89C52单片机为控制核心,介绍了基于单片机的智能窗帘控制系统,主要从硬件结构原理及软件编程方面进行讲解。硬件采用分块的模式,对整个系统的电路设计进行分析,分别给出了系统整体结构框图、光照传感电路、温度检测电路、系统主控模块电路、电源转换电路、步进电机控制电路、键盘显示电路以及时钟模块电路等相关电路;随后讲述了软件的编写过程,也是采用了分块的模式,主要包括软件主程序设计,步进电机程序设计,显示程序设计,键盘程序设计以及定时程序设计,每一模块都画出了相应的流程图。本设计重点讨论了窗帘自动控制系统的设计过程、硬件选用和软件调试等问题。
通过本系统最终实现了利用光照强度以及设置时间来控制窗帘自动开闭的仿真。此外本设计还实现了室内温度检测的功能。
关键词:单片机,智能窗帘,定时控制
I
DESIGN OF INTELLIGENT CURTAIN CONTROL SYSTEM
BASED ON MCU
ABSTRACT
At present, the family living environment of lighting and light avoidance problem mainly adopts is manually open and close the curtains, manual opening and closing is not only laborious and many not human, will cause some trouble for users. In this paper, the design of the intelligent curtain control system can solve these problems.
This paper mainly expounds the design process of the intelligent curtain controller. This design uses STC89C52 microcontroller as the core, introduces the intelligent curtain control system based on MCU, mainly from the hardware structure and software programming aspects of the explanation. Hardware using block model, carries on the analysis to the circuit design of the whole system are given, the system overall structure diagram, light sensing circuit, temperature detection circuit, system main control module circuit, power conversion circuit, stepper motor control circuit, keyboard and display circuit and clock circuit module circuit. Subsequently introduces the software of the writing process, but also uses a block mode, including software, the main program design, program design of stepping motor, showing design program, keyboard program design and program timing design, each module draw flow chart. This design focuses on the design process, hardware selection and software debugging of the curtain automatic control system.
II
Through the system, the simulation of the automatic blind opening and closing of the curtain is realized by the illumination intensity and the setting time. In addition, the design of indoor temperature detection function.
Key words: MCU, intelligent curtain, timing control
III
目 录
摘 要 .......................................................................................................................................... I ABSTRACT ............................................................................................................................. II 第一章 绪论 ............................................................................................................................. 1
1.1 研究的目的及意义 ..................................................................................................... 1 1.2 智能窗帘的国内外研究现状 ..................................................................................... 2
1.2.1国外研究现状 .................................................................................................... 2 1.2.2国内研究现状 .................................................................................................... 2 1.3 主要研究内容及章节安排 ......................................................................................... 2
1.3.1 主要研究内容 ................................................................................................. 2 1.3.2 章节安排 ......................................................................................................... 3
第二章 总体设计方案 ............................................................................................................. 4
2.1 方案选取 ..................................................................................................................... 4 2.2 系统总体设计与工作原理 ......................................................................................... 5 第三章 硬件设计 ..................................................................................................................... 6
3.1 STC89C52单片机及相关电路 ................................................................................... 6
3.1.1 STC89C52单片机概述 .................................................................................. 6 3.1.2 晶振电路 ......................................................................................................... 7 3.1.3 复位电路 ......................................................................................................... 9 3.1.4 电源电路设计 ................................................................................................. 9 3.2 时钟模块电路 ........................................................................................................... 11
3.2.1 DS1302性能简介 ......................................................................................... 11 3.2.2 DS1302接口电路设计 ................................................................................. 12 3.3 键盘显示电路 ........................................................................................................... 13
3.3.1 键盘电路 ....................................................................................................... 13 3.3.2 显示电路 ....................................................................................................... 14 3.4 光敏传感器电路 ....................................................................................................... 16 3.5 步进电机控制电路 ................................................................................................... 18 3.6 温度检测电路 ........................................................................................................... 20 第四章 软件设计 ................................................................................................................... 22
4.1 软件主程序设计 ....................................................................................................... 22 4.2 软件子程序设计 ....................................................................................................... 23
4.2.1 步进电机程序设计 ......................................................................................... 23 4.2.2 显示程序设计 ................................................................................................. 24 4.2.3 键盘程序设计 ................................................................................................. 25 4.2.4 定时程序设计 ................................................................................................. 25
第五章 系统仿真与总结 ....................................................................................................... 27
5.1 Proteus软件简介 ....................................................................................................... 27
IV
5.2 仿真过程与结果 ....................................................................................................... 27 第六章 总结 ........................................................................................................................... 34 参考文献 ................................................................................................................................. 36 致谢 ......................................................................................................................................... 38 附录A:系统设计原理图 ..................................................................................................... 39 附录B:系统设计仿真图 ..................................................................................................... 40 附录C:程序清单 ................................................................................................................. 41
V
第一章 绪论
1.1 研究的目的及意义
21世纪是科技飞速发展的时代,随着国民经济的发展和科学技术水平的提高,特别是计算机技术,通信技术,网络技术,控制技术的迅猛发展,生活现代化得以实现,居住环境向舒适化,安全化发展,智能家居也随之应运而生。由于我国的科技刚刚发展起来,各种科技产品还明显的落后于发达国家,人民的生活也刚刚开始富裕起来,许多智能系统也刚刚在我国兴起。但是,发展前景却广阔。这种系统可以为我们营造出高效、舒适、便捷的居住环境。并且它可以牵动一大批产业[1]。如此广泛的应用,他的前景也必将非常广阔。随着科学技术的飞速发展,人们的生活观念也在渐渐的发生转变。各种家电也在发生着变化。由于单片机技术和计算机技术的的不断成熟,家电越来越智能化。窗帘也不例外,在欧美等发达国家,智能窗帘系统已广泛应用。智能窗帘在国内算是高端前沿产业,市场广阔,有推广和应用的意义,在发达的欧美市场智能窗帘已经并不新鲜,已经广泛运用于平常百姓家中,所以有必要在国内推广。
随着现代社会的高速发展,人们对室内设计智能化的要求也越来越高,相对于传统的窗帘,智能窗帘更能满足人们对于生活品质的追求[2]。在一年四季中,随着不同的季节、气候,人们对于窗帘打开与闭合的需求是不同的;在每一天中,随着天气的变化及时间段的不同,人们对于窗帘打开与闭合的需求也是不一致的。这也就为智能窗帘系统的研发提供了市场价值[3]。随着信息、自动化和通信等技术的不断进步,智能窗帘控制系统在家居、大型会议室等领域得到了广泛的使用,最大限度地满足人们对窗帘开度的各种需求。尤其在智能家居领域克服传统的窗帘的许多缺点,为人们提供了更方便、快捷、舒适安全的生活环境,提供了人类的生活质量[4]。
智能窗帘控制系统的控制方式大体上有三种:光控,时控,遥控。遥控属于半自动类;而光控属于全自动式,但因光敏器件的灵敏度,以及不同季节的光照度的不同,以及人们对于窗帘开闭在时间上的要求不同,而难以实施和普及。因此,设计一款价格低廉,结构简单,灵敏度高,抗干扰能力强[5],实现时间控制、手动控制功能为一体的智能窗帘,具有十分重要的意义。
1 1
1.2 智能窗帘的国内外研究现状
1.2.1国外研究现状
在欧美等发达国家,电动窗帘已广泛应用。在十多年前,电动窗帘就已经进入我国,可一直没有大的推广,这两年,随着电控技术的不断提高及价格的不断下降,电动窗帘热才又卷土重来。在此后短短几年时间里,生产商由最初的几家增加到如今的百余家,发展十分迅速。据查我国目前共有170多种电动窗帘获得国家专利,其技术大同小异,但售价在五百到数千元居多,共同缺点是价格高、灵活性不强,而且自动化程度不高。尽管遥控自动窗帘系统在国内是一个新兴的行业,但是,它正以不可抵挡之势迅速崛起。遥控自动窗帘系统走进中国以来,在短短四年时间里,自动窗帘系统生产商由最初的几家公司增加到如今的百余家,其行业发展迅速是目前国内任何其他行业所无法比拟的。 1.2.2国内研究现状
目前,我国遥控自动窗帘系统生产厂商、分销商、集成商已形成相当规模,不少国内知名企业纷纷涉足遥控自动窗帘系统行业,如青岛海尔、清华同方、TCL等,并涌现出一些较具影响力的智能家居专业厂商,如上海索博智能电子有限公司、北京九州易居科技有限公司、天津瑞朗智能家居电子科技有限公司、深圳市正星特科技有限公司等。在应用范围拓展方面,除了写字楼、酒店、演播厅、教学楼等大型公共场所外,自动窗帘产品还走进了普通家庭,展示了巨大的应用潜力。
随着自动窗帘热潮在世界范围内兴起、电子技术的飞速发展以及人们生活水平的不断提高,电动窗帘的自动化程度不断提高,从目前的发展趋势来看,在未来的20年时间里,自动窗帘行业将成为中国的主流行业之一,其市场的发展前景是非常广阔的。
1.3 主要研究内容及章节安排
1.3.1 主要研究内容
根据自动窗帘的发展现状来规划其智能功能,从而对窗帘进行智能控制,设计的电动窗帘控制系统主要实现以下几大功能:1)手动控制:该功能使电动窗帘具有手动正转、手动反转和手动停止的功能,该功能是根据用户的需求通过按键进行窗帘的开关,此功能可以使窗帘的开闭处于任何一种状态。2)半自动手动控制:半自动手动控制是
2 2
在需要关闭和打开窗帘的时候,只需要人工按一下“正转”或“反转”按键后,窗帘到位自动停止。窗帘的正转、反转和停止功能可由单片机输出电平来控制步进电机的运转以实现。此功能可以使窗帘通过按键一次性开闭窗帘。3)光照控制:系统可以根据用户设定的光照强度值通过感光器采集光照自动开光窗帘。4)时间控制:此功能是根据用户设定的时间一次性开关窗帘,并显示当前温度。
其中采用步进电机为执行原件,通过单片机对驱动芯片输出不同的高、低电平来控制电机的正、反转,完成窗帘的开、关动作[6];以光敏电阻,温度传感器作为传感原件,光敏电阻是利用半导体的光电效应制成的一种电阻值随入射光的强弱而改变的电阻器,入射光强,电阻减小,入射光弱,电阻增大。窗帘在光照控制模式下,当光强高于所设定的标准值时,窗帘会自动关闭,反之,当光强低于该标准值时,窗帘将自动打开[7]。温度传感器用来检测当前温度,并显示当前温度值。89C52单片机作为控制芯片,辅助键盘和显示,实现自动窗帘的多项智能功能[8]。 1.3.2 章节安排
智能窗帘控制系统设计过程主要分为以下几个章节:
(1)绪论:介绍选题意义,目前国内外研究现状,主要研究内容及章节安排。 (2)总体设计方案:介绍智能窗帘控制系统的总体设计方案的选取以及硬件设计的总体概况。
(3)硬件设计:智能窗帘控制系统以89C51单片机为核心,系统的硬件部分包括:89C52,晶振电路,复位电路,时钟电路,键盘电路,显示电路,A\\D转换电路,光敏传感器,步进电机,温度模块等。
(4)软件设计:介绍各个功能模块的设计流程以及设计思路。智能窗帘控制系统的程序分析与设计:包括主程序设计,键盘程序设计,定时程序设计,步进电机程序设计,显示程序设计等。
(5)系统仿真与总结:对智能窗帘控制系统进行结果仿真,分析总结设计过程。
3 3
第二章 总体设计方案
智能窗帘控制系统总体设计方案是确定能够满足设计要求的总体方案的环节。本章从系统功能需求出发,规划并确定了系统的总体结构,并在此基础上考虑了系统的可扩展性及可实现性。
2.1 方案选取
单片机在各种电子产品中的应用已经越来越广泛,很多的电子产品利用单片机所取得的便利性得到了人们的好评,针对单片机控制的自动窗帘控制系统的智能化要求,实现其自动控制的方案有两种:
方案(一)基于温度检测以及声控检测器件的自动控制。 方案(二)基于光照强度器件以及时钟模块的自动控制。
这二个方案都是基于单片机控制的,采用步进电机控制以及液晶显示,不同的设计部分在于检测器件的选取上。
方案(一)的系统框图如图2.1:
温度模块 图2.1 方案(一)系统框图
电源模块 声控模块 89C52 键盘模块 显示模块 方案(一)与方案(二)的区别主要在于检测器件的应用,方案(一)采用温度采集和声音检测元件,通过设定的温度来控制窗帘的开闭,以减少光照对室内的温度影响,利用声音控制虽然方便性有所提高,但是其误差较大。方案(二)采用的时钟模块以及光照采集元件,通过设定光照值来控制窗帘的开闭,以实现白天开窗帘,晚上关窗帘的
4 4
功能,利用设定的时间来控制窗帘的开闭,实用性更强。综合考虑以上因素,系统设计采用方案(二)。
方案(二)的系统框图如图2.2:
光照检测 图2.2 方案(二)系统框图
电源模块 时钟模块 89C52 键盘模块 显示模块 2.2 系统总体设计与工作原理
智能窗帘控制系统的总体结构框图如图2.3所示
光敏电阻 A/D转换电路 温度模块 键盘模块 单片机 步进电机 由光敏传感器来探测外界的光强,从传感器出来的信号输入到A/D转换器。转换后的信号由单片机控制电机,来实现电机的运行与停止。温度模块用来采集温度,并且将采集到的温度通过显示模块显示。显示部件用来显示电动窗帘控制器的各种状态信息。
[9]
键盘是主要的输入设备,控制单片机的各种参量。电源模块用来提供单片机所需电压。
5 5
显示模块 窗 帘 图2.3 智能窗帘控制系统的总体结构框图
第三章 硬件设计
3.1 STC89C52单片机及相关电路
在总体硬件包括单片机外围电路,电源模块、按键模块、LCD1602液晶显示模块、步进电机驱动模块、DS1302时钟模块、AD模数转换模块、光照检测模块和温度检测模块组成。单片机外围电路提供各模块所需的5V电源。信号检测后的是模拟信号,经过A/D转换后输出数字信号给单片机。单片机的P2口控制步进电机的运行从而控制窗帘的升降。显示和键盘让人机交换变得更容易。 3.1.1 STC89C52单片机概述
单片机是将中央处理器(CPU)、随机存储器(RAM)、只读存储器(ROM或EPROM)、定时器芯片和一些输入/输出接口电路集成在一个芯片上的微控制器。89C52是INTEL公司MCS-51系列单片机中基本的产品,它采用ATMEL公司CMOS工艺技
[10]术制造的高性能8位单片机,属于标准的MCS-51的HCMOS产品。它结合了CMOS
的高速和高密度技术及CMOS的低功耗特征,它基于标准的MCS-51单片机体系结构和指令系统。
STC89C52主要参数有: 8k字节Flash,512字节RAM, 32 位I/O 口线,看门狗定时器,内置4KB EEPROM,MAX810复位电路,3个16 位定时器/计数器,4个外部中断,一个7向量4级中断结构(兼容传统51的5向量2级中断结构),全双工串行口。另外 STC89C52 可降至0Hz 静态逻辑操作,支持2种软件可选择节电模式。空闲模式下,CPU 停止工作,允许RAM、定时器/计数器、串口、中断继续工作。掉电保护方式下,RAM内容被保存,振荡器被冻结,单片机一切工作停止,直到下一个中断或硬件复位为止。最高运作频率35MHz,6T/12T可选。
89C52是INTEL公司MCS-51系列单片机中基本的产品,它采用ATMEL公司CMOS工艺技术制造的高性能8位单片机,属于标准的MCS-51的HCMOS产品。51系列优点之一是它从内部的硬件到软件有一套完整的按位操作系统,称作位处理器,或布尔处理器。它的处理对象不是字或字节而是位。它不光能对片内某些特殊功能寄存器的某位进行处理,如传送、置位、清零、测试等,还能进行位的逻辑运算,其功能十分
6 6
完备,使用起来得心应手。虽然其他种类的单片机也具有位处理功能,但能进行位逻辑运算的实属少见。51系列在片内RAM区间还特别开辟了一个双重功能的地址区间,十六个字节,单元地址20H~2FH,它既可作字节处理,也可作位处理(作位处理时,合128个位,相应位地址为OOH~7FH),使用极为灵活。这一功能无疑给使用者提供了极大的方便,因为一个较复杂的程序在运行过程中会遇到很多分支,因而需建立很多标志位,在运行过程中,需要对有关的标志位进行置位、清零或检测,以确定程序的运行方向。而实施这一处理(包括前面所有的位功能),只需用一条位操作指令即可。
51系列的另一个优点是乘法和除法指令,这给编程也带来了便利。八位除以八位的除法指令,商为八位,精度嫌不够,用得不多。而八位乘八位的乘法指令,其积为十六位,精度还是能满足要求的,用的较多。作乘法时,只需一条指令就行了,即MUL AB(两个乘数分别在累加器A和寄存器B中。积的低位字节在累加器A中,高位字节在寄存器B中)。很多的八位单片机都不具备乘法功能,作乘法时还得编上一段子程序调用,十分不便。
在51系列中,还有一条二进制一十进制调整指令DA,能将二进制变为BCD码,这对于十进制的计量十分方便。而在其他的单片机中,则也需调用专用的子程序才行。STC89C52单片机的引脚排列如图3.1所示。 3.1.2 晶振电路
电路中的晶振即石英晶体震荡器。由于石英晶体震荡器具有非常好的频率稳定性和抗外界干扰的能力,所以,石英晶体震荡器是用来产生基准频率的。通过基准频率来控制电路中的频率的准确性。同时,它还可以产生振荡电流,向单片机发出时钟信号。
晶振电路中的电容C1和C2的典型值通常选择为30μF左右,该电容的大小会影响
[10]振荡电路频率的高低、振荡器的稳定性和起振的快速性。晶体振荡频率的范围通常在
1.2~12MHz。晶体的频率越高,系统的时钟频率越快,单片机的运行速度越快。但反过来,运行速度对于存储器的速度要求就越高,对印刷电路板的工艺要求也就越高,即要求线间的寄生电容要小。晶体和电容应该尽可能安装得与单片机芯片靠近,以减少寄生电容,更好地保证振荡器稳定、可靠地工作。89C52常选择振荡频率12MHz的石英晶体。
7 7
图3.1 STC89C52单片机引脚排列图
图3.2是单片机的晶振电路。其中,XTAL1接外部晶体的一个引脚,XTAL2接外晶体的另一端。在单片机内部,接至上述振荡器的反相放大器的输出端。采用外部振荡器时,对HMOS单片机,该引脚接外部振。在石英晶体的两个管脚加交变电场时,它将会产生一定频率的机械变形,而这种机械振动又会产生交变电场,上述物理现象称为压电效应。一般情况下,无论是机械振动的振幅,还是交变电场的振幅都非常小。但是,当交变电场的频率为某一特定值时,振幅骤然增大,产生共振,称之为压电振荡。这一特定频率就是石英晶体的固有频率,也称谐振频率。石英晶振起振后要能在XTAL2线上输出一个3V左右的正弦波,以便使MCS-51片内的OSC电路按石英晶振相同频率自激振荡。通常,OSC的输出时钟频率fOSC为0.5MHz-16MHz,典型值为12MHz或者11.0592MHz。电容C1和C2可以帮助起振,调节它们可以达到微调fOSC的目的。
8 8
图3.2 晶振电路
3.1.3 复位电路
复位是单片机的初始化操作,只需要给89C52的复位引脚RST加上大于2个机器周期(即24个时钟震荡周期)的高电压就可以使89C52复位。复位时,单片机初始化为0000H,从0000H单元开始执行程序。除了进入系统的正常初始化之外,当程序运行错误(如程序跑飞)或者操作错误使系统处于锁死状态时,也需要复位键使RST引脚为高电平,使89C52摆脱“跑飞”或者“死锁”状态而重新启动。复位电路图如图3.3所示。
3.1.4 电源电路设计
单片机工作需要使用5V电压,因此需要给单片机设计电源电路。图3.4是单片机的电源电路。它采用LM7805三端集成稳压器,可输出+5V的直流电压供电。
三端集成稳压器LM7805,总共有三条引脚,分别是输入端、接地端和输出端。用LM78\\LM79系列三端稳压器来组成稳压电源所需的外围元件极少,电路内部还有过流、过热及调整管的保护电路,使用起来可靠、方便。其内部结构图如图3.5所示。
9 9
图3.3 复位电路
图3.4 单片机电源电路
10 10
图3.5 LM7805内部示意图
3.2 时钟模块电路
本设计需要窗帘在给定的时间自动开和关,所以需要用到定时器,而为了保证单片机与外界时钟一致,要用到一个实时时钟电路。这里使用DS1302实时时钟芯片来完成这项功能。
3.2.1 DS1302性能简介
DS1302 是DALLAS 公司推出的涓流充电时钟芯片,内含有一个实时时钟/日历和31 字节静态RAM ,通过简单的串行接口与单片机进行通信。实时时钟/日历电路提供秒、分、时、日、周、月、年的信息,每月的天数和闰年的天数可自动调整。时钟操作可通过AM/PM 指示决定采用24 或12 小时格式。DS1302 与单片机之间能简单地采用同步串行的方式进行通信,仅需用到三个口线:(1)RES 复位(2)I/O 数据线(3)SCLK串行时钟。时钟/RAM 的读/写数据以一个字节或多达31 个字节的字符组方式通信。DS1302 工作时功耗很低保持数据和时钟信息时功率小于1mW。
DS1302 是由DS1202 改进而来增加了以下的特性:双电源管脚用于主电源和备份电源供应,Vcc1 为可编程涓流充电电源,附加七个字节存储器。它广泛应用于电话、传真、便携式仪器以及电池供电的仪器仪表等产品领域。
下面将主要的性能指标作一综合:
(1) 实时时钟具有能计算2100 年之前的秒、分、时、日、星期、月、年的能力,还有闰年调整的能力。
(2)31 8 位暂存数据存储RAM。
(3)串行 I/O 口方式使得管脚数量最少。
11 11
(4)宽范围工作电压2.0 5.5V。 (5)工作电流 2.0V 时,小于300nA。
(6)读/写时钟或RAM 数据时有两种传送方式单字节传送和多字节传送字符组方式。
(7)8 脚DIP 封装或可选的8 脚SOIC 封装根据表面装配。 (8)简单 3 线接口。 (9)与 TTL 兼容Vcc=5V。
(10)可选工业级温度范围-40 +85。 (11)双电源管用于主电源和备份电源供应。
DS1302的外部引脚功能说明如图3.6所示。各引脚的功能为:⑴.VCC1:主电源。⑵.VCC2:备份电源。当VCC2>VCC1+0.2V时,由VCC2向DS1302供电;当VCC2 3.2.2 DS1302接口电路设计 DS1302时钟芯片和STC89C52单片机的接口电路如图3.7所示。DS1302与单片机的连接仅需要3条线:CE引脚、SCLK串行时钟引脚、I/O串行数据引脚,VCC2为备用电源,X1与X2外接一个32.768kHZ晶振,为芯片提供计时脉冲。 12 12 图3.7 DS1302与单片机的接口电路 3.3 键盘显示电路 3.3.1 键盘电路 键盘在由单片机控制的窗帘自动控制系统中的主要作用是通过按键向单片机输入指令,其中主要包括设定时间,控制窗帘的开关等等功能,是人工控制单片机的主要手段。 本设计中的键盘采用了五个按键。S2键为自动手动切换键。S3键为退出键,S4键为参数减/手动关,S5键为参数加/手动开,S6为设置键。 S2键可以在手动、自动状态切换。S6键为设置键,按下S6键有三种选项,可分别按S4-,S5+来设定窗帘的开启时间,关闭时间,定时开关窗帘时间以及光线值。按键接口电路如图3.8所示: 图3.8 键盘电路 13 13 3.3.2 显示电路 显示部分则主要用于显示、设置时间,以及显示温度。在日常生活中,我们对液晶显示器并不陌生。液晶显示模块已作为很多电子产品的通用器件,如在计算器、万用表、电子表及很多家用电子产品中都可以看到,显示的主要是数字、专用符号和图形。在单片机与人的人机交流界面中,一般的输出方式有以下几种:发光管、LED数码管、液晶显示器。本设计中采用的是液晶显示器作为输出器件的。 在单片机系统中应用液晶显示器作为输出有以下几个优点: (1)显示质量高:由于液晶显示器每一个点在收到信号后就一直保持那种色彩和亮度,恒定发光,而不像阴极射线管显示器(CRT)那样需要不断刷新新亮点。因此,液晶显示器画质高且不会闪烁。 (2)数字式接口液晶显示器都是数字式的,和单片机系统的接口更加简单可靠,操作更加方便。 (3)体积小、重量轻:液晶显示器通过显示屏上的电极控制液晶分子状态来达到显示的目的,在重量上比相同显示面积的传统显示器要轻得多 (4)低功耗:相对而言,液晶显示器的功耗主要消耗在其内部的电极和驱动IC上,因而耗电量比其它显示器要少得多。 字符型液晶显示模块是一种专门用于显示字母、数字、符号等点阵式LCD,目前常用16*1,16*2,20*2和40*2行等的模块。本设计采用的液晶显示器为1602字符型液晶显示器。 1602LCD主要技术参数: ① 显示容量:16×2个字符; ② 芯片工作电压:4.5—5.5V; ③ 工作电流:2.0mA(5.0V); ④ 模块最佳工作电压:5.0V字符尺寸:2.95×4.35(W×H)mm。 1602液晶显示器引脚接口说明: ① 第1脚:VSS为地电源。 ② 第2脚:VDD接5V正电源。 ③ 第3脚:VL为液晶显示器对比度调整端,接正电源时对比度最弱,接地时对比 14 14 度最高,对比度过高时会产生“鬼影”,使用时可以通过一个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脚:背光源负极。 1602液晶模块内部的控制器共有11条控制指令如表3.1所示: 表3.1 1602液晶模块控制指令表 序指令 RR/W D7 D6 D5 D4 D3 D2 D1 D0 号 S 1 清显示 0 0 0 0 0 0 0 0 0 1 2 光标返回 0 0 0 0 0 0 0 0 1 * 3 置输入模式 0 0 0 0 0 0 0 1 I/D S 4 显示开/关控制 0 0 0 0 0 0 1 D C B 5 光标或字符移位 0 0 0 0 0 1 S/C R/L * * 6 置功能 0 0 0 0 1 DL N F * * 7 置字符发生存贮器地址 0 0 0 1 字符发生存贮器地址 8 置数据存贮器地址 0 0 1 显示数据存贮器地址 9 读忙标志或地址 0 1 BF 计数器地址 10 写数到CGRAM或DDRAM 1 0 要写的数据内容 11 从CGRAM或DDRAM读数 1 1 读出的数据内容 1602液晶模块的读写操作、屏幕和光标的操作都是通过指令编程来实现的。(说明:1为高电平、0为低电平) 指令1:清显示,指令码01H,光标复位到地址00H位置。 指令2:光标复位,光标返回到地址00H。 指令3:光标和显示模式设置 I/D:光标移动方向,高电平右移,低电平左移 S:屏幕上所有文字是否左移或者右移。高电平表示有效,低电平则无效。 指令4:显示开关控制。 D:控制整体显示的开与关,高电平表示开显示,低电平 15 15 表示关显示 C:控制光标的开与关,高电平表示有光标,低电平表示无光标 B:控制光标是否闪烁,高电平闪烁,低电平不闪烁。 指令5:光标或显示移位 S/C:高电平时移动显示的文字,低电平时移动光标。 指令6:功能设置命令 DL:高电平时为4位总线,低电平时为8位总线 N:低电平时为单行显示,高电平时双行显示 F: 低电平时显示5x7的点阵字符,高电平时显示5x10的点阵字符。 指令7:字符发生器RAM地址设置。 指令8:DDRAM地址设置。 指令9:读忙信号和光标地址 BF:为忙标志位,高电平表示忙,此时模块不能接收命令或者数据,如果为低电平表示不忙。 指令10:写数据。 指令11:读数据。 液晶显示器电路如图3.9所示: 图3.9 1602液晶显示电路 3.4 光敏传感器电路 窗帘自动控制系统的光控功能是可以根据用户设定的光照强度值通过感光器采集光照自动开关窗帘,因此需要用到光照传感元器件,在本设计中采用了光敏电阻。 16 16 光敏电阻又称光导管,常用的制作材料为硫化镉,另外还有硒、硫化铝、硫化铅和硫化铋等材料。这些制作材料具有在特定波长的光照射下,其阻值迅速减小的特性。这是由于光照产生的载流子都参与导电,在外加电场的作用下作漂移运动,电子奔向电源的正极,空穴奔向电源的负极,从而使光敏电阻器的阻值迅速下降。光敏电阻属半导体光敏器件,除具灵敏度高,反应速度快,光谱特性及r值一致性好等特点外,在高温,多湿的恶劣环境下,还能保持高度的稳定性和可靠性,可广泛应用于照相机,太阳能庭院灯,草坪灯,验钞机,石英钟,音乐杯,礼品盒,迷你小夜灯,光声控开关,路灯自动开关以及各种光控玩具,光控灯饰,灯具等光自动开关控制领域。 光敏控制电路是由运算放大器组成比较电路,在运算放大器同相输入端用两个电阻分压,得到的电压值作为基准电压,在反相输入端则用光敏电阻对光进行采集,由于光敏电阻具有根据光照强度阻值变化的特点,可以得到反向输入端的电压值。然后将得到的两组电压值进行比较,比较后的信号经过A/D转换送入单片机89C52的P1接口,单片机处理后输出命令控制电机正转或者反转,以实现通过光照控制窗帘的开关功能。 应用光控原理工作,天亮窗帘自动打开,天黑窗帘自动关闭。由于光敏电阻信号检测后得到的是模拟信号,所以光控电路采集到的模拟信号需要经过A/D转换后输出数字信号给单片机。 A/D转换的作用是进行模数转换,把接收到的模拟信号转换成数字信号输出。在选择A/D转换时,先要确定A/D转换精度、转换速度以及转换位数等,A/D转换的位数确定与整个测量控制系统所需测量控制的范围和精度有关,在自定窗帘控制系统中采用了8位A/D转换器ADC0832。ADC0832是美国国家半导体公司生产的一种8位分辨率、双通道A/D转换芯片。 图3.10 光敏电阻电路图 17 17 图3.11 光控电路原理图 由运放组成比较电路,同向输入端有两个电阻分压得到一个电压值,作为基准电压进行比较,而反相输入端用一个光敏二极管对外部环境的光线进行采集,利用光敏二极管暗时电阻大,亮时电阻小的特点,来确定反向输入端的电压值。再两者进行比较,比较后的信号再送入单片机的P0口,从而通过单片机来控制电机的正反转。来实现天亮窗帘自动打开,天黑窗帘自动关闭这一自动控制功能。本设计采用了型号为GL3526的光敏电阻。光敏电阻电路图如图3.10所示。光控电路原理图如图3.11所示。 3.5 步进电机控制电路 步进电机为一种数字伺服执行元件,具有结构简单、运行可靠、控制方便、控制性能好等优点,广泛应用在数控机床、机器人、自动化仪表等领域。为了实现步进电机的简易运动控制,一般以单片机作为控制系统的微处理器,通过步进电机专用驱动芯片实现步进电机的速度和位置定位控制。 现在比较常用的步进电机包括反应式步进电机(vr)、永磁式步进电机(pm)、混合式步进电机(hb)和单相式步进电机等。永磁式步进电机一般为两相,转矩和体积较小,步进角一般为7.5度 或15度;反应式步进电机一般为三相,可实现大转矩输出,步进角一般为1.5度,但噪声和振动都很大。反应式步进电机的转子磁路由软磁材料制成,定子上有多相励磁绕组,利用磁导的变化产生转矩。 本设计采用的步进电机是混合式步进电机。混合式步进电机混合了永磁式和反应式步进电机的优点它又分为两相和五相:两相步进角一般为1.8度而五相步进角一般为 0.72度。这种步进电机的应用最为广泛。所以,本设计采用28BYJ-48型四相八拍步进电机。 18 18 步进电机28BYJ-48型四相八拍电机,电压为DC5V—DC12V。当对步进电机施加一系列连续不断的控制脉冲时,它可以连续不断地转动。每一个脉冲信号对应步进电机的某一相或者两相绕组的通电状态改变一次,也就对应转子转过一定的角度(一个步距角)。当通电状态改变完成一个循环时,转子转过一个齿距。步进电机驱动方式如表3.2: 表3.2 步进电机驱动方式 导线颜色 5红 4橙 3黄 2粉 1蓝 1 + - 2 + - - 3 + - 4 + - - 5 + - 6 + - - 7 + - 8 + - 28BYJ-48步进电机技术指标:1.额定电压:5VDC。2.减速比:1/16。3.步距角:5.625/16。4.驱动方式:四相八拍。5.牵入转距:≥200gf.cm(工作频率:100Hz)。6.打滑扭力:≥500~1600gf.cm。7.温升:≤55K(5VDC 工作频率:100Hz)。8.噪音:≤35dB(空载,100Hz,水平距马达10cm)。 由于单片机接口信号不够大需要通过ULN2003放大再连接到相应的电机接口。ULN2003晶体管阵列:ULN2003是一个单片高电压、高电流的达林顿晶体管阵列集成电路。它是由7对NPN达林顿管组成的,它的高电压输出特性和阴极箝位二极管可以转换感应负载。单个达林顿对的集电极电流是500mA。达林顿管并联可以承受更大的电流。此电路主要应用于继电器驱动器,字锤驱动器,灯驱动器,显示驱动器(LED气体放电),线路驱动器和逻辑缓冲器。ULN2003的每对达林顿管都有一个2.7kΩ串联电阻,可以直接和TTL或5V CMOS装置。ULN2003的主要特点: (1)500mA 额定集电极电流(单个输出)。 (2)高电压输出:50V。 (3)输入和各种逻辑类型兼容。 (4)继电器驱动器。 步进电机控制系统的方框图以及其控制系统的电路图如图3.12与3.13所示。 19 19 脉冲信号 脉冲控制器 功率驱动电路 步进电机 负载 图3.12 步进电机控制系统方框图 图3.13 步进电机控制系统电路图 在使用两相混合式步进电机时需注意,该种电机在低速运转时有振动和噪声,是其固有的缺点、一般可采用以下方案来克服: (1)如步进电机正好工作在共振区,可通过改变减速比等机械传动避开共振区; (2)采用带有细分功能的驱动器,这是最常用的、最简便的方法; (3)换成步距角更小的步进电机,如三相或五相步进电机; (4)在电机轴上加磁性阻尼器,市场上已有这种产品,但机械结构改变较大。 3.6 温度检测电路 本设计温度检测使用的温度传感器的型号为DS18B20。DS18B20采用单总线通信协议。它有独特的单线接口方式,DS18B20在与微处理器连接时仅需要一条口线即可实现微处理器与DS18B20的双向通讯。本系统只用到单片机的一条口线,即P1.0,如图3.14所示。由于采用单总线数据传输方式,DS18B20的数据I/O均由同一条线完成,因此,对读写的操作时序要求严格。为了保证DS18B20的严格I/O时序,需要做较精确的延时。DS18B20采用+5V电源供电。这些在程序中有体现。 20 20 图3.14 温度模块 21 21 第四章 软件设计 智能窗帘控制系统的程序分析与设计包括主程序设计,步进电机程序设计,显示程序设计,键盘程序设计,定时程序设计几部分。本章节系统的介绍了智能窗帘控制系统的主程序和各主要功能子程序的设计流程。 4.1 软件主程序设计 主程序主要完成单片机初始化,关中断,菜单显示内容初始化,按键扫描,电机运行,计时等功能。主程序的流程图如图4.1所示。 开始关中断设置堆栈复位初始化设定键?NY电机控制键显示设定时间YN有键操作?开始计时Y电机工作NN键码分析Y到点了?Y工作完成?命令键?NYN电机停止数码键处理 图4.1 主程序流程图 22 22 主程序流程说明:电路主要分为以下几个部分,分别是电源部分、显示部分、按键部分、步进电机控制部分、A\\D转换部分、单片机主控器件部分,各部分具有不同的子程序。 启动主程序,先关中断并且设置堆栈,接着初始化寄存器,初始化显示内容;然后执行按键查询,执行相应的操作。如果是设定键,则设定时间,开始计时;到时间后步进电机开始相应的工作,工作完成后停机。如果是电机控制键,则也执行相应的工作。如果都不是,则是复位键,采取复位操作。 4.2 软件子程序设计 4.2.1 步进电机程序设计 步进电机是操控窗帘开闭的主要执行器件,其设计主要是按照单片机指令以及按键指令进行正转或者反转。图4.2是步进电机工作流程图。 开始步进电机是正转吗?NY传送正转脉冲序列传送反转脉冲序列N传送步数是否完成?传送步数是否完成YNY返回 图4.2 步进电机工作流程图 23 23 步进电机程序设计的主要任务是: (1)判断旋转方向; (2)按顺序传送控制脉冲; (3)判断所要求的控制步数是否传送完毕。 总之,只要按一定的顺序改变 P2.0-P2.3 四位通电的状况,即可控制步进电机依选定的方向步进。而对于节拍比较多的控制程序,通常采用循环程序进行设计。 开始显示子程序显示器缓冲起始地址60H→R2显示位代码01H→R2位代码R2→89C52取显示数据查表转换成显示代码→89C52延时指针R0加16位显示完吗?R2左移一位返回 4.2.2 显示程序设计 图4.3 显示部分子程序流程图 显示程序开始后,起始地址60H发送到R0,01H发送至显示位代码R2,再将位代码发送到单片机A口,单片机取显示数据查表转换成显示代码发送至单片机B口,延时2ms,指针R0加1,然后判断6位显示是否完成。如果完成则返回,没完成则位代码R2左移一位,继续显示查表,一直到6位显示完成后返回。显示部分子程序流程图如图 24 24 4.3所示。 4.2.3 键盘程序设计 在操作按键时,无论是按下还是松开,触点在闭合和断开时均会产生抖动,此时逻辑电平是不稳的,如果得不到正确处理,可能会引起单片机对按键命令的错误执行。解决这个问题的简单方法是利用软件延时。在单片机处理按键操作后都延时6ms,如果确定是按键后再延时12ms,这样基本可以避免键盘的抖动。然后由单片机进行键码分析,并执行相应的命令,显示并且返回。图4.4是键盘程序设计流程图。 4.2.4 定时程序设计 定时程序的主要作用是在用户设定的时间后能够使单片机收到一个中断信号,从而发出相应的指令,控制窗帘的开关。时钟芯片发出50ms的信号给单片机后,计数器开始工作,计数器记到20,时间即为1秒,秒单元加1,当秒单元计数到60,分单元加1,此时秒单元清零。当时单元计数到24时单元清零。图4.5是定时程序流程图。 开始有按键闭合?N调用显示子程序延时6ms两次调用显示子程序延时12msYN有按键闭合?Y键码分析执行相应的模块显示返回 图4.4 键盘程序流程图 25 25 开始分单元加1,秒单元清零,分写入分个位和分十位现场保护,重置初值,启动下一个50msN50ms,计数器加1分单元=60?YN计数器=20?时单元加1,分单元清零,时写入时个位和时十位Y秒单元加1,50ms计数器清零,秒写入Y秒个位和秒十位N时单元=24?Y时单元清零N秒单元=60?返回Y图4.5 定时程序流程图 26 26 第五章 系统仿真与总结 5.1 Proteus软件简介 Proteus软件是英国Lab Center Electronics公司出版的EDA工具软件。它不仅具有其它EDA工具软件的仿真功能,还能仿真单片机及外围器件。它是目前比较好的仿真单片机及外围器件的工具。 Proteus是世界上著名的EDA工具(仿真软件),从原理图布图、代码调试到单片机与外围电路协同仿真,一键切换到PCB设计,是目前世界上唯一将电路仿真软件、PCB设计软件和虚拟模型仿真软件三合一的设计平台。 5.2 仿真过程与结果 首先,将在Keil软件中调试好的程序生成*.HEX文件,然后将本文所设计的智能窗帘控制系统的原理图在PROTEUS绘制好,最后调入已编译好的目标代码文件:*.HEX。本设计在接通电源时,系统自动复位,默认处于手动光控状态。 系统仿真前部分电路图如图5.1所示,图中STEPPER-MOTOR为步进电机,LCD1为1602液晶显示屏,DS18B20为温度检测,图中还有五个按键,S1,S2,S3,S4,S5。S1键为自动手动切换键。S2键为退出键,S3键为参数减/手动关,S4键为参数加/手动开,S5为设置键。 图5.1 系统仿真前部分电路图 27 27 点击开始仿真时系统部分电路图如5.2,本设计在接通电源时,系统自动复位,处于手动状态。LCD1602液晶显示屏从左到右第一排依次为当前控制状态,时分秒,以及星期。第二排从左到右依次为当前光线值,年月日,以及当前温度。 在手动模式下,系统可以实现一次性开光窗帘。此时按下S4电机正传,如图5.3所示,S2为停止键,S3为电机反转。 图5.2系统开始仿真时部分电路图 图5.3 电机正传 28 28 若此时按下S1手动/自动模式切换键则系统变为自动模式,如图5.4所示。 图5.4 自动模式电路图 在自动模式下,此时若按下S5键,系统则进入设置菜单,如图5.5,设置菜单由上到下分别为设置时间,设置窗帘开闭时间,以及设置光线值。可分别按S3-,S4+,来切换菜单,切换到设置光线值的菜单如图5.6所示。 图5.5 设置菜单 当光标分别位于数字“1”“2”“3”时,按下S5键可分别设置对应参数。若此时光 29 29 标位于“1”处,按下S5键,则此时进入系统时间设置如图5.7所示,则此时按下S3-,S4+设定当前光标的值,然后按下S5键向右切换光标位置,依次设定当前时间的时分秒,星期,以及年月日,设定完成后按S2返回主界面,系统时间设置完成,如图5.8所示。 图5.6设置光线值菜单 图5.7 系统时间设置 若此时光标位于“2”处,按下S5键,则此时进入窗帘定时开闭设置,如图5.9所示。显示屏第一排为关窗时间,第二排为开窗时间的设置,若设定关窗帘时间为 30 30 18:25,开窗帘时间设定为18:30。则此时按下S3-,S4+设定当前光标的值,然后按下S5键向右切换光标位置,设定好时间后如图5.10所示。然后按下S2键返回主界面。当时间到达18:25时电机转动,如图5.11,窗帘关闭;当时间到达18:30时电机转动,如图5.12,窗帘打开。 图5.8系统时间设置完成界面 图5.9窗帘定时开闭设置 31 31 图5.10 窗帘定时时间设置完毕 图5.11关窗时间到 32 32 图5.12开窗时间到 33 33 第六章 总结 经过这段时间资料的查找和设计,最终完成了毕业设计的任务。本文设计了基于单片机的智能窗帘控制系统,系统的介绍了智能窗帘控制系统从硬件电路设计到软件设计的一系列步骤。本设计采用光敏电阻、温度传感器作为检测元件,89C52单片机作为控制芯片,步进电机作为执行元件,结合键盘和显示器件,实现了智能窗帘控制器的多项智能项目。 从整体设计来看,使用了熟悉的89C52单片机,从而对控制芯片的功能了如指掌,熟悉的控制芯片设计起来也是得心应手。所用芯片简单实用,减少了开发和硬件开销。本设计的主要原理是光敏电阻受到外界条件影响后,经过A/D转换,传送给单片机一个电信号,在由单片机经过处理后,将信号传给步进电机,控制步进电机做出相应的动作,最终实现控制窗帘的开闭。在实现一般应用的基础上,又添加了定时元器件电路,用户可以自己设定开关时间,使窗帘的自动化性能得到进一步提升。再加上手动控制,使得本系统更加人性化。光敏电阻的良好感光性以及步进电机的结构简单,控制方便的优点使窗帘控制开关更加稳定。并且设计的温度检测电路可以实时显示室内当前温度值。 同时,智能项目是一项比较有价值的项目,智能窗帘也有许多问题和功能可以进一步研究,如解决光电开关的滞回特性,可以使用施密特电路来完成。一个完整的毕业设计过程,使我掌握了单片机系统和电子操作软件等方面的知识,尤其在动手能力方面有很大的提升,也给今后打下坚实的基础。 本次毕业设计的整个研究与设计过程包括选题、设计以及完善等。首先,在选题方面我查阅了很多与题目相关的资料和课题并且制定了几个详细的设计方案,进行设计的总体规划,从中选出经济,节能并且稳定容易实现的方案,然后将方案落实到设计环节中。其次,在制定的方案基础上运用所学的知识对硬件以及软件进行了设计,并用相关软件进行仿真设计。最后,对设计内容进一步修缮,以求达到最佳设计效果。但是由于个人水平能力有限,论文设计上存在许多不足之处,有待于进一步的改进。所以虽然设计内容完成了基本的功能要求,但是其中还是存在一定欠缺,比如在设计中没有考虑到窗帘工作方式的显示,以及没有添加类似红外遥控的设计等。 34 34 此次设计过程中,在完成设计任务之外也让我系统性地认识和全面地掌握了单片机相关技术,从本次毕业设计中我更加深刻地认识到了理念来源于实际的含义。并且在和老师以及同学就相关问题的互相讨论交流中,我认识到了自己的很多不足,但在这些不足中我又学到了很多知识,使我的综合应用能力有了很大提高。所以在本次毕业设计的实现中,使我对所学的科目进行了综合,让我对所学的知识更加的清楚,我也相信在不久的将来踏入社会,类似这样的设计绝不在少数,只要我们努力学习、勇于实践、勤学好问我们就会懂得以前不明白或不懂得道理,就会很快地成长和成熟起来。我也相信凭着我自强不息勇于拼搏的精神一定能够很快的适应类似设计的需要,适应这个多变的社会,充分发挥长处,朝需要我们的地方不断前进再前进! 35 35 参考文献 [1]石祚生.智能家居系统设计与实现[D].南京邮电大学,2013. [2]熊建桥,薛飙,马远,吴在罗,丁超.拟“向日葵”感光式智能窗帘系统设计[J].机电产品开发与创新,2014(01). [3]常丰.基于STM32F107的智能窗帘控制系统设计[J].电子世界,2013(23). [4]钱云,郑舒予,秦雷.基于ATMEGA16单片机的智能窗帘控制系统设计[J].微计算机信息,2009(29). [5]安森,张彦航,崔文华.基于凌阳61单片机的智能窗帘控制系统设计[J].微处理机, 2012(01). [6]何康旭,张婧婧.基于单片机的智能窗帘控制系统的设计与实现.现代计算机(专业版),2012. [7]孙健.智能家居电动窗帘的设计与实现.机械工程与自动化[J],2012. [8]张振福,张春艳.智能窗帘控制系统的设计[J].电子世界,2014(08). [9]刘守义.单片机应用技术.陕西:西安电子科技大学出版社[M],2007. [10]张鑫.单片机原理及应用(第二版).电子工业出版社[M],2010. [11]姚福安.电子电路设计与实践.济南:山东科学技术出版社[M],2005. [12]何西才,杨静,任力英.实用传感器接口电路实例.北京:中国电力出版社[M],2007. [13]杨亚让.基于AT89C51的窗帘控制系统设计[J].科技通报.2012(06). [14]陈晓燕,庞涛,廉若鑫.基于MCU的多机通信智能窗帘设计[J].测控技术.2012(06). [15]冯娟,李燕君.基于步进电动机的智能电动窗帘设计与实现[J].微特电机. 2014(10). [16]欧阳宇轩.智能窗帘系统设计[J].电子技术与软件工程.2013(15). [17]顾永乐.智能窗帘控制系统的设计[J].数字技术与应用.2013(10). [18]谌容,胡泽,张扯拉,汪维.基于单片机控制的智能光控窗帘系统研究[J].电子世界. 2013(09). [19]Behzad Razavi.Design of Analog CMOS Integrated Circuits[M].2001. [20]Jacob Fraden. Handbook of modern sensor principle Designs and application[M]. Springer New York Heidelberg Dordrecht London. 2010. 36 36 [21]DeitelMH.Visual Basic 6.0 How to Program.Prentice Hall[M].2003. [22]AT89C51 DATA SHEEP Philips Semiconductors 1999.dec. [23]Erika Cota Ffernanda Lima. Synthesis of an 8051-Like Micro-Controller Tolerant to Transient Faults[J]. Theory and Applications. 2001.17, 149–161. 37 37 致谢 经过这么长时间的忙碌,毕业设计和论文已经接近尾声。在毕业设计的过程中,由于经验的缺乏以及知识的局限性,难免有许多考虑不周全的地方,在选题,设计等方面,如果没有导师的督促指导,没有同学们的支持和帮助,单独完成这个设计,其中还是有一定难度的。在论文完稿之际,我想借此机会对在完成毕业设计期间关心、帮助、支持和鼓励过我的老师、同学以及朋友们致以最诚挚的谢意和最衷心的祝福! 首先我要感谢的是我的导师史健芳老师,在完成整个毕业设计的过程中,老师给我提供了很大的帮助,在选题、设计以及修改论文的各个环节里老师给我指出了很多错误,提出了很多宝贵意见,对于设计中存在的问题也是耐心的回答和指导,让我能够顺利的完成毕业设计。在此谨向老师致以诚挚的谢意和崇高的敬意。 其次要感谢的是所有在大学四年中教育指导过我的所有老师,你们传授给我的专业知识是我完成本设计的基础,也是日后踏入工作岗位的重要基石,对于老师们一丝不苟,兢兢业业的精神表示衷心的感谢。 我还要感谢所有关心和支持我学习的朋友和同学们,感谢你们对我的关心、关注和支持。无论是从学习还是生活中他们都给予我很大的帮助,谢谢你们。 最后感谢一直支持我、爱护我的父母,不仅养育了我,给了我经济上的援助,而且还在我最缺乏信心的时候鼓励我,在我情绪低落时安慰我,他们是最无私的,谢谢爸妈! 38 38 GNDVCC4321R21234P26P27CSCH0CH1GNDVCCCLKDODI8765U1VCCP10P11P12P13U2VCCPR1CP30P31P32P33P34CS1S2VCC10KP20P21P22P23S3S4S5S6C110uF1VO2RS3RW45ENP006P017P028P039P0410P0511P0612P071314151610KADC0832VCCVORSRWDEB0DB1DB2DB3DB4DB5BDGB/6VCCBDGB/7GND30pFC3Y112MHz212GANTDADVCCIND22kC50.01uFR5DS18B206VOUTGNDC4470uF1V31212123 234VCCGR11VCCP25DLCD11J1VCCDP30P31光敏电阻LCD1602VCCP00P01P02P03P04P05P06P07123456789P1R310K12345678IN1IN2IN3IN4IN5IN6IN7GNDULN2003OUT1OUT2OUT3OUT4OUT5OUT6OUT7VCC16151413121110912345motoVCC附录A:系统设计原理图 39 39 C2STC89C5230pFU3VCCVCCR44.7KSizeA4Date:File:23P10TitleP30P31P32P33P34RSRWENP27P26P25P24P23P22P21P201234567891011121314151617181920P1.0VCCP1.1P0.0P1.2P0.1P1.3P0.2STC89C52P1.4P0.3P1.5P0.4P1.6P0.5P1.7P0.6RSTP0.7P3.0/RxDEA/VppP3.1/TxDALE/PROGP3.2/INT0PSENP3.3/INT1P2.7P3.4/T0P2.6P3.5/T1P2.5P3.6/WRP2.4P3.7/RDP2.3XTAL2P2.2XTAL1P2.1GNDP2.0BT14039383736353433323130292827262524232221BBVCC3VD11N4007U4SW1J24A132.7685U51234VCC2X1X2GNDDS1302VCC1SCLKI/OCE8765P11P12P13电源3sw-灰色78L05AANumberRevision14-Jun-2015E:\\protel\\智能窗帘控制系统1.DDBSheet of Drawn By:41 23%VSSVDDVEERSRWE123456RSRWEP101P112P123P1345678P3.0/RXDP3.1/TXDP3.2/INT0P3.3/INT1P3.4/T0P3.5/T1P3.6/WRP3.7/RD101112131415RS16RW17EP1.0P1.1P1.2P1.3P1.4P1.5P1.6P1.7AT89C51U5P23P22P21P20+88.876543217B6B5B4B3B2B1BULN2003A7C6C5C4C3C2C1CCOM101112131415169d0d1d2d3d4d5d6d77891011121314D0D1D2D3D4D5D6D7 U381VCC1X1VCC22 X2CRYSTALX23RSTSCLKI/ODS1302C1RP11P13P11P1257622PFU1U4P25P27P26RV1X110k19XTAL1C212M18XTAL222PFR1RESPACK-810k9RSTP0.0/AD0P0.1/AD1P0.2/AD2P0.3/AD3P0.4/AD4P0.5/AD5P0.6/AD6P0.7/AD71234CSCH0CH1GNDADC0832VCCCLKDIDO875639d038d137d236d335d434d533d632d723456789d0d1d2d3d4d5d6d710kR6LCD1LM016LC3P25P26P27293031PSENALEEA10uFP2.0/A8P2.1/A9P2.2/A10P2.3/A11P2.4/A12P2.5/A13P2.6/A14P2.7/A152122232425262728P20P21P22P23附录B:系统设计仿真图 40 40 STEPPER-MOTORR2100R54.7kP10321U2VCCDQGNDDS18B2020.0SW1C5C4220uF0.1uFD2LED-REDSW-DPDT电源模块 附录C:程序清单 智能窗帘.c #include #define uchar unsigned char #define uint unsigned int bit flag_200ms ; bit flag_relay_en; uchar flag_kaig_moshi=0;//开关模式 bit flag_zd_sd; //自动 手动 模式 bit flag_lj_en; //按键连加使能 bit flag_lj_3_en; //按键连3次连加后使能 加的数就越大了 uchar key_time,flag_value; //用做连加的中间变量 bit key_500ms ; uchar menu_shudu = 20; //用来控制连加的速度 uchar value,i; uchar k_shi=1,k_fen=2; //开窗帘时间 uchar g_shi=3,g_fen=4; //关窗帘时间 sbit DO=P2^6; //DO定义为P1口的第4位脚,连接ADC0832DO脚 sbit SCL=P2^7; //SCL定义为P1口的第3位脚,连接ADC0832SCL脚 sbit CS=P2^5; //CS定义为P1口的第4位脚,连接ADC0832CS脚 uchar guanxian,guanxian_set = 4; //光线 void write_eepom(); #include \"eepom52.h\" #include \"key.h\" #include \"ds1302.h\" #include \"lcd1602.h\" #include \"18b20_2lu.h\" #include \"bujindianji.h\" sbit key_jia = P3^1; //加 sbit key_jie = P3^2; //减 /*************写单片机内部EEPOM*************/ void write_eepom() { SectorErase(0x2000); byte_write(0x2000,flag_zd_sd); byte_write(0x2001,k_shi); byte_write(0x2002,k_fen); 41 41 byte_write(0x2003,g_shi); byte_write(0x2004,g_fen); byte_write(0x2009,guanxian_set); byte_write(0x2010,bjdj_value); byte_write(0x2050,a_a); } /*************读单片机内部EEPOM*************/ void read_eepom() { flag_zd_sd = byte_read(0x2000); k_shi = byte_read(0x2001); k_fen = byte_read(0x2002); g_shi = byte_read(0x2003); g_fen = byte_read(0x2004); guanxian_set = byte_read(0x2009); bjdj_value = byte_read(0x2010); a_a = byte_read(0x2050); } /*************初始化EEPROM************/ void init_eepom() //初始化EEPROM { read_eepom(); if(a_a == 0xff) { flag_zd_sd = 1; //模式设置 a_a = 1; k_shi=8; k_fen=2; //开 g_shi=3; g_fen=4; //关 guanxian_set = 4; bjdj_value = 0; write_eepom(); } } #include \"menu.h\" /***************读数模转换数据****************/ //请先了解ADC0832模数转换的串行协议,再来读本函数,主要是对应时序图来理解,本函数是模拟0832的串行协议进行的 // 1 0 0 通道 // 1 1 1 通道 42 42 unsigned char ad0832read(bit SGL,bit ODD) { unsigned char i=0,value=0,value1=0; SCL=0; DO=1; CS=0; //开始 SCL=1; //第一个上升沿 SCL=0; DO=SGL; SCL=1; //第二个上升沿 SCL=0; DO=ODD; SCL=1; //第三个上升沿 SCL=0; //第三个下降沿 DO=1; for(i=0;i<8;i++) { SCL=1; SCL=0; //开始从第四个下降沿接收数据 value<<=1; if(DO) value++; } for(i=0;i<8;i++) { //接收校验数据 value1>>=1; if(DO) value1+=0x80; SCL=1; SCL=0; } CS=1; SCL=1; if(value==value1) //与校验数据比较,正确就返回数据,否则返回0 return value; return 0; } /******************1ms 延时函数*******************/ void delay_1ms(uint q) { uint i,j; 43 43 for(i=0;i /*************定时器0初始化程序***************/ void init_1602_ds1302() { write_sfm2_ds1302(2,4,nian); write_sfm2_ds1302(2,7,yue); write_sfm2_ds1302(2,10,ri); write_sfm2_ds1302(1,4,shi); write_sfm2_ds1302(1,7,fen); write_sfm2_ds1302(1,10,miao); write_sfm1(1,14,week); } /*************定时器0初始化程序***************/ void init_time0() { EA = 1; //开总中断 TMOD = 0X01; //定时器0、工作方式1 ET0 = 1; //开定时器0中断 TR0 = 1; //允许定时器0定时 } /*************手动开关窗帘***************/ void shoudong_kaiguan() //手动开关窗帘 { if(flag_zd_sd == 0) //手动模式 { if(menu_1 == 0) { if(flag_kaig_moshi == 0) { if(key_can == 2) flag_z_f = 1; //手动开窗 if(key_can == 3) flag_z_f = 2; //手动关窗 if(flag_lj_en == 0) flag_z_f = 0; } } } if(flag_kaig_moshi == 0) 44 44 { if(flag_zd_sd == 1) //自动模式 { if(guanxian <= guanxian_set) flag_z_f = 1; //手动开窗 else flag_z_f = 2; //手动关窗 } } } /*********************智能窗帘处理函数***********************/ void zinengchuanglian_dis() //智能窗帘处理函数 { if((miao == 0) && (fen == k_fen) && (shi == k_shi)) //定时开窗帘 { flag_z_f = 1; //开窗帘 flag_kaig_moshi = 1; } if((miao == 0) && (fen == g_fen) && (shi == g_shi)) //定时关窗帘 { flag_z_f = 2; //关窗帘 flag_kaig_moshi = 2; } } void main() { init_eepom(); //初始化EEPROM init_1602(); //lcd1602初始化 init_1602_dis_csf(); //lcd1602初始化显示 init_ds1302_io(); //初始化ds1302Io init_time0(); //初始化定时器 menu_1_break(); //菜单初始界面 init_ds1302(); //ds1302初始化 temperature1 = read1_temp(); //读温度1 delay_1ms(650); while(1) { key(); //按键程序 if(key_can < 10) { 45 45 key_with(); } shoudong_kaiguan(); //手动开关窗帘 if(flag_200ms == 1) { flag_200ms = 0; temperature1 = read1_temp(); //读温度1 环境温度 if(temperature1 >= 99) temperature1 = 99; zinengchuanglian_dis(); //智能窗帘处理函数 guanxian = ad0832read(1,0) * 9.0 / 255; if((menu_1 == 0)) { read_time(); //读时间 init_1602_ds1302(); //显示时钟 write_sfm_18b20(2,13,temperature1); //显示温度 write_sfm1(2,0,guanxian); //显示温度 } } bujindj(); //步进电机函数 } } void time0() interrupt 1 { static uchar value; TH0 = 0X3C; TL0 = 0XB0; //50ms value ++; if(value >= 4) //200ms { value = 0; flag_200ms = 1; } if(flag_lj_en == 1) //按下按键使能 { key_time ++; if(key_time >= menu_shudu) //500ms { key_time = 0; key_500ms = 1; //500ms flag_value ++; 46 46 if(flag_value > 3) { flag_value = 10; flag_lj_3_en = 1; //3次后1.5秒后连加大些 } } } } LCD1602.h #ifndef _LCD1602_H_ #define _LCD1602_H_ #define uchar unsigned char #define uint unsigned int #define data_1602 P0 uchar code table_num[]=\"0123456789abcdefg\"; sbit rs=P3^5; //寄存器选择信号 H:数据寄存器 L:指令寄存器 sbit rw=P3^6; //寄存器选择信号 H:数据寄存器 L:指令寄存器 sbit e =P3^7; //片选信号 下降沿触发 /***********************延时函数************************/ void delay_uint(uint q) { while(q--); } /***********************lcd1602写命令函数************************/ void write_com(uchar com) { e=0; rs=0; rw=0; data_1602=com; delay_uint(10); e=1; delay_uint(50); e=0; } /***********************lcd1602写数据函数************************/ void write_data(uchar dat) { e=0; rs=1; rw=0; 47 47 data_1602=dat; delay_uint(10); e=1; delay_uint(50); e=0; } /***********************lcd1602初始化设置************************/ void init_1602() { write_com(0x38); // write_com(0x0c); write_com(0x06); } /***********************lcd1602上显示两位十进制数************************/ void write_sfm1(uchar hang,uchar add,uchar date) { if(hang==1) write_com(0x80+add); else write_com(0x80+0x40+add); write_data(0x30+date % 10); } /***********************lcd1602上显示两位十进制数************************/ void write_sfm2_ds1302(uchar hang,uchar add,uchar date) { uchar shi,ge; if(hang==1) write_com(0x80+add); else write_com(0x80+0x40+add); shi=date/16; ge=date%16; write_data(table_num[shi]); write_data(table_num[ge]); } /***********************lcd1602上显示这字符函数************************/ void write_string(uchar hang,uchar add,uchar *p) { if(hang==1) write_com(0x80+add); else 48 48 write_com(0x80+0x40+add); while(1) { if(*p == '\\0') break; write_data(*p); p++; } } /***********************lcd1602上显示 两位温度正************************/ void write_sfm_18b20(uchar hang,uchar add,uint date) { if(hang==1) write_com(0x80+add); else write_com(0x80+0x40+add); write_data(0x30+date / 10 % 10); write_data(0x30+date % 10); write_data(0xdf); //度 } /***********************lcd1602清除显示************************/ void clear_1602() { write_string(1,0,\" \"); write_string(2,0,\" \"); } /****************开机液晶显示函数 初始化液晶的内********************************/ void init_1602_dis_csf() { write_string(1,0,\" : : W \"); write_string(2,0,\" 2000- - \"); if(flag_zd_sd == 0) //手动 write_string(1,0,\" sd\"); if(flag_zd_sd == 1) //自动 write_string(1,0,\" zd\"); } #endif DS1302.h #ifndef _DS1302_H_ #define _DS1302_H_ 49 49 负容/****************** ds1302 内部RAM RAM0 1100 000R/W 1读 0写 RAM1 1100 001R/W ....... RAM30 1111 110R/W ********************/ sbit clk = P1^1; //ds1302时钟线定义 sbit io = P1^2; //数据线 sbit rst = P1^3; //复位线 //秒 分 时 日 月 年 星期 uchar code write_add[]={0x80,0x82,0x84,0x86,0x88,0x8c,0x8a}; //uchar code read_add[] ={0x81,0x83,0x85,0x87,0x89,0x8d,0x8b}; //uchar code init_ds[] ={0x55,0x59,0x23,0x01,0x01,0x13,0x13}; uchar miao,fen,shi,ri,yue,week,nian; uchar i; bit open1,open2; /*************写一个数据到对应的地址里***************/ void write_ds1302(uchar add,uchar dat) { rst = 1; //把复位线拿高 for(i=0;i<8;i++) { //低位在前 clk = 0; //时钟线拿低开始写数据 io = add & 0x01; add >>= 1; //把地址右移一位 clk = 1; //时钟线拿高 } for(i=0;i<8;i++) { clk = 0; //时钟线拿低开始写数据 io = dat & 0x01; dat >>= 1; //把数据右移一位 clk = 1; //时钟线拿高 } rst = 0; //复位线合低 clk = 0; io = 0; } /*************从对应的地址读一个数据出来***************/ uchar read_ds1302(uchar add) { 50 50 写地址读地址 uchar value,i; rst = 1; //把复位线拿高 for(i=0;i<8;i++) { //低位在前 clk = 0; //时钟线拿低开始写数据 io = add & 0x01; add >>= 1; //把地址右移一位 clk = 1; //时钟线拿高 } for(i=0;i<8;i++) { clk = 0; //时钟线拿低开始读数据 value >>= 1; if(io == 1) value |= 0x80; clk = 1; //时钟线拿高 } rst = 0; //复位线合低 clk = 0; io = 0; return value; //返回读出来的数据 } /*************把要的时间 年月日 都读出来***************/ void read_time() { miao = read_ds1302(read_add[0]); //读秒 fen = read_ds1302(read_add[1]); //读分 shi = read_ds1302(read_add[2]); //读时 ri = read_ds1302(read_add[3]); //读日 yue = read_ds1302(read_add[4]); //读月 nian = read_ds1302(read_add[5]); //读年 week = read_ds1302(read_add[6]); //读星期 } /*************把要写的时间 年月日 都写入ds1302里***************/ void write_time() { write_ds1302(0x8e,0x00); //打开写保护 write_ds1302(write_add[0],miao); //写秒 write_ds1302(write_add[1],fen); //写分 write_ds1302(write_add[2],shi); //写时 write_ds1302(write_add[3],ri); //写日 51 51 write_ds1302(write_add[4],yue); //写月 write_ds1302(write_add[5],nian); //写星期 write_ds1302(write_add[6],week); //写年 write_ds1302(0x8e,0x80); //关闭写保护 } /*************把数据保存到ds1302 RAM中**0-31*************/ void write_ds1302ram(uchar add,uchar dat) { add <<= 1; //地址是从第二位开始的 add &= 0xfe; //把最低位清零 是写的命令 add |= 0xc0; //地址最高两位为 1 write_ds1302(0x8e,0x00); write_ds1302(add,dat); write_ds1302(0x8e,0x80); } /*************把数据从ds1302 RAM读出来**0-31*************/ uchar read_ds1302ram(uchar add) { add <<= 1; //地址是从第二位开始的 add |= 0x01; //把最高位置1 是读命令 add |= 0xc0; //地址最高两位为 1 return(read_ds1302(add)); } /*************初始化ds1302时间***************/ void init_ds1302() { // uchar i; rst = 0; //第一次读写数据时要把IO品拿低 clk = 0; io = 0; i = read_ds1302ram(30); if(i != 3) { i = 3; write_ds1302ram(30,i); write_ds1302(0x8e,0x00); //打开写保护 for(i=0;i<7;i++) write_ds1302(write_add[i],init_ds[i]); //把最高位值0 允许ds1302工作 write_ds1302(0x8e,0x80); //关写保护 } 52 52 } void init_ds1302_io() { rst = 0; //第一次读写数据时要把IO品拿低 clk = 0; io = 0; } /**********************设置ds1302时间函数**********************/ void set_ds1302time(uchar num,uchar *shi,uchar dat) //调时 { if(num == 1) { *shi+=0x01; if((*shi & 0x0f) >= 0x0a) *shi = (*shi & 0xf0) + 0x10; if(*shi >= dat) *shi = 0; } else { if(*shi == 0x00) *shi = dat; if((*shi & 0x0f) == 0x00) *shi = (*shi | 0x0a) - 0x10; *shi -=0x01 ; } } #endif 18B20_2LU.h #ifndef _18B20_2LU_H_ #define _18B20_2LU_H_ sbit dq1 = P1^0; //18b20 IO口的定义 uint temperature1 ; // /***********************18b20初始化函数*****************************/ void init1_18b20() { bit q; dq1 = 1; //把总线拿高 delay_uint(1); //15us dq1 = 0; //给复位脉冲 delay_uint(80); //750us 53 53 dq1 = 1; //把总线拿高 等待 delay_uint(10); //110us q = dq1; //读取18b20初始化信号 delay_uint(20); //200us dq1 = 1; //把总线拿高 释放总线 } /*************写18b20内的数据***************/ void write1_18b20(uchar dat) { uchar i; for(i=0;i<8;i++) { //写数据是低位开始 dq1 = 0; //把总线拿低写时间隙开始 dq1 = dat & 0x01; //向18b20总线写数据了 delay_uint(5); // 60us dq1 = 1; //释放总线 dat >>= 1; } } /*************读取18b20内的数据***************/ uchar read1_18b20() { uchar i,value; for(i=0;i<8;i++) { dq1 = 0; //把总线拿低读时间隙开始 value >>= 1; //读数据是低位开始 dq1 = 1; //释放总线 if(dq1 == 1) //开始读写数据 value |= 0x80; delay_uint(5); //60us 读一个时间隙最少要保持60us的时间 } return value; //返回数据 } /*********1111****读取温度的值 读出来的是小数***************/ uint read1_temp() { uint value; uchar low; //在读取温度的时候如果中断的太频繁了,就应该把中断给关了,否则会影响到18b20的时序 init1_18b20(); //初始化18b20 54 54 write1_18b20(0xcc); //跳过64位ROM write1_18b20(0x44); //启动一次温度转换命令 delay_uint(50); //500us EA = 0; init1_18b20(); //初始化18b20 write1_18b20(0xcc); //跳过64位ROM write1_18b20(0xbe); //发出读取暂存器命令 low = read1_18b20(); //读温度低字节 value = read1_18b20(); //读温度高字节 EA = 1; value <<= 8; //把温度的高位左移8位 value |= low; //把读出的温度低位放到value的低八位中 value *= 0.0625; //转换到温度值 小数 return value; //返回读出的温度 } #endif BUJINDIANJI.h #ifndef _BUJINDIANJI_H_ #define _BUJINDIANJI_H_ void write_eepom_shoudong(); uchar flag_z_f; //正反标志位 0为顺时钟 1为逆时史上转 unsigned char code zheng[4]={0xf8,0xf4,0xf2,0xf1};//正转表格 unsigned char code fan[4]={0xf1,0xf2,0xf4,0xf8};//反转表格 uint bjdj_value; //步进电机的量 uchar bjdj_zidong; //步进电机的量 自动 void bujindj() //步进电机函数 { static uchar i; if(flag_z_f != 0) { if(flag_z_f == 1) //开 { if(bjdj_value >= 254) { flag_z_f = 0; bjdj_value = 254; P2 = P2 & 0xf0; //让4个IO口都不输出 write_eepom(); //保存 55 55 }else bjdj_value ++; } if(flag_z_f == 2) //关 { if(bjdj_value <= 1) { flag_z_f = 0; bjdj_value = 1; P2 = P2 & 0xf0; //让4个IO口都不输出 write_eepom(); //保存 }else bjdj_value --; } for(i=0;i<4;i++) //4相 { if(flag_z_f == 1) //开 P2=zheng[i];// & (P2 | 0xf0); // else if(flag_z_f == 2)//关 P2=fan[i];// & (P2 | 0xf0); // delay_uint(500); //改变这个参数可以调整电机转速 } } } #endif MENU.h #ifndef _MENU_H_ #define _MENU_H_ #include \"menu_value.h\" #include \"menu_1.h\" void key_exit() { (*key_break)(); // 退出键 } void key_up() { (*key_up_down)(2); // 向上键 } 56 56 void key_down() { (*key_up_down)(1); // 向下键 } void key_sure_1() // 确定键 { menu_1_fun(); } void key_with() { switch(key_can) { case 1: key_sure_1(); // 确定键 break; case 4: key_exit(); // 退出键 break; case 3: key_up(); // 向上键 break; case 2: key_down(); // 向下键 break; default: break; } if(menu_1 == 0) if(key_can == 5) //设置手动还是自动模式 { flag_zd_sd = ~flag_zd_sd; if(flag_zd_sd == 0) //手动 write_string(1,0,\" sd\"); if(flag_zd_sd == 1) //自动 write_string(1,0,\" zd\"); write_eepom(); //保存 flag_kaig_moshi = 0; } } #endif MENU_VALUE.h #ifndef _MENU_VALUE_H_ #define _MENU_VALUE_H_ 57 57 #define uchar unsigned char #define uint unsigned int /****************菜单变量的定义*******************/ uchar menu_1; //第1级菜单变量 uchar menu_2; //第2级菜单变量 uchar menu_3; //第3级菜单变量 uchar menu_4; //第4级菜单变量 uchar menu_5; //第5级菜单变量 uchar menu_i; //做上下键的变量 void (*key_up_down)(uchar n); //定义上下键指针函数 void (*key_shuzi)(uchar n); //定义数字键指针函数 void (*key_break)(void); //定义退出键指针函数 /***********************延时函数************************/ //void delay_uchar(uchar q) //{ // while(q--); //} /***********************空函数************************/ void null() { } /***********************带形参的空函数************************/ void null_1(uchar num) { num = num; } #endif MENU_1.h #ifndef _MENU_1_H_ #define _MENU_1_H_ #include \"lcd1602.h\" #include \"menu_value.h\" #include \"menu_2.h\" void menu_1_n(uchar num); void menu_1_break() //第一级菜单退出函数 { menu_1 = 0; menu_2 = 0; menu_3 = 0; clear_1602(); //清除LCD1602显示 init_1602(); 58 58 init_1602_dis_csf(); //初始化LCD1602显示 key_break = null; //给退出键赋空函数 key_up_down = null_1; //给上下键赋空函数 key_shuzi = null_1; //给数字键赋空函数 } void menu_1_dis() { write_string(1,0,\"1.set-time \"); write_string(2,0,\"2.set-time on-off\"); } void menu_2_dis() { write_string(1,0,\"3.set-LIGHT\"); write_string(2,0,\" \"); } void menu_1_init() //第一级菜单第一项 { menu_1 = 1; menu_2 = 0; //menu._1 = 1; 说明菜单到了第一级第一项 menu_1_dis(); write_com(0x80+0); //将光标移动到秒个位 write_com(0x0f); //显示光标并且闪烁 key_up_down = menu_1_n; //上下键指针函数赋值 key_break = menu_1_break; //退出键指针函数赋值 menu_i = 1; menu_shudu = 20 ; //50ms 的定时、 10就对应500ms 20对应1s } void menu_2_init() //第一级菜单第2项 { menu_1 = 2; menu_2 = 0; //menu._1 = 2; 说明菜单到了第一级第2项 menu_1_dis(); write_com(0x80+0x40); //将光标移动到秒个位 write_com(0x0f); //显示光标并且闪烁 key_up_down = menu_1_n; //上下键指针函数赋值 key_break = menu_1_break; //退出键指针函数赋值 menu_i = 2; menu_shudu = 20 ; //50ms 的定时、 10就对应500ms 20对应1s } void menu_3_init() //第一级菜单第3项 { menu_1 = 3; menu_2 = 0; //menu._1 = 3; 说明菜单到了第一级第3项 59 59 menu_2_dis(); write_com(0x80); //将光标移动到秒个位 write_com(0x0f); //显示光标并且闪烁 key_up_down = menu_1_n; //上下键指针函数赋值 key_break = menu_1_break; //退出键指针函数赋值 menu_i = 3; menu_shudu = 20 ; //50ms 的定时、10就对应500ms 20对应1s } void menu_1_n(uchar num) //上下键的原函数 { if(num == 1) //如果形参为1 则代表是向下键 { menu_i ++; if(menu_i > 3) menu_i = 1; } else //只要形参不为1 则代表是向上键 { menu_i -- ; if(menu_i < 1) menu_i = 2; } switch(menu_i) { case 1: menu_1_init(); break; //3个初始化显示函数调用 case 2: menu_2_init(); break; case 3: menu_3_init(); break; } } /***************************第一级菜单的功能函数****************************/ void menu_1_fun() { switch(menu_1) { case 0: menu_1_init(); break; case 1: menu_1_1_fun(); break; 60 60 case 2: menu_2_1_fun(); break; case 3: menu_3_1_fun(); break; } } #endif MENU.h #ifndef _MENU_2_H_ #define _MENU_2_H_ #include \"menu_value.h\" void menu_1_init(); void menu_2_init(); void menu_3_init(); void menu_1_1_n(uchar num); void menu_1_2_n(uchar num); void menu_1_3_n(uchar num); void menu_1_4_n(uchar num); void menu_1_5_n(uchar num); void menu_1_6_n(uchar num); void menu_1_7_n(uchar num); void menu_2_1_n(uchar num); void menu_2_2_n(uchar num); void menu_2_3_n(uchar num); void menu_2_4_n(uchar num); void menu_3_1_n(uchar num); /**************************_1_1******************************/ void menu_1_1_dis() { write_string(1,0,\" - - W: \"); write_string(2,0,\" 20 - - \"); write_sfm2_ds1302(2,3,nian); write_sfm2_ds1302(2,6,yue); write_sfm2_ds1302(2,9,ri); write_sfm2_ds1302(1,2,shi); write_sfm2_ds1302(1,5,fen); write_sfm2_ds1302(1,8,miao); write_sfm1(1,14,week); } 61 61 void menu_1_1_shudu() { if(flag_lj_3_en == 0) menu_shudu = 10 ; //500ms 加减一次 else menu_shudu = 6; //200ms 加减一次 } void menu_1_1_init() //时 { menu_2 = 1; menu_3 = 0; menu_1_1_dis(); write_com(0x80+2); //将光标移动到秒个位 write_com(0x0f); //显示光标并且闪烁 key_up_down = menu_1_1_n; key_break = menu_1_init; menu_i = 1; menu_shudu = 20 ; //50ms 的定时、 10就对应500ms 20} void menu_1_2_init() //分 { menu_2 = 2; menu_3 = 0; write_com(0x80+5);//将光标移动到秒个位 write_com(0x0f);//显示光标并且闪烁 key_up_down = menu_1_2_n; key_break = menu_1_init; menu_i = 2; menu_shudu = 20 ; //50ms 的定时、 10就对应500ms 20} void menu_1_3_init() //秒 { menu_2 = 3; menu_3 = 0; write_com(0x80+8);//将光标移动到秒个位 write_com(0x0f);//显示光标并且闪烁 key_up_down = menu_1_3_n; key_break = menu_1_init; menu_i = 3; menu_shudu = 20 ; //50ms 的定时、 10就对应500ms 20} void menu_1_4_init() //星期 { menu_2 = 3; menu_3 = 0; 62 62 对应1s 对应1s 对应1s write_sfm1(1,14,week); write_com(0x80+14);//将光标移动到秒个位 write_com(0x0f); //显示光标并且闪烁 key_up_down = menu_1_4_n; key_break = menu_1_init; menu_i = 4; menu_shudu = 20 ; //50ms 的定时、 10就对应500ms 20对应1s } void menu_1_5_init() //年 { menu_2 = 5; menu_3 = 0; write_com(0x80+0x40+3);//将光标移动到秒个位 write_com(0x0f);//显示光标并且闪烁 key_up_down = menu_1_5_n; key_break = menu_1_init; menu_i = 5; menu_shudu = 20 ; //50ms 的定时、 10就对应500ms 20} void menu_1_6_init() //月 { menu_2 = 6; menu_3 = 0; write_sfm2_ds1302(2,6,yue); write_com(0x80+0x40+6);//将光标移动到秒个位 write_com(0x0f);//显示光标并且闪烁 key_up_down = menu_1_6_n; key_break = menu_1_init; menu_i = 6; menu_shudu = 20 ; //50ms 的定时、 10就对应500ms 20} void menu_1_7_init() //日 { menu_2 = 7; menu_3 = 0; write_sfm2_ds1302(2,9,ri); write_com(0x80+0x40+9);//将光标移动到秒个位 write_com(0x0f);//显示光标并且闪烁 key_up_down = menu_1_7_n; key_break = menu_1_init; menu_i = 7; menu_shudu = 20 ; //50ms 的定时、 10就对应500ms 20} void menu_1_1_n(uchar num) //调时 63 63 对应1s 对应1s 对应1s { menu_1_1_shudu(); if(num == 1) { shi+=0x01; if((shi & 0x0f) >= 0x0a) shi = (shi & 0xf0) + 0x10; if(shi >= 0x24) shi = 0; } else { if(shi == 0x00) shi = 0x24; if((shi & 0x0f) == 0x00) shi = (shi | 0x0a) - 0x10; shi -- ; } write_sfm2_ds1302(1,2,shi); write_com(0x80+2); //将光标移动到秒个位 write_com(0x0f); //显示光标并且闪烁 write_time(); } void menu_1_2_n(uchar num) //调分 { menu_1_1_shudu(); if(num == 1) { fen+=0x01; if((fen & 0x0f) >= 0x0a) fen = (fen & 0xf0) + 0x10; if(fen >= 0x60) fen = 0; } else { if(fen == 0x00) fen = 0x5a; if((fen & 0x0f) == 0x00) fen = (fen | 0x0a) - 0x10; fen -- ; 64 64 } write_sfm2_ds1302(1,5,fen); write_com(0x80+5); //将光标移动到秒个位 write_com(0x0f); //显示光标并且闪烁 write_time(); } void menu_1_3_n(uchar num) //调秒 { menu_1_1_shudu(); if(num == 1) { miao+=0x01; if((miao & 0x0f) >= 0x0a) miao = (miao & 0xf0) + 0x10; if(miao >= 0x60) miao = 0; } else { if(miao == 0x00) miao = 0x5a; if((miao & 0x0f) == 0x00) miao = (miao | 0x0a) - 0x10; miao -- ; } write_sfm2_ds1302(1,8,miao); write_com(0x80+8); //将光标移动到秒个位 write_com(0x0f); //显示光标并且闪烁 write_time(); } void menu_1_4_n(uchar num) //调星期 { menu_1_1_shudu(); if(num == 1) { week+=0x01; if((week & 0x0f) >= 0x0a) week = (week & 0xf0) + 0x10; if(week >= 0x08) week = 1; } 65 65 else { if(week == 0x01) week = 0x08; if((week & 0x0f) == 0x00) week = (week | 0x0a) - 0x10; week -- ; } write_sfm1(1,14,week); write_com(0x80+14); //将光标移动 write_com(0x0f); //显示光标并且闪烁 write_time(); } void menu_1_5_n(uchar num) //调年 { menu_1_1_shudu(); if(num == 1) { nian+=0x01; if((nian & 0x0f) >= 0x0a) nian = (nian & 0xf0) + 0x10; if(nian >= 0x9a) nian = 1; } else { if(nian == 0x01) nian = 0x9a; if((nian & 0x0f) == 0x00) nian = (nian | 0x0a) - 0x10; nian -- ; } write_sfm2_ds1302(2,3,nian); write_com(0x80+0x40+3); //将光标移动到秒个位 write_com(0x0f); //显示光标并且闪烁 write_time(); } void menu_1_6_n(uchar num) //调月 { menu_1_1_shudu(); if(num == 1) 66 66 { yue+=0x01; if((yue & 0x0f) >= 0x0a) yue = (yue & 0xf0) + 0x10; if(yue >= 0x13) yue = 1; } else { if(yue == 0x01) yue = 0x13; if((yue & 0x0f) == 0x00) yue = (yue | 0x0a) - 0x10; yue -- ; } write_sfm2_ds1302(2,6,yue); write_com(0x80+0x40+6); //将光标移动到秒个位 write_com(0x0f); //显示光标并且闪烁 write_time(); } void menu_1_7_n(uchar num) //调日 { menu_1_1_shudu(); if(num == 1) { ri+=0x01; if((ri & 0x0f) >= 0x0a) ri = (ri & 0xf0) + 0x10; if(ri >= 0x32) ri = 0; } else { if(ri == 0x01) ri = 0x32; if((ri & 0x0f) == 0x00) ri = (ri | 0x0a) - 0x10; ri -- ; } write_sfm2_ds1302(2,9,ri); write_com(0x80+0x40+9); //将光标移动到秒个位 67 67 write_com(0x0f); //显示光标并且闪烁 write_time(); } void menu_1_1_fun() { switch(menu_i) { case 1: menu_1_1_init(); break; case 2: menu_1_2_init(); break; case 3: menu_1_3_init(); break; case 4: menu_1_4_init(); break; case 5: menu_1_5_init(); break; case 6: menu_1_6_init(); break; case 7: menu_1_7_init(); break; } menu_i ++; if(menu_i > 7) menu_i = 1; } /**************_2_1_ 设置开关时间***********/ void menu_2_1_dis() { write_string(1,0,\" OFF 00:00 \"); write_string(2,0,\" ON 00:00 \"); } void menu_2_1_init() //开时 { menu_2 = 1; menu_3 = 0; menu_2_1_dis(); write_sfm2_ds1302(1,5,k_shi); //显示开时 write_sfm2_ds1302(1,8,k_fen); //显示开分 write_sfm2_ds1302(2,5,g_shi); //显示关时 write_sfm2_ds1302(2,8,g_fen); //显示关分 key_up_down = menu_2_1_n; key_break = menu_2_init; write_com(0x80+5); //将光标移动到秒个位 write_com(0x0f); //显示光标并且闪烁 menu_i = 1; } void menu_2_2_init() //开分 { 68 68 menu_2 = 2; menu_3 = 0; write_com(0x80+8); //将光标移动到秒个位 write_com(0x0f); //显示光标并且闪烁 key_up_down = menu_2_2_n; key_break = menu_2_init; menu_i = 2; } void menu_2_3_init() //关时 { menu_2 = 3; menu_3 = 0; write_com(0x80+0x40+5); //将光标移动到秒个位 write_com(0x0f); //显示光标并且闪烁 key_up_down = menu_2_3_n; key_break = menu_2_init; menu_i = 3; } void menu_2_4_init() //关分 { menu_2 = 4; menu_3 = 0; write_com(0x80+0X40+8); //将光标移动到秒个位 write_com(0x0f); //显示光标并且闪烁 key_up_down = menu_2_4_n; key_break = menu_2_init; menu_i = 4; } void menu_2_1_n(uchar num) //开时 { menu_1_1_shudu(); set_ds1302time(num,&k_shi,0x24) ; write_sfm2_ds1302(1,5,k_shi); //显示开时 write_com(0x80+5); //将光标移动到秒个位 write_com(0x0f); //显示光标并且闪烁 write_eepom(); //保存设置 } void menu_2_2_n(uchar num) //开分 { menu_1_1_shudu(); set_ds1302time(num,&k_fen,0x60) ; write_sfm2_ds1302(1,8,k_fen); //显示开分 write_com(0x80+8); //将光标移动到秒个位 write_com(0x0f); //显示光标并且闪烁 69 69 write_eepom(); //保存设置 } void menu_2_3_n(uchar num) //关时 { menu_1_1_shudu(); set_ds1302time(num,&g_shi,0x24) ; write_sfm2_ds1302(2,5,g_shi); //显示关时 write_sfm2_ds1302(2,8,g_fen); //显示关分 write_com(0x80+0x40+5); //将光标移动到秒个位 write_com(0x0f); //显示光标并且闪烁 write_eepom(); //保存设置 } void menu_2_4_n(uchar num) //关分 { menu_1_1_shudu(); set_ds1302time(num,&g_fen,0x60) ; write_sfm2_ds1302(2,8,g_fen); //显示关分 write_com(0x80+0x40+8); //将光标移动到秒个位 write_com(0x0f); //显示光标并且闪烁 write_eepom(); //保存设置 } void menu_2_1_fun() { menu_2 ++; if(menu_2 > 4) menu_2 = 1; switch(menu_2) { case 1: menu_2_1_init(); break; case 2: menu_2_2_init(); break; case 3: menu_2_3_init(); break; case 4: menu_2_4_init(); break; } } /**************_3_1_ 设置光线等级***********/ void menu_3_1_dis() { write_string(1,0,\" Set Guanxian \"); write_string(2,0,\" \"); } 70 70 void menu_3_1_init() //开时 { menu_2 = 1; menu_3 = 0; menu_3_1_dis(); key_up_down = menu_3_1_n; key_break = menu_3_init; write_sfm1(2,7,guanxian_set); //显示光线等级度 write_com(0x0c); //关光标 menu_i = 1; } void menu_3_1_n(uchar num) // 设置光线 { menu_1_1_shudu(); if(num == 1) //加光线等级 { guanxian_set ++ ; if(guanxian_set > 9) guanxian_set = 9; } else //减光线等级 { if(guanxian_set < 1) guanxian_set = 1; guanxian_set -- ; } write_sfm1(2,7,guanxian_set); //显示光线等级度 write_eepom(); //保存数据 } void menu_3_1_fun() { switch(menu_2) { case 0: menu_3_1_init(); break; case 1: menu_3_1_init(); break; } } #endif KEY.h #ifndef _KEY_H_ #define _KEY_H_ #include \"lcd1602.h\" 71 71 #define key_io P3 //按键IO口的宏定义 uchar key_can; //按键值的变量 void key() { static uchar key_new = 0,key_old = 0,key_value = 0; key_io |= 0x1f; if(key_new == 0) //按键松开 { if((key_io & 0x1f) == 0x1f) key_value ++; else key_value = 0; if(key_value >= 5) //按键松开松手检测 { key_value = 0; key_new = 1; flag_lj_en = 0; //关闭连加使能 flag_lj_3_en = 0; //关闭3秒后使能 flag_value = 0; //清零 key_time = 0; // write_eepom(); //保存 } } else { if((key_io & 0x1f) != 0x1f) //按键按下 key_value ++; else key_value =0; if(key_value >= 2) //按键按下消抖 { key_value = 0; key_new = 0; flag_lj_en = 1; //连加使能 } } key_can = 20; if(key_500ms == 1) { key_500ms = 0; key_new = 0; 72 72 key_old = 1; } if((key_new == 0) && (key_old == 1)) { switch(key_io & 0x1f) { case 0x1e: key_can = 5; break; //得到按键值 case 0x1d: key_can = 4; break; case 0x1b: key_can = 3; break; case 0x17: key_can = 2; break; case 0x0f: key_can = 1; break; } flag_kaig_moshi = 0; // write_sfm1(1,0,key_can); } key_old = key_new; } #endif 73 73 得到按键值 得到按键值 得到按键值 得到按键值 // // // // 因篇幅问题不能全部显示,请点此查看更多更全内容for(j=0;j<120;j++); }