找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 27624|回复: 6
打印 上一主题 下一主题
收起左侧

基于51单片机的DS18B20温控系统设计资料(源码+论文+仿真)

  [复制链接]
跳转到指定楼层
楼主
基于51单片机的温度控制系统资料包:


摘要
在日常生活中温度在我们身边无时不在,温度的控制和应用在各个领域都有重要的作用。很多行业中都有大量的用电加热设备,和温度控制设备,如用于报警的温度自动报警系统,热处理的加热炉,用于融化金属的坩锅电阻炉及各种不同用途的温度箱等,这些都采用单片机技术,利用单片机语言程序对它们进行控制。而单片机技术具有控制和操作使用方便、结构简单便于修改和维护、灵活性大且具有一定的智能性等特点,可以精确的控
制技术标准,提高了温控指标,也大大的提高了产品的质量和性能。

由于单片机技术的优点突出,智能化温度控制技术正被广泛地采用。本文介绍了基于单片机STC89C52 的温度控制系统的设计方案与软硬件实现。采用温度传感器DS18B20 采集温度数据,7段数码管显示温度数据,按键设置温度上下限,当设置为低于下降报警时,当温度低于设定的下限时,点亮发光二极管同时继电器工作,启动加热设备,当温度上升到上限时,断开继电器,停止加热设备工作,如此循环。当设置为高于上限报警时,当温度高于设定的上限时,点亮发光二极管同时继电器工作,启动制冷设备,当温度下降到下限时,熄灭LED,同时断开继电器,使制冷设备停止工作,使温度控制在上下限范围内。上限报警或者是下限报警可以设置,上限和下限温度也可以设置,同时设置的数据掉电后可以存储。给出了系统总体框架、程序流程图和Protel 原理图,并在硬件平台上实现了所设计功能。
目录
摘要
ABSTRACT
第一章 前言
1.1 温度控制系统设计发展历史及意义            
1.2 温度控制系统的目的            
1.3 温度控制系统完成的功能            
第二章 总体设计方案            
2.1 方案一            
2.2 方案二            
3.1 DS18B20简介            
3.1.1DS18B20封装与引脚            
3.1.2 DS18B20的简单性能            
3.2 DS18B20的工作原理            
3.3 DS18B20的测温原理            
3.3.1 测温原理:            
3.3.2 DS18B20的温度采集过程            
3.4  AT24CXX系列掉电存储器的介绍
第四章 单片机接口设计            
4.1 设计原则            
4.2 单片机引脚连接            
4.2.1 单片机引脚图            
4.2.2 串口引脚            
第五章 硬件电路设计            
5.1 主要硬件电路设计            
5.2 软件系统设计            
5.2.1 软件系统设计            
5.2.2 程序组成            
结束语            
致谢            
附录            
参考文献

1.1 温度控制系统设计发展历史及意义

温度控制系统广泛应用于社会生活的各个领域 ,如家电、汽车、材料、电力电子等 ,常用的控制电路根据应用场合和所要求的性能指标有所不同 , 在工业企业中,如何提高温度控制对象的运行性能一直以来都是控制人员和现场技术人员努力解决的问题。这类控制对象惯性大,滞后现象严重,存在很多不确定的因素,难以建立精确的数学模型,从而导致控制系统性能不佳,甚至出现控制不稳定、失控现象。传统的继电器调温电路简单实用 ,但由于继电器动作频繁 ,可能会因触点不良而影响正常工作。控制领域还大量采用传统的PID控制方式,但PID控制对象的模型难以建立,并且当扰动因素不明确时,参数调整不便仍是普遍存在的问题。而采用数字温度传感器DS18B20,因其内部集成了A/D转换器,使得电路结构更加简单,而且减少了温度测量转换时的精度损失,使得测量温度更加精确。数字温度传感器DS18B20只用一个引脚即可与单片机进行通信,大大减少了接线的麻烦,使得单片机更加具有扩展性。由于DS18B20芯片的小型化,更加可以通过单跳数据线就可以和主电路连接,故可以把数字温度传感器DS18B20做成探头,探入到狭小的地方,增加了实用性。更能串接多个数字温度传感器DS18B20进行范围的温度检测。

1.2 温度控制系统的目的

温度控制在日常生活及工业领域应用相当广泛,比如温室、水池、发酵缸、电源等场所的温度控制。而以往温度控制是由人工完成的而且不够重视,其实在很多场所温度都需要监控以防止发生意外。针对此问题,本系统设计的目的是实现一种可连续高精度调温的温度监测和控制系统,实现对温度的实时检测,具有提醒和控制的功能,本设计的内容是温度测试控制系统,控制对象是温度。它的特点在于应用广泛,功能强大,小巧美观,便于携带,是一款既实用又廉价的控制系统。

1.3 温度控制系统完成的功能

本设计是对温度进行实时监测与控制,设计的温度控制系统实现了基本的温度控制功能:此设计中温度恒定值设置为60℃,上下跳转温度为1℃,设计精度值为0.1。当温度低于设定下限温度即59℃时,绿灯亮,报警提醒需要外界的加热措施。当温度上升到上限温度时,停止加温,红灯亮保持温度。当温度高于设定上限温度即61℃时,红灯亮,需要外界采取降温措施(本设计中没有附加外界的加热和降温措施)。当温度下降到恒温度时,停止降温。温度在上下限温度之间时,执行机构不执行。

第二章 总体设计方案2.1 方案一

利用温度传感器将温度测出,通过某种电信号传给外部电路产生一种变化,然后由外部电路控制装置的开启。测温电路的设计,可以使用热敏电阻之类的传感器件利用其感温效应,(如电阻随温度的变化有一个变化的曲线,即利用它的变化特性曲线)温度的变化使得电阻发生了变化根据欧姆定律,电阻的变化会带来电流或这电压的变化。再将随被测温度变化的电压或电流采集过来,然后进行模拟信号换成数字信号(A/D)转换,将数字信号送入单片机,用单片机进行数据的处理,将温度显示在电路上,这样就可以将被测温度显示出来。最后还有外围的控制电路,采取一定的措施来控制产生温度的电路,如加温、降温、保持不动、或者报警。这种设计需要用到A/D转换电路,感温电路比较麻烦。

设计流程图如图2.1

图2.1 设计流程图

2.2 方案二

利用温度传感器芯片直接将温度数据测出,之后通过单片机程序控制温度的上、下限值,用外部电路产生显示和控制加热和降,来达到设计的要求。

考虑使用温度传感器,结合单片机电路设计,采用一只DS18B20温度传感器,直接读取被测温度值,之后进行转换,依次完成设计要求。

比较以上两种方案,很容易看出,采用方案二,电路比较简单,软件设计容易实现,故实际设计中拟采用方案二。

在设计中的控制流程如图2.2所示。

图2.2 温度控制整体流程

在本系统的总体电路设计方框图如图2.3所示,它由五部分组成:单片机STC89C52控制部分; DS18B20温度传感器采集部分;AT24C16数据掉电存储部分;3位LED数码管显示部分;按键调节部分;二极管报警部分;继电器驱动部分。

图2.3  温度计电路总体设计方案


整个设计总体分为以下几个部分:控制部分、显示部分、温度采集部分、按键控制部分,输出部分。

1、控制部分

由单片机STC89C52芯片在程序控制和外围简单组合电路作用下运行,和控制温度的上、下限,和 LED的温度显示。控制发光二级管的亮灭和继电器动作或复位,起到提醒报警功能。

2、显示部分

显示电路采用3位7断共阳LED数码管,从P3口送数,P0口扫描。有两部分显示电路,第一是显示DS18B20温度传感器所检测的当前温度,第二是设定恒定的温度值。

3、温度采集部分

由DS18B20智能温度传感器直接采集被测温度。

4、按键控制部分

由三个按键控制调节,用来调节温度的恒定限值,起到预设调节作用。

第三章 温度传感器DS18B20

3.1 DS18B20简介3.1.1 DS18B20封装与引脚

   DS18B20封装与引脚如图3.1

图3.1  DS18B20的封装与引脚

3.1.2 DS18B20的简单性能

1、 独特的单线接口方式,DS18B20在与微处理器连接时仅需要一条口线即可实现微处理器与DS18B20的双向通讯。
  2、 测温范围 -55℃~+125℃,固有测温分辨率0.5℃。
  3、 支持多点组网功能,多个DS18B20可以并联在唯一的三线上,实现多点测温。
  4、 工作电源: 3~5V/DC。
  5、 在使用中不需要任何外围元件。
  6、 测量结果以9~12位数字量方式串行传送。
  7、 不锈钢保护管直径 Φ6 。
  8、 适用于DN15~25, DN40~DN250各种介质工业管道和狭小空间设备测温。
  9、 标准安装螺纹 M10X1, M12X1.5, G1/2”任选。
  10、 PVC电缆直接出线或德式球型接线盒出线,便于与其它电器设备连接。

3.2 DS18B20的工作原理

DS18B20内部的低温度系数振荡器是一个振荡频率随温度变化很小的振荡器,为计数器1提供一频率稳定的计数脉冲。

高温度系数振荡器是一个振荡频率对温度很敏感的振荡器,为计数器2提供一个频率随温度变化的计数脉冲。

初始时,温度寄存器被预置成-55℃,每当计数器1从预置数开始减计数到0时,温度寄存器中寄存的温度值就增加1℃,这个过程重复进行,直到计数器2计数到0时便停止。

初始时,计数器1预置的是与-55℃相对应的一个预置值。以后计数器1每一个循环的预置数都由斜率累加器提供。为了补偿振荡器温度特性的非线性性,斜率累加器提供的预置数也随温度相应变化。计数器1的预置数也就是在给定温度处使温度寄存器寄存值增加1℃计数器所需要的计数个数。

DS18B20内部的比较器以四舍五入的量化方式确定温度寄存器的最低有效位。在计数器2停止计数后,比较器将计数器1中的计数剩余值转换为温度值后与0.25℃进行比较,若低于0.25℃,温度寄存器的最低位就置0;若高于0.25℃,最低位就置1;若高于0.75℃时,温度寄存器的最低位就进位然后置0。这样,经过比较后所得的温度寄存器的值就是最终读取的温度值了,其最后位代表0.5℃,四舍五入最大量化误差为±1/2LSB,即0.25℃。

温度寄存器中的温度值以9位数据格式表示,最高位为符号位,其余8位以二进制补码形式表示温度值。测温结束时,这9位数据转存到暂存存储器的前两个字节中,符号位占用第一字节,8位温度数据占据第二字节。

DS18B20测量温度时使用特有的温度测量技术。DS18B20内部的低温度系数振荡器能产生稳定的频率信号;同样的,高温度系数振荡器则将被测温度转换成频率信号。当计数门打开时,DS18B20进行计数,计数门开通时间由高温度系数振荡器决定。芯片内部还有斜率累加器,可对频率的非线性度加以补偿,测量结果存入温度寄存器中。一般情况下的温度值应该为9位,但因符号位扩展成高8位,所以最后以16位补码形式读出。

DS18B20工作过程一般遵循以下协议:初始化——ROM操作命令——存储器操作命令——处理数据。

3.3 DS18B20的测温原理3.3.1 测温原理

每一片DSl8B20在其ROM中都存有其唯一的48位序列号,在出厂前已写入片内ROM 中。主机在进入操作程序前必须用读ROM(33H)命令将该DSl8B20的序列号读出。ROM命令代码见表3.1。

程序可以先跳过ROM,启动所有DSl8B20进行温度变换,之后通过匹配ROM,再逐一地读回每个DSl8B20的温度数据。

DS18B20的测温原理,低温度系数晶振的振荡频率受温度的影响很小,用于产生固定频率的脉冲信号送给减法计数器1,高温度系数晶振随温度变化其震荡频率明显改变,所产生的信号作为减法计数器2的脉冲输入,还隐含着计数门,当计数门打开时,DS18B20就对低温度系数振荡器产生的时钟脉冲后进行计数,进而完成温度测量。计数门的开启时间由高温度系数振荡器来决定,每次测量前,首先将-55 ℃所对应的基数分别置入减法计数器1和温度寄存器中,减法计数器1和温度寄存器被预置在-55 ℃所对应的一个基数值。减法计数器1对低温度系数晶振产生的脉冲信号进行减法计数,当减法计数器1的预置值减到0时温度寄存器的值将加1,减法计数器1的预置将重新被装入,减法计数器1重新开始对低温度系数晶振产生的脉冲信号进行计数,如此循环直到减法计数器2计数到0时,停止温度寄存器值的累加,此时温度寄存器中的数值即为所测温度。图3.2中的斜率累加器用于补偿和修正测温过程中的非线性,其输出用于修正减法计数器的预置值,只要计数门仍未关闭就重复上述过程,直至温度寄存器值达到被测温度值。

表3.1  ROM操作命令

指令
约定代码
功                  能
读ROM
33H
读DS18B20 ROM中的编码

符合ROM

55H
发出此命令之后,接着发出64位ROM编码,访问单线总线上与该编码相对应的DS18B20 使之作出响应,为下一步对该DS18B20的读写作准备
搜索ROM
0F0H
用于确定挂接在同一总线上DS18B20的个数和识别64位ROM地址,为操作各器件作好准备
跳过ROM
0CCH
忽略64位ROM地址,直接向DS18B20发温度变换命令,适用于单片工作。
告警搜索
命   令
0ECH
执行后,只有温度超过设定值上限或者下限的片子才做出响应
温度变换
44H
启动DS18B20进行温度转换,转换时间最长为500MS,结果存入内部9字节RAM中
读暂存器
0BEH
读内部RAM中9字节的内容
写暂存器
4EH
发出向内部RAM的第3,4字节写上、下限温度数据命令,紧跟读命令之后,是传送两字节的数据
复制暂存器
48H
将E2PRAM中第3,4字节内容复制到E2PRAM中
重调E2PRAM
0BBH
将E2PRAM中内容恢复到RAM中的第3,4字节
读供电方式
0B4H
读DS18B20的供电模式,寄生供电时DS18B20发送“0”,外接电源供电DS18B20发送“1”


   

图3.2测温原理内部装置

3.3.2 DS18B20温度采集过程

由于DS18B20单线通信功能是分时完成的,他有严格的时隙概念,因此读写时序很重要,系统对DS18B20的各种操作必须按协议进行。操作协议为:初始化DS18B20(发复位脉冲)→发ROM功能命令→发存储器操作命令→处理数据。温度的采集流程如图3.3所示。



图3.3 DS18B20测温流程

为防止断电后密码丢失,特在此项目设计中加入了以AT24C16为核心的存储模块。其电路原理图如下所示:

AT24c16,是IIc总线协议的通信方式。单片机本身不具有IIc通行的硬件设备,因此采用软件模拟的方式完成与单片机的通信。

摘抄文献:

IIC总线工作原理
        I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。
               
起始和终止信号 :SCL线为高电平期间,SDA线由高电平向低电平的变化表示起始信号;SCL线为高电平期间,SDA线由低电平向高电平的变化表示终止信号。
数据传送格式(1)字节传送与应答
每一个字节必须保证是8位长度。数据传送时,先传送最高位(MSB),每一个被传送的字节后面都必须跟随一位应答位(即一帧共有9位)。如果一段时间内没有收到从机的应答信号,则自动认为从机已正确接收到数据。
     AT24C16的芯片地址如下图,1010为固定,A0,A1,A2正好与芯片的1,2,3引角对应,为当前电路中的地址选择线,三根线可选择8个芯片同时连接在电路中,当要与哪个芯片通信时传送相应的地址即可与该芯片建立连接,TX-1B实验板上三根地址线都为0。最后一位R/W为告诉从机下一字节数据是要读还是写,0为写入,1为读出。


      AT24C016芯片地址(0xa0为写,0xa1为读)
任一地址写入数据格式


操作时序图如下:

下面是本项目的源程序:


//*************************************************

//功能:发送非应答信号

void nack_24c16()

{

sda_24c16=1;   

delay_3us();

delay_3us();

scl_24c16=1;

delay_3us();

delay_3us();

scl_24c16=0;

sda_24c16=0;

}

//*************************************************

//功能:发送IIC停止信号

void stop_24c16()

{

   sda_24c16=0;

   scl_24c16=1;                              

   delay_3us();

   delay_3us();                       

   sda_24c16=1;

   delay_3us();

   delay_3us();                                

   scl_24c16=0;

}

//*************************************************

//功能:发送启动通讯的信号

void star_24c16()

{

  sda_24c16=1;

  scl_24c16=1;

  delay_3us();

  delay_3us();

  sda_24c16=0;

  delay_3us();

  delay_3us();

  scl_24c16=0;

}

//****************************************************

//功能:判断应答或非应答

//说明:通讯出错时标志为1,否则为0

void cack_24c16()

{

   scl_24c16=0;

   sda_24c16=1;

   delay_3us();        

   scl_24c16=1;            

   flag12=0;//清除错误标志  

   if(sda_24c16)flag12=1;

   scl_24c16=0;

}     

//****************************************************

//功能:发送应答信号

void mack_24c16()

{

  sda_24c16=0;

  scl_24c16=1;

  delay_3us();

  delay_3us();

  scl_24c16=0;

  sda_24c16=1;

}

//*************************************************

//功能:向24C16写入一字节的数据

void w1byte_24c16(uchar byte1)

{

  uchar i=8;

  while(i--)   

  {            

    delay_3us();

    delay_3us();

    delay_3us();

    if(byte1 & 0x80)

    {sda_24c16=1;}

    else

    {sda_24c16=0;}

    delay_3us();

    delay_3us();

    delay_3us();

    scl_24c16=1;

    delay_3us();

    delay_3us();

    delay_3us();

    scl_24c16=0;

    byte1<<=1;

  }

}

//****************************************************

//功能:从24C16中读出一字节的数据

uchar rd1byte_24c16(void)//;读1字节子程序(通用)读出的数据存放在30H中

{

  uchar i;

  uchar ddata=0;

  sda_24c16=1;//置IO口为1,准备读入数据                     

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

  {

     ddata<<=1;

     delay_3us();

     delay_3us();

     delay_3us();

     scl_24c16=1;

     if(sda_24c16) ddata++;

     delay_3us();

     delay_3us();

     delay_3us();   

     scl_24c16=0;

  }

  return ddata;

}

1





第四章 单片机接口设计4.1 设计原则

DS18B20有2种供电方式,一种是直流电源,还有一种是寄生虫方式供电。采用电源供电方式,此时DS18B20的1脚接地,2脚作为信号线,3脚接电源。电源是利用直流稳压电源。当DS18B20处于写存储器操作和温度A/D变换操作时,总线上必须有强的上拉,上拉开启时间最大为10 μs。采用寄生电源供电方式是VDD和GND端均接地。由于单线制只有一根线,因此发送接收口必须是三状态的。主机控制DS18B20完成温度转换必须经过3个步骤:

  • 初始化
  • ROM操作指令
  • 存储器操作指令。
4.2 单片机引脚连接4.2.1 单片机引脚图

单片机引脚如图4.1所示。



图4.1单片机引脚


4.2.2 串口引脚

串口引脚的连接图如附录1。


第五章 硬件电路设计5.1 主要硬件电路设计

硬件电路主要包括:显示电路,DS18B20温度传感器检测电路,按键电路,晶振电路,二极管显示报警电路,电源电路。

(1) 显示电路

显示电路采用了7段共阴数码管扫描电路,通过单片机的P0.0到P0.7八个端口接数码管的八个引脚,数码管的9号引脚接地。用来显示当前检测的温度值,精确度为0.1。如图5.1所示。节约了单片机的输出端口,便于程序的编写。

本设计中还有一组数码管由P2.0到P2.7连接,除接口不同外其他一样,如图5.2。



图5.2显示电路

(2) DS18B20温度传感器检测电路

温度采集通过数字化的温度传感器DS18B20,通过QD接向单片机的P3.0口。

DS18B20温度传感器电路如图5.3所示。


图5.3 温度传感器电路引脚图

(3) 按键电路

按键电路如图5.4所示。由K2、K3、K4三个按键控制上、下限温度值。P3.1接口接K4按键。P3.2接口接入K3按键。P3.3接口接K2按键。

1.K2温度上下限减少键:减少温度上下限的值。
2.K3温度上下限增加键:增加温度上下限的值。
3.K4温控开关键:进入温控的切换键。


图5.4 按键电路图

(4) 晶振控制电路

晶振采用的是12MHZ的标准晶振。接入单片机的XTAL1、XTAL2。

晶振控制电路如图5.5所示。


图5.5 晶振控制电路图


  (5) 复位电路

复位电路采用了人工复位的方式,按下按键K1使单片机复位。直接接到单片机的RESET引脚。

  复位电路如图5.6所示


图5.6 复位电路图

(6)二极管显示报警电路

二极管显示报警电路如图5.7所示。通过单片机的P3.4和P3.5两个端口送出,采用的是高电平驱动,使其发光发出警告。


图5.7 二极管显示电路

      (8)电源部分

电源部分才用的是直流稳压电源,产生5V的稳定直流电压。电源设计部分如图5.8所示。


图5.8 电源部分电路

5.2 软件系统设计5.2.1 软件系统设计

一个应用系统要完成各项功能,首先必须有较完善的硬件作保证。同时还必须得到相应设计合理的软件的支持,尤其是微机应用高速发展的今天,许多由硬件完成的工作,都可通过软件编程而代替。甚至有些必须采用很复杂的硬件电路才能完成的工作,用软件编程有时会变得很简单,如数字滤波,信号处理等。因此充分利用其内部丰富的硬件资源和软件资源,采用与C51系列单片机相对应的51汇编语言和结构化程序设计方法进行软件编程。

程序设计语言有三种:机器语言、汇编语言和高级语言。机器语言是机器唯一能“懂”的语言,用汇编语言或高级语言编写的程序(称为源程序)最终都必须翻译成机器语言的程序(成为目标程序),计算机才能“看懂”,然后逐一执行。

高级语言是面向问题和计算过程的语言,它可通过于各种不同的计算机,用户编程时不必仔细了解所用的计算机的具体性能与指令系统,而且语句的功能强,常常一个语句已相当于很多条计算机指令,于是用高级语言编制程序的速度比较快,也便于学习和交流,但是本系统却选用了汇编语言。原因在于,本系统是编制程序工作量不大、规模较小的单片机微控制系统,使用汇编语言可以不用像高级语言那样占用较多的存储空间,适合于存储容量较小的系统。同时,本系统对位处理要求很高,需要解决大量的逻辑控制问题。

51指令系统的指令长度较短,它在存储空间和执行时间方面具有较高的效率,编成的程序占用内存单元少,执行也非常的快捷,与本系统的应用要求很适合。而且AT89C—51指令系统有丰富的位操作(或称位处理)指令,可以形成一个相当完整的位操作指令子集,这是AT89C—51指令系统主要的优点之一。对于要求反应灵敏与控制及时的工控、检测等实时控制系统以及要求体积小、系统小的许多“电脑化”产品,可以充分体现出汇编语言简明、整齐、执行时间短和易于使用的特点。

本装置的软件包括主程序、读出温度子程序、复位应答子程序、写入子程序、以及有关DS18B20的程序(初始化子程序、写程序和读程序)。

5.2.2 程序组成

系统程序主要包括主程序,读出温度子程序,写入子程序,门限调节子程序等。

1)主程序

主程序的主要功能是负责温度的实时显示、读出并处理DS18B20的测量的当前温度值,温度测量每1s进行一次。这样可以在一秒之内测量一次被测温度,其程序流程见图5.9所示。

通过调用读温度子程序把存入内存储中的整数部分与小数部分分开存放在不同的两个单元中,然后通过调用显示子程序显示出来。


图5.9 主程序流程图

2)读出温度子程序

读出温度子程序的主要功能是读出RAM中的9字节,在读出时需进行CRC校验,校验有错时不进行温度数据的改写,程序流程图如图5.10所示。

DS18B20的各个命令对时序的要求特别严格,所以必须按照所要求的时序才能达到预期的目的,同时,要注意读进来的是高位在后低位在前,共有12位数,小数4位,整数7位,还有一位符号位。


结束语
本文详细讲述了系统设计方案,并给出了相关程序流程。本设计应用性比较强,可以应用在仓库温度、大棚温度、机房温度、水池等的监控。另外,如果把本设计方案扩展为多点温度控制,加上上位机,则可以实现远程温度监控系统,将具有更大的应用价值。
    本文的创新点在于详细设计了基于单片机AT89C51 的温度监控系统,设计程序已经.此系统可广泛用于温度在DS18B20 测温范围之内的场合,有良好的应用前景。由于单片机的各种优越的特性,使得它的经济效益显的更加突出,有很好的实用性。



附录

附录1

原理电路总设计图


单片机源程序如下:
  1. #include <reg52.h>
  2. #include <intrins.h>

  3. #define uchar unsigned char
  4. #define uint  unsigned int
  5. sbit    jidianqi=P2^0;//继电器控制口
  6. sbit    dis_bit1=P2^6;//定义数码管控制口
  7. sbit    dis_bit2=P2^5;//定义数码管控制口
  8. sbit    dis_bit3=P2^4;//定义数码管控制口
  9. sbit    dis_bit4=P2^7;//定义数码管控制口

  10. sbit    s1_bit=P1^0;  //定义按键S1控制口
  11. sbit    s2_bit=P1^1;  //定义按键S2控制口
  12. sbit    s3_bit=P1^2;  //定义按键S3控制口

  13. sbit  sda_24c16=P3^4;//定义24C16串行数据线 第5脚
  14. sbit  scl_24c16=P3^5;//定义24C16串行时钟线 第6脚

  15. sbit    dq_ds18b20=P1^3;//定义控制DS18B20

  16. #define smg_data    P0//定义数码管数据口

  17. void    delay_3us();//3US的延时程序
  18. void    nack_24c16();//24C16非应答信号  
  19. void    stop_24c16();//停止通讯信号
  20. void    star_24c16();//启动信号
  21. void    cack_24c16();//检测应答信号
  22. void    mack_24c16();//发送应答信号
  23. void    w1byte_24c16(uchar byte1);//向24C16写入一字节的数据
  24. uchar   rd1byte_24c16(void);
  25. void    read_24c16();//读数据操作
  26. void    write_24c16();//写入16字节的数据操作


  27. void  init_t0();//定时器0初始化函数
  28. void  judge_s1();//S1按键处理函数
  29. void  judge_s2();//S2按键处理函数
  30. void  judge_s3();//S3按键处理函数
  31. void  dis(uchar s1,uchar s2,uchar s3,uchar s4);//显示子程序
  32. void  dis_san(uchar s1,uchar s2,uchar s3,uchar s4,uchar san);//闪烁显示子程序
  33. void  judge_dis();//显示处理函数


  34. void  judge_dongzuo();//判断继电器是否动作
  35. //***********************************************************************
  36. //DS18B20测温函数定义
  37. void w_1byte_ds18b20(uchar value);//向DS18B20写一个字节
  38. uchar r_1byte_ds18b20(void);//从DS18B20读取一个字节的数据
  39. void rest_ds18b20(void);//DS18B20复位程序
  40. void readtemp_ds18b20(void);//读取温度
  41. void  countavetemp(void);//计算平均温度
  42. void dis_temp();//温度显示函数

  43. void  delay_3us();//3US的延时程序
  44. void  delay_8us(uint t);//8US延时基准程序
  45. void  delay_50us(uint t);//延时50*T微妙函数的声明
  46. void  display1(uchar dis_data);//数码管1显示子程序
  47. void  display2(uchar dis_data);//数码管2显示子程序
  48. void  display3(uchar dis_data);//数码管3显示子程序
  49. void  display4(uchar dis_data);//数码管4显示子程序
  50. void  display3_dian(uchar dis_data);//数码管3显示子程序


  51. //共阳数码管断码表
  52. const uchar tabl1[18]={0xA0,0xBE,0x62,0x2A,0x3c,0x29,
  53.                      // 0     1    2    3    4    5
  54.                        0x21,0xBa,0x20,0x38,0x61,0x65,0xFF,
  55.                       //6   7     8    9   10 E 11T   12灭
  56.                        0xe1,0x5f,0x65,0xE5,0X34};
  57.                  //    13C  14-   15t     L    H
  58. //共阳数码管断码表(带小数点)
  59. const uchar  tabl2[10]={0x80,0x9e,0x42,0x0A,0x1c,0x09,0x01,
  60. //                        0    1    2     3   4    5    6
  61.                       0x9a,0x00,0x18};
  62.                     //  7   8    9
  63. const uchar tabl3[]={0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x04,0x05,0x06,0x06,0x07,0x08,0x08,0x09,0x09};



  64. uchar flag1,zancun1,zancun2,zancun3;
  65. uchar t0_crycle,msecond_count;
  66. uchar set_h,set_l,dongzuo_flag;//存储设置温度的上限和下限
  67. uchar setlow_f,sethigh_f;//存储设置问的上下限的符号
  68. uchar low_high;//存储低下动作还是高上动作
  69. //unsigned long  temp32_1,temp32_2,temp_ave;
  70. uchar templ,temph,temp_flag;
  71. uchar temp32,flag12;
  72. uchar  t_b,t_s,t_g,t_x,temp_flag2;//从左到右分别存储温度百位,十位,个位,小数位
  73. //主程序
  74. void main()
  75. {
  76.     uchar i;
  77.     P3=0x00;
  78.     dongzuo_flag=0;//继电器动作标志位,0复位,1动作
  79.     jidianqi=0;//继电器复位

  80.     flag1=0;   
  81.     read_24c16();//单片机上电的时候先读取4组密码
  82.     init_t0();
  83.      while(1)
  84.     {
  85.       if(flag1==0)
  86.       {
  87.          countavetemp();//求取平均温度
  88.          judge_dongzuo();
  89.       }
  90.       for(i=0;i<250;i++)
  91.       {
  92.         judge_dis();//显示处理
  93.         judge_s1();
  94.         judge_s2();
  95.         judge_s3();

  96.       }
  97.     }
  98. }

  99. //***************************************************
  100. //读数据操作
  101. void read_24c16()
  102. {
  103.   uchar  i,j;
  104. read1:
  105.        nack_24c16();
  106.         star_24c16();//发送启动脉冲
  107.         w1byte_24c16(0xa0);//24C16的芯片地址,高四位固定为1010,选择第一区,写操作
  108.         cack_24c16();
  109.         if(flag12)goto read1;
  110.         w1byte_24c16(j*6+i+1);//写入24C16的内部地址,选择第二页
  111.         cack_24c16();
  112.         if(flag12)goto read1;
  113.         nack_24c16();
  114.         stop_24c16();//重新开始  
  115.         star_24c16();//
  116.         w1byte_24c16(0xa1);// 24C16的芯片地址,高四位固定为1010,选择第一区,读操作
  117.         cack_24c16();
  118.         if(flag12)goto read1;
  119.         low_high=rd1byte_24c16();
  120.         mack_24c16();
  121.         setlow_f=rd1byte_24c16();
  122.         mack_24c16();
  123.         set_l=rd1byte_24c16();
  124.         mack_24c16();
  125.         sethigh_f=rd1byte_24c16();
  126.         mack_24c16();
  127.         set_h=rd1byte_24c16();

  128.   mack_24c16();
  129.   nack_24c16();
  130.   stop_24c16();
  131.      if(low_high>=2)low_high=1;
  132.      if(setlow_f>=2)setlow_f=1;
  133.      if(set_l>=100)set_l=20;
  134.      if(sethigh_f>=2)sethigh_f=1;
  135.      if(set_h>=100)set_h=38;
  136. }
  137. //****************************************************
  138. //写入数据操作
  139. void write_24c16()
  140. {
  141. write1:
  142.    star_24c16();//发送启动脉冲
  143.    w1byte_24c16(0xa0);//写24C16的芯片地址,高四位固定为1010,选择第一区,写操作
  144.    cack_24c16();// 读取应答或非应答信号
  145.    if(flag12)goto write1;//判断
  146.    w1byte_24c16(01);//写入24C16的内部地址
  147.    cack_24c16();
  148.    if(flag12)goto write1;
  149.    w1byte_24c16(low_high);
  150.    cack_24c16();
  151.    if(flag12)goto write1;
  152.    w1byte_24c16(setlow_f);
  153.    cack_24c16();
  154.    if(flag12)goto write1;
  155.    w1byte_24c16(set_l);
  156.    cack_24c16();
  157.    if(flag12)goto write1;
  158.    w1byte_24c16(sethigh_f);
  159.    cack_24c16();
  160.    if(flag12)goto write1;
  161.    w1byte_24c16(set_h);
  162.    cack_24c16();
  163.    if(flag12)goto write1;
  164.    stop_24c16();//写数据完毕,发送停止脉冲      

  165. }
  166. //set1 进入设置低于下限动作或者高于上下动作
  167. //set2 进入设置上限温度
  168. //set3 进入设置下限温度

  169. //**************************************************
  170. //显示处理函数
  171. void  judge_dis()
  172. {   
  173.     if(flag1==0)
  174.     {
  175.         dis_temp();//温度显示函数
  176.     }
  177.     if(flag1!=0)
  178.     {
  179.        switch(flag1)
  180.        {
  181.            case 1:
  182.                dis(5,10,11,1);//显示SET1

  183.                 break;
  184.            case 2:
  185.                 dis(5,10,11,2);//显示SET2
  186.                 break;
  187.            case 3:
  188.                 dis(5,10,11,3);//显示SET3
  189.                 break;
  190.            case 6://设置高于上限或者低于下限报警
  191.                 dis_san(16+low_high,12,12,12,1);
  192.                 break;
  193.            case 10://进入修改上限温度的正负
  194.            case 15://修改下限温度的正负
  195.                 dis_san(14+zancun1,zancun2/100,zancun2/10%10,zancun2%10,1);
  196.                 break;
  197.            case 11://进入修改上限的百位数据
  198.            case 16:
  199.                 dis_san(14+zancun1,zancun2/100,zancun2/10%10,zancun2%10,2);
  200.                 break;
  201.            case 12://进入修改闹钟,闹钟小时十位闪烁
  202.            case 17:
  203.                 dis_san(14+zancun1,zancun2/100,zancun2/10%10,zancun2%10,3);
  204.                 break;
  205.            case 13://进入修改闹钟,闹钟小时个位闪烁
  206.            case 18:
  207.                 dis_san(14+zancun1,zancun2/100,zancun2/10%10,zancun2%10,4);
  208.                 break;
  209.             default:
  210.                 break;
  211.         }
  212.     }
  213. }
  214. //**************************************************
  215. //S1按键处理函数
  216. void  judge_s1()
  217. {
  218.     s1_bit=1;//置IO为1,准备读入数据
  219.     if(s1_bit==0)//判断是否有按键按下
  220.     {
  221.         delay_50us(1);// 延时,去除机械抖动
  222.         if(s1_bit==0)
  223.         {
  224.            switch(flag1)
  225.            {
  226.                case 0:
  227.                case 1:
  228.                case 2:
  229.                case 10:
  230.                case 11:
  231.                case 12:
  232.                case 15:
  233.                case 16:
  234.                case 17:
  235.                     flag1++;
  236.                     dongzuo_flag=0;
  237.                     jidianqi=0;
  238.                     TR0=1;//
  239.                     break;
  240.                case 3:
  241.                     flag1=1;
  242.                     break;
  243.                case 13:
  244.                     flag1=10;
  245.                     break;
  246.                case 18:
  247.                     flag1=15;
  248.                     break;
  249.                default:
  250.                     break;
  251.            }         
  252.            while(s1_bit==0)
  253.            {
  254.               judge_dis();
  255.            }//等待按键释放
  256.         }
  257.     }
  258. }
  259. //**************************************************
  260. //S2按键处理函数
  261. void  judge_s2()
  262. {
  263.     s2_bit=1;//置IO为1,准备读入收据
  264.     if(s2_bit==0)//判断是否有按键按下
  265.     {
  266.         delay_50us(1);// 延时,去除机械抖动
  267.         if(s2_bit==0)
  268.         {
  269.            switch (flag1)
  270.            {
  271.               case 1: //在显示SET1状态下按S2件,进入修改时间
  272.                  flag1=6;
  273.                  break;
  274.               case 2://在显示SET2状态下按S2,进入设置闹钟
  275.                  zancun1=sethigh_f;
  276.                  zancun2=set_h;
  277.                  flag1=10;
  278.                  break;
  279.               case 6://确定修改低于下限动作或者高于上限动作
  280.                  flag1=0;
  281.                  TR0=0;//
  282.                  write_24c16();
  283.                  break;
  284.               case 10://修改上限温度正负性时按下确定键S2
  285.               case 11://修改上限温度百位数据时按下确定键S2
  286.               case 12://修改上限温度十位数据时按下确定键S2
  287.               case 13://修改上限温度个位数据时按下确定键S2
  288.                  sethigh_f=zancun1;
  289.                  set_h=zancun2;
  290.                  flag1=0;
  291.                  TR0=0;//
  292.                  write_24c16();
  293.                  break;
  294.               case 3:
  295.                  flag1=15;
  296.                  zancun1=setlow_f;
  297.                  zancun2=set_l;
  298.                  break;
  299.               case 15:
  300.               case 16:
  301.               case 17:
  302.               case 18:
  303.                  setlow_f=zancun1;
  304.                  set_l=zancun2;
  305.                  flag1=0;
  306.                  TR0=0;//
  307.                  write_24c16();
  308.                  break;
  309.       /*        case 22:
  310.                  flag1=21;
  311.                  break;
  312.               case 21:
  313.                  flag1=22;
  314.                  break;
  315.               case 4:
  316.                  flag1=23;//秒表暂停
  317.                  msecond_minute=0;
  318.                  msecond_second=0;
  319.                  msecond_msecond=0;
  320.                  break;
  321.               case 23:
  322.                  flag1=24;
  323.                  break;
  324.               case 24:
  325.                  flag1=23;
  326.                  break;
  327.               case 5:
  328.                  flag1=25;//进入计数器模式
  329.                  zancun1=0;
  330.                  zancun2=0;
  331. //                 zancun3=0;
  332.                  break;
  333.               default:
  334.                  break;*/
  335.                
  336.            }  
  337.            while(s2_bit==0)
  338.            {
  339.               judge_dis();
  340.            }//等待按键释放
  341.         }
  342.     }
  343. }
  344. //**************************************************
  345. //S3按键处理函数
  346. void  judge_s3()
  347. {
  348.     s3_bit=1;//置IO为1,准备读入收据
  349.     if(s3_bit==0)//判断是否有按键按下
  350.     {
  351.         delay_50us(1);// 延时,去除机械抖动
  352.         if(s3_bit==0)
  353.         {
  354.            switch (flag1)
  355.            {

  356.               case 6://修改低于下限动作还是高于上限动作
  357.                  if(low_high==0)
  358.                  {
  359.                      low_high=1;
  360.                  }
  361.                  else
  362.                  {
  363.                      low_high=0;
  364.                  }
  365.                  break;
  366.               case 7://修改时间小时的个位数
  367.                  zancun1=zancun1/10*10+(zancun1%10+1)%10;
  368.                  if(zancun1>=24)zancun1=20;
  369.                  break;
  370.               case 8://修改时间分钟的十位数
  371.                  zancun2+=10;
  372.                  if(zancun2>=60)zancun2-=60;
  373.                  break;
  374.               case 9://修改时间分钟的个位数
  375.                  zancun2=zancun2/10*10+(zancun2%10+1)%10;
  376.                  break;
  377.               case 10://修改上限温度的正负性
  378.                  if(zancun1==0)
  379.                  {zancun1=1;}
  380.                  else
  381.                  {zancun1=0;}
  382.                  break;
  383.               case 11://修改上限温度的百位数据
  384.                  zancun2+=100;
  385.                  if(zancun2>=200)zancun2-=200;
  386.                  break;
  387.               case 12://修改上限温度的十位
  388.                  zancun3=zancun2/10%10+1;
  389.                  if(zancun3>=10)zancun3=0;
  390.                  zancun2=zancun2/100*100+zancun3*10+zancun2%10;
  391.                  break;
  392.               case 13://修改上限温度的个位数据
  393.                  zancun3=zancun2%10+1;
  394.                  if(zancun3>=10)zancun3=0;
  395.                  zancun2=zancun2/10*10+zancun3;
  396.                  break;
  397.               case 15://修改下限的正负性
  398.                  if(zancun1==0)
  399.                  {zancun1=1;}
  400.                  else
  401.                  {zancun1=0;}
  402.                  break;
  403.               case 16: //修改下限的百位
  404.                  zancun2+=100;
  405.                  if(zancun2>=200)zancun2-=200;
  406.                  break;
  407.                case 17://修改倒计时分钟的十位数
  408.                  zancun3=zancun2/10%10+1;
  409.                  if(zancun3>=10)zancun3=0;
  410.                  zancun2=zancun2/100*100+zancun3*10+zancun2%10;
  411.                  break;
  412.              case 18: //修改倒计时分钟的个位数
  413.                  zancun3=zancun2%10+1;
  414.                  if(zancun3>=10)zancun3=0;
  415.                  zancun2=zancun2/10*10+zancun3;
  416.                  break;
  417.               default:
  418.                  break;

  419.            }  
  420.            while(s3_bit==0)
  421.            {
  422.               judge_dis();
  423.            }//等待按键释放
  424.         }
  425.     }
  426. }
  427. //****************************************
  428. ////闪烁显示子程序
  429. void  dis_san(uchar s1,uchar s2,uchar s3,uchar s4,uchar san)
  430. {   
  431.      if(san==1)
  432.      {
  433.         if(msecond_count<5)
  434.         {
  435.            display1(s1);
  436.         }
  437.      }
  438.      else
  439.      {
  440.          display1(s1);
  441.      }
  442.      if(san==2)
  443.      {
  444.         if(msecond_count<5)
  445.         {
  446.            display2(s2);
  447.         }
  448.      }
  449.      else
  450.      {
  451.          display2(s2);
  452.      }
  453.      if(san==3)
  454.      {
  455.         if(msecond_count<5)
  456.         {
  457.            display3(s3);
  458.         }
  459.      }
  460.      else
  461.      {
  462.          display3(s3);
  463.      }
  464.      if(san==4)
  465.      {
  466.         if(msecond_count<5)
  467.         {
  468.            display4(s4);
  469.         }
  470.      }
  471.      else
  472.      {
  473.          display4(s4);
  474.      }     
  475. }
  476. //****************************************
  477. //时钟显示程序
  478. void  dis(uchar s1,uchar s2,uchar s3,uchar s4)
  479. {
  480.      display1(s1);
  481.      display2(s2);
  482.      display3(s3);
  483.      display4(s4);

  484. }



  485. //****************************************
  486. //判断继电器是否动作处理函数
  487. void  judge_dongzuo()
  488. {
  489.    if(low_high==0)//低于下限时继电器动作或复位处理程序
  490.    {
  491.      if(dongzuo_flag==0 && temp_flag==0 && setlow_f==0 && temp32>=set_l)
  492.      {
  493.         jidianqi=1;//继电器动作  
  494.         dongzuo_flag=1;//继电器动作标志为1
  495.      }
  496.      if(dongzuo_flag==0 && temp_flag==0 && setlow_f==1)
  497.      {
  498.         jidianqi=1;//继电器动作
  499.         dongzuo_flag=1;//继电器动作标志为1
  500.      }
  501.      if(dongzuo_flag==0 && temp_flag==1 && setlow_f==1 && temp32<set_l)
  502.      {
  503.         jidianqi=1;
  504.         dongzuo_flag=1;
  505.      }
  506.      if(dongzuo_flag==1 && temp_flag==1 && sethigh_f==1&& temp32>=set_h)
  507.      {
  508.         dongzuo_flag=0;
  509.         jidianqi=0;
  510.      }
  511.      if(dongzuo_flag==1 && temp_flag==0 && sethigh_f==0 && temp32<=set_h)
  512.      {
  513.         dongzuo_flag=0;
  514.         jidianqi=0;
  515.      }
  516.      if(dongzuo_flag==1 && temp_flag==1 && sethigh_f==0 )
  517.      {
  518.         dongzuo_flag=0;
  519.         jidianqi=0;
  520.      }
  521.    }
  522.    if(low_high==1)//高于上限时继电器动作和复位处理程序
  523.    {
  524.      if(dongzuo_flag==0 && temp_flag==0 && sethigh_f==0 && temp32<set_h)
  525.      {
  526.         jidianqi=1;//继电器动作  
  527.         dongzuo_flag=1;//继电器动作标志为1
  528.      }
  529.      if(dongzuo_flag==0 && temp_flag==1 && sethigh_f==0)
  530.      {
  531.         jidianqi=1;//继电器动作
  532.         dongzuo_flag=1;//继电器动作标志为1
  533.      }
  534.      if(dongzuo_flag==0 && temp_flag==1 && sethigh_f==1 && temp32>=set_h)
  535.      {
  536.         jidianqi=1;
  537.         dongzuo_flag=1;
  538.      }
  539.      if(dongzuo_flag==1 && temp_flag==1 && setlow_f==1&& temp32<set_l)
  540.      {
  541.         dongzuo_flag=0;
  542.         jidianqi=0;
  543.      }
  544.      if(dongzuo_flag==1 && temp_flag==0 && setlow_f==0 && temp32>=set_l)
  545.      {
  546.         dongzuo_flag=0;
  547.         jidianqi=0;
  548.      }
  549.      if(dongzuo_flag==1 && temp_flag==0 && setlow_f==1 )
  550.      {
  551.         dongzuo_flag=0;
  552.         jidianqi=0;
  553.      }

  554.    }


  555. }
  556. void  countavetemp()//计算平均温度
  557. {
  558.     /* readtemp_ds18b20();
  559.     // temp32=5;
  560.     // t_x=4;
  561.      temp32_1=temp32*100+t_x*10;
  562.      readtemp_ds18b20();
  563.      //temp32=28;
  564.     // t_x=5;
  565.      temp32_2=temp32*100+t_x*10;
  566.      temp_ave=temp32_2+temp32_1;
  567.      temp32_1=temp_ave/2;
  568.      t_x=temp32_1/10%10;
  569.      temp_ave=temp32_1/100;
  570.      t_b=temp_ave/100%10;//计算温度的百位数据
  571.      t_s=temp_ave/10%10;//计算温度的十位数据
  572.      t_g=temp_ave%10;//计算温度的个位数据*/
  573.      readtemp_ds18b20();
  574.      t_b=temp32/100%10;//计算温度的百位数据
  575.      t_s=temp32/10%10;//计算温度的十位数据
  576.      t_g=temp32%10;//计算温度的个位数据*/

  577. }
  578. //****************************************************
  579. //读取温度
  580. void readtemp_ds18b20(void)
  581. {

  582.       rest_ds18b20();
  583.       w_1byte_ds18b20(0xcc); //跳过读序列号的操作
  584.       w_1byte_ds18b20(0x44); //启动温度转换
  585.       delay_8us(2);
  586.       rest_ds18b20();
  587.       w_1byte_ds18b20(0xcc); //跳过读序列号的操作
  588.       w_1byte_ds18b20(0xbe); //读取温度寄存器等(共可读9个寄存器) 前两个就是温度
  589.       templ=r_1byte_ds18b20();
  590.       temph=r_1byte_ds18b20();
  591.    //  templ=0x98;
  592.    //  temph=0xFc;
  593.       if((temph&0xf0))//判断温度的正负性
  594.       {
  595.       temp_flag=0;//温度为负数标志
  596.       temph=~temph;
  597.       templ=~templ;
  598.       t_x=tabl3[templ & 0x0f];//计算温度的小数
  599.       temp32=temph & 0x0f;
  600.       temp32<<=4;
  601.       templ>>=4;
  602.       temp32=temp32 | templ;

  603.     }
  604.     else//为正数
  605.     {
  606.       temp_flag=1;
  607.       t_x=tabl3[templ & 0x0f];//计算温度的小数
  608.       temp32=temph & 0x0f;
  609.       temp32<<=4;
  610.       templ>>=4;
  611.       temp32=temp32 | templ;
  612.      }
  613. }

  614. void dis_temp()//温度显示函数
  615. {

  616.      if(temp_flag==1)//温度为正数
  617.      {
  618.         if(t_b==0)//判断温度的百位数
  619.        {
  620.           display1(12);
  621.           display2(t_s);//显示温度的十位数据
  622.           display3_dian(t_g);//显示温度的个位数据
  623.           display4(t_x);//显示温度的小数位
  624.        }
  625.        else
  626.        {
  627.           display1(t_b);//显示温度的百位数据
  628.           display2(t_s);//显示温度的十位数据
  629.           display3_dian(t_g);//显示温度的个位数据
  630.           display4(t_x);//显示温度的小数位
  631.        }
  632.      }
  633.      else//下为负温度的处理程序
  634.      {
  635.          display1(14);//显示-号
  636.          display2(t_s);//显示温度的十位数据
  637.          display3_dian(t_g);//显示温度的个位数据
  638.          display4(t_x);//显示温度的小数位
  639.      }
  640. }

  641. //***************************************************************
  642. //功能:把数据1显示在数码管1上
  643. void display4(uchar dis_data)
  644. {
  645.    smg_data=tabl1[dis_data];//送显示断码
  646.    dis_bit4=0;//锁存数据
  647.    delay_50us(40);
  648.    dis_bit4=1;
  649. }//***************************************************************
  650. //功能:把数据1显示在数码管1上
  651. void display3(uchar dis_data)
  652. {
  653.    smg_data=tabl1[dis_data];//送显示断码
  654.    dis_bit3=0;//锁存数据
  655.    delay_50us(40);
  656.    dis_bit3=1;
  657. }
  658. //功能:带小数点,把数据显示在数码管3上
  659. void display3_dian(uchar dis_data)
  660. {
  661.    smg_data=tabl2[dis_data];//送显示断码
  662.    dis_bit3=0;//锁存数据
  663.    delay_50us(40);
  664.    dis_bit3=1;
  665. }
  666. //***************************************************************
  667. //功能:把数据1显示在数码管1上
  668. void display1(uchar dis_data)
  669. {
  670.    smg_data=tabl1[dis_data];//送显示断码
  671.    dis_bit1=0;//锁存数据
  672.    delay_50us(40);
  673.    dis_bit1=1;
  674. }
  675. //***************************************************************
  676. //功能:把数据1显示在数码管1上
  677. void display2(uchar dis_data)
  678. {
  679.    smg_data=tabl1[dis_data];//送显示断码
  680.    dis_bit2=0;//锁存数据
  681.    delay_50us(40);
  682.    dis_bit2=1;
  683. }
  684. //**************************************************************************************************
  685. //函数名称:void delay_50US(unsigned int t)
  686. //功能: 延时50*t(us)
  687. void delay_50us(uint t)
  688. {
  689.   unsigned char j;
  690.   for(;t>0;t--)
  691.   {
  692.     for(j=19;j>0;j--);
  693.   }
  694. }
  695. //*******************************************************************************
  696. //8微秒延时基准程序
  697. void delay_8us(uint t)
  698. {
  699. while(--t);
  700. }
  701. //*******************************************************************************
  702. //3微秒延时程序
  703. void delay_3us()
  704. {
  705.   ;
  706.   ;
  707. }
  708. //*******************************************************************************
  709. //子程序功能:向DS18B20写一字节的数据
  710. void w_1byte_ds18b20(uchar value)
  711. {
  712.    uchar i=0;
  713.    for(i=0;i<8;i++)
  714.    {
  715.     dq_ds18b20=0;
  716.     delay_3us();
  717.     if (value & 0x01) dq_ds18b20=1; //DQ = 1
  718.     delay_50us(1); //延时50us 以上
  719.    value>>=1;
  720.      dq_ds18b20=1; //DQ = 1
  721.    }
  722.     delay_50us(1);
  723. }
  724. //读一个字节
  725. uchar r_1byte_ds18b20(void)
  726. {
  727.   uchar i=0;
  728.   uchar value = 0;
  729.   for (i=0;i<8;i++)
  730.   {
  731.    value>>=1;
  732.    dq_ds18b20=0;// DQ_L;
  733.    delay_3us();
  734.    dq_ds18b20=1;
  735.    delay_3us();
  736.   delay_3us();
  737.    if(dq_ds18b20==1) value|=0x80;
  738.    delay_50us(1); //延时40us
  739.   }
  740.   return value;
  741. }
  742. //;**************************************************
  743. //ds18b20复位子程序
  744. void rest_ds18b20(void)
  745. {
  746. rest:delay_3us(); //稍做延时
  747.      delay_3us();
  748.      dq_ds18b20=1;
  749.      delay_3us();
  750.      dq_ds18b20=0;// DQ_L;
  751.      delay_8us(75);//480us<T<960us
  752.      dq_ds18b20=1;//拉高总线
  753.      delay_8us(8);
  754.      if(dq_ds18b20==1)
  755.      {
  756.        return;
  757.      }
  758.      delay_8us(11); //延时90us
  759.      if(dq_ds18b20==1)
  760.      {
  761.        return;
  762.       }
  763.       else
  764.       {
  765.        goto rest;
  766.       }
  767. }
  768. void timer0() interrupt 1
  769. {
  770.               TH0=(65536-50000)/256;
  771.               TL0=(65536-50000)%256;
  772.               t0_crycle++;
  773.               if(t0_crycle==2)// 0.1秒
  774.               {
  775.                 t0_crycle=0;
  776.                 msecond_count++;
  777.       if(msecond_count==10)//1秒
  778.       {
  779.         msecond_count=0;
  780.       }   
  781.               }
  782. }
  783. //********************************************************************************************
  784. void init_t0()
  785. {
  786.                  TMOD=0x01;//设定定时器工作方式1,定时器定时50毫秒
  787.               TH0=(65536-50000)/256;
  788.               TL0=(65536-50000)%256;
  789.               EA=1;//开总中断
  790.               ET0=1;//允许定时器0中断
  791.               t0_crycle=0;//定时器中断次数计数单元
  792. }
  793. //*************************************************
  794. //功能:发送非应答信号
  795. void nack_24c16()
  796. {
  797. sda_24c16=1;   
  798. delay_3us();
  799. delay_3us();
  800. scl_24c16=1;
  801. delay_3us();
  802. delay_3us();
  803. scl_24c16=0;
  804. sda_24c16=0;
  805. }
  806. ……………………

  807. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)



所有资料51hei提供下载:
温控.zip (516.96 KB, 下载次数: 228)


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏7 分享淘帖 顶1 踩1
回复

使用道具 举报

沙发
ID:310766 发表于 2018-4-19 11:17 | 只看该作者
什么东西,原理图与论文不符,原理图垃圾的还是错的
回复

使用道具 举报

板凳
ID:434678 发表于 2019-2-20 09:49 | 只看该作者
下载的东西乱七八糟的。
回复

使用道具 举报

地板
ID:490650 发表于 2019-3-14 13:36 | 只看该作者
感谢分享                    
回复

使用道具 举报

5#
ID:490694 发表于 2019-3-14 14:18 | 只看该作者
学习一下,谢谢分享
回复

使用道具 举报

6#
ID:425316 发表于 2019-11-10 15:14 | 只看该作者
学习一下,感谢分享!
回复

使用道具 举报

7#
ID:619763 发表于 2019-11-29 19:35 | 只看该作者
很好的一篇
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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