51单片机-温度控制-PID算法-DS18B20-C语言

发布者:InspiredDreamer最新更新时间:2016-09-05 来源: eefocus关键字:51单片机  温度控制  PID算法  DS18B20 手机看文章 扫描二维码
随时随地手机看文章
#include

#include

#include

#include

struct PID {

unsigned int SetPoint; // 设定目标 Desired Value

unsigned int Proportion; // 比例常数 Proportional Const

unsigned int Integral; // 积分常数 Integral Const

unsigned int Derivative; // 微分常数 Derivative Const

unsigned int LastError; // Error[-1]

unsigned int PrevError; // Error[-2]

unsigned int SumError; // Sums of Errors

};

struct PID spid; // PID Control Structure

unsigned int rout; // PID Response (Output)

unsigned int rin; // PID Feedback (Input)

sbit data1=P1^0;

sbit clk=P1^1;

sbit plus=P2^0;

sbit subs=P2^1;

sbit stop=P2^2;

sbit output=P3^4;

sbit DQ=P3^3;

unsigned char flag,flag_1=0;

unsigned char high_time,low_time,count=0;//占空比调节参数

unsigned char set_temper=35;  

unsigned char temper;       

unsigned char i;

unsigned char j=0;

unsigned int s;

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

延时子程序,延时时间以12M晶振为准,延时时间为30us×time

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

void delay(unsigned char time)

  {

   unsigned char m,n;

     for(n=0;n

       for(m=0;m<2;m++){}

  }

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

写一位数据子程序

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

void write_bit(unsigned char bitval)

  {

    EA=0;

      DQ=0;  /*拉低DQ以开始一个写时序*/

    if(bitval==1)

       {

        _nop_();

        DQ=1;   /*如要写1,则将总线置高*/

        }

      delay(5);   /*延时90us供DS18B20采样*/

    DQ=1;  /*释放DQ总线*/

    _nop_();

    _nop_();

   EA=1;

   }

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

写一字节数据子程序

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

void write_byte(unsigned char val)

{

  unsigned char i;

  unsigned char temp;

  EA=0;

  TR0=0;

  for(i=0;i<8;i++)  /*写一字节数据,一次写一位*/

      {

       temp=val>>i;  /*移位操作,将本次要写的位移到最低位*/

       temp=temp&1;

       write_bit(temp);  /*向总线写该位*/

       }

   delay(7);   /*延时120us后*/

// TR0=1;

  EA=1;

  }

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

读一位数据子程序

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

unsigned char read_bit()

{

  unsigned char i,value_bit;

  EA=0;

  DQ=0;   /*拉低DQ,开始读时序*/

  _nop_();

  _nop_();

  DQ=1;   /*释放总线*/

  for(i=0;i<2;i++){}

  value_bit=DQ;

  EA=1;

  return(value_bit);

  }

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

读一字节数据子程序

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

unsigned char read_byte()

  {

   unsigned char i,value=0;

   EA=0;

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

      {

       if(read_bit())  /*读一字节数据,一个时序中读一次,并作移位处理*/

         value|=0x01<

       delay(4);  /*延时80us以完成此次都时序,之后再读下一数据*/

       }

   EA=1;

   return(value);

  }

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

复位子程序

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

unsigned char reset()

  {

   unsigned char presence;

   EA=0;

   DQ=0;   /*拉低DQ总线开始复位*/

   delay(30);   /*保持低电平480us*/

   DQ=1;   /*释放总线*/

   delay(3);  

   presence=DQ;   /*获取应答信号*/

   delay(28);   /*延时以完成整个时序*/

   EA=1;

   return(presence);  /*返回应答信号,有芯片应答返回0,无芯片则返回1*/

  }

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

获取温度子程序

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

void get_temper()

{

  unsigned char i,j;

  do

  {

    i=reset();  /*复位*/

  }while(i!=0);  /*1为无反馈信号*/

  i=0xcc;  /*发送设备定位命令*/

  write_byte(i);

  i=0x44;  /*发送开始转换命令*/

  write_byte(i);

  delay(180);  /*延时*/

  do

  {

  i=reset();  /*复位*/

  }while(i!=0); 

  i=0xcc;  /*设备定位*/

  write_byte(i);

  i=0xbe;  /*读出缓冲区内容*/

  write_byte(i);

  j=read_byte();

  i=read_byte();  

  i=(i<<4)&0x7f;

  s=(unsigned int)(j&0x0f);

  s=(s*100)/16;

  j=j>>4;

  temper=i|j;                                      /*获取的温度放在temper中

*/

  }

/*=========================================================================

===========================

Initialize PID Structure

===========================================================================

==========================*/

void PIDInit (struct PID *pp)

{

memset ( pp,0,sizeof(struct PID));

}

/*=========================================================================

===========================

PID计算部分

===========================================================================

==========================*/

unsigned int PIDCalc( struct PID *pp, unsigned int NextPoint )

{

unsigned int dError,Error;

Error = pp->SetPoint - NextPoint; // 偏差

pp->SumError += Error; // 积分

dError = pp->LastError - pp->PrevError; // 当前微分

pp->PrevError = pp->LastError;

pp->LastError = Error;

return (pp->Proportion * Error // 比例项

+ pp->Integral * pp->SumEror // 积分项

+ pp->Derivative * dError); // 微分项

}

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

温度比较处理子程序

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

compare_temper()

{

  unsigned char i;

     if(set_temper>temper)

         {

          if(set_temper-temper>1)  

             {

              high_time=100;

              low_time=0;

             }

          else

             {

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

                 {  get_temper();

                    rin = s; // Read Input

                    rout = PIDCalc ( &spid,rin ); // Perform PID Interation

                 }

               if (high_time<=100)

                 high_time=(unsigned char)(rout/800);

               else

                 high_time=100;

               low_time= (100-high_time);

             }

         }

      else if(set_temper<=temper)

             {

               if(temper-set_temper>0)

                 {

                   high_time=0;

                   low_time=100;

                 }

               else

               {

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

                 {  get_temper();

                    rin = s; // Read Input

                    rout = PIDCalc ( &spid,rin ); // Perform PID Interation

                 }

                 if (high_time<100)

                   high_time=(unsigned char)(rout/10000);

                 else

                   high_time=0;

                 low_time= (100-high_time);

               }

             }

     //  else

     //      {}

    }

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

T0中断服务子程序,用于控制电平的翻转 ,40us*100=4ms周期

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

void serve_T0() interrupt 1 using 1

  {

   if(++count<=(high_time))

     output=1;

   else if(count<=100)

     {

      output=0;

      }

   else

      count=0;

   TH0=0x2f;

   TL0=0xe0;

   }

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

串行口中断服务程序,用于上位机通讯

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

void serve_sio() interrupt 4 using 2

  {

/*   EA=0;

   RI=0; 

   i=SBUF;

   if(i==2)

      {

       while(RI==0){} 

       RI=0;

       set_temper=SBUF; 

       SBUF=0x02; 

       while(TI==0){}

       TI=0;

       }

    else if(i==3) 

       {

        TI=0;

       SBUF=temper;

        while(TI==0){}

        TI=0;

        }

     EA=1;   */

   }

void disp_1(unsigned char disp_num1[6])

{

     unsigned char n,a,m;

     for(n=0;n<6;n++)

      {

     //  k=disp_num1[n];

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

         {

          clk=0;

           m=(disp_num1[n]&1);

            disp_num1[n]=disp_num1[n]>>1;

          if(m==1)

             data1=1;

          else

             data1=0;

          _nop_();

          clk=1;

          _nop_();

          }

       }

}

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

显示子程序

功能:将占空比温度转化为单个字符,显示占空比和测得到的温度

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

void display()

{

unsigned char code number[]=

{0xfc,0x60,0xda,0xf2,0x66,0xb6,0xbe,0xe0,0xfe,0xf6};

unsigned char disp_num[6];

unsigned int k,k1;

k=high_time;

k=k%1000;

k1=k/100;

if(k1==0)

    disp_num[0]=0;

else

    disp_num[0]=0x60;

k=k%100;

disp_num[1]=number[k/10];

disp_num[2]=number[k%10];

k=temper;

k=k%100;

disp_num[3]=number[k/10];

disp_num[4]=number[k%10]+1;

disp_num[5]=number[s/10];

disp_1(disp_num);

}

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

主程序

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

main()

{

  unsigned char z;

  unsigned char a,b,flag_2=1,count1=0;

  unsigned char phil[]={2,0xce,0x6e,0x60,0x1c,2};;

  TMOD=0x21;  

  TH0=0x2f;  

  TL0=0x40;

  SCON=0x50;  

  PCON=0x00;            

  TH1=0xfd;  

  TL1=0xfd;

  PS=1;          

  EA=1;   

  EX1=0;  

  ET0=1;  

  ES=1;   

  TR0=1; 

  TR1=1;

  high_time=50;                

  low_time=50;

  PIDInit ( &spid ); // Initialize Structure

  spid.Proportion = 10; // Set PID Coefficients

  spid.Integral = 8;

  spid.Derivative =6;

  spid.SetPoint = 100; // Set PID Setpoint

  while(1)

       {

           if(plus==0)

             {

              EA=0;

              for(a=0;a<5;a++)

                for(b=0;b<102;b++){} 

                if(plus==0)

                  {

                  set_temper++;

                  flag=0;

                  }

              }

            else if(subs==0)

              {

               for(a=0;a<5;a++)

                  for(b=0;a<102;b++){} 

                  if(subs==0)

                  {

                    set_temper--;

                    flag=0;

                   }

               }

            else if(stop==0)

               {

                for(a=0;a<5;a++)

                   for(b=0;b<102;b++){} 

                   if(stop==0)

                   {

                   flag=0;         

                   break;

                   }

             EA=1;

             }

      get_temper();

      b=temper;

      if(flag_2==1)

         a=b;

      if((abs(a-b))>5)

        temper=a;

      else

        temper=b;

      a=temper;

      flag_2=0;

      if(++count1>30)

         {

          display();

          count1=0;

          }

      compare_temper();  

       }

    TR0=0;

    z=1;

while(1)

      {

       EA=0;

       if(stop==0)

        {

         for(a=0;a<5;a++)

           for(b=0;b<102;b++){}

         if(stop==0)

           disp_1(phil);

        //        break;

           }

      EA=1;

         }

关键字:51单片机  温度控制  PID算法  DS18B20 引用地址:51单片机-温度控制-PID算法-DS18B20-C语言

上一篇:用C51编写单片机延时函数
下一篇:单片机控制的LED数码管动态驱动电路

推荐阅读最新更新时间:2024-03-16 15:08

51单片机学习——4--数码管显示
数码管静态显示原理 显示器及其接口 单片机系统中常用的显示器有: 发光二极管LED(Light Emitting Diode)显示器、液晶LCD(Liquid Crystal Display)显示器、TFT液晶显示器等。LED显示器有两种显示结构:段显示(7段、米字型等)和点阵显示(5×8、8×8点阵等)。 LED数码管根据LED的不同接法可以分为2类:共阴和共阳。 使用LED显示器时,要注意区分这两种不同的接法。为了显示数字或字符,必须对数字或字符进行编码。七段数码管加上一个小数点,共计8段。因此为LED显示器提供的编码正好是一个字节。我们实验板用共阴LED显示器,根据电路连接图显示16进制数的编码已列在下表。 0x
[单片机]
<font color='red'>51单片机</font>学习——4--数码管显示
浅析51单片机P0口上拉电阻的选择应用
  P0口作为I/O口输出的时候时,输出低电平为0 输出高电平为高组态(并非5V,相当于悬空状态,也就是说P0 口不能真正的输出高电平)。给所接的负载提供电流,因此必须接上拉电阻(一电阻连接到VCC),由电源通过这个上拉电阻给负载提供电流。   P0作输入时不需要上拉电阻,但要先置1。因为P0口作一般I/O口时上拉场效应管一直截止,所以如果不置1,下拉场效应管会导通,永远只能读到0。因此在输入前置1,使下拉场效应管截止,端口会处于高阻浮空状态,才可以正确读入数据。     由于P0口内部没有上拉电阻,是开漏的,不管它的驱动能力多大,相当于它是没有电源的,需要外部的电路提供,绝大多数情况下P0口是必需加上拉电阻的。   1.一般51
[单片机]
51单片机使用槽型光耦测速模块
【测速模块】 模块资料 我使用的是窄体的槽型光耦测速模块,如下图所示: 接线 1、VCC接电源正极3.3V-5V 2、GND接电源负极 3、D0(TTL开关信号输出)接单片机外部中断 4、A0无效 使用说明 1、模块槽中无遮挡时,接收管导通,模块DO输出低电平,遮挡时,DO输出高电平; 2、DO输出接口可以与单片机10口直接相连,检测传感器是否有遮档,如用电机码盘则可检测电机的转速。 3、模块DO可与继电器相连,组成限位开关等功能,也可以与有源蜂鸣器模块相连,组成报警器。 【单片机程序】 我使用的是传统的89C51单片机,外部晶振为11.0592M。以下程序仅提供思路,省去无关的定义内容等等
[单片机]
<font color='red'>51单片机</font>使用槽型光耦测速模块
51单片机避坑指南
内存的使用 和stm32不同,51往往内存资源非常紧张,所以建立工程之时要列出资源使用统计表。 规则: 要给所有使用到的内存变量都指定好存放位置。 51单片机的存储器资源使用情况如下图所示: 各区域使用场合如下: 1、data区空间小,所以只有频繁用到或对运算速度要求很高的变量才放到data区内,比如for循环中的计数值。 2、data区内最好放局部变量。因为局部变量的空间是可以覆盖的(某个函数的局部变量空间在退出该函数是就释放,由别的函数的局部变量覆盖),可以提高内存利用率。当然静态局部变量除外,其内存使用方式与全局变量相同; 4、程序中遇到的逻辑标志变量可以定义到bdata中,可以大大降低内存占用空间
[单片机]
<font color='red'>51单片机</font>避坑指南
51单片机教程(八):图型带字库液晶128×64
简介:上期我向大家介绍了字符型液晶1602的基本功能,并用51单片机的驱动显示,你可以用它表达你的幸运日期或者你喜欢的数字。虽然说1602液晶使用方便,但如果你想用它表达更多的语言,就难以满足要求了。 一、原理简介 我手里的这款128×64液晶内部是以ST7920芯片作为控制器,是一种具有4位/8位并行、2线或3线串行多种接口方式,内部含有国标一级、二级简体中文字库的点阵图形液晶显示模块;其显示分辨率为128×64, 内置8192个16×16点汉字,和128个16×8点ASCII字符集。可以显示8×4行16×16点阵的汉字。因此利用该液晶模块可以灵活的构成全中文人机交互图形界面,也可完成图形显示。低电压低功耗也是其一显着特点。
[单片机]
<font color='red'>51单片机</font>教程(八):图型带字库液晶128×64
51单片机寄存器寻址方式与指令举例
寄存器寻址的寻址范围是: 1、4个工作寄存器组共有32个通用寄存器,但在 指令 中只能使用当前寄存器组(工作寄存器组的选择在前面专用寄存器的学习中,我们已知道,是由程序状态字PSW中的RS1和RS0来确定的),因此在使用前常需要通过对PSW中的RS1、RS0位的状态设置,来进行对当前工作寄存器组的选择。 2、部份专用寄存器。例如,累加器A、通用寄存器B、地址寄存器DPTR和进位位CY。 寄存器寻址方式是指操作数在寄存器中,因此指定了寄存器名称就能得到操作数。 例如:MOV A,R0 这条指令的意思是把寄存器R0的内容传送到累加器A中,操作数就在R0中。 INC R3 这条指令的意思是把寄存器R3中的内容加1 从前面的学习中我产
[单片机]
基于51单片机太阳能风能风光互补路灯控制器设计
一.硬件方案 本设计由STC89C52单片机电路+太阳能电池板电路+风机发电电路+锂电池充电保护电路+升压电路+稳压电路+光敏电阻电路+4位高亮LED灯电路+2档拨动开关电路+电源电路设计而成。 二.设计功能 (1)采用风机和太阳能电池板给锂电池充电,具有充电保护电路和稳压电路。 (2)锂电池升压到5V给单片机和附属电路供电。 (3)路灯用4个高亮LED灯模拟。 (4)用光敏传感器测光线亮度,低于设置值时自动开启灯光。 (5)路灯控制分为手动模式和自动模式,手动模式下可以自由的开灯或者关灯,自动模式下通过光敏电阻根据光照强度自动控制灯的开和关。 三.设计原理图 (1)原理图主要采用AD软件进行设计,如图: (2)PCB
[单片机]
基于<font color='red'>51单片机</font>太阳能风能风光互补路灯控制器设计
智能温度传感器DS18B20的原理与应用
DS18B20是美国DALLAS半导体公司继DS1820之后最新推出的一种改进型智能温度传感器。与传统的热敏电阻相比,他能够直接读出被测温度并且可根据实际要求通过简单的编程实现9~12位的数字值读数方式。可以分别在93.75 ms和750 ms内完成9位和12位的数字量,并且从DS18B20读出的信息或写入DS18B20的信息仅需要一根口线(单线接口)读写,温度变换功率来源于数据总线,总线本身也可以向所挂接的DS18B20供电,而无需额外电源。因而使用DS18B20可使系统结构更趋简单,可靠性更高。他在测温精度、转换时间、传输距离、分辨率等方面较DS1820有了很大的改进,给用户带来了更方便的使用和更令人满意的效果。 1DS18
[应用]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
热门活动
换一批
更多
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

更多精选电路图
换一换 更多 相关热搜器件
更多每日新闻
随便看看
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved