找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 32462|回复: 21
收起左侧

单片机智能温控风扇的设计与实现 资料下载

  [复制链接]
ID:188484 发表于 2017-4-11 15:34 | 显示全部楼层 |阅读模式
以下是部分内容预览:
到目前,我已经将软件程序烧入单片机并完成了实物的焊接 ,结果并不是让人很满意。温控风扇的DS18B20传感器可能有一些问题,因为数码管所显示的温度和实际温度相差很大,而我检查了几遍数码管及单片机引脚的焊接、软件程序的编排,并仿真了好几遍,仿真结果十分好,所以我觉得可能是温度传感器出了一些问题。
  
从开始着手做智能温控风扇到现在,我遇到了很多问题和麻烦。比如说,在线路焊接的时候特别容易将太多引脚的单片机与其他组件焊接错误。再比如说,温度显示不准确的时候我还曾怀疑是不是焊接错误而想把线路全拆了重新开始焊接,是室友在那时候提醒我可以尝试用仿真去解决这个问题。而目前存在的问题,我觉得文档方面没有太多,只是温度显示错误方面我得多用一些心思了。
  
下一步我准备再买一个DS18B20传感器回来重新装上去试一下,如果真的是传感器的问题那就太好了,如果不是我还要仔细、反复的检查几遍。

拟采取的方式、方法及计划进程、方案(主要技术路线):
系统设计基于单片机的风扇温控仪采用DS18B20传感器,将检测到的温度转化为数字信号,单片机对输入的数字信号进行分析处理,当温度高于上限值时,风扇全速旋转;当温度低于下限时,风扇停转;当温度处于上限值与下限之间时,风扇转速越慢。硬件方面,首先我得购买DS18B20传感器、89C51单片机、驱动风扇、数码显示管、按键等,紧接着就是设计电路并将软件程序烧入单片机内,最后再焊接并进行反复的调试。其中,软件程序方面,我将采取分块编程的思想,先将各个模块编写调试,最后进行整机连调。其中,图1所示为硬件设计结构框图图2所示为软件流程图。
0.png



本设计作为一种智能温控风扇系统,用户设置出两个档位的高、低温度值,温度传感器DS18B20测出灵敏的温度变化并用数码管显示出来,作为控制平台的AT89C52单片机芯片对风扇开关以及转速进行控制,当实际温度在两档之间时打开弱风档,当实际温度高于高温度设定值时自动切换到强风档,当实际温度低于低温度设定值时自动关闭风扇,风扇状态随外界实际温度而改变。

温控风扇系统,是根据当时温度情况去自动开通和关闭电风扇,能很好的节约电能,同时也方便用户们的使用更具人性化。而且温控风扇系统在工业生产、日常生活中都有广泛的应用,如在工业生产中大型机械设备的散热系统,或限制笔记本电脑上的智能CPU风扇等基于单片机的温控风扇都能够根据环境温度的高低自动启动或停止转动,并能够根据温度的变化实现转速的自动调节,在现实生活中具非常广泛的用途,因此它的设计具有一定的价值意义。



目    录

绪  论              5
一  系统概述              6
1.1  AT89C52单片机简介              6
1.2  本设计任务和主要内容              6
二  系统原理及其硬件设计              7
2.1 系统总体设计
2.2 控制装置原理              7
2.3 温度检测和显示电路              8
2.3.1 DS18B20的温度处理方法              8
2.3.2 温度传感器和显示电路组成              9
2.4 电机调速电路              10
2.4.1  电机调速原理              11
2.4.2  电机控制模块设计
三  控制器软件设计
3.1  主程序
3.2  数字温度传感器模块和显示子模块
3.3  电机调速与控制子模块
结 束 语
参考文献              18
附录一              19

绪  论


近些年来,随着空调行业的迅速发展,空调价格的大幅度“跳水”,电风扇行业曾被普遍认为是“夕阳产业”。其实并非如此,市场人士称,家用电风扇并没有随着空调的普及而淡出市场,近两年反而出现了市场销售复苏的态势。其主要原因:一是风扇和空调的降温效果不同;(空调有强大的制冷功能,可以快速有效地降低环境温度,但电风扇的风更温和,更加适合老人儿童和体质较弱的人使用。)二是电风扇有价格优势,价格便宜而且相对省电,安装和使用都非常简单。

传统电风扇多采用机械方式进行控制,功能少,噪音大,各档的风速变化大。随着科技的发展和人们生活水平的提高,家用电器产品趋向于自动化、智能化、环保化和人性化,使得由微机控制的智能电风扇得以出现。

生活中,我们经常会使用一些与温度有关的设备。比如,现在虽然不少城市家庭用上了空调,但在占中国大部分人口的农村地区依旧使用电风扇作为降温防暑设备,春夏(夏秋)交替时节,白天温度依旧很高,电风扇应高转速、大风量,使人感到清凉;到了晚上,气温降低,当人入睡后,应该逐步减小转速,以免使人感冒。虽然电风扇都有调节不同档位的功能,但必须要人手动换档,睡着了就无能为力了,而普遍采用的定时器关闭的做法,一方面是定时时间长短有限制,一般是一两个小时;另一方面可能在一两个小时后气温依旧没有降低很多,而风扇就关闭了,使人在睡梦中热醒而不得不起床重新打开风扇,增加定时器时间,非常麻烦,而且可能多次定时后最后一次定时时间太长,在温度降低以后风扇依旧继续吹风,使人感冒;第三方面是只有简单的到了定时时间就关闭风扇电源的单一功能,不能满足气温变化对风扇风速大小的不同要求。又比如在较大功率的电子产品散热方面,现在绝大多数都采用了风冷系统,利用风扇引起空气流动,带走热量,使电子产品不至于发热烧坏。要使电子产品保持较低的温度,必须用大功率、高转速、大风量的风扇,而风扇的噪音与其功率成正比。如果要低噪音,则要减小风扇转速,又会引起电子设备温度上升,不能两全其美。为解决上述问题,我们设计了这套温控自动风扇系统。本系统采用高精度集成温度传感器,用单片机控制,能显示实时温度,并根据使用者设定的温度自动在相应温度时作出小风、大风、停机动作,精确度高,动作准确。


一、系统概述


1.1  AT89C52单片机简介

AT89C52是美国ATMEL公司生产的低电压、高性能CMOS8位单片机,片内4bytes的可反复擦写的只读程序存储器(PEROM)和128 bytes的随机存取数据存储器(RAM),器件采用ATMEL公司的高密度、非易失性存储技术生产,兼容标准MCS-51指令系统,片内置用8位中央处理器(CPU)和Flash存储单元,功能强大。STC89C52单片机可灵活应用于各种控制领域。

STC89C52单片机提供以下标准功能:4K字节Flash闪速存储器,128字节内部RAM,32个I/O口线,两个16位定时、计数器,一个5向量两级中断结构,一个全双工串行通信口,片内振荡器及时钟电路。同时,STC89C52单片机可降至0Hz的静态逻辑操作,并支持两种软件可选的节电工作模式。空闲方式停止CPU的工作,但允许RAM,定时、计数器,串行通行口及中断系统继续工作。掉电方式保存RAM中的内容,但振荡器停止工作并禁止其它所有部件工作直到下一个硬件复位。


1. 2  本设计任务和主要内容

本文以STC89C52单片机为核心,通过数字温度传感器对外界环境温度进行数据采集,从而建立一个控制系统,使电风扇随温度的变化而自动调节档位,实现“温度高、风力大、温度低、风力弱”的性能。另外,通过红外发射和接收装置及按键实现各种功能的启动与关闭,并且可对各种功能实现遥控,用户可以在一定范围内设置电风扇的最低工作温度,当温度低于所设置温度时,电风扇将自动关闭,当高于此温度时电风扇又将重新启动。

本设计主要内容如下:

(1)风速设为从低到高共2个档位,可由用户通过键盘设定。

(2)每当温度低于下限值时,则电风扇风速关闭。

(3)每当温度在下限和上限之间时,则电风扇转速缓慢。

(4))每当温度高于上限值时,则电风扇风速全速运转。





二、系统原理


2.1  系统总体设计

1.005.jpg
图1 系统总体结构框图


2.2  控制装置原理

传统电风扇供电采用的是220V交流电,电机转速分为几个档位,通过人工手动调整电机转速达到改变风速的目的,亦即,每改变一次风力,必然有人参与操作,这样就会带来诸多不便。

本文介绍了一种基于AT89C52单片机的智能电风扇调速器的设计,该设计巧妙利用红外线遥控技术、单片机控制技术、无级调速技术和温度传感技术,把智能控制技术应用于家用电器的控制中,将电风扇的电机转速作为被控制量,由单片机分析采集到的数字温度信号,再通过可控硅对风扇电机进行调速。从而达到无须人为控制便可自动调整风速的效果。



23  温度检测和显示电路

可以选用LM324A运算放大器作为温度传感器,将其设计成比例控制调节器,输出电压与热敏电阻的阻值成正比,但这种方案需要多次检测后方可使采样精确,过于烦琐。所以我采用更为优秀的DS18B20数字温度传感器,它可以直接将模拟温度信号转化为数字信号,降低了电路的复杂程度,提高了电路的运行质量。


2.3.1  DS18B20的温度处理方法

DS18B20是美国DALLAS半导体公司继DS1820之后最新推出的一种改进型智能温度传感器。与传统的热敏电阻相比,它能够直接读出被测温度并且可根据实际要求通过简单的编程实现9~12位的数字值读数方式。可以分别在93.75 ms和750 ms内完成9位和12位的数字量,并且从DS18B20读出的信息或写入DS18B20的信息仅需要一根口线(单线接口)读写,温度变换功率来源于数据总线,总线本身也可以向所挂接的DS18B20供电,而无需额外电源,因而使用DS18B20可使系统结构更趋简单可靠性更高。他在测温精度、转换时间、传输距离、分辨率等方面较DS1820有了很大的改进,给用户带来了更方便的使用和更令人满意的效果。

DS18B20简介:

(1)独特的单线接口方式:DS18B20与微处理器连接时仅需要一条口线即可实现微处理器与DS18B20的双向通讯。

(2)在使用中不需要任何外围元件。

(3)可用数据线供电,电压范围:+3.0~ +5.5 V。

(4)测温范围:-55 ~+125 ℃。固有测温分辨率为0.5 ℃。

(5)通过编程可实现9~12位的数字读数方式。

(6)用户可自设定非易失性的报警上下限值。

(7)支持多点组网功能,多个DS18B20可以并联在惟一的三线上,实现多点测温。

(8)负压特性,电源极性接反时,温度计不会因发热而烧毁,但不能正常工作。

单线(1—wire)技术:

该技术采用单根信号线,既可传输时钟,也能传输数据,而且是双向传输。适用于单主机系统,主机能够控制一个或多个从机设备,通过一个漏极开路或三态端口连至该数据线,以允许设备在不发送数据时能释放该线,而让其他设备使用。单线通常要求外接一个5K的上拉电阻,这样当该线空闲时,其状态为高电平。

主机和从机之间的通讯分成三个步骤:初始化单线器件、识别单线器件和单线数据传输。

单线1—wire协议由复位脉冲、应答脉冲、写0、写1、读0、读1,这几种信号类型实现,这些信号中除了应答脉冲其他都由主机发起,并且所有指令和数据字节都是低位在前。

DS18B20直接将测量温度值转化为数字量提交给单片机,工作时必须严格遵守单总线器件的工作时序。

温度值/℃                 数字输出(二进制)               数字输出(十六进制)
   +125                     0000 0111 1101 0000                     07D0H
+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
表1 部分温度值与DS18B20输出的数字量对照表


2.3.2  温度传感器和显示电路组成

本模块用更为优秀的DS18B20作为温度传感器,STC89C52单片机作为处理器,配以温度显示作为温度控制输出单元。整个系统力求结构简单,功能完善。电路图如图2所示。

系统工作原理如下:

DS18B20数字温度传感器采集现场温度,将测量到的数据送入STC89C52单片机的P2.4口,经过单片机处理后显示当前温度值,并与设定温度值的上下限值作比较,若高于设定上限值或低于设定下限值则控制电机转速进行自动调整。

对于显示电路,我们本有两种方案可以实施,方案一:采用五位共阳数码管显示温度,动态扫描显示方式;方案二:采用液晶显示屏LCD显示温度。

对于方案一,该方案成本低廉,显示温度明确醒目,在夜间也能看见,功耗极低,显示驱动程序的编写也相对简单,这种显示方式得到广泛应用。不足的地方是扫描显示方式是使五个LED逐个点亮,因此会有闪烁,但是人眼的视觉暂留时间为20MS,当数码管扫描周期小于这个时间时人眼将感觉不到闪烁,因此可以通过增大扫描频率来消除闪烁感。

对于方案二,液晶体显示屏具有显示字符优美,不但能显示数字还能显示字符甚至图形的优点,这是LED数码管无法比拟的。但是液晶显示模块价格昂贵,驱动程序复杂,从简单实用的原则考虑,本系统采用方案一。



1.006.jpg

图2 DS18B20温度计原理图




2.4  电机调速电路


对于调速电路,也有两种方案。其一:采用变压器调节方式,运用电磁感应原理将220V电压通过线圈降压到不同的电压,控制风扇电机接到不同电压值的线圈上可控制电机的转速,从而控制风扇风力大小;其二:采用晶闸管构成无级调速电路。

对于方案一,由于采用变压器改变电压调节,有风速级别限制,不能适应人性化要求。且在变压过程中会有损耗发热,效率不高,发热有不安全因素。

对于方案二,以电位器控制晶闸管的导通角大小,可实现由最大风速到关闭的无级别调速,可将风力调节在关闭无风到最大风之间的任意风力,实现“自由风”。且在调速环节中基本无电力损耗。故本系统采用方案二。

电机调速是整个控制装置中的一个相当重要的方面。通过控制改变三极翻出的导,使输出端电压发生改变,从而使施加在电风扇的输入电压发生改变,以调节风扇的转速,实现各档位风速的无级调速。


2.4.1  电机调速原理

双向可控硅的导通条件如下:

(1)阳-阴极间加正向电压;

(2)控制极-阴极间加正向触发电压;

(3)阳极电流IA 大于可控硅的最小维持电流IH。

电风扇的风速从高到低设为2、1档,每档风速都有一个限定值。在额定电压、额定功率下,以最高转速运转时,要求风叶最大圆周上的线速度不大于2150m/min。且线速度可由下列公式求得

V=πDn×103                          (1)

式(1)中,V为扇叶最大圆周上的线速度(m/min),D为扇中的最大顶端扫出圆的直径(mm),n为电风扇的最高转速(r/min)。

代入数据求得n5≤1555r/min,取n5=1250 r/min.又因为:

1.007.jpg

取n1=875r/min。则可得出五个档位的转速值:

n1=875r/min,n2=980r/min,n3=1063r/min,n4=1150 r/min,n5=1250r/min

又由于负载上电压的有效值

u0=u1 1.008.jpg                                  (2)

式(2)中,u1为输入交流电压的有效值,α为控制角。解得:

  • α5=0°时,t=0ms
  • α4=23.5°时,t=1.70ms
  • α3=46.5°时,t=2.58ms
  • α2=61.5°时,t=3.43ms
  • α1=76.5°时,t=4.30ms

上述计算出的是控制角和触发时间,当检测到过零点时,按照所求得的触发时间延时发脉冲,便可实现预期转速。


2.4.2  电机控制模块设计

本模块电路中采用了过零双向可控硅型光耦MOC3041M ,集光电隔离、过零检测、过零触发等功能于一身,避免了输入输出通道同时控制双向可控硅触发的缺陷, 简化了输出通道隔离2驱动电路的结构。所设计的可控硅触发电路原理图见图3。其中RL即为电机负载,其工作原理是:单片机响应用户的参数设置, 在I/ O 口输出一个高电平, 经反向器反向后, 送出一个低电平,使光电耦合器导通, 同时触发双向可控硅, 使工作电路导通工作。给定时间内,负载得到的功率为:

1.009.jpg                              (3)

式中: P 为负载得到的功率( kW); n 为给定时间内可控硅导通的正弦波个数; N 为给定时间内交流正弦波的总个数; U为可控硅在一个电源周期全导通时所对应的电压有效值(V); I 为可控硅在一个电源周期全导通时所对应的电流有效值(A)。由式(3) 可知,当U , I ,N 为定值时, 只要改变n 值的大小即可控制功率的输出,从而达到调

节电机转速的目的。


1.010.jpg


图3 电机控制原理图


三、控制器软件设计


本系统的运行程序采用C语言编写,采用模块化设计,整体程序由主程序和显示、键盘扫描、红外线接收以及电机控制等子程序模块组成。


3.1  主程序

在主程序进行初始化后,开始反复检测各模块相关部分的缓冲区的标志,如果缓冲区置位,说明相应的数据需要处理,然后主程序调用相应的处理子模块。如图7所示。

1.011.jpg 图7 主程序模块流程图

3.2  数字温度传感器模块和显示子模块

1.012.jpg 如图8所示,主机控制DS18B20数字温度传感器完成温度转换工作必须经过三个步骤:初始化、ROM操作指令、存储器操作指令。单片机所用的系统频率为12MHz。

根据DS18B20数字温度传感器进行初始化时序、读时序和写时序分别可编写3个子程序:初始化子程序、写子程序、读子程序。

图8 数字温度传感器模块程序流程图




DS18B20芯片功能命令表如下:

命令                                         说明                        协议
READ ROM                                读取激光ROM64位                  33H
MATCHROM                                   匹配ROM                     55H
SKIP ROM                                      跳过ROM                     CCH
SEARCH ROM                                   搜索ROM                     F0H
ALARM SEARCH                                告警搜索                      ECH
WRITE SCRATCHPAD                  把字节写入暂存器的地址2和3            4EH
READ SCRATCHPAD                     读取暂存器和CRC字节                 BEH
COPY SCRATCHPAD                 把暂存器内容拷贝到非易失性存储器中        48H
CONVERT T                                  开始温度转换                    44H
RECALL E2                          把非易失性存储器中的值召回暂存器          B8H
READ POWER SUPPLY           读电源供电方式:0为寄生电源,1为外电源       B4H

表2  DS18B20功能命令表


3.3  电机调速与控制子模块

本模块采用双向可控硅过零触发方式,由单片机控制双向可控硅的通断,通过改变每个控制周期内可控硅导通和关断交流完整全波信号的个数来调节负载功率,进而达到调速的目的。

因为INT0信号反映工频电压过零时刻,所以只要在外中断0的中断服务程序中完成控制门的开启与关闭,并利用中断服务次数对控制量n进行计数和判断,即每中断一次,对n进行减1计数,如果n不等于0,保持控制电平为“1”,继续打开控制门;如n=0,则使控制电平复位为“0”,关闭控制门,使可控硅过零触发脉冲不再通过。这样就可以按照控制处理得到的控制量的要求,实现可控硅的过零控制,从而达到按控制量控制的效果,实现速度可调。

(1)中断服务程序:执行中断服务程序时,首先保护现场,INT0中断标志置位,禁止主程序修改工作参数,然后开始减1计数,判断是否关断可控硅,最后INT0中断标志位清零,还原初始化数据,恢复现场,中断返回。(设1秒钟通过波形数N=100)

(2)回路控制执行程序:主回路控制执行程序的任务是初始化数据存储单元,确定

1.013.jpg 电机工作参数nmin/nmax,并将其换算成“有效过零脉冲”的个数;确定中断优先级、开

中断,为了保证正弦波的完整,工频过零同步中断INT0确定为高一级的中断源。


图9 电机控制模块中断响应流程图








结 束 语

本系统以STC89C52单片机为核心,单片机主要完成对外界环境温度信号的采集、处理、显示等功能;用Altium Designer 6软件绘制电路原理图和PCB电路印刷板图,由Protues软件进行访真测试,利用MCS-51 C语言编制。

运行程序该系统的主要特点是:

(1)适用性强,用户只需对界面参数进行设置并启动系统正常运行便可满足不同用户对最适合温度的要求,实现对最适温度的实时监控。

(2)随时可以根据软件编写新的功能加入产品。操作界面可扩展性强,只要稍加改变,即可增加其他按键的使用功能。

本系统温度控制采用DS18B20数字温度传感器作为感温元件。可控硅串接在电源与负载电风扇,借改变定周期内可控硅的导通与截止时间之比来实现调速功能,其设计完使用方便就,适应人们睡办公等不同场合的使用。

基于STC89C52单片机所设计与研制的电风扇智能调速系统,造价低且具有稳定性高、性能优越、节约电能等优点,在夜间无需定时,同样能给人们带来更多的方便。

本设计在模拟检测中运行较好,但采样据不太稳定。功能上的缺憾是对于两个档之间的临界温度处理不好,并且档位太少,还有待改进。





附录一


数字温度传感器模块和显示子模块程序:

  1. #include<reg52.h>                        //调用单片机头文件

  2. #define uchar unsigned char  //无符号字符型 宏定义              变量范围0~255

  3. #define uint  unsigned int              //无符号整型 宏定义              变量范围0~65535

  4. #include "eeprom52.h"



  5. //数码管段选定义      0     1    2    3    4    5              6              7                8                 9            

  6. uchar code smg_du[]={0x28,0xee,0x42,0x52,0xe5,0xa8,0x41,0xe7,0x20,0xa0,

  7.                                                                         0x60,0x25,0x39,0x26,0x31,0x71,0xff};              //断码

  8. //数码管位选定义

  9. uchar code smg_we[]={0xef,0xdf,0xbf,0x7f};

  10. uchar dis_smg[8] = {0x28,0xee,0x32,0xa2,0xe4,0x92,0x82,0xf8};            

  11. uchar smg_i = 3;    //显示数码管的个位数

  12. sbit dq   = P2^4;              //18b20 IO口的定义



  13. bit flag_lj_en;                            //按键连加使能

  14. bit flag_lj_3_en;              //按键连3次连加后使能  加的数就越大了

  15. uchar key_time,key_value;      //用做连加的中间变量

  16. bit key_500ms  ;

  17. sbit pwm = P2^3;

  18. uchar f_pwm_l ;                //越小越暗



  19. uint temperature ;  //

  20. bit flag_300ms ;

  21. uchar menu_1;       //菜单设计的变量

  22. uint t_high = 300,t_low = 100;                 //温度上下限报警值



  23. /***********************1ms延时函数*****************************/

  24. void delay_1ms(uint q)

  25. {

  26.               uint i,j;

  27.               for(i=0;i<q;i++)

  28.                             for(j=0;j<120;j++);

  29. }



  30. /***********************小延时函数*****************************/

  31. void delay_uint(uint q)

  32. {

  33.               while(q--);

  34. }





  35. /***********************数码显示函数*****************************/

  36. void display()

  37. {

  38.               static uchar i;  

  39.               i++;

  40.               if(i >= smg_i)

  41.                             i = 0;            

  42.               P1 = 0xff;                                          //消隐

  43.               P3 = smg_we[i];                                          //位选

  44.               P1 = dis_smg[i];                            //段选                     



  45. }



  46. /******************把数据保存到单片机内部eepom中******************/

  47. void write_eeprom()

  48. {

  49.               SectorErase(0x2000);

  50.               byte_write(0x2000, t_high % 256);

  51.               byte_write(0x2001, t_high / 256);

  52.               byte_write(0x2002, t_low % 256);

  53.               byte_write(0x2003, t_low / 256);

  54.               byte_write(0x2055, a_a);            

  55. }



  56. /******************把数据从单片机内部eepom中读出来*****************/

  57. void read_eeprom()

  58. {

  59.               t_high  = byte_read(0x2001);

  60.               t_high <<= 8;

  61.               t_high  |= byte_read(0x2000);

  62.               t_low   = byte_read(0x2003);

  63.               t_low <<= 8;

  64.               t_low   |= byte_read(0x2002);

  65.               a_a      = byte_read(0x2055);

  66. }



  67. /**************开机初始化保存的数据*****************/

  68. void init_eeprom()

  69. {

  70.               read_eeprom();                            //先读

  71.               if(a_a != 22)                            //新的单片机初始单片机内问eeprom

  72.               {

  73.                             t_high = 320;

  74.                             t_low  = 280;

  75.                             a_a = 22;

  76.                             write_eeprom();                 //保存数据

  77.               }            

  78. }





  79. /***********************18b20初始化函数*****************************/

  80. void init_18b20()

  81. {

  82.               bit q;

  83.               dq = 1;                                                        //把总线拿高

  84.               delay_uint(1);                  //15us

  85.               dq = 0;                                                        //给复位脉冲

  86.               delay_uint(80);                            //750us

  87.               dq = 1;                                                        //把总线拿高 等待

  88.               delay_uint(10);                            //110us

  89.               q = dq;                                                        //读取18b20初始化信号

  90.               delay_uint(20);                            //200us

  91.               dq = 1;                                                        //把总线拿高 释放总线

  92. }



  93. /*************写18b20内的数据***************/

  94. void write_18b20(uchar dat)

  95. {

  96.               uchar i;

  97.               for(i=0;i<8;i++)

  98.               {                                                                      //写数据是低位开始

  99.                             dq = 0;                                          //把总线拿低写时间隙开始

  100.                             dq = dat & 0x01; //向18b20总线写数据了

  101.                             delay_uint(5);              // 60us

  102.                             dq = 1;                                          //释放总线

  103.                             dat >>= 1;

  104.               }            

  105. }



  106. /*************读取18b20内的数据***************/

  107. uchar read_18b20()

  108. {

  109.               uchar i,value;

  110.               for(i=0;i<8;i++)

  111.               {

  112.                             dq = 0;                                          //把总线拿低读时间隙开始

  113.                             value >>= 1;              //读数据是低位开始

  114.                             dq = 1;                                          //释放总线

  115.                             if(dq == 1)                            //开始读写数据

  116.                                           value |= 0x80;

  117.                             delay_uint(5);              //60us              读一个时间隙最少要保持60us的时间

  118.               }

  119.               return value;                            //返回数据

  120. }



  121. /*************读取温度的值 读出来的是小数***************/

  122. uint read_temp()

  123. {

  124.               uint value;

  125.               uchar low;                                             //在读取温度的时候如果中断的太频繁了,就应该把中断给关了,否则会影响到18b20的时序

  126.               init_18b20();                               //初始化18b20

  127.               EA = 0;

  128.               write_18b20(0xcc);                 //跳过64位ROM

  129.               write_18b20(0x44);                 //启动一次温度转换命令

  130.               EA = 1;

  131.               delay_uint(50);                               //500us



  132.               init_18b20();                               //初始化18b20

  133.             

  134.               EA = 0;

  135.               write_18b20(0xcc);                 //跳过64位ROM

  136.               write_18b20(0xbe);                 //发出读取暂存器命令

  137.             

  138.               low = read_18b20();                 //读温度低字节

  139.               value = read_18b20();  //读温度高字节

  140.               EA = 1;

  141.               value <<= 8;                               //把温度的高位左移8位

  142.               value |= low;                               //把读出的温度低位放到value的低八位中

  143.               value *= 0.625;                     //转换到温度值 小数

  144.               return value;                               //返回读出的温度 带小数

  145. }



  146. /*************定时器0初始化程序***************/

  147. void time_init()               

  148. {

  149.               EA   = 1;                              //开总中断

  150.               TMOD = 0X11;                //定时器0、定时器1工作方式1

  151.               ET0  = 1;                              //开定时器0中断

  152.               TR0  = 1;                              //允许定时器0定时



  153.               ET1  = 1;                              //开定时器0中断

  154.               TR1  = 0;                              //允许定时器0定时

  155. }



  156. /********************独立按键程序*****************/

  157. uchar key_can;              //按键值



  158. void key()              //独立按键程序

  159. {

  160.               static uchar key_new;

  161.               key_can = 20;                   //按键值还原

  162.               P2 |= 0x07;

  163.               if((P2 & 0x07) != 0x07)                            //按键按下

  164.               {

  165.                             if(key_500ms == 1)              //连加

  166.                             {

  167.                                           key_500ms = 0;

  168.                                           key_new = 1;

  169.                             }

  170.                             delay_1ms(1);                                 //按键消抖动

  171.                             if(((P2 & 0x07) != 0x07) && (key_new == 1))

  172.                             {                                                                                    //确认是按键按下

  173.                                           key_new = 0;

  174.                                           switch(P2 & 0x07)

  175.                                           {

  176.                                                         case 0x06: key_can = 3; break;                 //得到k2键值

  177.                                                         case 0x05: key_can = 2; break;                 //得到k3键值

  178.                                                         case 0x03: key_can = 1; break;                 //得到k4键值

  179.                                           }

  180.                                           flag_lj_en = 1;              //连加使能

  181.                             }                                         

  182.               }

  183.               else

  184.               {

  185.                             if(key_new == 0)

  186.                             {

  187.                                           key_new = 1;

  188.                                           write_eeprom();                            //保存数据

  189.                                           flag_lj_en = 0;                            //关闭连加使能

  190.                                           flag_lj_3_en = 0;              //关闭3秒后使能

  191.                                           key_value = 0;                            //清零

  192.                                           key_time = 0;

  193.                                           key_500ms = 0;

  194.                             }

  195.               }            

  196. }



  197. /****************按键处理数码管显示函数***************/

  198. void key_with()

  199. {

  200.               if(key_can == 1)                //设置键

  201.               {

  202.                             f_pwm_l = 30;

  203.                             menu_1 ++;

  204.                             if(menu_1 >= 3)

  205.                             {

  206.                                           menu_1 = 0;

  207.                                           smg_i = 3;                              //数码管显示3位

  208.                             }

  209.               }

  210.               if(menu_1 == 1)                                          //设置高温报警

  211.               {

  212.                             smg_i = 4;                              //数码管显示4位

  213.                             if(key_can == 2)

  214.                             {

  215.                                           if(flag_lj_3_en == 0)

  216.                                                         t_high ++ ;                            //按键按下未松开自动加三次            

  217.                                           else

  218.                                                         t_high += 10;              //按键按下未松开自动加三次之后每次自动加10

  219.                                           if(t_high > 990)

  220.                                                         t_high = 990;

  221.                             }

  222.                             if(key_can == 3)

  223.                             {

  224.                                           if(flag_lj_3_en == 0)

  225.                                                         t_high -- ;                            //按键按下未松开自动减三次            

  226.                                           else

  227.                                                         t_high -= 10;              //按键按下未松开自动减三次之后每次自动减10

  228.                                           if(t_high <= t_low)

  229.                                                         t_high = t_low + 1;

  230.                             }

  231.                             dis_smg[0] = smg_du[t_high % 10];                         //取小数显示

  232.                             dis_smg[1] = smg_du[t_high / 10 % 10] & 0xdf;  //取个位显示

  233.                             dis_smg[2] = smg_du[t_high / 100 % 10] ;                 //取十位显示

  234.                             dis_smg[3] = 0x64;              //H

  235.               }            

  236.               if(menu_1 == 2)                                          //设置低温报警

  237.               {

  238.                             smg_i = 4;                              //数码管显示4位

  239.                             if(key_can == 2)

  240.                             {

  241.                                           if(flag_lj_3_en == 0)

  242.                                                         t_low ++ ;                                          //按键按下未松开自动加三次            

  243.                                           else

  244.                                                         t_low += 10;                            //按键按下未松开自动加三次之后每次自动加10

  245.                                           if(t_low >= t_high)

  246.                                                         t_low = t_high - 1;

  247.                             }

  248.                             if(key_can == 3)

  249.                             {

  250.                                           if(flag_lj_3_en == 0)

  251.                                                         t_low -- ;                                          //按键按下未松开自动减三次            

  252.                                           else

  253.                                                         t_low -= 10;                            //按键按下未松开自动加三次之后每次自动加10

  254.                                           if(t_low <= 10)

  255.                                                         t_low = 10;

  256.                             }

  257.                             dis_smg[0] = smg_du[t_low % 10];                         //取小数显示

  258.                             dis_smg[1] = smg_du[t_low / 10 % 10] & 0xdf;   //取个位显示

  259.                             dis_smg[2] = smg_du[t_low / 100 % 10] ;                     //取十位显示

  260.                             dis_smg[3] = 0x3D;                //L

  261.               }            

  262. }



  263. /****************风扇控制函数***************/

  264. void fengshan_kz()

  265. {

  266. //              static uchar value;

  267.               if(temperature >= t_high)                //风扇全开

  268.               {            

  269.                             TR1 = 1;

  270.                             pwm = 0;

  271.               }

  272.               else if((temperature < t_high)              && (temperature >= t_low))                               //风扇缓慢

  273.               {

  274.                             f_pwm_l = 60;              

  275.                             TR1 = 1;

  276.               }

  277.               else if(temperature < t_low)              //关闭风扇

  278.               {

  279.                             TR1 = 0;

  280.                             pwm = 1;

  281.               }                                         

  282. }

  283.                            



  284. /****************主函数***************/

  285. void main()

  286. {

  287.               time_init();                    //初始化定时器

  288.               temperature = read_temp();                            //先读出温度的值            

  289.               init_eeprom();  //开始初始化保存的数据

  290.               delay_1ms(650);                                                      

  291.               temperature = read_temp();                                     //先读出温度的值

  292.               dis_smg[0] = smg_du[temperature % 10];              //取温度的小数显示

  293.               dis_smg[1] = smg_du[temperature / 10 % 10] & 0xdf; //取温度的个位显示

  294.               dis_smg[2] = smg_du[temperature / 100 % 10] ;                 //取温度的十位显示

  295.               f_pwm_l = 50;

  296.               while(1)

  297.               {                           

  298.                             key();                                                                      //按键程序

  299.                             if(key_can < 10)

  300.                             {

  301.                                           key_with();                                          //设置报警温度            

  302.                             }

  303.                             if(flag_300ms == 1)                  //300ms 处理一次温度程序

  304.                             {               

  305.                                           flag_300ms = 0;            

  306.                                           temperature = read_temp();              //先读出温度的值

  307.                                           if(menu_1 == 0)

  308.                                           {            

  309.                                                         smg_i = 3;

  310.                                                         dis_smg[0] = smg_du[temperature % 10];              //取温度的小数显示

  311.                                                         dis_smg[1] = smg_du[temperature / 10 % 10] & 0xdf; //取温度的个位显示

  312.                                                         dis_smg[2] = smg_du[temperature / 100 % 10] ;                 //取温度的十位显示

  313.                                           }

  314.                             }

  315.                             fengshan_kz();        //风扇控制函数

  316.               }

  317. }



  318. /*************定时器0中断服务程序***************/

  319. void time0_int() interrupt 1

  320. {            

  321.               static uchar value;                                          //定时2ms中断一次

  322.               TH0 = 0xf8;

  323.               TL0 = 0x30;     //2ms

  324.               display();                            //数码管显示函数

  325.               value++;               

  326.               if(value >= 150)

  327.               {

  328.                             value = 0;               

  329.                             flag_300ms = 1;

  330.               }

  331.               if(flag_lj_en == 1)                 //按下按键使能

  332.               {

  333.                             key_time ++;

  334.                             if(key_time >= 250) //500ms

  335.                             {

  336.                                           key_time = 0;

  337.                                           key_500ms = 1; //500ms

  338.                                           key_value ++;

  339.                                           if(key_value > 3)

  340.                                           {

  341.                                                         key_value = 10;

  342.                                                         flag_lj_3_en = 1; //3次后1.5秒连加大些

  343.                                           }                                                                                   

  344.                             }

  345.               }

  346. }



  347. /*******************定时器1用做单片机模拟PWM 调节***********************/

  348. void Timer1() interrupt 3  //调用定时器1

  349. {

  350.               static uchar value_l;

  351.               TH1=0xfe;    //    定时10ms中断一次

  352.               TL1=0x0c;              //500us

  353.               if(pwm==1)

  354.               {

  355.                             value_l+=3;

  356.                             if(value_l > f_pwm_l)   //高电平



  357. …………限于本文篇幅 余下代码请从51黑下载附件…………
  358. }
复制代码
word文档下载: 1308441054 钱子健 智能温控风扇的设计与实现.rar (1.28 MB, 下载次数: 379)
回复

使用道具 举报

ID:1 发表于 2018-3-7 23:09 | 显示全部楼层
好资料,51黑有你更精彩!!!
回复

使用道具 举报

ID:365127 发表于 2018-7-4 20:09 | 显示全部楼层
好资料,51黑有你更精彩!!!
回复

使用道具 举报

ID:354902 发表于 2018-7-5 20:56 | 显示全部楼层

58行这里提示 SectorErase(0x2000);  有错怎么回事?
回复

使用道具 举报

ID:414431 发表于 2018-10-24 09:14 | 显示全部楼层

好资料,51黑有你更精彩
回复

使用道具 举报

ID:424564 发表于 2018-11-11 16:44 | 显示全部楼层
真棒,谢谢分享
回复

使用道具 举报

ID:428097 发表于 2018-11-17 11:39 | 显示全部楼层
666,大神
回复

使用道具 举报

ID:453635 发表于 2018-12-24 18:37 | 显示全部楼层
写的很详细,谢谢楼主分享。对我很有启发
回复

使用道具 举报

ID:338103 发表于 2018-12-27 18:16 | 显示全部楼层
好资料,51黑有你更精彩!!!
回复

使用道具 举报

ID:463362 发表于 2019-1-6 22:47 | 显示全部楼层
赞一个!
回复

使用道具 举报

ID:476354 发表于 2019-2-15 11:48 | 显示全部楼层

写的很详细,谢谢楼主分享。对我很有启发
回复

使用道具 举报

ID:492803 发表于 2019-3-17 21:21 | 显示全部楼层
好资料,51黑有你更精彩!!!
回复

使用道具 举报

ID:475713 发表于 2019-3-18 00:08 | 显示全部楼层
厉害厉害
回复

使用道具 举报

ID:503706 发表于 2019-4-2 22:39 | 显示全部楼层
十分感谢啊,很好的资料
回复

使用道具 举报

ID:507829 发表于 2019-4-9 14:00 | 显示全部楼层
十分感谢啊,很好的资料
回复

使用道具 举报

ID:490858 发表于 2019-4-10 17:00 | 显示全部楼层
没有电路图吗
回复

使用道具 举报

ID:56665 发表于 2019-4-10 18:21 | 显示全部楼层
好资料,51黑有你更精彩!!!
回复

使用道具 举报

ID:506152 发表于 2019-4-10 22:28 | 显示全部楼层
厉害了!
回复

使用道具 举报

ID:515501 发表于 2019-4-18 15:07 | 显示全部楼层
好资料,51黑有你更精彩
回复

使用道具 举报

ID:515501 发表于 2019-4-18 15:12 | 显示全部楼层
上传附件

广东海洋大学数电历年考题-答案.pdf

641.65 KB, 下载次数: 3, 下载积分: 黑币 -5

回复

使用道具 举报

ID:513536 发表于 2019-4-18 16:55 来自手机 | 显示全部楼层
谢谢分享
回复

使用道具 举报

ID:706683 发表于 2020-3-12 08:57 来自手机 | 显示全部楼层
666,楼主太厉害了
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表