高分求stc89c51和DS18B20温度报警器的程序,低于10度绿灯亮,高于10度红灯亮,四位共阴数码管

高分求stc89c51和DS18B20温度报警器的程序,低于10度绿灯亮,高于10度红灯亮,四位共阴数码管,第1张

/ 题目:温度采集系统设计

时间:2010年5月14日

作者:杨国宏/

#include <REGX51H>

#include<stdioh>

#define uchar unsigned char

#define uint unsigned int

sbit ds=P3^5; //温度传感器信号线

sbit beep=P3^4; //蜂鸣器引脚

uint temp;

float f_temp ;

uint warn_l1=270;//温度值乘以10的结果

uint warn_l2=250;

uint warn_h1=300;

uint warn_h2=320;

sbit seg1=P2^4;/数码管一控制/

sbit seg2=P2^5;

sbit seg3=P2^6;

sbit seg4=P2^7;

sbit led0=P1^0;/指示灯用于报警控制/

sbit led1=P1^1;

sbit led2=P1^2;

sbit led3=P1^3;

unsigned char table[]={

0xC0, 0xF9, 0xA4, 0xB0, 0x99,

0x92, 0x82, 0xF8, 0x80, 0x90, //共阳极数码管0到9编码不带小数点

0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10 //共阳极数码管0到9编码带小数点

};

void delay(uint z)

{

uint x,y;

for(x=z;x>0;x--)

for(y=110;y>0;y--);

}

void dsreset()//复位函数(温度传感器)初始化

{

uint i;

ds=0;

i=103;

while(i>0)i--;

ds=1;

i=4;

while(i>0)i--;

}

bit tempreadbit() //读一位数据函数

{

uint i;

bit dat;

ds=0;

i++;

ds=1;

i++;i++; //i++起延时作用

dat=ds;

i=8;

while(i>0)i--;

return(dat);

}

uchar tempread() //读一个字节函数

{

uchar i,j,dat;

dat=0;

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

{

j=tempreadbit();

dat=(j<<7)|(dat>>1); // 读出的数据最低位在最前面,这样刚好一个字节在DAT里

}

return(dat);

}

void tempwritebyte(uchar dat) //向DS18B20写一个字节数据

{

uint i;

uchar j;

bit testb;

for(j=1;j<=8;j++)

{

testb=dat&0x01;

dat=dat>>1;

if(testb) //写1

{

ds=0;

i++;i++;

ds=1;

i=8;while(i>0)i--;

}

else //写0

{

ds=0;

i=8;while(i>0)i--;

ds=1;

i++;i++;

}

}

}

void tempchange()//获取温度并转换

{

dsreset();

delay(1);

tempwritebyte(0xcc);//写跳过读ROM指令

tempwritebyte(0x44); //写温度转换指令

}

uint get_temp()

{

uchar a,b;

dsreset();

delay(1);

tempwritebyte(0xcc);

tempwritebyte(0xbe);

a=tempread(); // 读低八位;

b=tempread();// 读高八位;

temp=b;

temp<<=8; // 两个字节组合为一个字

temp=temp|a;

f_temp=temp00625; // 温度在寄存器中为12位,分辨率为00625度

temp=f_temp10+05; // 乘以10表示小数点后面只取1位,加05是四舍五入

f_temp=f_temp+005;//

return temp; //temp是整型

}

void dis_temp(uint t)

{

uchar shuge,shushi,shubai;

shubai=t/100; //温度数值的十位

shushi=t%100/10; //温度显示的个位

shuge=t%100%10; //温度显示的小数点后一位

seg3=0;

P0=table[shubai];

delay(5);

seg3=1;

seg2=0;

P0=table[shushi+10]; //带小数点显示

delay(10);

seg2=1;

seg1=0;

P0=table[shuge];

delay(5);

seg1=1;

}

void warn (uint s,uchar led)//蜂鸣器报警,灯闪烁

{

uchar i;i=s; //S控制音调,LED控制灯

beep=0;

P1=~(led); //控制相应的灯亮

while(i--);

{

dis_temp(get_temp()); //温度函数起延时作用

}

beep=1; //蜂鸣器不响

P1=0xff; //控制相应的灯

i=s;

while(i--);

{

dis_temp(get_temp());//温度函数起延时作用

}

}

void deal(uint t)

{

uchar i;

if((t>warn_l2)&&(t<=warn_l1)) //温度处理函数

{

warn(40,0x01); //温度大于25度,小于27度,第一个灯亮,蜂鸣器发出“滴”声

}

else if(t<warn_l2)

{ //温度小于25度

warn(40,0x03); //第一个和第二个灯亮,蜂鸣器发出“滴”声

}

else if(t<warn_h2&&(t>warn_h1)) //温度小于32度而大于30度

{

warn(40,0x04); //第三个灯亮,蜂鸣器发出“滴”声

}

else if(t>warn_h2) //温度大于32度

{

warn(10,0x0c); //第三个灯亮,蜂鸣器发出“滴”声

}

else

{

i=40; //在27到30度之间只是调用显示函数延时

while(i--)

{

dis_temp(get_temp());

}

}

}

void init_com()

{

TMOD=0x20; //串口初始化函数

PCON=0x00;

SCON=0x50;

TH1=0xfd; // 波特率9600

TL1=0xfd;

TR1=1;

}

void comm(charparr) //串口数据发送

{

do

{

SBUF=parr++; //发送数据

while(!TI); //等待发送完成标志为1

TI=0; //标志清零

}

while(parr); //保持循环直到字符为'\0'

}

void main() //主函数

{ //电子表部分

uchar buff[4],i;

init_com();

//温度部分

while(1)

{

tempchange(); //温度转换函数

for(i=10;i>0;i--)

{

dis_temp(get_temp()); //获取温度并显示

}

deal(temp); //进行温度处理

sprintf(buff,"%f",f_temp); //浮点型温度格式化为字符型

for(i=10;i>10;i--)

{

dis_temp(get_temp()); //温度显示

}

comm(buff); //串口发送数据

for(i=10;i>10;i--)

{

dis_temp(get_temp()); //温度显示

}

}

}

这个你自己修改下好了 我这个是成功的例子,有问题可以详细看完我的注释

可以安装一个 PCTemperature软件。

PCTemperature随时监控电脑的CPU和显卡温度,并在达到危险时监测报警,程序拥有温度监测和报警的基本功能,同时又很小巧,占用资源很少。

CPU和显卡是电脑最容易出现高温的设备,特别是在游戏过程中,使用PCTemperature(电脑CPU显卡温度监测报警)可以帮你预警提示。

而且,电脑CPU、显卡温度监测报警程序绝对不会更改主页。

功能特点:

1、实时监测电脑的CPU温度和显卡温度,以图形显示温度走势图。

2、可设置最高温度,当CPU或显卡温度超过最高温度时,d出提示框。避免在游戏过程中导致CPU或显卡温度过高而损害硬件设备。

所以可以安装 PCTemperature软件对电脑的温度进行实时监控。

这个是自动控制温度的一个例子,温度降低到一定程度就启动加热。

//温度传感器:DS18B20

//显示方式:LED

#include <reg51h>

#define uchar unsigned char

sbit keyup=P1^0;

sbit keydn=P1^1;

sbit keymd=P1^2;

sbit out=P3^7; //接控制继电器

sbit DQ = P3^4;   //接温度传感器18B20

uchar t[2],number=0,pt;    //温度值

uchar  TempBuffer1[4]={0,0,0,0};

uchar Tmax=18,Tmin=8;

uchar distab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0xff,0xfe,0xf7};

uchar dismod=0,xiaodou1=0,xiaodou2=0,currtemp;

bit flag;

void t0isr() interrupt 1

{

 TH0=(65536-5000)/256;

 TL0=(65536-5000)%256;

 switch(number)

 {

  case 0:

       P2=0x08;

        P0=distab[TempBuffer1[0]];

        break;

  case 1:

       P2=0x04;

        P0=distab[TempBuffer1[1]];

        break;

  case 2:

       P2=0x02;

        P0=distab[TempBuffer1[2]]&0x7f;

        break;

  case 3:

       P2=0x01;

        P0=distab[TempBuffer1[3]];

        break;

  default:

       break;

 }

 number++;

 if(number>3)number=0;

}

void delay_18B20(unsigned int i)

{

 while(i--);

}

/ds18b20初始化函数/

void Init_DS18B20(void)

{

  bit x=0;

 do{

  DQ=1;

  delay_18B20(8);

  DQ = 0;          //单片机将DQ拉低

  delay_18B20(90); //精确延时 大于 480us

  DQ = 1;          //拉高总线

  delay_18B20(14);

  x=DQ;            //稍做延时后 如果x=0则初始化成功 x=1则初始化失败,继续初始化

 }while(x);

  delay_18B20(20);

}

/ds18b20读一个字节/

unsigned char ReadOneChar(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_18B20(4);

  }

  return(dat);

}

/ds18b20写一个字节/

void WriteOneChar(unsigned char dat)

{

  unsigned char i=0;

  for (i=8; i>0; i--)

  {

   DQ = 0;

   DQ = dat&0x01;

    delay_18B20(5);

   DQ = 1;

    dat>>=1;

 }

}

/读取ds18b20当前温度/

unsigned char ReadTemperature(unsigned char rs)

{

 unsigned char tt[2];

  delay_18B20(80); 

 Init_DS18B20();

 WriteOneChar(0xCC);   //跳过读序号列号的 *** 作

 WriteOneChar(0x44);  //启动温度转换

  delay_18B20(80); 

 Init_DS18B20();

 WriteOneChar(0xCC);  //跳过读序号列号的 *** 作

 WriteOneChar(0xBE);  //读取温度寄存器等(共可读9个寄存器)前两个就是温度

 tt[0]=ReadOneChar();  //读取温度值低位

 tt[1]=ReadOneChar();  //读取温度值高位

 return(tt);

}

void covert1(void) //将温度转换为LED显示的数据

{

   uchar x=0x00,y=0x00;

   t[0]=pt;

   pt++;

   t[1]=pt;

   if(t[1]&0x080)      //判断正负温度

   {

    TempBuffer1[0]=0x0c;      //c代表负

  t[1]=~t[1];    /下面几句把负数的补码/

  t[0]=~t[0];    /换算成绝对值/

  x=t[0]+1;

  t[0]=x;

  if(x==0x00)t[1]++;

   }

  else TempBuffer1[0]=0; //A代表正

  t[1]<<=4;  //将高字节左移4位

  t[1]=t[1]&0xf0;

  x=t[0];     //将t[0]暂存到X,因为取小数部分还要用到它

  x>>=4;     //右移4位

  x=x&0x0f;     //和前面两句就是取出t[0]的高四位 

  y=t[1]|x;   //将高低字节的有效值的整数部分拼成一个字节

  TempBuffer1[1]=(y%100)/10;

  TempBuffer1[2]=(y%100)%10;

  t[0]=t[0]&0x0f; //小数部分

  TempBuffer1[3]=t[0]10/16;

  //以下程序段消去随机误检查造成的误判,只有连续12次检测到温度超出限制才切换加热装置

 if(currtemp>Tmin)xiaodou1=0;

 if(y<Tmin)

  {

   xiaodou1++;

   currtemp=y;

   xiaodou2=0;

  }

 if(xiaodou1>12)

  {

   out=0;

   flag=1;

   xiaodou1=0;

  }

 if(currtemp<Tmax)xiaodou2=0;

 if(y>Tmax)

  {

   xiaodou2++;

   currtemp=y;

   xiaodou1=0;

  }

 if(xiaodou2>12)

  {

   out=1;

   flag=0;

   xiaodou2=0;

  }

 out=flag;

}

void convert(char tmp)

{

 uchar a;

 if(tmp<0)

 {

  TempBuffer1[0]=0x0c;

  a=~tmp+1;

 }

 else

 {

  TempBuffer1[0]=0;

  a=tmp;

 }

  TempBuffer1[1]=(a%100)/10;

  TempBuffer1[2]=(a%100)%10;

}

void keyscan( )

{

uchar keyin;

 keyin=P1&0x07;

 if(keyin==0x07)return;

 else if(keymd==0)

  {

   dismod++;

   dismod%=3;

   while(keymd==0);

   switch(dismod)

   {

    case 1:

         convert(Tmax);

          TempBuffer1[3]=0x11;

          break;

    case 2:

         convert(Tmin);

          TempBuffer1[3]=0x12;

          break;

    default:

         break;

   }

  }

 else if((keyup==0)&&(dismod==1))

  {

   Tmax++;

   convert(Tmax);

   while(keyup==0);

  }

 else if((keydn==0)&&(dismod==1))

  {

   Tmax--;

   convert(Tmax);

   while(keydn==0);

  }

 else if((keyup==0)&&(dismod==2))

  {

   Tmin++;

   convert(Tmin);

   while(keyup==0);

  }

 else if((keydn==0)&&(dismod==2))

  {

   Tmin--;

   convert(Tmin);

   while(keydn==0);

  }

 xiaodou1=0;

 xiaodou2=0;

}

main()

{

 TMOD=0x01;

 TH0=(65536-5000)/256;

 TL0=(65536-5000)%256;

 TR0=1;

 ET0=1;

 EA=1;

 out=1;

 flag=0;

 ReadTemperature(0x3f);

  delay_18B20(50000); //延时等待18B20数据稳定 

 while(1)

 {

  pt=ReadTemperature(0x7f); //读取温度,温度值存放在一个两个字节的数组中

  if(dismod==0)covert1();

  keyscan();

  delay_18B20(30000);

 }

}

本设计的温度测量及加热控制系统以 AT89S52 单片机为核心部件,外加温度采集电

路、键盘及显示电路、加热控制电路和越限报警等电路。采用单总线型数字式的温度传

感器 DS18B20,及行列式键盘和动态显示的方式,以容易控制的固态继电器作加热控制

的开关器件。本作品既可以对当前温度进行实时显示又可以对温度进行控制,以使达到

用户需要的温度,并使其恒定在这一温度。人性化的行列式键盘设计使设置温度简单快

速,两位整数一位小数的显示方式具有更高的显示精度。建立在模糊控制理论上的控制

算法,使控制精度完全能满足一般社会生产的要求。通过对系统软件和硬件设计的合理

规划,发挥单片机自身集成众多系统级功能单元的优势,在不减少功能的前提下有效降

低了硬件成本,系统 *** 控简便。

实验证明该温控系统能达到 02℃的静态误差,045℃的控制精度,以及只有 083%

的超调量,因而本设计具有很高的可靠性和稳定性。

关键 词: 单片机 恒温控制 模糊控制

1

引 言

温度是工业生产中主要的被控参数之一,与之相关的各种温度控制系统广泛应用于

冶金、化工、机械、食品等领域。温度控制是工业生产过程中经常遇到的过程控制,有

些工艺过程对其温度的控制效果直接影响着产品的质量,因而设计一种较为理想的温度

控制系统是非常有价值的。

硬件 系统的设计

1、电路总体原理框图

温度测量及加热系统控制的总体结构如图 1 所示。系统主要包括现场温度采集、实

时温度显示、加热控制参数设置、加热电路控制输出、与报警装置和系统核心 AT89S52

单片机作为微处理器。

图 1:系统总体原理框图

温度采集电路以数字量形式将现场温度传至单片机。单片机结合现场温度与用户设

定的目标温度,按照已经编程固化的模糊控制算法计算出实时控制量。以此控制量控制

固态继电器开通和关断,决定加热电路的工作状态,使水温逐步稳定于用户设定的目标

值。在水温到达设定的目标温度后,由于自然冷却而使其温度下降时,单片机通过采样

回的温度与设置的目标温度比较,作出相应的控制,开启加热器。当用户需要比实时温

度低的温度时,此电路可以利用风扇降温。系统运行过程中的各种状态参量均可由数码

管实时显示。

2、温度采集电路的设计

温度采集电路模块如图 2 示。DS18B20 内部结构主要由四部分组成:64 位光刻 ROM、

温度传感器、非挥发的温度报警触发器 TH 和 TL、配置寄存器。其中 DQ 为数字信号输

入/输出端;GND 为电源地;VDD 为外接供电电源输入端。

2

图 2:温度采集电路

DS18B20 中的温度传感器可完成对温度的测量,以 12 位转化为例:用 16 位符号扩展

的二进制补码读数形式提供,以 00625℃/LSB 形式表达,其中 S 为符号位。

这是 12 位转化后得到的 12 位数据,存储在 18B20 的两个 8 比特的 RAM 中,二进

制中的前面 5 位是符号位,如果测得的温度大于 0,这 5 位为 0,只要将测到的数值乘

于 00625 即可得到实际温度;如果温度小于 0,这 5 位为 1,测到的数值需要取反加 1

再乘于 00625 即可得到实际温度。

3、键盘和显示的设计

键盘采用行列式和外部中断相结合的方法,图 3 中各按键的功能定义如下表 1。其

中设置键与单片机的 INT 0 脚相连,S 0 −−S 9 、YES、NO 用四行三列接单片机 P0 口,REST

键为硬件复位键,与 R、C 构成复位电路。模块电路如下图 3:

表 1:按键功能

按键 键名 功能

REST 复位键 使系统复位

RET 设置键 使系统产生中断,进入设置状态

S 0 −−S 9 数字键 设置用户需要的温度

YES 确认键 用户设定目标温度后进行确认

NO 清除键 用户设定温度错误或误按了 YES 键后使用

3

图 3 键盘接口电路

显示采用 3 位共阳 LED 动态显示方式,显示内容有温度值的十位、个位及小数点后

一位。用 P2 口作为段控码输出,并用 74HC244 作驱动。P10—P12 作为位控码输出,

用 PNP 型三极管做驱动。模块电路如下图 4:

4、加热控制电路的设计

图 4 显示接口电路

用于在闭环控制系统中对被控对象实施控制,被控对象为电热杯,采用对加在电热

杯两端的电压进行通断的方法进行控制,以实现对水加热功率的调整,从而达到对水温

控制的目的。对电炉丝通断的控制采用 SSR-40DA 固态继电器。它的使用非常简单,只

要在控制端 TTL 电平,即可实现对继电器的开关,使用时完全可以用 NPN 型三极管接

成电压跟随器的形式驱动。当单片机的 P13 为高点平时,三极管驱动固态继电器工作

接通加热器工作,当单片机的 P13 为低电平时固态继电器关断,加热器不工作。控制

电路图如下图 5:

4

图 5 加热控制电路

5、报警及指示灯电路的设计

当用户设定的目标温度达到时需用声音的形式提醒用户,此时蜂鸣器为三声断续的

滴答滴答的叫声。在本系统中我们为用户设计了越限报警,当温度低于用户设置的目标

温度 10 度或高于 10 度时蜂鸣器为连续不断的滴答滴答叫声。当单片机 P17 输出高电

平时,三极管导通,蜂鸣器工作发出报警声。P17 为低电平时三极管关断,蜂鸣器不

工作。

D1 为电热杯加热指示灯,P15 低电平有效;D0 为检测到 DS18B20 的指示,高电平

有效;D10 为降温指示灯,低电平有效。报警及指示灯电路如下图 6 示:

图 6 报警及指示灯电路

5

软 件系统的设计

系统的软件由三大模块组成:主程序模块、功能实现模块和运算控制模块。

1、主程序模块

主程序主要完成加热控制系统各部件的初始化和实现各功能子程序的调用,以及实

际测量中各个功能模块的协调在无外部中断申请时,单片机通过循环对外部温度进行实

时显示。把设置键作为外部中断 0,以便能对数字按键进行相应处理。主程序流程图如

下图 7:

6

图 7 主程序流程图

7

2、功能实现模块

以用来执行对固态继电器及电热杯的控制。功能实现模块主要由中断处理子程序、

温度比较处理子程序、键盘处理子程序、显示子程序、报警子程序等部分组成。键盘显

示及中断程序流程图如下图 8:

3、运算控制模块

图 8 键盘、显示、中断 子程序流程图

该模块由标度转换、模糊控制算法,及其中用到的乘法子程序。

31 标度转换

16

式中 A 为二进制的温度值, A0 为 DS18B20 的数字信号线送回来的温度数据。

8

单片机在处理标度转换时是通过把 DS18B20 的信号线送回的 16 位数据右移 4 位得

到二进制的温度值。其小数部分通过查小数表的形式获取。程序流程图如下图 9:

开始

将28H低4位与29H高4位组合成

一个字节

将合成的字节(整数部分)送29H

单元

将29H单元低4位送A

给DPTR赋常数表格2首地址

将查到的数值(即小数部分)送

30H单元

结束

32 模糊控制算法子程序

图 9 标度转换子程序流程图

该系统为一温度控制系统,由于无法确切确定电炉的物理模型,因而无法建立其数

学模型和传递函数。加热器为一惯性系统,我们采用模糊控制的方法,通过多次温度测

量模糊计算当用户设定目标温度时需提前关断加热器的温度,利用加热器自身的热惯性

使温度上升到其设定温度。每隔 5 摄氏度我们进行一次温度测量,并当达到其温度时关

断加热器记录下因加热器的热惯性而上升的温度值。从而可以建立热惯性的温度差值

表,在程序中利用查表法,查出相应设定温度对应的关断温度。通过实验数据我们可以

看出,当水温从 0℃加热到 50℃这段温度区域,其温度惯性曲线可近似成线性的直线,

水温从 50℃加热到 100℃这段温度惯性曲线可近似成另一条线性的直线段。通过对设置

的目标温度与温控系统监测温度进行差值处理就可近似的求出单片机的提前关断温度。

程序流程图如图 10:

9

4.源程序见附录[2]

图 10 模糊控制算法子程序流程图

设计 总结

我们的温度控制系统是基于 AT89S52 单片机的设计方案,她能实时显示当前温度,

并能根据用户的要求作出相应的控制。此系统为闭环系统,工作稳定稳定性高,控制精

度高,利用模糊控制算法使超调量大大降低。软件采用模块化结构,提高了通用性。本设

计的目的不仅仅是温度控制本身,主要提供了单片机外围电路及软件包括控制算法设计

的思想,应该说,这种思想比控制系统本身更为重要。

1、设计所达到的性能指标

11 温控系统的标度误差

我们将标准温度计和温控系统探头放人同一容器中,选定若干不同的温度点,记

录下标准温度计显示的温度和温控系统显示的温度进行比较。测量数据如下表 2 所示:

表 2 标准温度计测量的温度和温控系统显示的温度

标准温度计和温控系统显示的温度(℃)

标准温度计 169 477 578 630 728 851 909

温控系统 165 480 583 629 730 855 905

差值比较 -04 03 05 01 02 04 -04

标度误差 15%

10

12 温控系统的静态误差

通过测量在不同的温度点同标准温度的温度差来确定温控系统的静态误差。其测量

数据如下表 3:

表 3 标准温度和温控系统显示的温度

标准温度和温控系统显示的温度(℃)

标准温度 260 370 460 600 700 830

系统显示值 257 364 461 596 700 833

差值 -03 -06 -01 -04 0 03

静态误差 018℃

13 温控系统的控制精度

通过设定不同的温度值,使加热器加热,待温度稳定时记录各温度点的温度计数据

和温控系统的显示值。其记录数据如下表 4:

温度计读数和温控系统显示的温度(℃)

设定温度

值 200 280 350 450 550 750 870 910

系统显示

值 205 277 344 451 541 749 861 912

差值 05 -03 -06 01 -09 -01 -09 02

控制精度 045℃

超调量 083%

2、结果分析论述

我们的系统完全满足设计要求,静态误差方面可以达到 018℃的误差,在读数正确

方面与标准温度计的读数误差为 15%,对一般的工业生产完全可以采用我们的设计。

该系统具有较小的超调值,超调值大约为 083%左右。虽然超调为不利结果,但另

一方面却减小了系统的调节时间。从其数据表可以看出该系统为稳定系统。

3、设计方案评价

31 优点

在硬件方面:本设计方案采用了单总线型数字式的温度传感器,提高了温度的采集

精度,节约了单片机的口线资源。方案还使用仅一跟口线就可控制的美国生产的固态继

电器 SSR—40DA 作加热控制器件,使设计简单化,且可靠性强。在控制精度方面,本设

计在不能确定执行机构的数学模型的情况下,大胆的假设小心的求证,利用模糊控制的

算法来提高控制精度。

在软件方面:我们采用模块化编程,思路清晰,使程序简洁、可移植性强。

32 缺点

本设计方案虽然采用了当前市场最先进的电子器件,使电路设计简单,但设计方案

造价高。本系统虽然具有较小的超调量,但加大了调节时间。如果需要更高的控制精度,

则我们的模糊控制将不适应,需修改程序。

11

33 方案的改进

在不改变加热器容量的情况下,为减小调节时间,可以实行在加热快达到设定温度

时开启风扇来减小热惯性对温度的影响的措施。在控制精度上可采用先进的数字 PID

控制算法,对加热时间进行控制,提高控制精度。

可以改进控制系统使能同 PC 联机通信,以利用 PC 的图形处理功能打印显示温度曲

线。AT89S52 串行口为 TTL 电平,PC 串行口为 RS232 电平,使用一片 MAX232 作为电

平转换驱动。

参考 文献

[1] 李广弟 单片机基础 北京:北京航空航天大学出版社,2001

[2] 王福瑞 单片微机测控系统设计大全 北京:北京航空航天大学出版社,1997

[3] 赵茂泰 智能仪器原理及应用(第 2 版) 北京:电子工业出版社,2004

[4] 赖寿涛 微型计算机控制技术 北京:机械工业出版社,2000

[5] 沙占友 模拟与数字万用表检测及应用技术 北京:电子工业出版社 1999

12

附 录

附录[1]使用说明书

按 键功能说明

数字键:按 SET 键后,按相应的数字键(0~9)可对温度进行设置,所设置的温

度将实时显示在 LED 显示器上;

SET 键:按 SET 键可对温度的十位、个位以及小数部分进行设置;

YES 键:设置好温度后按 YES 键,系统将据你所设置的温度(须大于当前实际

温度)对水进行加热;

NO 键:若误按了 SET 键,或对输入有误,可按 NO 键进行取消;

RST 键:对系统进行复位。

指示 灯及报警器说明

红 灯:加热状态标志;

绿 灯:温度传感器正常工作标志;

蓝 灯:保温状态标志;

报警器:功能①当水温达到预设值时报警提醒;

功能②当水温达到或超越上、下限时报警提示。

13

附录[2]设计总电路

14

附录[3]程序清单

TEMPER_L EQU 29H ;用于 保存读出温度的低 8 位

TEMPER_H EQU 28H ;用于 保存读出温度的高 8 位

FLAG EQU 38H ;是否 检测到 DS 18B20 标志位

DAYU EQU 44H ;设温 >实温

XIYU EQU 45H ;设温 <实温

DEYU EQU 46H ;设温 =实温

GAOLE EQU 47H ;水温 高于最高温度

DILE EQU 48H ;水温 低于最低温度

A_bit EQU 79h ;数码 管个位数存放内存位置

B_bit EQU 7Ah ;数码 管十位数存放内存位置

C_BIT EQU 78H ;数码 管小数存放内存位置

ORG 0000H

AJMP START

ORG 0003H

AJMP PITO

ORG 0030H

START: CLR P17

CLR P13

CLR P15

SETB P16

MOV R4, #00H

MOV SP, #60H ;确立堆栈区

MOV PSW, #00H ;

MOV R0, #20H ;RAM 区首地址

MOV R7, #60H ;RAM 区单元个数

ML: MOV @R0, #00H

INC R0

DJNZ R7, ML

CLR IT0

MAIN:LCALL GET_TEMPER ;调用读温度子程序 进行温度显示,这里我们考

;虑用网站提供的两位数码管来显示温度

;显示范围 00 到 99 度,显示精度为 1 度

;因为 12 位转化时每一位的精度为 00625 度,

;我们不要求显示小数所以可以抛弃 29H 的低 4

;位将 28H 中的低 4 位移入 29H 中的高 4 位,这

;样获得一个新字节,这个字节就是实际测量获

;得的温度

LCALL DISPLAY ;调用数码管显示 子程序

JNB 00H, MAIN

CLR 00H

15

MOV A, 38H

CJNE A, #00H, SS

AJMP MAIN

SS: LCALL GET_TEMPER

LCALL DISPLAY;调用 数码管显示子程序

LCALL BIJIAO

LCALL XIAOYU

LCALL JIXIAN

JNB DEYU ,LOOP

CLR P13 ;关加热器

SETB P16 ;关 蓝灯

SETB P07 ;关风扇

CLR DEYU

LCALL GET_TEMPER

LCALL DISPLAY

AJMP TT2

LOOP:JNB DAYU ,TT

CLR DAYU

SETB P13

SETB P16

SETB P07

CLR P17

LCALL GET_TEMPER

LCALL DISPLAY

AJMP TT2

TT:JNB XIYU, TT2

CLR XIYU

CLR P07

CLR P16

CLR P13

CLR P17

LCALL GET_TEMPER

LCALL DISPLAY

TT2:MOV A, 29H

CLR C

CJNE A, 50H, JX

MOV A , 30H

CLR C

CJNE A, 51H, JIA1

AJMP YS2

JIA1:JC JX

MOV A, 51H

MOV 52H, A

ADD A, #2

16

MOV 52H, A

CLR C

MOV A, 30H

CJNE A, 52H, JIA2

JIA2:JNC JX

YS2:SETB P17

CLR P16

MOV R5, #20H

YS:LCALL GET_TEMPER

LCALL DISPLAY

DJNZ R5, YS

CLR P17

SETB P16

MOV R5, #20H

YS1:LCALL GET_TEMPER

LCALL DISPLAY

DJNZ R5, YS1

YS3:SETB P17

CLR P16

MOV R5, #20H

YS0:LCALL GET_TEMPER

LCALL DISPLAY

DJNZ R5, YS0

CLR P17

SETB P16

MOV R5, #20H

YS01:LCALL GET_TEMPER

LCALL DISPLAY

DJNZ R5, YS01

YS4:SETB P17

CLR P16

MOV R5, #20H

YS02:LCALL GET_TEMPER

LCALL DISPLAY

DJNZ R5, YS02

CLR P17

SETB P16

MOV R5, #20H

YS03:LCALL GET_TEMPER

LCALL DISPLAY

DJNZ R5, YS03

JX: MOV A, 29H

CJNE A, 31H, JX00

JX01:SETB P17

17

CLR C

AJMP LAST

JX00:JC JX01

CLR P17

CJNE A,

JX02:SETB P17

CLR C

AJMP LAST

JX03:JNC JX02

32H,

JX03

CLR P17

LAST:LCALL GET_TEMPER

LCALL DISPLAY

AJMP SS

;常数表格区

TAB:DB 0C0H,0F9H,0A4H,0B0H,99H,92H,82H,0F8 H,80H ;0-8

DB 90H,88H,83H,0C6H,0A1H,86H,8EH,0FFH ,0CH ;9,A,B,C,D,E,F,灭,p

TAB1:DB40H,79H,24H,30H,19H,12H,02H,78H,00H ,10H, ;0--9

TAB2:DB 0, 0, 1, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 8, 9, 9, ;小数点

;1ms 延时程序

; 中断服务程序

; 完成按键识别,键值求取,按键实时显示 等功能;

;

PITO: PUSH ACC

PUSH PSW

SETB RS0

CLR RS1

SET B 00H

MAIN1: MOV R7 , #03H ;显示位数为 2 位

MOV R0, #7AH

MOV 78H, #00H

MOV 79H, #00H

MOV 7AH, #00H

KK: LCALL DIR

LCALL KEY1

LOOP1:CJNE A, #11, LOOP2

AJMP LAST0

LOOP2:CJNE A, #12, LOOP3

LJMP LAST3

LOOP3: CJNE A, #10, L4

MOV A, #00H

L4: MOV @R0, A

LCALL DIR

DEC R0

DJNZ R7, KK

18

SETB 01H

LAST0:JNB 01H, KK

LOOP4:LCALL KEY1

CJNE A, #12, LOOP5

AJMP LAST3

LOOP5:CJNE A, #11, LOOP4

LAST1:LCALL DIR

LCALL MUN

LCALL JD

LCALL BIJIAO

LAST3:POP PSW

POP ACC

RETI

;精度控制 子程序

JD: PUSH ACC

PUSH PSW

CLR C

MOV A, 38H

MOV 50H, A

MOV A, 39H

MOV 51H, A

CJNE A, 29H, L001

L001:JC LAST02 ;设温<实温,则跳出

MOV A, 29H

MOV 41H, A

MOV A, 38H

CJNE A, #25, L002

L003:CLR C ;0 <T<25

SUBB A, 41H

CJNE A, #3, L004

L005:MOV A, 30H

ADD A, #5 ;0<T<25, 差值小于 3 度

DA A

JNB ACC4, L0051

ANL A, #0FH

SETB C

L0051:MOV 39H, A

MOV A, 29H

ADDC A, #1

MOV 38H, A

AJMP LAST2

LAST02: AJMP LAST2

L004:JC L005

MOV A, 39H

19

SUBB A, #0

DA A

MOV 39H, A

JNC L0041

DEC 38H

L0041:MOV A, 38H

SUBB A, #2 ;0<T<25, 差值大 于 3 度

MOV 38H, A

AJMP LAST2

L002:JC L003

CJNE A, #50, L006

L007:CLR C ;25<T<5 0

SUBB A, 41H

CJNE A, #3, L008

L009:MOV A, 30H

ADD A, #1

DA A

JNB ACC4, L0091

ANL A, #0FH

SETB C

L0091:MOV 39H, A

MOV A, 29H

ADDC A, #1

MOV 38H, A

AJMP LAST2

L008:JC L009

MOV A, 39H

SUBB A, #0

MOV 39H, A

MOV A, 38H

SUBB A, #2

MOV 38H, A

AJMP LAST2

L006:JC L007

CJNE A, #65, L010

L011:CLR C

SUBB A, 41H

CJNE A, #3, L012

L013:MOV A, 30H

ADD A, #2

JNB ACC4, L00131

ANL A, #0FH

SETB C

L00131:MOV 39H, A

20

MOV A, 29H

ADDC A, #1

MOV 38H, A

AJMP LAST2

L012:JC L013

MOV A, 39H

SUBB A, #0

MOV 39H, A

MOV A, 38H

SUBB A, #2

MOV 38H, A

AJMP LAST2

L010:JC L011

CJNE A, #90, L016

L017:CLR C

SUBB A, 41H

CJNE A, #2, L014

L015:MOV A, 30H

ADD A, #0

JNB ACC4, L00151

ANL A, #0FH

SETB C

L00151:MOV 39H, A

MOV A, 29H

ADDC A, #1

MOV 38H, A

AJMP LAST2

L014:JC L015

CLR C

MOV A, 38H

SUBB A, #1

MOV 38H, A

AJMP LAST2

L016:JC L017

LAST2:POP PSW

POP ACC

RET

;键扫描

KEY1:LCALL KS1 ;键 扫描

JNZ LK1

LCALL DIR

AJMP KEY1

LK1:LCALL DIR

LCALL DIR

21

LCALL KS1

JNZ LK2

LCALL DIR

AJMP KEY1

LK2:MOV R2, #0FEH ;确定键值

MOV R4, #01H

MOV A, R2

LK4:MOV P0, A

NOP

MOV A, P0

JB ACC3, LONE

MOV A, #00H

AJMP LKP

LONE:JB ACC4 , LTWO

MOV A, #03H

AJMP LKP

LTWO:JB ACC5, LTHR

MOV A, #06H

AJMP LKP

LTHR:JB ACC6, NEXT5

MOV A, #09H

AJMP LKP

NEXT5:INC R4

MOV A, R2

JNB ACC2 ,KND

RL A

MOV R2, A

AJMP LK4

KND:AJMP KEY1

LKP: ADD A, R4

PUSH ACC

LK3:LCALL DIR

LCALL KS1

JNZ LK3

POP ACC

RET

KS1: PUSH PSW

MOV P0, #78H

NOP

MOV A, P0 ;判断有无键按下

CPL A

ANL A, #78H

POP PSW

22

RET

;求设置温度的二 进制代码,值保存在 38H 单元

MUN: PUSH PSW

MOV R0, #7AH ;求键值

MOV A, @R0

SWAP A

DEC R0

ADD A, @R0

MOV R1, A

ANL A, #0F0 H

SWAP A

MOV B, #10

MUL AB

MOV R2, A

MOV A, R1

ANL A, #0FH

ADD A, R2

MOV 38H, A

MOV R0, #78H

MOV 39H, @R0

POP PSW

RET

;比较实际温度和设置温度的大小 并设置相应的标志位

BIJIAO:MOV A, 29 H ;实际温度

摘自百度知道

这个有现成的,楼主可以省很多力气了,请在网上下一个proteusv78,里边程序,仿真电路都有。

程序所在路径:

C:\Program Files\Labcenter Electronics\Proteus 7 Professional\SAMPLES\VSM for 8051\8051 with a DS18B20 Temperture Sensor

源程序:

ds18b20asm

要代码,追问哈。

没仔细看楼主要求,1602也有哈,

楼主把两个程序中和一下就可以了。

改起来也不难,自己弄哦。

我受点累,楼主可以这样改:

11602引脚挪到P2口,及P3口,程序也要改哈,编译运行,这个非常简单。

2再把1602剪下,粘贴到18b20那张图上;1602的程序也粘贴到18b20程序上,改掉标号重复的地方,改掉初始化程序。将18b20的结果显示在LCD上,如有必要,删除7段数码管程序。

#include <reg52h>

#define uchar unsigned char

#define uint unsigned int

sbit DS=P3^7; //define interface 定义DS18B20接口

uint temp; // variable of temperature

uchar flag1; // sign of the result positive or negative

sbit p0_5=P0^5;

sbit p2_7=P2^7;

sbit p2_4=P2^4;

sbit p2_5=P2^5;

sbit p2_6=P2^6;

unsigned char code TABLE[]={

0xd7,0x11,0xcd,0x5d,0x1b,

0x5e,0xde,0x15,0xdf,0x5f,

0x9f,0xdf,0xc6,0xd7,0xce,0x8e};

void delay(uint count) //delay

{

uint i;

while(count)

{

i=200;

while(i>0)

i--;

count--;

}

}

void Init_Com(void)

{

TMOD = 0x20;

PCON = 0x00;

SCON = 0x50;

TH1 = 0xFd;

TL1 = 0xFd;

TR1 = 1;

}

void dsreset(void) //send reset and initialization command

{

uint i; //DS18B20初始化

DS=0;

i=103;

while(i>0)i--;

DS=1;

i=4;

while(i>0)i--;

}

bit tmpreadbit(void) //read a bit 读一位

{

uint i;

bit dat;

DS=0;i++; //i++ for delay 小延时一下

DS=1;i++;i++;

dat=DS;

i=8;while(i>0)i--;

return (dat);

}

uchar tmpread(void) //read a byte date 读一个字节

{

uchar i,j,dat;

dat=0;

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

{

j=tmpreadbit();

dat=(j<<7)|(dat>>1); //读出的数据最低位在最前面,这样刚好

//一个字节在DAT里

}

return(dat); //将一个字节数据返回

}

void tmpwritebyte(uchar dat) //write a byte to ds18b20

{ //写一个字节到DS18B20里

uint i;

uchar j;

bit testb;

for(j=1;j<=8;j++)

{

testb=dat&0x01;

dat=dat>>1;

if(testb) //write 1 写1部分

{

DS=0;

i++;i++;

DS=1;

i=8;while(i>0)i--;

}

else

{

DS=0; //write 0 写0部分

i=8;while(i>0)i--;

DS=1;

i++;i++;

}

}

}

void tmpchange(void) //DS18B20 begin change 发送温度转换命令

{

dsreset(); //初始化DS18B20

delay(1); //延时

tmpwritebyte(0xcc); // 跳过序列号命令

tmpwritebyte(0x44); //发送温度转换命令

}

uint tmp() //get the temperature 获得温度

{

float tt;

uchar a,b;

dsreset();

delay(1);

tmpwritebyte(0xcc);

tmpwritebyte(0xbe); //发送读取数据命令

a=tmpread(); //连续读两个字节数据

b=tmpread();

temp=b;

temp<<=8; //two byte compose a int variable

temp=temp|a; //两字节合成一个整型变量。

tt=temp00625; //得到真实十进制温度值,因为DS18B20

//可以精确到00625度,所以读回数据的最低位代表的是

//00625度。

temp=tt10+05; //放大十倍,这样做的目的将小数点后第一位

//也转换为可显示数字,同时进行一个四舍五入 *** 作。

return temp; //返回温度值

}

void delay10ms() //delay

{

uchar a,b;

for(a=10;a>0;a--)

for(b=60;b>0;b--);

}

void display(uint temp)

{

uchar a,b,c,d;

a=temp/100;

b=temp/10-a10;

d=temp%10;

c=(temp%100-d)/10;

P0=TABLE[d];

p0_5=0;

p2_7=0;

delay(1);

p2_7=1;

P0=TABLE[c];

p2_4=0;

delay(1);

p2_4=1;

P0=TABLE[b];

p0_5=1;

p2_5=0;

delay(1);

p2_5=1;

P0=TABLE[a];

p2_6=0;

delay(1);

p2_6=1;

}

void main() //主函数

{

uchar a;

Init_Com(); //初始化串口

do

{

tmpchange(); //温度转换

for(a=10;a>0;a--)

{

display(tmp()); //显示十次

}

}

while(1);

}

#include<reg52h>

#include<intrinsh>

#define _Nop() _nop_() /定义空指令/

sbit D18B20=P3^7;

sbit k1=P1^5;

unsigned char flag;

unsigned char u,d[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40};

void TempDelay (unsigned char us)

{

while(us--);

}

void Init18b20 (void)

{

D18B20=1;

_nop_();

D18B20=0;

TempDelay(80); //delay 530 uS//80

_nop_();

D18B20=1;

TempDelay(14); //delay 100 uS//14

_nop_();

_nop_();

_nop_();

if(D18B20==0)

flag = 1; //detect 1820 success!

else

flag = 0; //detect 1820 fail!

TempDelay(20); //20

_nop_();

_nop_();

D18B20 = 1;

}

/

Function:向18B20写入一个字节

parameter:

Return:

Modify:

/

void WriteByte (unsigned char wr) //单字节写入

{

unsigned char idata i;

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

{

D18B20 = 0;

_nop_();

D18B20=wr&0x01;

TempDelay(3); //delay 45 uS //5

_nop_();

_nop_();

D18B20=1;

wr >>= 1;

}

}

/

Function:读18B20的一个字节

parameter:

Return:

Modify:

/

unsigned char ReadByte (void) //读取单字节

{

unsigned char idata i;

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

{

D18B20 = 0;

u >>= 1;

D18B20 = 1;

if(D18B20==1)

u |= 0x80;

TempDelay (2);

_nop_();

}

return(u);

}

main()

{unsigned char a,b,c,j;

while(1)

{

Init18b20();

WriteByte(0xcc); //skip rom

WriteByte(0x44); //保存设定值

Init18b20();

WriteByte(0xcc); //skip rom

WriteByte(0xbe); //read Temperature//回调设定值

a=ReadByte();

b=ReadByte();

a=a>>4;

b=b<<4;

c=a+b;

if(c>30)

k1=0;

else

k1=1;

for(j=0;j<250;j++)

{

P0=d[c/10];

P2=0xe3;

TempDelay(100);

P0=d[c%10];

P2=0xe7;

TempDelay(100);

}

}

}

以上就是关于高分求stc89c51和DS18B20温度报警器的程序,低于10度绿灯亮,高于10度红灯亮,四位共阴数码管全部的内容,包括:高分求stc89c51和DS18B20温度报警器的程序,低于10度绿灯亮,高于10度红灯亮,四位共阴数码管、如何设置电脑温度监控器报警温度、51单片机温度报警器原理图和程序有吗等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://www.54852.com/zz/10172840.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-06
下一篇2023-05-06

发表评论

登录后才能评论

评论列表(0条)

    保存