电风扇智能控制系统设计
第1节 引 言„„„„„„„„„„„„„„„„„„„„„„„„„„„2
1.1 智能电风扇控制系统概述 „„„„„„„„„„„„„„„„„„2
1.2 本设计任务和主要内容 „„„„„„„„„„„„„„„„„„„2
第2节 方案论证 „„„„„„„„„„„„„„„„„„„„„„„„„4
2.1 温度传感器的选用„„„„„„„„„„„„„„„„„„„„„4
2.2 控制核心的选择„„„„„„„„„„„„„„„„„„„„„„4
2.3 显示电路的选择 „„„„„„„„„„„„„„„„„„„„„„5
第3节 系统主要硬件电路设计 „„„„„„„„„„„„„„„„„„„6
3.1 数字温度传感器模块设计„„„„„„„„„„„„„„„„„„6
3.2 电机调速与控制模块设计„„„„„„„„„„„„„„„„„„6
3.3 电机调速模块设计„„„„„„„„„„„„„„„„„„„„„9
3.4 温度显示与控制模块设计„„„„„„„„„„„„„„„„„„12
3.5 键盘模块设计„„„„„„„„„„„„„„„„„„„„„„„14
第4节 程序设计与仿真 „„„„„„„„„„„„„„„„„„„„„„16
4.1 数字温度传感器模块程序设计„„„„„„„„„„„„„„„„16
4.2 显示模块程序流程„„„„„„„„„„„„„„„„„„„„„19
4.3 电机调速与万年历程序流程„„„„„„„„„„„„„„„„„23
4.4 按键总控制流程„„„„„„„„„„„„„„„„„„„„„„26
4.5 主程序„„„„„„„„„„„„„„„„„„„„„„„„„„38
第5节 成品调试 „„„„„„„„„„„„„„„„„„„„„„„„„38
5.1 静态测试„„„„„„„„„„„„„„„„„„„„„„„„„38
5.2 联机调试„„„„„„„„„„„„„„„„„„„„„„„„„38
结 束 语 „„„„„„„„„„„„„„„„„„„„„„„„„„„„„39 参考文献 „„„„„„„„„„„„„„„„„„„„„„„„„„„„„41
基于单片机的智能电风扇控制系统
第1节 引 言
电风扇曾一度被认为是空调产品冲击下的淘汰品,其实并非如此,市场人士称,家用电风扇并没有随着空调的普及而淡出市场,近两年反而出现了市场销售复苏的态势。其主要原因:一是风扇和空调的降温效果不同——空调有强大的制冷功能,可以快速有效地降低环境温度,但电风扇的风更温和,更加适合老人儿童和体质较弱的人使用;二是电风扇有价格优势,价格低廉而且相对省电,安装和使用都非常简单。
尽管电风扇有其市场优势,但传统电风扇还是有许多地方应当进行改良的,最突出的缺点是它不能根据温度的变化适时调节风力大小,对于夜间温差大的地区,人们在夏夜使用电风扇时可能遇到这样的问题:当凌晨降温的时候电风扇依然在工作,可是人们因为熟睡而无法察觉,既浪费电资源又容易引起感冒,传统的机械定时器虽然能够控制电风扇在工作一定后关闭,但定时范围有限,且无法对温度变化灵活处理。鉴于以上方面的考虑,我们需要设计一种智能电风扇控制系统来解决这些问题。
1.1 智能电风扇控制系统概述
传统电风扇是220V交流电供电,电机转速分为几个档位,通过人为调整电机转速达到改变风力大小的目的,亦即,每次风力改变,必然有人参与操作,这样势必带来诸多不便。
本设计中的智能电风扇控制系统,是指将电风扇的电机转速作为被控制量,由单片机分析采集到的数字温度信号,再通过可控硅对风扇电机进行调速。从而达到无须人为控制便可自动调整风力大小的效果。
1.2 设计任务和主要内容
本设计以STC89C51单片机为核心,通过温度传感器对环境温度进行数据采集,从而建立一个控制系统,使电风扇随温度的变化而自动变换档位,实现“温度高,风力大,温度低,风力弱”的性能。另外,通过键盘控制面板,用户可以在一定范围内设置电风扇的最低工作温度,当温度低于所设置温度时,电风扇将自动关闭,当高于此温度时电风扇又将重新启动。
本设计主要内容如下:
① 风速设为从高到低5个档位,可由用户通过键盘手动设定。
② 当温度每降低2℃则电风扇风速自动下降一个档位。
③ 当温度每升高2℃则电风扇风速自动上升一个档位。
④ 用户可设定电风扇最低工作温度,当低于该温度时,电风扇自动停转。
第二节 方案论证
本系统实现风扇的温度控制,需要有较高的温度变化分辨率和稳定可靠的换 档停机控制部件。
2.1 温度传感器的选用
温度传感器可由以下几种方案可供选择:
方案一:选用热敏电阻作为感测温度的核心元件,通过运算放大器放大山于 温度变化引起热敏电阻电阻的变化、进而导至的输出电压变化的微弱电压变化信 号,再用AD转换芯片ADC0809将模拟信号转化为数字信号输入单片机处理。 方案二:采用热电偶作为感测温度的核心元件,配合桥式电路,运算放大电 路和AD转换电路,将温度变化信号送入单片机处理。
方案三:采用数字式集成温度传感器 DS18B20作为感测温度的核心元件,直 接输出数字温度信号供单片机处理
对于方案一,采用热敏电阻有价格便宜、元件易购的优点,但热敏电阻对温 度的细微变化不敏感,在信号采集、放大、转换过程中还会产生失真和误差,并 且由于热敏电阻的R-T关系的非线性,其本身电阻对温度的变化存在较大误差, 虽然可以通过一定电路予以纠正,但不仅将使电路复杂稳定性降低,而且在人体 所处温度环境温度变化中难以检测到小的温度变化。故该方案不适合本系统。 对于方案二,采用热电偶和桥式测量电路相对于热敏电阻其对温度的敏感性 和器件的非线性误差都有较大提高,其测温范围也非常宽,从一50摄氏度到1600 摄氏度均可测量。但是依然存在电路复杂,对温度敏感性达不到本系统要求的标 准,故不采用该方案。
对于方案三,山于数字式集成温度传感器DS18B20的高度集成化,大大降低 了外接放大转换等电路的误差因素,温度误差很小,并且由于其感测温度的原理 与上述两种方案的原理有着本质的不同,使得其温度分辨力极高。温度值在器刊 内部转换成数字量直接输出,简化了系统程序设计,又由于该传感器采用先进的
单总线技术(1-WR工E),与单片机的接口变的非常简洁,抗干扰能力强。关于 DS18B20的详细参数参看下面“硬件设计”中的器件介绍.
2.2 控制核心的选择
方案一:采用电压比较电路作为控制部件。温度传感器采用热敏电阻或热电 偶等,温度信号转为电信号并放大,山集成运放组成的比较电路判决控制风扇转 速,当高于或低于某值时将风扇切换到相应档位。
方案二:采用单片机作为控制核心。以软件编程的方法进行温度判断,并在 端口输出控制信号。
对于方案一,采用电压比较电路具有电路简单、易于实现,以及无需编写软 件程序的特点,但控制方式过于单一,不能自由设置上下限动作温度,无法满足 不同用户以及不同环境下的多种动作温度要求,故不在本系统中采用。
对于方案二,以单片机作为控制器,通过编写程序不但能将传感器感测到的 温度通过显示电路显示出来,而且用户能通过键盘接口,自由设置上下限动作温 度值,满足全方位的需求.并且通过程序判断温度具有极高的精准度,能精确把 握环境In度的微小变化。故本系统采用方案二
2.3 显示电路
方案一:采用五位共阳数码管显示温度,动态扫描显示方式.
方案二:采用液晶显示屏LCD显示温度
对于方案一,该方案成本低廉,显示温度明确醒目,在夜间也能看见,功耗 极低,显示驱动程序的编写也相对简单,这种显示方式得到广泛应用。不足的地 方是扫描显示方式是使五个LED逐个点亮,因此会有闪烁,但是人眼的视觉暂留时间为20M8,当数码管扫描周期小于这个时间时人眼将感觉不到闪烁,因此可
以通过增大扫描频率来消除闪烁感。
对于方案二,液晶体显示屏具有显示字符优美,不但能显示数字还能显示字 符甚至图形的优点,这是LED数码管无法比拟的。但是液晶显示模块价格昂贵, 驱动程序复杂,从硬件电路复杂性原则考虑,本系统采用方案二。
第三节 系统主要硬件电路设计
3.1 总体硬件设计
系统总体设计框图如图3-1所示
图3-1 系统原理框图 对于单片机中央处理系统的方案设计,根据要求,我们可以选用STC89C51单片机作为中央处理器。作为整个控制系统的核心,STC89C51内部已包含了定时器、程序存储器、数据存储器等硬件,其硬件能符合整个控制系统的要求,不需要外接其他存储器芯片和定时器件,方便地构成一个最小系统。整个系统结构紧凑,抗干扰能力强,性价比高。是比较合适的方案
3.2 数字温度传感器模块设计
3.2.1 DS18B20单线数字温度传感器简介
DS18820单线数字温度传感器是Dallas半导体公司开发的世界上第一片支 持“一线总线”接口的温度传感器。它具有3引脚TO-92小体积封装形式。温 度测量范围为一55`C—+125'C,可编程为9位—12位A/D转换精度,测温分 辨率可达0. 06250C.被测温度用符号扩展的16位数字量方式串行输出.工作电
压支持3V-一一5. 5V的电压范围,既可在远端引入,也可采用寄生电源方式产生。 DS18B20还支持“一线总线”接口,多个DS18B20可以并联到3根或2根线上,
CPU只需一根端口线就能与诸多DS18B20通信,占用微处理器的端口较少,可节 省大量的引线和逻辑电路.
DS18820内部结构主要由4部分组成:64位ROM,温度传感器、非挥发的温度报警触发器TH和TL,配置寄存器。其管脚排列如图2所示,DQ为数字信号端,cnIl为电源地,VDD为电源输入端口。
图3.1 DS18B20内部结构
图3.2 DS18B20外形与管脚
温度传感器也可以选用LM324A的运算放大器,将其设计成比例控制调节器,输出电压与热敏电阻的阻值成正比,但这种方案需要多次检测后方可使采样精确,过于烦琐。所以我采用更为优秀的DS18B20数字温度传感器,它可以直接将模拟温度信号
转化为数字信号,降低了电路的复杂程度,提高了电路的运行质量。
3.2.2 温度传感器模块组成
本模块以DS18B20作为温度传感器,STC89C51作为处理器,配以温度显示作为温度控制输出单元。整个系统力求结构简单,功能完善。电路图如图3.3所示。
图3.3 温度传感器模块
DS18B20进行现场温度测量,将测量数据送入STC89C51的P3.3口,经过单片机处理后显示温度值,并与设定温度值的上下限值比较,若高于设定上限值或低于设定下限值则控制电机转速进行调整。
3.2.3 DS18B20的温度处理方法
DS18B20直接将测量温度值转化为数字量提交给单片机,工作时必须严格遵守单总线器件的工作时序。
表2-1 部分温度值与DS18B20输出的数字量对照表
温度值/℃ 数字输出(二进制) 数字输出(十六进制) +85℃ 0000 0101 0101 0000 0550H
+25.625℃ 0000 0001 1001 0001 0191H
+10.125℃ 0000 0000 1010 0010 00A2H
+0.5℃ 0000 0000 0000 1000 0008H
0℃ 0000 0000 0000 0000 0000H
-0.5℃ 1111 1111 1111 1000 FFF8H
-10.125℃ 1111 1111 0110 1110 FF5EH
-25.625℃ 1111 1111 0110 1111 FF6FH
-55℃
1111 1100 1001 0000 FC90H
3.3 电机调速与控制模块设计
电机调速是整个控制系统中的一个重要的方面。通过控制L298来调节PWM输出,使输出端电压发生改变,从而使施加在电风扇的输入电压发生改变,以调节风扇的转速,实现各档位风速的调速。
3.3.1 L298芯片介绍
L298驱动芯片是SGS公司的产品,内部包含4通道逻辑驱动电路。是一种二相和四相电机的专用驱动器,即内包含二个H桥的高压大电六双全桥式驱动器,接收标准TTL逻辑电平信号,可驱动46V、2A以下的电机。实物图如图3.1所示。
图3.1 实物图
图3.2 管脚图
L298有两路电源分别为逻辑电源6V和动力电源12V,ENA、ENB直接接入5V电源使电机进入使能状态,IN1和IN2用来控制电路的逻辑功能状态。由于使用的电机是线圈式,在从运行状态突然转到停止状态和从顺时状态突然转换到逆时针状态时会形成很大的方向电流,在电路中加入二极管就是在产生方向电流的时候进行泄流,保护芯片的安全。下图为L298的逻辑功能状态。
3.3.2 电机调速原理
我们采用的是PWM来实现直流电动机的调速,优点:控制原理简单,输出波动小,线性好,对邻近电路干扰小。缺点是:功率低,散热问题严重。
电动机的电驱绕组两端的电压平均值U为:U=(t1*U)/(t1+t2)=(t1*U)/T=D*U式中D为占空比,D=t/T。
占空比D表示了在一个周期T里开关管导通的时间与周期的比值。D的变化范围为0
3.3.2 电机调速模块设计
根据图3.3所示连接好电路图,A/B接入单片机上通过程序来控制L298输出来控制直流电机的转动。PWM1赋值为1时,使能直流电机转动。
3.4 温度显示与控制模块设计
3.4.1 1602液晶模块的特性
字符型液晶模块1602是一种用5×7点阵图形来显示字符的液晶显示器,根据显示的容量可以分为1行16个字、2行16个字、2行20个字等等,常用的2行16个字的1602液晶模块来的编程方法如下。
1602采用标准的16脚接口,其中:第1脚:VSS为地电源;第2脚:VDD接5V正电源;第3脚:V0为液晶显示器对比度调整端,接正电源时对比度最弱,接地电源时对比度最高,对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度。第4脚:RS为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。第5脚:RW为读写信号线,高电平时进行读操作,低电平时进行写操作。当RS和RW共同为低电平时可以写入指令或者显示地址,当RS为低电平RW为高电平时可以读忙信号,当RS为高电平RW为低电平时可以写入数据。第6脚:E端为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。第7~14脚:D0~D7为8位双向数据线。 第15~16脚:空脚。
1602液晶模块内部的字符发生存储器(CGROM)已经存储了160个不同的点阵字符图形,如表1所示,这些字符有:阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等,每一个字符都有一个固定的代码,比如字母“A”的代码是01000001B(41H),显示时模块把地址41H中的点阵字符图形显示出来,我们就能看到“A”。它的读写操作、屏幕和光标的操作都是通过指令编程来实现的。(说明:1为高电平、0为低电平)。 3.4.2 显示模块设计
液晶显示模块是一个慢显示器件,所以在执行每条指令之前一定要确认模块的忙标志为低电平,表示不忙,否则此指令失效。要显示字符时要先输入显示字符地址,也就是告诉模块在哪里显示字符,如下表。
3.5 键盘模块设计
3.5.1 键盘方式选择
常用的键识别方法有:行扫描法、线翻转法和利用8279键盘接口的中断法。在本系统中,完全可以不使用中断法完成键盘接口,这是由系统的特殊性决定的。 首先,对于本系统而言,要实现便携式的设计,硬件电路使用的器件越少越好。 其次,被测信号由外中断引脚输入,未占用单片机4个并行I/O口中的任何一个,系统有足够的资源利用自身I/O口完成接口。
最后,只有当传感器输出信号频率为空载频率,系统处于空闲待测的状态下,才允许键盘输入,因此键盘识别占用的CPU时间不会对系统正常工作造成影响。因此直接利用单片机并行接口完成键盘的接口,采用线翻转法进行键盘识别。
3.5.2 实现方案
本单片机系统使用简单的键盘和液晶显示器件来完成输入/输出操作的人机界面。键盘输入信息的主要过程是:
·CPU判断是否有健按下。 ·确定按下的是哪一个键。
·把此键代表的信息翻译成计算机所能识别的代码,如ASCII或其他特征码。 键盘上有很多键,每一个键对应一个键码,以便根据键码转到相应的键处理子程序,进一步实现数据输入和命令处理的功能。键盘识别的流程如图所示。
3.5.3 模块设计
第四节 PCB图及原理图的制作
1、设计步骤 1.1 电路板设计步骤
一般而言,设计电路板最基本的过程可以分为三大步骤。 1. 电路原理图的设计
电路原理图的设计主要是PROTEL98的原理图设计系统(Advanced Schematic)来绘制一张电路原理图。在这一过程中,要充分利用PROTEL98所提供的各种原理图绘图工具、各种编辑功能,来实现我们的目的,即得到一张正确、精美的电路原理图。 2. 产生网络表
网络表是电路原理图设计(SCH)与印制电路板设计(PCB)之间的一座桥梁,它是电路板自动的灵魂。网络表可以从电路原理图中获得,也可从印制电路板中提取出来。
3. 印制电路板的设计
印制电路板的设计主要是针对PROTEL99的另外一个重要的部分PCB而言的,在这个过程中,我们借助PROTEL98提供的强大功能实现电路板的版面设计,完成高难度的等工作。
1.2 绘制简单电路图 1.2.1 原理图设计过程
原理图的设计可按下面过程来完成。
(1)设计图纸大小 Protel 98/ Schematic后,首先要构思好零件图,设计好图纸大小。图纸大小是根据电路图的规模和复杂程度而定的,设置合适的图纸大小是设计好原理图的第一步。
(2)设置Protel 98/Schematic设计环境 设置Protel 98/Schematic设计环境,包括设置格点大小和类型,光标类型等等,大多数参数也可以使用系统默认值。 (3)旋转零件 用户根据电路图的需要,将零件从零件库里取出放置到图纸上,
并对放置零件的序号、零件封装进行定义和设定等工作。
(4)原理图布线 利用Protel 98/Schematic提供的各种工具,将图纸上的元件用具有电气意义的导线、符号连接起来,构成一个完整的原理图。
(5)调整线路 将初步绘制好的电路图作进一步的调整和修改,使得原理图更加美观。
(6)报表输出 通过Protel 98/Schematic提供的各种报表工具生成各种报表,其中最重要的报表是网络表,通过网络表为后续的电路板设计作准备。 (7)文件保存及打印输出 最后的步骤是文件保存及打印输出。
(3)总电路图
(4)总电路PCB板
第五节 程序设计与仿真
本系统的运行程序采用C语言编写,采用模块化模块化编程的方法,整体程序由主程序(.c文件)和子程序(.h文件)构成。
4.1 数字温度传感器模块程序设计
4.2 主要程序如下(以下程序为一个ds18b20.h的程序包):
/***********ds18b20子程序*************************/ #ifndef __ds18b20_H__
#define __ds18b20_H__
//sbit DQ = P2^3; //定义通信端口 sbit DQ = P3^3;
void delay(unsigned int i) {
while(i--); }
/*初始化函数*/
Init_DS18B20(void)
{
unsigned char x=0;
DQ = 1; //DQ复位 delay(4); //稍做延时
DQ = 0; //单片机将DQ拉低 delay(80); //精确延时 大于 480us DQ = 1; //拉高总线 delay(20);
x=DQ; //稍做延时后 如果x=0则初始化成功 x=1则初始化失败 delay(20); }
/*读一个字节 */ RChar(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; delay(10); } return(dat); }
/*写一个字节 */
WChar(unsigned char dat) {
unsigned char i=0; for (i=8; i>0; i--) { DQ = 0; DQ = dat&0x01; delay(10); DQ = 1; dat>>=1;
}
}
/*读取温度*/ ReadTemp(void) {
unsigned char a=0; unsigned char b=0; unsigned int t=0; Init_DS18B20(); WChar(0xCC); // 跳过读序号列号的操作 WChar(0x44); // 启动温度转换 delay(100); Init_DS18B20(); WChar(0xCC); //跳过读序号列号的操作
WChar(0xBE); //(读取温度寄存器) 前两个就是温度 a=RChar(); //低八位 b=RChar(); //高八位 t = (b*256+a)*25; //传感器返回值除16得实际温度值
//为了得到2位小数位,先乘100,再除1 6 (先乘以25再除以4) return( t >> 2 ); } #endif
4.2 显示模块程序流程
4.2.4 程序如下(以下程序为一个LCD1602.h的程序包): #ifndef __ _H__
#define __LCD1602_H__ #define LCD_DB P0
sbit LCD_RS=P2^0;//命令数据端口 sbit LCD_RW=P2^1;//读写控制端口 sbit LCD_E=P2^2;//使能端口
/******定义函数****************/ void LCD_init(void);//初始化函数
void LCD_write_command(unsigned char command);//写指令函数ao void LCD_write_data(unsigned char dat);//写数据函数
void LCD_disp_char(unsigned char x,unsigned char y,unsigned char dat);//在某个屏幕位置上显示一个字符,X(0-16),y(1-2) void delay_n40us(unsigned int n);//延时函数
/*******初始化函数***************/
void LCD_init(void)
{ LCD_write_command(0x01);//清除屏幕显示
delay_n40us(100);//实践证明,我的LCD1602上,用for循环100次就能可靠完成清屏指令。
LCD_write_command(0x38);//设置8位格式,2行,5x7 LCD_write_command(0x0c);//整体显示,关光标,不闪烁 LCD_write_command(0x06);//设定输入方式,增量不移位 }
//********写指令函数************
void LCD_write_command(unsigned char dat) {
LCD_DB=dat; LCD_RS=0;//指令 LCD_RW=0;//写入 LCD_E=1;//允许 LCD_E=0;
delay_n40us(2);//实践证明,我的LCD1602上,用for循环2次就能完成普通写指令。 }
//********写数据函数*************
void LCD_write_data(unsigned char dat) {
LCD_DB=dat; LCD_RS=1;//数据 LCD_RW=0;//写入 LCD_E=1;//允许 LCD_E=0;
delay_n40us(2); }
//*******显示一个字符函数*********
void LCD_disp_char(unsigned char x,unsigned char y,unsigned char dat) {
unsigned char address; if(y==1)
address=0x80+x; else
address=0xc0+x;
LCD_write_command(address); LCD_write_data(dat); }
//********延时函数*************** void delay_n40us(unsigned int n) { unsigned int i;
unsigned char j;
for(i=n;i>0;i--)
for(j=0;j
void LCD_disp_str(unsigned char column,unsigned char line,unsigned char *str)
{
unsigned char n=0;
while(*str!='\0')
LCD_disp_char(column++,line,*str++);
}
#endif
4.3 电机调速与万年历程序流程
(以下程序为time.h的程序包):
#ifndef __time_H__
#define __time_H__
//sbit fl=P2^7;
sbit fl=P1^0;
unsigned int m_second_1=0,m_second=0;
/*定时1ms*/
void time0()
{ EA = 0;
TMOD = 0x11;
TH0 = (65535-12500)/255;
TL0 = (65535-12500)%255;
TH1 = (65535-10)/255;
TL1 = (65535-10)%255;
TR0= 1;
ET0 = 1;
TR1= 1;
ET1 = 1;
EA = 1;
}
/*定时器T1的中断服务函数. 晶振频率为11.0592MHz*/
void T1INTSVC() interrupt 1
{
TR0 = 0;//暂时停止定时器(在重新设置初值之前必须暂停)
TH0 = (65535-12500)/255;
TL0 = (65535-12500)%255; //重新设置定时器初值,设置时间为10ms TR0 = 1; //重新启动定时器 m_second_1++;
if(m_second_1>=80)
{
m_second_1=0;second++;
if(second==1) change=1;
if(second==60)
{ second=0;g_minute++;
if(g_minute==10) {s_minute++;g_minute=0;}
if(s_minute==6)
{g_hour++;s_minute=0;g_minute=0;}
if(g_hour==10) {s_hour++;g_hour=0;}
if((s_hour==2)&&(g_hour==4)) {g_day++;g_hour=0;s_hour=0;} if(g_day==10) {s_day++;g_day=0;}
} if((s_day==3)&&(g_day==1)) {g_mouth++;g_day=0;s_day=0;} if(g_mouth==10) {s_mouth++;g_mouth=0;} if((s_mouth==1)&&(g_mouth==3)) {g_year++;g_mouth=0;s_mouth=0;} if(g_year==10) {s_year++;g_year=0;} if((s_year==2)&&(g_year==0)) {s_year=0;g_year=0;}
}
}
#endif
注:程序中还包含一个万年历程序。
(2)、以下程序为time00.h的程序包
#ifndef __time00_H__
#define __time00_H__
void t0() interrupt 3
{ TR1=0;
TH1 = (65535-1)/255;
TL1 = (65535-1 )%255;
TR1=1;
if(temp0>temp) {fl=0;Vo1=0;pwm=0;}
else
{
m_second++;
if(m_second==Vo2)
{
fl=1;Vo1=0;
pwm=1;
}
else
if(m_second==Vo3)
{fl=0;Vo1=0;m_second=0;pwm=1;}
}
}
#endif
注:通过Vo2、Vo3的值来控制PWM输出。
4.4 按键总控制流程
以下程序为key.h的程序包
#ifndef __key_H__
#define __key_H__
unsigned int tmp;
unsigned char temp,temp0,s_tmp_s=1,g_tmp_s=8;
sbit keyM_D=P2^7;
sbit keyM_A=P2^6;
sbit pwm= P1^2;
sbit keya=P2^3;
sbit f1= P1^0;
sbit key_9=P2^5;
sbit key_8=P2^4;
unsigned char i=0;
unsigned char wu=1,Vo2,Vo3;
bit change;
unsigned char
g_hour=0,s_hour=1,g_minute=0,s_minute=3,second,g_day=0,s_day=2,
s_mouth=0,g_mouth=6,g_year=1,s_year=1,Modle=0;//
sbit Vo1=P1^1;
unsigned char str_temp0[3]={'0','0','\0'};
unsigned char str_temp[5]={'0','0','0','0','\0'};
unsigned char str_Modle[2]={'0','\0'};
unsigned char
str_date[9]={'0','0','/','0','0','/','0','0','\0'};
unsigned char
str_time[9]={'0','0',':','0','0',':','0','0','\0'};//用于装载要在LCD上显示的时间的ASCALL码
unsigned char code table[] = {0,0,1,2,3,4,5,6,7,8,9,0};
void DelayXus(int x)
{
unsigned char j;
while (x-- ) for(j =0; j
}
//温度比较
void bijiao()
{
if(((temp-temp0)>=0)&&((temp-temp0)=4)&&((temp-temp0)=8){Vo2=1;Vo3=10;}
if(temp
}
void display()
{
if(change==0)
{
LCD_disp_str(0,1," welcome to ");
LCD_disp_str(0,2,"zwb.cll.sxf.ok");
str_temp0[1]=0x30+g_tmp_s;
str_temp0[0]=0x30+s_tmp_s;
temp0=(s_tmp_s*10+g_tmp_s);
tmp = ReadTemp();
//temp=tmp/10;
str_temp[3]=0x30+tmp%10;
str_temp[2]=0x2e;
str_temp[1]=0x30+tmp/10%10;
str_temp[0]=0x30+tmp/100%10;
bijiao() ;
}
if(change==1)
{
if(wu==1)
{
if(Modle==1)
{
{if(key_9==0)
{
i++ ;
if(i>=11) i=0;
else
tmp = table[i];
if(tmp!=0xff)
{ g_minute=tmp;
}
else
if(key_8==0)
{
i--;
if(i
tmp = table[i];
tmp&=0x0f ;
g_minute=tmp;
}
}
}
if(Modle==2)
{
{if(key_9==0)
{
i++ ;
if(i>=7) i=0; tmp = table[i];
tmp&=0x0f ;
s_minute=tmp;
}
else
if(key_8==0)
{
i--;
if(i
tmp = table[i];
tmp&=0x0f ;
s_minute=tmp;
}
}
}
if(Modle==3)
{
{if(key_9==0)
{
i++ ;
if(i>=11) i=0; tmp = table[i];
tmp&=0x0f ;
g_hour=tmp;
tmp= 255-(1
else
if(key_8==0)
{
i--;
if(i
tmp = table[i];
tmp&=0x0f ;
g_hour=tmp;
tmp= 255-(1
}
}
if(Modle==4)
{
{if(key_9==0)
{
i++ ;
if(i>=4) i=0; tmp = table[i];
tmp&=0x0f ;
s_hour=tmp;
tmp= 255-(1
else
if(key_8==0)
{
i--;
if(i
tmp = table[i];
tmp&=0x0f ;
s_hour=tmp;
tmp= 255-(1
}
}
if(Modle==5)
{
{if(key_9==0)
{
i++ ;
if(i>=11) i=0;
tmp = table[i];
tmp&=0x0f ;
g_day=tmp;
tmp= 255-(1
else
if(key_8==0)
{
i--;
if(i
tmp = table[i];
tmp&=0x0f ;
g_day=tmp;
tmp= 255-(1
}
}
if(Modle==6)
{
{if(key_9==0)
{
i++ ;
if(i>=5) i=0; tmp = table[i];
tmp&=0x0f ;
s_day=tmp;
tmp= 255-(1
else
if(key_8==0)
{
i--;
if(i
tmp = table[i];
tmp&=0x0f ;
s_day=tmp;
tmp= 255-(1
}
}
if(Modle==7)
{
{if(key_9==0)
{
i++ ;
if(i>=11) i=0; tmp = table[i];
tmp&=0x0f ;
g_mouth=tmp;
tmp= 255-(1
else
if(key_8==0)
{
i--;
if(i
tmp = table[i];
tmp&=0x0f ;
g_mouth=tmp;
tmp= 255-(1
}
}
if(Modle==8)
{
{if(key_9==0)
{
i++ ;
if(i>=3) i=0; tmp = table[i];
tmp&=0x0f ;
s_mouth=tmp;
tmp= 255-(1
else
if(key_8==0)
{
i--;
if(i
tmp = table[i];
tmp&=0x0f ;
s_mouth=tmp;
tmp= 255-(1
}
}
if(Modle==9)
{
{if(key_9==0)
{
i++ ;
if(i>=11) i=0; tmp = table[i];
tmp&=0x0f ;
g_year=tmp;
tmp= 255-(1
else
if(key_8==0)
{
i--;
if(i
tmp = table[i];
tmp&=0x0f ;
g_year=tmp;
tmp= 255-(1
}
}
if(Modle==10)
{
{if(key_9==0)
{
i++ ;
if(i>=11) i=0; tmp = table[i];
tmp&=0x0f ;
s_year=tmp;
}
else
if(key_8==0)
{
i--;
if(i
tmp = table[i];
tmp&=0x0f ;
s_year=tmp;
tmp= 255-(1
}
}
LCD_disp_str(0,2,"Time: "); LCD_disp_str(0,1,"Data:");
LCD_disp_str(13,1," Md"); LCD_disp_str(13,2," ");
LCD_disp_str(5,2,str_time); LCD_disp_str(5,1,str_date); LCD_disp_str(14,2,str_Modle); delay_n40us(10000);
str_date[0]=0x30+s_year;
str_date[1]=0x30+g_year; str_date[3]=0x30+s_mouth; str_date[4]=0x30+g_mouth; str_date[6]=0x30+s_day;
str_date[7]=0x30+g_day;
str_time[0]=0x30+s_hour;
str_time[1]=0x30+g_hour;
str_time[3]=0x30+s_minute; str_time[4]=0x30+g_minute; str_time[6]=0x30+second/10; str_time[7]=0x30+second%10; str_Modle[1]=0x30+Modle%10; str_Modle[0]=0x30+Modle/10;
//比较设定的和正常的温度值,输出高或低电平 str_temp0[1]=0x30+g_tmp_s; str_temp0[0]=0x30+s_tmp_s; temp0=(s_tmp_s*10+g_tmp_s); tmp = ReadTemp();
temp=tmp/10;
str_temp[3]=0x30+tmp%10; str_temp[2]=0x2e;
str_temp[1]=0x30+tmp/10%10; str_temp[0]=0x30+tmp/100%10; bijiao();
if(wu==2)
{
if(Modle==11)
{
{if(key_9==0)
{
i++ ;
if(i>=11) i=0;
tmp = table[i];
tmp&=0x0f ;
g_tmp_s=tmp;
}
else
if(key_8==0)
{
i--;
if(i
tmp = table[i];
tmp&=0x0f ;
g_tmp_s=tmp;
}
}
}
if(Modle==12)
{
{if(key_9==0)
{
i++ ;
if(i>=11) i=0;
tmp = table[i];
tmp&=0x0f ;
s_tmp_s=tmp;
}
else
if(key_8==0)
{
i--;
if(i
tmp = table[i];
s_tmp_s=tmp;
}
}
}
LCD_disp_str(0,1,"now tempture= Md");
LCD_disp_str(4,2,"'C S=");
LCD_disp_str(11,2,"'C");
LCD_disp_str(13,2," ");
LCD_disp_str(14,2,str_Modle);
LCD_disp_str(0,2,str_temp);
LCD_disp_str(9,2,str_temp0);
str_temp0[1]=0x30+g_tmp_s;
str_temp0[0]=0x30+s_tmp_s;
str_Modle[1]=0x30+Modle%10;
str_Modle[0]=0x30+Modle/10;
temp0=(s_tmp_s*10+g_tmp_s);
tmp = ReadTemp()/10;
temp=tmp/10;
str_temp[3]=0x30+tmp%10;
str_temp[2]=0x2e;
str_temp[1]=0x30+tmp/10%10;
str_temp[0]=0x30+tmp/100%10;
bijiao();
}
}
}
void scan_0() interrupt 0
{Modle=Modle+1;
}
/*按键扫描*/
void scan()
{
if((keyM_A==0)&&(keyM_D==0)) {wu++;if(wu==3) wu=1;while((keyM_A==0)&&(keyM_D==0));}
if(keyM_A==0){Modle++;Modle&=0x0f;if(Modle==13) Modle=0; while(keyM_A==0);}
if(keyM_D==0){if(Modle==0) Modle=13;Modle--;Modle&=0x0f; while(keyM_D==0);}
else Modle=Modle;
}
#endif
4.5 主程序
主程序为一个.c文件,使用#include语句把所有.h子程序包含进来,主函数为一个循环语句一直在调用子程序、按键扫描。
程序如下:
#include
#include "LCD1602.H"
#include "ds18b20.H"
#include "keyq.H"
#include "time.H"
#include "time00.H"
//*********主函数*****************
void main(void)
{ time0();
LCD_init();
while(1)
{
display();
scan();
}
}
结 束 语
首先,通过这次应用系统设计,在很大程度上提高了自己的独立思考能力和单片机的专业知识,也深刻了解写一篇应用系统的步骤和格式,有过这样的一次训练,相信在接下来的日子我们都会了,而且会做得更好。
我所写的系统主要根据目前节智能化电风扇技术的发展趋势和国内实际的应用特点和要求,采用了自动化的结构形式,实现对电风扇转速的自动控制。
系统以单片机AT89C51为核心部件,单片机系统完成对环境温度信号的采集、处理、显示等功能;用Protel软件绘制电路原理图和PCB电路印刷板图,由Protues软件进行访真测试,利用MCS51汇编语言编制,运行程序该系统的主要特点是:
1)适用性强,用户只需对界面参数进行设置并启动系统正常运行便可满足不同用户对最适合温度的要求,实现对最适温度的实时监控。
2)系统成本低廉,操作非常简单,随时可以根据软件编写新的功能加入产品。操作界面可扩展性强,只要稍加改变,即可增加其他按键的使用功能。
本系统在当今提倡人性化设计和健康产品的环境下具有非常好的市场前景。 本设计在模拟检测中运行较好,但采样据不太稳定。功能上的缺憾是对于两个档之间的临界温度处理不好,并且档位太少。还有待改进。
参考文献
[1] 张鑫.单片机原理及应用.电子工业出版社
[1] 明德刚.DS18B20在单片机温控系统中的应用.贵州大学学报,2006,2
[2] 黄朝民,肖明清,吴志强.单片机原理与应用.现代电子技术,2006,12
[3] 刘进山.基于MCS-51电风扇智能调速器的设计.电子质量,2004,10