[计算机硬件及网络]液晶显示电冰箱温控器报告
常州信息职业技术学院
智能电子产品综合项目实践
设计报告
2011 — 2012 学年 第 二 学期
项目: 液晶显示电冰箱温控器的设计与实现 班级: *****
学号: ****** 姓名: ** 授课教师: **
制定日期: 2012 年 6 月 20 日
目 录
摘要((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((1
第一章 总体设计
1.1 背景((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((2 1.2 系统功能描述((((((((((((((((((((((((((((((((((((((((((((((((((((2 1.3 系统总体结构((((((((((((((((((((((((((((((((((((((((((((((((((((3
第二章 硬件系统的设计
2.1微处理器(单片机)((((((((((((((((((((((((((((((((((((((((((((((((4 2.2温度传感器DS18B20(((((((((((((((((((((((((((((((((((((((((((((((4 2.3液晶显示模块TG12864B(((((((((((((((((((((((((((((((((((((((((((5 2.4定时器((((((((((((((((((((((((((((((((((((((((((((((((((((((((((6 2.5功能按键((((((((((((((((((((((((((((((((((((((((((((((((((((((((7 2.6原理图((((((((((((((((((((((((((((((((((((((((((((((((((((((((((8
第三章 系统的软件的设计
3.1 液晶显示模块((((((((((((((((((((((((((((((((((((((((((((((((((9 3.2 温度传感器((((((((((((((((((((((((((((((((((((((((((((((((((((9 3.3压缩机状态((((((((((((((((((((((((((((((((((((((((((((((((((((10 3.4 总结构框图(((((((((((((((((((((((((((((((((((((((((((((((((((10 第四章 程序调试与运行
4.1 调试方法(((((((((((((((((((((((((((((((((((((((((((((((((((((((12 4.2 调试过程中遇到的问
以及解决(((((((((((((((((((((((((((((((((((12
第五章 设计小结((((((((((((((((((((((((((((((((((((((((((((((((((14
附录((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((15
摘要
随着集成电路技术的发展,单片微型计算机的功能也不断增强,许多高性能的新型机种不断涌现出来。单片机以其功能强、体积小、可靠性高、造价低和开发周期短等优点,称为自动化和各个测控领域中广泛应用的器件,在工业生产中称为必不可少的器件,尤其在日常生活中发挥的作用也越来越大。人们对家用电冰箱的控制功能越来越高,这对电冰箱控制器提出了更高的要求。多功能,智能化是其发展方向之一,传统的机器控制,简单的电子控制已经难以满足发展的要求。而采用基于单片机温度控制系统,不仅可大大缩短设计新产品的时间,同时只要增加少许外围器件在软件设计方面就能实现功能的扩展,以及智能化方面的提高,因此可最大限度地节约成本。本文即为基于单片机的电冰箱温度控制系统。
目前市场销售的双门直冷式电冰箱,含有冷冻室和冷藏室,冷冻室通常用于冷冻的温度为-6,-18?;冷藏室用于在相对冷冻室较高的温度下存放食品,要求有一定的保鲜作用,不能冻伤食品,室温一般为0,10?.
传统的电冰箱温度一般是由冷藏室控制,冷藏室、冷冻室的不同温度是通过调节蒸发器在两室的面积大小来实现的,温度调节完全依靠压缩机的开停来控制.但是冰箱内的温度受诸多因素的影响,如放入冰箱物品初始温度的高低、存放品的散热特性及热容量、物品在冰箱的充满率、环境温度的高低、开门的频繁程度等.因此对这种受控参数及随机因素很多的温度控制,既难以建立一个
的数学模型,也无法用传统的PID调节来实现.一台品质优良的电冰箱应该具有较高的温度控制精度,同时又有最优的节能效果,而为了达到这一设计要求采用模糊控制技术无疑是最佳的选择。
1
第一章 总体设计方案
1.1背景
随着技术的发展,目前有些冰箱采用电脑只能温控及LCD(或LED)箱门外温度显示。所谓智能温控就是通过感温头精确感应,把冰箱内温度的变化传递给中央控制芯片,由芯片控制制冷系统使冰箱内温度达到显示屏上设定值,使用者只需要根据食物的种类不同设定不同的温度即可,以此达到最大的保鲜程度。
传统的电冰箱的冷藏室温控器旋钮一般有7个数字,这些数字并不
示冰箱内具体的温度值,而是表示所控制的温度档位。数字越小,箱内温度越高。随着人们的生活水平的提高,对冰箱的控制功能要求越来越高,这对电冰箱控制器提出了更高的要求,传统冰箱的温控器也就无法满足人们的需求了。因此,能够实现精确控制温度、方便的设定和修改并且能够实时显示当前温度是非常重要的。 1.2总体功能
液晶显示电冰箱温控器的设计是以单片机AT89C51作为核心控制器,利用DALAS一线式温度传感器DS18B20实现对电冰箱内冷藏室和冷冻室的温度采集。通过按键可以对电冰箱内冷藏室和冷冻室的温度进行预先设定。当电冰箱内的温度值高于用户设定的温度值时,系统将由单片机控制继电器自动开启压缩机进行制冷,使冰箱内温度自动降温,当电冰箱内的温度值低于设定温度值时,系统将由单片机控制继电器自动关闭压缩机停止制冷,以此来自动实现电冰箱内温度的自动调节。同时相关的状态信息要在点阵汉字液晶屏上实时地显示。
具体显示
有:
1、实时时钟:**:**:**。
2、冷藏室温度:**.*?。
3、冷冻室温度:—**.*?。
4(压缩:开或关。
5、冰箱外环境温度:**.*?。
6、按键预置的温度值(冷藏室温度、冷冻室温度)。
2
1.3 总体框图
使用定
时器,实
现实时
时间自
动走时
通过按键加减TG12864B预设冷藏室和 液晶屏显示冷冻室温度, 冷藏室、冷与冷藏室、冷单片机80C51 冻室温度和冻室温度相比室外温度。 较,决定压缩
机的开或关
温度传感器
DS18B20调
节冷藏室、
冷冻室当前
温度和室外
温度
图1.3
图2.1 AT89S52 图2.2 AT89S51实物图(基本与AT89S52一样)
3
第二章 硬件系统的设计
2.1 微处理器(单片机)
AT89S52是美国ATMEL公司生产的低功耗,高性能CMOS 8位单片机,片内含4k bytes的可系统编程的Flash只读程序存储器,器件采用ATMEL公司的高密度、非易失性存储技术生产,兼容标准8051指令系统及引脚。它集Flash程序存储器既可在线编程(ISP)也可用传统方法进行编程及通用8位微处理器于单片芯片中。
AT89S52提供以下标准功能:8k字节Flash闪速存储器,256字节内部RAM, 32个I/O口线,看门狗(WDT),两个数据指针,三个16位定时/计数器,一个6向量两级中断结构,一个全双工串行通信口,片内振荡器及时钟电路。同时,AT89S52可降至0Hz的静态逻辑操作,并支持两种软件可选的节电工作模式。空闲方式停止CPU的工作,但允许RAM,定时/计数器,串行通信口及中断系统继续工作。掉电方式保存RAM中的内容,但振荡器停止工作并禁止其它所有部件工作直到下一个硬件复位。
AT89S52的引脚图和实物图分别如上图2.1和图2.2所示。 2.2 温度传感器DS18B20
2.2.1 DS18B20(如图2.2.1)是美国DALLAS公司推出的数字温
度传感器,传感器及相关的数字转换电路都被集成到了一起,外形如同一只三极管,具有微型化、低耗能、高性能、抗干扰能力强等优点;独特的单线接口方式,DS18B20在与微处理器连接时
的双向通讯;每仅需要一条I/O口线即可实现微处理器与DS18B20
片DA18B20均有唯一的产品序列号,所以允许在单总线上挂接数
十至百片温度传感器,这样可以非常方便地构成多路温度测量系统。
2.2.2 DS18B20的特点: 图2.2.1
(1)适应电压范围宽,电压范围:3.0-5.5V,在寄生电源方式下可以由数据线供电;
(2)DS18B20支持多点组网功能,多个DS18B20可以并联在唯一的三线上,实
4
现组网多点测量。
(3)DS18B20在使用中不需要任何外围元件,全部传感元
(4)温度范围-55?,+125?,在-10,+85?时精度为?0.5?;
(5)可编程的分辨率为9,12位,对应的可分辨温度分别为0.5?,0.25?,0.125?,0.0625?,可以实现高精度测温;在9位分辨率时最多在93.75ms内把温度转换为数字,12位分辨率时最多在750ms内把温度值转换为数字,速度更快。
(7)测量结果直接输出数字温度信号,以“一线总线”串行传送给CPU,同时可以传送CRC校验码,具有极强的抗干扰纠错能力;
(8)负压特性:电源极性接反时,芯片不会因为发热而烧毁,但是不能正常工作。
2.2.3 单片机与DS18B20的接口电路(如图2.2.3)
图2.2.3 单片机与DS18B20的接口电路
2.3 液晶显示模块TG12864B
TG12864B点阵液晶屏(如图2.3.1)
显示模块是由128*64个液晶屏显示点组
合的一个阵列,每个显示点对应一位二进
制数,1表示点亮,0表示灭,储存这些点
阵信息的RAM称为显示数据存储器,为了
在屏幕指定位置显示某个图形或字符,需
要将相应的点阵信息写入到DDRAM相应的
单元中。 图 2.3.1
TG12864B液晶屏实际上是由左右两块独立的64*64点阵液晶屏拼接而成,
5
图2-4
每半屏有一个8*64*8bitDDRAM,左右半屏驱动电路及存储分别有片选信号CS1和CS2选择。
显示点在64*64液晶屏上的位置由行号(0~63)与列号(0~63)确定。DDRAM
)和列地址(0~63)确定。每个存储单元的8位中某个存储单元由页地址(0~7
二进制数对应屏幕上同一列的8个点阵。
其引脚功能说明如表2.3.2所示
管脚号 管脚 引脚说明
1 V电源地 SS
2 V DD 电源正极(+5V)。使用可变电阻调整,通常接地。
3 VO 液晶显示器对比试调整端
4 D/I 数据 /指令选择:当D/I为高电平时,DB0~DB7为显示数据
当D/I为低电平时,DB0~DB7为指令数据
5 R/W 读 /写选择:当R/W为高电平(即R/W=1)时,从液晶模块
读数据
当R/W为低电平(即R/W=0)时,将数据写入液晶模块
6 E 读写使能,高电平有效,下降沿锁定数据
DB0~DB7 7,14 双向数据总线的第0—7位共8位并行数据总线
15 CS1 片选择信号,高电平时选择前64列
16 CS2 片选择信号,高电平时选择后64列
17 RST 复位信号,低电平有效
18 V LCD驱动电源(,10V) EE
19 BLA 背光电源, LED+
20 BLK 背光电源, LED-
表2.3.2
2.4 定时器
在51系列单片机中有两个16位的加法计数器,分别叫做T0和T1.它们在计数脉冲的作用下,其计数值不断加1,在此过程中,计数器可能产生溢出(溢出是指计数器的计数值全为“1”时,在计数脉冲的作用下,全部归0的动作),产生溢出后,可以向CPU发出中断请求。计数脉冲可以来源于系统时钟或外部电路。如果计数脉冲来自系统时钟,称之为”定时器”,每个机器周期(一个机器周期由12个时钟周期组成)计数器加1;如果计数脉冲来自外部电路,称之为”计数器”,此时单片机在每个机器周期对T0引脚进行检测。
定时器方式寄存器TMOD用于控制定时器/计数器的工作方式,不具有位寻址能力。TMOD寄存器的高4位用于T1的设定,低4位用于T0的设定,其定义相
6
同,其中:
定时器/计数器T1 定时器/计数器T0
D7 D6 D5 D4 D3 D2 D1 D0 GATE C/T M1 M0 GATE C/T M1 M0 1) M0、M1:选择定时器/计数器的工作方式,T0有4种工作方式,T1有三种工
作方式,00为方式0,01为方式1,10为方式2,11为方式3,由M1,M2设定。
:定时方式/计数方式的选择控制位。C/?T=0,选定时方式,计数脉冲2) C/?T
来自系统时钟的12分频;C/?T=1,选计数方式,计数脉冲来自外部电路(对
于T0来说,由P3.4引脚输入,对于T1来说,由P3.5引脚输入)。 3) GATE:位被称为“门控位”。当GATE=0时,只要TR0=1,与门的输出就为1,
计数开始。如果GATE为1时,只有TR0=1,并且P3.2-1时,才允许计数。
其功能可通过图2.4来分析。
图2.4 定时器/计数器T0的逻辑示意图
2.5 功能按键
本设计中用到了4个按键,分别为K13,K14,K15,K16,通过按键来预设冷藏和冷冻温度值。其定义如下:
#define KSET 0xe0
#define KSET_LONG 0xe1
#define KINC 0xd0
#define KDEC 0xb0
7
#define KDOWN 0x70
2.6 原理图
LCD1LGM12641BS1R
U11CS1D091939XTAL1P0.0/AD02D138CS2P0.1/AD18U5D2373P0.2/AD2GNDD3183637XTAL2P0.3/AD3VCC4D4353.02D0VCCP0.4/AD4DQ6D53415P0.5/AD5GNDD7D1D633V05P0.6/AD66D7932DS18B20D6D2RSTP0.7/AD7DI47U4D5D321R/WP2.0/A832238P2.1/A9VCCD4D4EKSET23-9.022P2.2/A10DQ929241D3D5PSENP2.3/A11DB0GNDKINC302510ALEP2.4/A12D2D63126DS18B20DB1U2:A1EAP2.5/A13KDEC1127D1D774LS04P2.6/A14DB2U3RP128P2.7/A151212KDOWND03RESPACK-8DB3VCC1103.0213P1.0P3.0/RXDDQDB42111P1.1P3.1/TXDGND14312DB5P1.2P3.2/INT0413DS18B2015P1.3P3.3/INT1514DB6P1.4P3.4/T016615P1.5P3.5/T1DB7716P1.6P3.6/WR17817RSTP1.7P3.7/RD18-Vout80C51
开始
以filldata充填液晶屏
初始化液晶屏,复位驱动芯
片,打开显示
在液晶屏的cy(0~3)行,cx(0~7)
列显示汉字字符点阵
N
列号为8,
Y 在右半屏显示 在左半屏显示
求出汉字在屏幕上的起始列
设置汉字的页,列地址,显示汉字
结束
图3.2液晶显示流程图 8
第三章 系统的软件的设计
液晶显示电冰箱温控器含有四个模块,分别是液晶显示模块,温度传感器,定时器走时和主函数,。
3.1 液晶显示模块
液晶显示结果如图3.1所示,第一行为实时时间,第二行为冷藏温度,
图3.1
第三行为冷冻温度,第四行为压缩,开或关,液晶显示流程图如上图3.2。
TG12864B液晶屏显示4行16*16点阵的汉字,每行显示8列,如果列号小于4,则显示在左半屏,否则显示在右半屏。由于一个汉字占用2页,程序首先必须设置上半个汉字的页地址,起始列,并输出16个字节数据,随后设置下半个汉字的页地址、起始列地址,并输出16个字节数据。
3.2 温度传感器
使用三个温度传感器DS18B20实现冷藏室,冷冻室和当前温度的调节与设置,并及时地在液晶屏上显示出来,如下:图3.2.1为三个温度传感器。图3.2.2即为液晶屏上对应的三个温度的显示。
图3.2.1 温度传感器
图3.2.2.
9
3.3 压缩机状态
如果当前冷藏室温度和冷冻室温度中只要有一个温度值大于预设的冷藏室,冷冻室温度时,则压缩机状态为开,如图3.3.1和3.3.2
图3.3.1 图3.3.2
如果当前冷藏室温度和冷冻室温度值都小于预设的冷藏室,冷冻室温度时,则压缩机状态为关,如图3.3.3和图3.3.4。
图3.3.3 图3.3.4 3.4 总流程图
开始
初始化液晶屏,在指定位
置显示汉字
检测传感器的温度值
10
当前温度<0
N Y
求出绝对值
将温度值转换为“XX.X”格式的字符串,去除高
位的“0”字符,在LCD指定位置显示温度值
定时器控制当前时间走时,在屏幕指定位置显示
N 原界面:显示冷短按KSET 藏冷冻室温度 Y
进入预设冷藏室冷冻室温度的界面
温度值加1 按键KINC是否按下
Y N
温度值减1 按键KDEC是否按下
Y N
温度下移 按键KDOWN是否按下
Y N Y
长按KSET N
退出温度设定 N
压缩机状态改变(开或关)
结束
11
第四章 程序调试与运行
4.1 调试方法
我们用Keil uVision2以及Proteus 6 Professional这两个软件调试,在调试中,我们用Keil uVision2编写和调试程序,用Proteus 6 Professional
画电路图,液晶屏的DI接到单片机的P3^4,RW端连接到单片机的P3^5,CS选择屏端连接到单片机的P3^3,E端连接到单片机的P3^6,DB0~DB7显示数据连接到单片的P0^0~P0^7,温度传感器DS18B20的ˉ(RST)端接到单片机的P3^7口,最终将两个软件连接起来,编译并全速运行,看电路图上液晶屏的显示是否正确。
一:检查液晶屏上汉字是否正确显示,如果液晶屏没有正确显示,先检查电路,如果硬件电路图连线没有错误,然后检查程序,用断点或单目进行调试运行,看程序中哪一步出现错误,加以修改。
二:调节温度传感器的温度,检查改变后的温度是否正常显示,当前时间是否正常走时。
三:短按K12进入更改预设温度状态,K13加数值,K14减数值,K15上下移,长按K12键退出设置界面,返回原来界面。检查压缩机状态是否根据温度的变化而变化。
4.2 调试过程中遇到的问题以及解决方法
4.2.1 问题: DS18B20上的温度不能及时地显示在TG12864B液晶屏上。
解决方法:首先检查电路,看是否有因为粗心连错了引脚,检查后发现,由于每个DS18B20都有一个属于自己的序列号,所以要更改protues仿真图中的温度传感器的序列号,修改后,还是不能正常显示,然后通过断点调试,发现定义的温度字节L写成了1,改正后就可以了。
4.2.2 问题:预设的冷藏室温度5?,冷冻室温度-5?,只能显示一个5?,-5?要按KDOWN键后才出现。
解决方法:缺少语句 LCD_DispDat(no*2+4,10,dbuf[1])。 4.2.3 问题:压缩机一直处于开的状态,不能随着温度的改变转变为关。
解决方法:检查相关语句,通过断点调试以及全速运行,发现小数位没有正确移位,编译运行,发现可以正常切换开和关。
4.2.4 问题:实时时间不能正常走时。
解决方法:仔细观察图,其中其它有个地方总是闪,所以试着更改实现走时的时间位置,后来时间就能正常走时了。
4.2.5 问题:在显示界面,时、分、秒显示的行和列有问题。
12
解决方法:修改LCD_DispDat2(7,5+col*3,time[col])使之与前面的内容相对应。
4.2.6 问题:按键无效
解决方法:按键无效,硬件没有问题,那么问题就出现在软件,按键无效,按键键值没有正确读取,单目运行,发现在按键的函数中出现死循环,键值根本没有传递,所以按键无效,更改函数,可以正常使用。
13
第五章 设计小结
这次为期三周的智能电子产品综合项目实践做的是液晶显示电冰箱温控器的设计,它是以单片机80C51为中心,加上液晶显示屏TG12864B,温度传感器DS18B20和定时器构成的,在项目中涉及到了液晶显示,温度传递,定时中断等知识,很好地让我复习了以前的知识,温故而知新,同时也让我将理论知识运用到实践中,领悟到了“纸上得来终觉浅,绝知此事要躬行”的乐趣,让我获益匪浅。
第一周,老师让我们做了几个小项目,目的是让我们回忆,复习一下以前学习的知识,为做液晶显示电冰箱温控器作基础,我通过不断编写和调试渐渐地熟练地掌握了Keil uVision2以及Proteus 6 Professional两个软件的使用,为后面的做项目提供了很多方便。第二周和第三周,老师发给我们这个项目的任务书,要求中最基础的是在液晶显示屏上显示冷藏室、冷冻室温度,这个不怎么难,以前学过,然后就是要把温度传感器DS18B20和液晶显示屏上的冷藏室、冷冻室温度联系起来,实现冷藏室、冷冻室温度随着温度传感器的调节而改变,在运行与调试中,经常出现问题,后来通过对照书上的类似代码查找错误,多次修改尝试,终于成功联系起来了。接着是实时时间正常走时,要使用定时器中断来实现,最后就是实现压缩机的状态开或关的变换,通过将当前冷藏室与冷冻室的温度与预设的温度值相比较,这个有一定的难度,自己调试了好几次都没实现,后来请教老师,老师用断点调试,发现我的小数位没有正确地移动,修改了之后就可以正确地切换开和关了。
通过这次的项目实践,我学到了许多知识,例如液晶显示,温度传感器以及定时器的使用比以前熟练多了,而且在老师的帮助下,学会了断点调试,任何问题只要用这种方法,一步一步地调试和运行,终会找到错误之处,从而对症下药,修改错误,使我们不用做无用功,节省了很多时间,可以说是事半功倍。更重要的是,我认识到了,面对遇到的问题和错误,要冷静从容地应对,不要干着急,或者害怕。老师说的对,遇到问题是好事,可以让我们在解决问题、修改错误中获得知识,提高自己的能力,怕就怕没有问题,那样我们就不会去积极地思考和不断地尝试,只会坐在这儿无所事事,不会提高。所以在今后的日子里,一定要直视问题,冷静从容地面对困难,积极地寻找解决问题的方法,这样才能使自己学到更多的知识,获得提高,从而走向成功。
14
附录
一、Main.C 主函数模块
#include
#define uchar unsigned char #define uint unsigned int
extern void LCD_DispIni(void); extern void LCD_DispFill(uchar filldata);
extern void LCD_DispChar(uchar cy,uchar cx,char dispdata);
extern void LCD_DispStr(uchar cy,uchar cx,char*disp_str);
extern void LCD_DispHZ(uchar cy,uchar cx,uchar dispdata);
extern void LCD_DispHZStr(uchar cy,uchar cx,uchar*disp_str);
extern void gettemp(int temp[]); extern void readid(uchar * id); extern void InitTimer0(void); uchar dp[16]={0,0,1,1,2,3,3,4,5,5,6,6,7,8,8,9}; //小数部分转换 #define KSET 0xe0
#define KSET_LONG 0xe1
#define KINC 0xd0
#define KDEC 0xb0
#define KDOWN 0x70
uint count;
char idata dbuf[2]={5,-5};
uchar idata str[6]={0,0,0,0,0,0}; char cang=5;
char dong=-5;
uchar time[3]={11,59,55};
uchar buf0[]={0,1,2,3,4,0xff}; //冷藏温度
uchar buf1[]={0,5,2,3,4,0xff}; // 冷冻温度
uchar buf2[]={6,7,4,0xff}; //压缩
uchar buf3[]={15,16,11,12,0xff}; //温度设置
uchar buf4[]={10,0xff}; //关
uchar buf5[]={9,0xff}; //开
uchar buf6[]={0,1,14,4,0xff}; //冷藏室
15
uchar buf7[]={0,5,14,4,0xff}; //冷冻室 void delay(uchar t) {uchar i;
while(t--)
for(i=0;i<250;i++); }
void LCD_DispDat(uchar cy,uchar cx,char dat)
{uchar str[4];
bit zf=0;
if(dat<0)
{ zf=1;
dat=-dat;
}
str[1]=dat/10+0x30; //将变量dat转换为2位字符串
str[2]=dat%10+0x30;
str[3]=0; //字符串用0作为结束符
if(zf==1)
{ if(str[1]=='0')
{ str[0]=' ';
str[1]='-';
}
else
str[0]='-';
}
else
{ if(str[0]=='0')
str[1]=' ';
str[0]=' ';
}
LCD_DispStr(cy,cx,str); //显示字符串 }
uchar GetKey(void) {uchar key;
16
uchar t;
if((key=P2&0xf0)==0xf0) return 0xff;
for(t=0;t<5;t++) delay(5);
if((key=P2&0xf0)==0xf0) return 0xff;
while((P2&0xf0)!=0xf0) //检测按键时间
{delay(5);
if(t<250) t++;
}
if((t>100)&&(key==0xE0))
return 0xE1;
return key;
}
void DispTime(void)
{
LCD_DispDat(0,5,time[0]); //时
LCD_DispChar(0,8,':');
LCD_DispDat(0,9,time[1]); //分
LCD_DispChar(0,12,':');
LCD_DispDat(0,13,time[2]); // 秒
}
void EditTemper(void) //修改温度
{uchar no=0;
uchar key;
LCD_DispDat(no*2+2,10,dbuf[0]);
LCD_DispDat(no*2+4,10,dbuf[1]);
while(1)
{key=GetKey();
if(key==KINC) //+
{dbuf[no]++;
LCD_DispDat(no*2+2,10,dbuf[no]);
}
else if(key==KDEC) //-
{
17
dbuf[no]--;
LCD_DispDat(no*2+2,10,dbuf[no]);
}
else if(key==KDOWN)
{
LCD_DispDat(no*2+2,10,dbuf[no]);
no=(no+1)&0x01;
LCD_DispDat(no*2+2,10,dbuf[no]);
}
else if(key==KSET_LONG)
{
cang=dbuf[0];
dong=dbuf[1];
LCD_DispIni();
break;
}
}
}
void main(void)
{ uchar str[6]={0,0,0,0,0,0};
uchar i,key;
int temp_back[2];
int temp[3];
bit zf;
LCD_DispIni();
InitTimer0();
while(1)
{
InitTimer0();
DispTime();
LCD_DispHZStr(1,0,buf0);
LCD_DispHZ(1,7,13);
LCD_DispHZStr(2,0,buf1);
LCD_DispHZ(2,7,13);
18
LCD_DispHZStr(3,0,buf2);
LCD_DispHZ(3,7,13);
key=GetKey();
if(key==KSET)
{
LCD_DispIni();
LCD_DispHZStr(0,2,buf3);
LCD_DispHZStr(1,0,buf6);
LCD_DispHZ(1,7,13);
LCD_DispHZStr(2,0,buf7);
LCD_DispHZ(2,7,13);
EditTemper();
}
gettemp(temp);
for(i=0;i<2;i++)
{
temp_back[i]=temp[i];
temp_back[i]=temp_back[i]>>4;
}
if((temp_back[0]>4;
str[0]=temp[i]/100+0x30;
temp[i]=temp[i]%100;
str[1]=temp[i]/10+0x30;
str[2]=temp[i]%10+0x30;
19
str[3]='.';
if(zf==1)
{ if(str[1]=='0')
{ str[0]=' ';
str[1]='-';
}
else
str[0]='-';
}
else
{ if(str[0]=='0')
{ if(str[1]=='0')
str[1]=' ';
str[0]=' ';
}
}
LCD_DispStr((i*2)+3,9,str);
}
}
}
二、TG12864B.C 液晶显示模块
#include
#include
#include
#define uchar unsigned char #define uint unsigned int sbit LCD_RST= P3^7;
sbit DI = P3^4;
sbit RW = P3^5;
sbit CS = P3^3;
sbit EN = P3^6;
sbit RDY = P0^7;
sfr LCD = 0x80;
#define LCD_DISPON 0x3f
20
#define LCD_STARTROW 0xc0
#define LCD_ADDRSTRY 0xb8
#define LCD_ADDRSTRX 0x40
#define CS1 0
#define CS2 1
void LCD_WrCmd(bit port,uchar cmd)
{ EN=0;
CS=port;
DI=0;
RW=0;
EN=1;
LCD=cmd;
EN=0;
}
void LCD_WrDat(bit port,uchar wrdata)
{ EN=0;
CS=port;
DI=1;
RW=0;
EN=1;
LCD=wrdata;
EN=0;
}
uchar code ASCII_TAB[480] = //0x20~0x7F之间 ASCII码对应的点阵数据
表
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x82, 0x00,
0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x82, 0x44, 0x38, 0x00, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x28, 0x10, 0x7c, 0x10, 0x28,
0x28, 0xfe, 0x28, 0xfe, 0x28, 0x10, 0x10, 0x7c, 0x10, 0x10,
0x48, 0x54, 0xfe, 0x54, 0x24, 0x00, 0xa0, 0x60, 0x00, 0x00,
0x46, 0x26, 0x10, 0xc8, 0xc4, 0x10, 0x10, 0x10, 0x10, 0x10,
0x6c, 0x92, 0xaa, 0x44, 0xa0, 0x00, 0xc0, 0xc0, 0x00, 0x00,
0x00, 0x0a, 0x06, 0x00, 0x00, 0x40, 0x20, 0x10, 0x08, 0x04,
21
0x7C, 0xA2, 0x92, 0x8A, 0x7C, 0x8C, 0x92, 0x92, 0x92, 0x62,
0x00, 0x84, 0xFE, 0x80, 0x00, 0x02, 0x02, 0xFE, 0x02, 0x02,
0x84, 0xC2, 0xA2, 0x92, 0x8C, 0x7E, 0x80, 0x80, 0x80, 0x7E,
0x42, 0x82, 0x8A, 0x96, 0x62, 0x3E, 0x40, 0x80, 0x40, 0x3E,
0x30, 0x28, 0x24, 0xFE, 0x20, 0x7E, 0x80, 0x70, 0x80, 0x7E,
0x4E, 0x8A, 0x8A, 0x8A, 0x72, 0xC6, 0x28, 0x10, 0x28, 0xC6,
0x78, 0x94, 0x92, 0x92, 0x60, 0x0E, 0x10, 0xE0, 0x10, 0x0E,
0x02, 0xE2, 0x12, 0x0A, 0x06, 0xC2, 0xA2, 0x92, 0x8A, 0x86,
0x6C, 0x92, 0x92, 0x92, 0x6C, 0x00, 0xFE, 0x82, 0x82, 0x00,
0x0C, 0x92, 0x92, 0x52, 0x3C, 0x04, 0x08, 0x10, 0x20, 0x40,
0x00, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x82, 0x82, 0xFE, 0x00,
0x00, 0xAC, 0x6C, 0x00, 0x00, 0x08, 0x04, 0x02, 0x04, 0x08,
0x10, 0x28, 0x44, 0x82, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80,
0x28, 0x28, 0x28, 0x28, 0x28, 0x00, 0x02, 0x04, 0x08, 0x00,
0x00, 0x82, 0x44, 0x28, 0x10, 0x40, 0xA8, 0xA8, 0xA8, 0xF0,
0x04, 0x02, 0xA2, 0x12, 0x0C, 0xFE, 0x90, 0x88, 0x88, 0x70,
0x64, 0x92, 0xF2, 0x82, 0x7C, 0x70, 0x88, 0x88, 0x88, 0x40,
0xFC, 0x22, 0x22, 0x22, 0xFC, 0x70, 0x88, 0x88, 0x90, 0xFE,
0xFE, 0x92, 0x92, 0x92, 0x6C, 0x70, 0xA8, 0xA8, 0xA8, 0x30,
0x7C, 0x82, 0x82, 0x82, 0x44, 0x10, 0xFC, 0x12, 0x02, 0x04,
0xFE, 0x82, 0x82, 0x44, 0x38, 0x18, 0xA4, 0xA4, 0xA4, 0x7C,
0xFE, 0x92, 0x92, 0x92, 0x82, 0xFE, 0x10, 0x08, 0x08, 0xF0,
0xFE, 0x12, 0x12, 0x12, 0x02, 0x00, 0x88, 0xFA, 0x80, 0x00,
0x7C, 0x82, 0x92, 0x92, 0xF4, 0x40, 0x80, 0x88, 0x7A, 0x00,
0xFE, 0x10, 0x10, 0x10, 0xFE, 0xFE, 0x20, 0x50, 0x88, 0x00,
0x00, 0x82, 0xFE, 0x82, 0x00, 0x00, 0x82, 0xFE, 0x80, 0x00,
0x40, 0x80, 0x82, 0x7E, 0x02, 0xF8, 0x08, 0x30, 0x08, 0xF8,
0xFE, 0x10, 0x28, 0x44, 0x82, 0xF8, 0x10, 0x08, 0x08, 0xF0,
0xFE, 0x80, 0x80, 0x80, 0x80, 0x70, 0x88, 0x88, 0x88, 0x70,
0xFE, 0x04, 0x18, 0x04, 0xFE, 0xF8, 0x28, 0x28, 0x28, 0x10,
0xFE, 0x08, 0x10, 0x20, 0xFE, 0x10, 0x28, 0x28, 0x30, 0xF8,
0x7C, 0x82, 0x82, 0x82, 0x7C, 0xF8, 0x10, 0x08, 0x08, 0x10,
0xFE, 0x12, 0x12, 0x12, 0x0C, 0x90, 0xA8, 0xA8, 0xA8, 0x40,
0x7C, 0x82, 0xA2, 0x42, 0xBC, 0x08, 0x7E, 0x88, 0x80, 0x40,
0xFE, 0x12, 0x32, 0x52, 0x8C, 0x78, 0x80, 0x80, 0x40, 0xF8,
22
0x38, 0x40, 0x80, 0x40, 0x38, 0x00, 0x10, 0x6C, 0x82, 0x00,
0x78, 0x80, 0x60, 0x80, 0x78, 0x00, 0x00, 0xFE, 0x00, 0x00,
0x88, 0x50, 0x20, 0x50, 0x88, 0x00, 0x82, 0x6C, 0x10, 0x00,
0x18, 0xA0, 0xA0, 0xA0, 0x78, 0x10, 0x10, 0x54, 0x38, 0x10,
0x88, 0xC8, 0xA8, 0x98, 0x88, 0x10, 0x38, 0x54, 0x10, 0x10};
void LCD_DispFill(uchar filldata) { uchar x, y;
LCD_WrCmd(CS1,LCD_STARTROW); //设置左半屏显示起始行为0
LCD_WrCmd(CS2,LCD_STARTROW); //设置右半屏显示起始行为0
for(y=0; y<8; y++) //循环充填8页
{ LCD_WrCmd(CS1,LCD_ADDRSTRY+y); // 设置左半屏页地址
LCD_WrCmd(CS1,LCD_ADDRSTRX); // 设置左半屏列地址
LCD_WrCmd(CS2,LCD_ADDRSTRY+y); // 设置右半屏页地址
LCD_WrCmd(CS2,LCD_ADDRSTRX); // 设置右半屏列地址
for(x=0; x<64; x++) //充填每页的64个单元(列)
{ LCD_WrDat(CS1,filldata);
LCD_WrDat(CS2,filldata);
}
}
}
//液晶模块初始
void LCD_DispIni(void)
{ uint i;
LCD_RST = 0; // 复位驱动芯
for(i=0; i<500; i++);
LCD_RST = 1;
LCD_WrCmd(CS1,LCD_DISPON); // 打开显示
LCD_WrCmd(CS1,LCD_STARTROW); // 设置显示起始行为0
LCD_WrCmd(CS2,LCD_DISPON);
LCD_WrCmd(CS2,LCD_STARTROW);
LCD_DispFill(00); // 清屏
LCD_WrCmd(CS1,LCD_ADDRSTRY+0); // 设置页(字符行)地址
LCD_WrCmd(CS1,LCD_ADDRSTRX+0); // 设置列地址
LCD_WrCmd(CS2,LCD_ADDRSTRY+0);
23
LCD_WrCmd(CS2,LCD_ADDRSTRX+0); }
//在液晶屏的cy(0-7)行、cx(0-15)列显示字符dispdata void LCD_DispChar(uchar cy, uchar cx, char dispdata)
{ uchar code *pch;
uchar i;
bit port;
cy = cy&0x07; // 参数过滤
cx = cx&0x0f;
pch = &ASCII_TAB[(dispdata-0X20)*5]; //指向字符起始列的点阵码
if( (cx&0x08) == 0 ) // 列号cx<8,在左半屏显示
{ port=CS1;
i=cx<<3; //求出该字符在屏幕上的起始列号
}
else // 列号cx>8,在右半屏显示
{ port=CS2;
i = (cx&0x07)<<3; //求出该字符在屏幕上的起始列号
}
LCD_WrCmd(port,LCD_ADDRSTRX+i); // 设置当前列地址
LCD_WrCmd(port,LCD_ADDRSTRY+cy); // 设置当前页地址
for(i=0; i<5; i++); //延时
LCD_WrDat(port,0x00); // 显示一列空格
for(i=0; i<5; i++) //送出字符的5列点阵码
{ LCD_WrDat(port,*pch);
pch++;
}
LCD_WrDat(port,0x00); //显示一列空格
for(i=0; i<5; i++);
LCD_WrDat(port,0x00); }
//在液晶屏的cy(0-7)行、cx(0-15)列显示字符disp_str void LCD_DispStr(uchar cy, uchar cx, char *disp_str)
{ while( *disp_str != '\0')
{ cy = cy&0x07; // 参数过滤
cx = cx&0x0f;
24
LCD_DispChar(cy, cx, *disp_str); // 显示字符
disp_str++; // 指向下一字符数据
cx++;
if(cx>15) cy++; // 指向下一显示行
}
}
uchar code HZTAB[]=
{
0x02,0x1C,0xC8,0x30,0x40,0x20,0x10,0x0C,
0x23,0xC4,0x08,0x10,0x30,0x60,0x20,0x00,
0x02,0x7E,0x01,0x00,0x01,0x01,0x01,0x09,
0x11,0x71,0x29,0x07,0x01,0x00,0x00,0x00,/*"冷",0*/
0x02,0xE2,0x82,0xF2,0x12,0xDF,0x52,0xD2,
0x52,0x17,0xFA,0x16,0xDA,0x92,0x12,0x00,
0x10,0x8E,0x62,0x1F,0x00,0x1F,0x15,0x1D,
0x57,0x20,0x13,0x0C,0x33,0x40,0x30,0x00,/*"藏",1*/
0x10,0x21,0x86,0x70,0x00,0x7E,0x4A,0x4A,
0x4A,0x4A,0x4A,0x7E,0x00,0x00,0x00,0x00,
0x02,0xFE,0x01,0x40,0x7F,0x41,0x41,0x7F,
0x41,0x41,0x7F,0x41,0x41,0x7F,0x40,0x00,/*"温",2*/
0x00,0x00,0xFC,0x04,0x24,0x24,0xFC,0xA5,
0xA6,0xA4,0xFC,0x24,0x24,0x24,0x04,0x00,
0x80,0x60,0x1F,0x80,0x80,0x42,0x46,0x2A,
0x12,0x12,0x2A,0x26,0x42,0xC0,0x40,0x00,/*"度",3*/
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x36,0x36,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*":",4*/
0x02,0x04,0xCC,0x30,0x84,0xC4,0xA4,0x9C,
0x87,0xF4,0x84,0x84,0xC4,0x84,0x04,0x00,
0x02,0xFE,0x01,0x40,0x20,0x10,0x0E,0x44,
0x80,0x7F,0x00,0x02,0x0C,0x38,0x10,0x00,/*"冻",5*/
0x00,0x00,0xFE,0x02,0x42,0x42,0x42,0x42,
0xFA,0x42,0x42,0x42,0x62,0x42,0x02,0x00,
25
0x20,0x18,0x27,0x20,0x20,0x20,0x20,0x20,
0x3F,0x20,0x21,0x2E,0x24,0x20,0x20,0x00,/*"压",6*/
0x20,0x30,0xAC,0x67,0x22,0x10,0x8C,0x64,
0x04,0xA5,0xA6,0xE4,0xA4,0xAC,0x04,0x00,
0x22,0x23,0x32,0x12,0x12,0x01,0x7F,0x00,
0x00,0x7F,0x24,0x24,0x24,0x7F,0x00,0x00,/*"缩",7*/
0x08,0x08,0xC8,0xFF,0x48,0x88,0x08,0x00,
0xFE,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,
0x04,0x03,0x00,0xFF,0x00,0x41,0x30,0x0C,
0x03,0x00,0x00,0x00,0x3F,0x40,0x78,0x00,/*"机",8*/
0x40,0x42,0x42,0x42,0x42,0xFE,0x42,0x42,
0x42,0x42,0xFE,0x42,0x42,0x42,0x42,0x00,
0x00,0x40,0x20,0x10,0x0C,0x03,0x00,0x00,
0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,/*"开",9*/
0x00,0x10,0x10,0x10,0x11,0x1E,0x14,0xF0,
0x10,0x18,0x17,0x12,0x18,0x10,0x00,0x00,
0x01,0x81,0x41,0x21,0x11,0x09,0x05,0x03,
0x05,0x09,0x31,0x61,0xC1,0x41,0x01,0x00,/*"关",10*/
0x40,0x20,0xE2,0x04,0x00,0x40,0x20,0x9C,
0x82,0x82,0xBE,0x20,0x20,0x00,0x00,0x00,
0x00,0x00,0x1F,0x08,0x24,0x20,0x11,0x0A,
0x04,0x0A,0x11,0x30,0x20,0x20,0x20,0x00,/*"设",11*/
0x00,0x00,0x00,0x4C,0x54,0x54,0xFA,0xAA,
0xAE,0xAA,0x2A,0x26,0x00,0x00,0x00,0x00,
0x00,0x20,0x20,0x20,0x20,0x3F,0x2A,0x2A,
0x20,0x1F,0x10,0x10,0x10,0x10,0x00,0x00,/*"置",12*/
0x00,0x0E,0x0A,0x0E,0xE0,0x10,0x08,0x04,
0x04,0x04,0x04,0x04,0x08,0x38,0x00,0x00,
0x00,0x00,0x00,0x00,0x03,0x04,0x08,0x10,
0x10,0x10,0x10,0x10,0x08,0x04,0x00,0x00,/*"?",13*/
0x00,0x10,0x2C,0x24,0xA4,0x64,0x25,0x26,
0x24,0x24,0xA4,0x24,0x34,0x2C,0x04,0x00,
0x40,0x40,0x48,0x49,0x49,0x49,0x49,0x7F,
0x49,0x49,0x49,0x4B,0x48,0x40,0x40,0x00,/*"室",14*/
0x20,0x40,0x04,0x08,0x00,0x0C,0x34,0x54,
26
0x4A,0x2A,0xB2,0x8E,0x00,0x00,0x00,0x00,
0x00,0x18,0x06,0x11,0x10,0x1F,0x11,0x1F,
0x09,0x0F,0x08,0x0F,0x08,0x08,0x00,0x00,/*"温",15*/
0x00,0x00,0x00,0xF8,0x08,0x28,0xF8,0xA9,
0xA6,0x7C,0x14,0x14,0x00,0x00,0x00,0x00,
0x20,0x18,0x06,0x21,0x20,0x22,0x16,0x0A,
0x09,0x17,0x30,0x20,0x20,0x20,0x20,0x00/*"度",16*/
};
void LCD_DispHZ(uchar cy,uchar cx,uchar dispdata) { uchar code * pdat;
uchar i,s,page;
bit port;
cy = cy&0x03; //参数过滤
cx = cx&0x07;
pdat = &HZTAB[dispdata*32];
if((cx&0x04) == 0) //如果在左半屏显
{ port = 0;
s = cx<<4; //求出该汉字在屏幕上的起始列
}
else //在右半屏显示
{ port=1;
s = (cx<<4)-64; //求出该汉字在屏幕上的起始列
}
for(page=0;page<2;page++) //每个汉字2页
{ LCD_WrCmd(port,LCD_ADDRSTRX + s); //设置当前列地址
LCD_WrCmd(port,LCD_ADDRSTRY + (cy<<1) + page);
for(i=0;i<5;i++);
for(i=0;i<16;i++) //每个汉字16列
{ LCD_WrDat(port,* pdat); //发送数据
pdat++;
}
for(i=0;i<5;i++);
}
}
27
void LCD_DispHZStr(uchar cy,uchar cx,uchar * disp_str)
{ while( * disp_str!=0xff)
{ cy = cy&0x03;
cx = cx&0x07; //参数过滤
LCD_DispHZ(cy,cx, * disp_str); //显示汉字
disp_str++; //指向下一个汉
cx++; //列号加1
if(cx>7)
{ cy++; //一行汉字显示完,行号
cx=0;
}
}
}
三、DS18B20.C 温度传感器模块
#define uchar unsigned char #define uint unsigned int #include
#include
sbit DQ=P1^0; //DS18B20的数据线
bdata uchar dat; //用于数据收发
sbit dat0=dat^0; //变量dat的最低
sbit dat7=dat^7; //变量dat的最高
uchar code id[3][8]={{0x28,0x30,0xc5,0xb8,0x00,0x00,0x00,0x8e},
{0x28,0x31,0xc5,0xb8,0x00,0x00,0x00,0xb9},
{0x28,0x32,0xc5,0xb8,0x00,0x00,0x00,0xe0}};
void delay15(uchar n) //15s延时函数
{ do
{
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
28
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
n--;
}
while(n);
}
void late()
{ uchar i;
for(i=0;i<200;i++)delay15(200);
}
bit reset(void) //初始化DS18B20
{ bit err;
DQ=0; //在数据线上产生600?s的低电平
delay15(40);
DQ=1; //数据线拉高
delay15(4); //延时60?s
err=DQ; //读取数据线状态,err=0:复位成功
delay15(18); // err=1:复位失败
return(err);
}
void wrbyte(uchar d) //向DS18B20写入一个字节
{ uchar i;
dat=d;
for(i=8;i>0;i--) //循环写8位(先低位,后高位)
{ DQ=0; //产生15?s的负脉冲
delay15(1);
DQ=dat0; //将当前数据位送数据线
dat=dat>>1; //将下一位要写入的数据移到最低位
delay15(1); //延时15?s
DQ=1; //数据线拉高,为写入下一位做准备
29
}
}
uchar rdbyte(void) //从DS18B20 读取一个字节
{ uchar i;
dat=0; //读出数据初值为0
for(i=8;i>0;i--) //循环读8位(先低位,后高位)
{ dat=dat>>1; //读出数据先右移一位
DQ=0; //产生1?s的负脉冲
_nop_();
DQ=1; //数据总线拉高
delay15(1); //延时15?s
dat7=DQ; //读取数据
delay15(4); //延时,为读下一位做准备
}
return(dat);
}
void gettemp(int temp[]) //巡回检测出4个传感器的温度值送数组temp
{ uchar m,n;
uchar h,l;
reset(); //复位所有DS18B20
wrbyte(0xcc); //跳过ROM
wrbyte(0x44); //启动所有DS18B20转换
late(); //延时750ms
for(m=0;m<4;m++) //循环检测各DS18B20
{ reset(); //复位
wrbyte(0x55); //发匹配ROM命令
for(n=0;n<8;n++) //发8字节的序列号
wrbyte(id[m][n]); //选中指定DS18B20
wrbyte(0xbe); //发读暂存器命令
l=rdbyte(); //读取温度低字节、高字节
h=rdbyte();
temp[m]=h*256+l; //保存16位温度值
}
}
30
四、Time.C 定时器控制走时模块
/************************************** 功能:定时器开程序
入口参数:无
出口参数:无
**************************************/ #include
#include
#include
#include
extern unsigned char time[]; //时间:时、分、秒缓存 extern unsigned int count; void InitTimer0(void) { TMOD = 0x01; //定时器工作在方式2
TH0 = -25000/256; //定时时间为 250us
TL0 = -25000%256;
EA = 1; //单片机中断
ET0 = 1; //允许T0中断
TR0=1 ;
}
void time0(void) interrupt 1 { count++;
if(count==20)
{ count=0;
time[2]++;
if(time[2]==60)
{ time[2]=0;
time[1]++;
if(time[1]==60)
{ time[1]=0;
time[0]++;
if(time[0]==24)
31
time[0]=0;
}
}
}
}
32