⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 温控最终程序.c

📁 一种用于温度PID控制的程序
💻 C
字号:
#include<absacc.h>
#include<reg51.h>
#define uchar unsigned char
#define uint unsigned int
#include<math.h> 
#include<string.h>  
#define AD0809 XBYTE[0xf605]
sbit p_clock=P2^1;                 //P2.1口为AD0809的时钟输入
sbit ad_busy=P3^2;                 //AD转换结束标志
sbit Start=P2^3;                   //开始转换启动信号
sbit LE=P2^0;                      //锁存标志
sbit P1_3=P1^3;
sbit P1_4=P1^4;
uchar Date_AD;                      //Date_AD来接受AD转换后得到的数据 
uchar led[8];                       //缓冲区
const uchar DATA_7SEG[ ] ={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
                           0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00};   //数码管段码
uchar sed0=0,sed1=0,min0=0,min1=0;   //秒表程序所要用到的四个全局变量
int count=0;                         //用count来控制产生1秒所要循环的次数
uchar Judge;                         //用于PID比较的全局变量,经AD转换的采样温度
uchar value[31];                     //存储采样值,用于滤波
uint sum=0;
uint temp=0;
uchar tt;
struct PID                       //PID结构体 
{  
  uint q1; 
  uint q2; 
  uint q3; 
  uint LastError;                  // 上次误差E(k-1)
  uint PrevError;                  // 上上次误差E(k-2) 
}; 
struct PID spid;                 
int rout;                           
uchar high_time,low_time;              //占空比调节参数 
uchar set_temper;                  //设定温度值


void pdelay(unsigned char time)           //温控延时延时时间为30*time微秒
{ 			                 
 unsigned char m,n; 
 for(n=0;n<time;n++) 
 for(m=0;m<2;m++){} 
} 

void PIDInit (struct PID *pp)            //PID结构体初始化
{ 
  memset ( pp,0,sizeof(struct PID)); 
  spid.q1 = 11;                
  spid.q2 = 15;  
  spid.q3 =10; 
  spid.LastError = 0;        
  spid.PrevError = 0;
  high_time=50;                       //占空比初始化
  low_time=50; 
} 


uint PIDCalc( struct PID *pp, unsigned int NextPoint )     //增量式偏差运算,NextPoint为采样值
{ 
  int Pk,Error; 
  Error =set_temper- NextPoint;                            // 偏差Pk就是△U(k)
  Pk=pp->q1 * Error-pp->q2 * pp-> LastError+pp->q3*pp->PrevError; 
  pp->PrevError = pp->LastError; 
  pp->LastError = Error; 
  return (Pk); 
} 

void compare_temper()                         //温度控制
{ 
      if(set_temper>Judge) 
      { 
        if(set_temper-Judge>4) 
         { 
             high_time=100; 
             low_time=0; 
         } 
        else if((set_temper-Judge>=1)&&(set_temper-Judge<=4))
        { 
           rout = PIDCalc ( &spid,Judge );       
         
            if(rout<0)
         { 
            high_time=2; 
            low_time=98;
         }
            else
         {
             high_time=(unsigned char)(rout*2+4);  
             low_time= (100-high_time); 
         }
       } 
        else  
       { 
            high_time=5; 
            low_time=95; 
       }
   }
else { 
         high_time=0; 
         low_time=100; 
      }

}

void con_temper(void)				//与设定温度比较 
{ int i;
   compare_temper();
   for(i=0;i<low_time;i++)
  {P1_3=1;  P1_4=1; pdelay(2);}
   for(i=0;i<high_time;i++)
  { P1_3=0;  P1_4=0; pdelay(2);}
  
}

void delay(uint x)      //延时程序                    
{
  uchar j;
  while(x--)
  {
    for(j=0;j<125;j++)
	{;}
  }
}  
void display(void)       //显示子程序                    
{
  uchar i;
  uchar sp=0x1f&P1;
 
 for (i=0;i<8;i++)
   {
      P1=sp;         //位选移位
       if(i==6)
        P0=DATA_7SEG[led[i]]+0x80;    //加点
     else
        P0=DATA_7SEG[led[i]];   //送段码
        LE=1;
        sp+=0x20;
        delay(1);
   }
 }


void adc0809()     //AD转换程序
{  
   int i;
   Start=0;
   WR=1;
   P0=0x05;
   WR=0;
   WR=1;
   P0=0xff;
   i=i;
   i=i;
   i=i;
   i=i;
   	do 
  	{     
      p_clock=~p_clock;   //给时钟信号
      i=i;  
      i=i; 
  	} 
	 while(ad_busy==1);  //等待AD转换结束
      Start=0;
      RD=0;
      Date_AD=P0;   //把转换结果保存
      RD=1;         //数据保存后立即使AD的输出锁存,防止干扰显示
  }

void watch()       //秒表程序
{
   if(count==20)             //循环20次才是1秒
    {
        sed0++;
         count=0;
         if(sed0==10)
          {sed1++;sed0=0;}
         if(sed1==6)
          {min0++;sed1=0;}
         if(min0==10)
          {min1++;min0=0;}
         if(min1==6)
          {min1=min0=sed1=sed0=0;}
     }
  led[7]=min1;                       //填写缓冲区
  led[6]=min0;
  led[5]=sed1;
  led[4]=sed0;
  TF0=0;			//定时器T0溢出标志
}

time0() interrupt 1 using 2    //中断服务程序
{
  count++;
  TH0=(65536-46080)/256;    //定时器装入初值 为50微秒
  TL0=(65536-46080)%256; 
}

void sub_one()
{ 
  TH0=(65536-46080)/256;    //定时器装入初值 为50微秒
  TL0=(65536-46080)%256;     
  EA=1;                     //cpu开中断
  ET0=1;                    //定时器0开中断
  TR0=1;                    //启动T/C开始定时(T0运行控制位)
}

void sub_two()
{
   int i=0;
   for(i=30;i>0;i--)              //一下为数字滤波部分
   value[i]=value[i-1];
   value[0]=Date_AD;              //每次采样后的值保存在数组的第零位 
   sum=sum+value[0]-value[30];
   temp=sum/30;                    //求算术平均值
   tt=temp/5;
   led[3]=tt/100;                      //填缓冲区
   led[2]=tt%100/10;
   led[1]=tt%10;
   led[0]=12;                     //显示字符C,表示摄氏度
   Judge=led[2]*10+led[1];       //用Judge保存转换后的温度(十进制式)
}

void communication()                 //通讯子函数
{
    TH1=0xfd;                  //装入初值  
    TL1=0xfd;
    SCON=0xd8;                 //串行口工作在方式3
    PCON=0x00;				   //波特率不加倍
    TR1=1;                     //启动定时
   while(RI==0);               //等待接受数据
     RI=0;				    
     set_temper=SBUF;
     SBUF=Judge;
   while(TI==0);            //判断是否发送完毕
     TI=0;                  //发送完毕则清零
   
}

void main()
{
   int k=0;
   sub_one();               //定时器初始化子程序
   TMOD=0x21;               //两个定时器的设置
   while(1)
   {
   watch();                 //秒表子程序
     if(k==10)
       {
        k=0;
         adc0809();          //AD转换
         sub_two();         //AD转换后数据的处理子程序
       } k++;  
     display();              //显示子程序
     communication();         //串口通讯子程序
     con_temper();           //PID温度控制子程序
    }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -