单片机PID温控,阴影部分什么意思??

如题所述

第1个回答  推荐于2017-09-02
  单片机PID温控,阴影部分是高低温计数程序。
  /*****************************************************/
  /*采用AT89C51为主控制芯片*/
  /*P0口为数码管的段选口,P2.4~P2.7为位选口*/
  /*DS18B20的DQ接P2.3,12MHZ晶振*/
  /*P2^2,PWM控制脚*/
  /*****************************************************/
  #include<reg51.h>
  #define Kp 1 //比例系数
  #define Ki 0.25 //积分系数
  #define Kd 1 //微分系数

  unsigned char m,n,p; //温度的十位 个位 小数
  unsigned char test_temp; //温度检定标志
  unsigned char key_set_flag; //按键设定进入标志
  unsigned char key_hold; //按键保持标志
  unsigned char Change_step=1; //温度设置步进
  int Real_temp; //实际温度值
  int Set_temp; //设置温度
  int Disp_temp; //显示温度
  int last_error; //上次误差
  float I_term; //前面温差和

  int PID_MAX;
  unsigned int out,PWMT,counter;
  int time; //可控硅脉冲触发时刻

  sbit DQ=P2^3; //定义DS18b20的管脚
  sbit L1=P2^7; //定义控制数码管的管脚
  sbit L2=P2^6;
  sbit L3=P2^5;
  sbit L4=P2^4;
  sbit PWM=P2^2; //PWM控制脚

  unsigned char table[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,
  0x82,0xF8,0x80,0x90,0x7F,0xbF,0xC6};//0-9数字,后面为". - C"

  /*****延时子程序*****/
  void delay(unsigned int t)
  {
  for(;t>0;t--);
  }
  void delay_50us(unsigned int t)
  {
  unsigned char j;
  for(;t>0;t--)
  for(j=19;j>0;j--);
  }

  /*****初始化DS18B20*****/
  unsigned char Init_DS18B20(void)
  {
  unsigned char x=0;
  DQ = 1; //DQ复位
  delay(8); //稍做延时
  DQ = 0; //单片机将DQ拉低
  delay(80); //精确延时,大于480us
  DQ = 1; //拉高总线
  delay(8);
  x = DQ; //稍做延时后,如果x=0则初始化成功,x=1则初始化失败
  delay(4);
  return x;
  }

  /*****读一个字节*****/
  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(4);
  }
  return(dat);
  }

  /*****写一个字节*****/
  void WriteOneChar(unsigned char dat)
  {
  unsigned char i=0;
  for (i=8; i>0; i--)
  {
  DQ = 0;
  DQ = dat&0x01;
  delay(4);
  DQ = 1;
  dat>>=1;
  }
  delay(4);
  }

  /*****读取温度*****/
  int ReadTemperature(void)
  {
  unsigned char a=0;
  unsigned char b=0;
  unsigned int t=0;

  t=Init_DS18B20();
  if(t) return Real_temp;
  WriteOneChar(0xCC); //跳过读序号列号的操作
  WriteOneChar(0x44); //启动温度转换
  // delay(10);
  t=Init_DS18B20();
  if(t) return Real_temp;
  WriteOneChar(0xCC); //跳过读序号列号的操作
  WriteOneChar(0xBE); //读取温度寄存器
  a=ReadOneChar(); //读低8位
  b=ReadOneChar(); //读高8位
  t=b;
  t<<=8;
  t=t|a;
  if(t<=0||t>0x900) return Real_temp;
  return(t);
  }

  void display(signed int dd)//数码管扫描函数
  {
  int tt=0;

  tt= (unsigned int)(dd*0.625+0.5); //放大10倍输出并四舍五入
  m=tt/100; //分离出十位
  n=(tt%100)/10; //分离出个位
  p=tt%10; //分离出小数位

  P0=table[m];
  L1=1; //暂未1,如用三极管驱动要改为0
  delay(300);
  L1=0; //后关闭显示

  P0=table[n];
  //P1=table[10];//第二位后显示中间点
  L2=1;
  delay(300);
  L2=0;
  P0=table[10];
  L2=1;
  delay(300);
  L2=0;

  P0=table[p]; //小数部分
  L3=1;
  delay(300);
  L3=0;

  P0=table[12];
  L4=1;
  delay(300);
  L4=0;
  }

  void key_set(void)
  {
  unsigned char key_value;

  key_value=P1;

  key_value&=0x07; //提取按键键值

  if(key_value!=7) //按键按下
  {
  if(!key_hold) //按键第一次按下
  {
  key_hold=1; //标志按键处于保持按下状态

  switch (key_value)
  {
  //set键按下
  case 6: { if(key_set_flag==0) //首次进入温度设置
  {
  key_set_flag=1; //标志温度设定状态
  Disp_temp=Set_temp; //显示温度值为原设定温度
  }else
  {
  Set_temp=Disp_temp; //新设定温度为当前显示温度
  key_set_flag=0; //清温度设定标志
  Change_step=1; //恢复缺省设定步进值
  }
  break;
  }
  //+键按下
  case 5: { if(key_set_flag) Disp_temp+=Change_step;
  break;
  }
  //-键按下
  case 3: { if(key_set_flag) Disp_temp-=Change_step;
  break;
  }
  //其他组合按键可以扩充,现暂未设置
  default: break;
  }

  }
  else if(key_set_flag)
  { //按键处于一直按下状态
  key_hold++;
  if(key_hold>20) //按键计数超过设定时长
  {
  Change_step=16; //设定步长按1度步进
  key_hold=0; //清按键保持状态,可进入加减按键功能
  }
  
  }
  }else if(key_hold)
  {
  key_hold=0; //标志按键松开状态
  Change_step=1;
  }
  }

  int PID(int Set_value,int Real_value) //标准PID温度控制算法
  {
  int error;
  float P_term, D_term;
  int pid_out;

  error=Set_value - Real_value;//误差量

  P_term =Kp*error; //比例量

  I_term+=Ki*error; //积分量
  if(I_term>PID_MAX) I_term=PID_MAX; //限定积分量上限
  else if(I_term<0) I_term=0; //限定积分量下限

  D_term =Kd*(error - last_error); //微分量

  last_error=error; //缓存当前误差量

  pid_out=(signed int)(P_term+I_term+D_term); //PID控制量计算
  if(pid_out>PID_MAX) pid_out=PID_MAX; //控制量上限=PID_MAX
  else if(pid_out<0) pid_out=0; //控制量下限=0

  return(pid_out);
  }

  void Init0(void) interrupt 0
  {
  TH0=time>>8;
  TL0=time&0x00FF;

  TF0=0;
  ET0=1;

  counter++;
  }

  void T0_int(void) interrupt 1
  {
  TH0=0xFF;
  TL0=0x80;

  if(PWM)
  { PWM=0;
  TH0=0xDA;
  TL0=0x00;
  }
  else PWM=1;
  }
  void main()
  {
  PWMT=128; //128级步进PWM控制
  PID_MAX=PWMT;
  counter=0;
  out=0;
  PWM=0;

  I_term=0;
  last_error=0;

  Set_temp=41; //初始设定温度为41度
  Set_temp<<=4;
  Real_temp=Set_temp;

  Init_DS18B20();
  WriteOneChar(0xCC); //跳过读序号列号的操作
  WriteOneChar(0x44); //启动温度转换
  delay_50us(15000); //等待温度测量

  TMOD=0x01; //定时器0模式1
  TH0=0xFD; //初始计数字用于780us定时
  TL0=0x00;
  TR0=1;
  ET0=1;
  IT0=1;
  EX0=1;
  EA=1;

  while(1)
  { if(counter>=5)
  {
  test_temp=1; //5*20ms=100ms 进行一次温度检定
  counter=0;
  }
  if(test_temp) //温度检定标志置位,进入温度PID调节
  {
  Real_temp=ReadTemperature(); //采集当前实际温度
  out=PID(Set_temp,Real_temp); //PID程序

  time=~((9500/PID_MAX)*(PID_MAX-out)+250); //可控硅触发时刻计数

  test_temp=0; //检定完成,清温度检定标志
  }

  // Real_temp=ReadTemperature(); //读取当前温度
  // out=PID(Set_temp,Real_temp); //PID程序

  //显示温度(设定状态显示设定温度,非设定状态显示实际温度)
  if(!key_set_flag) Disp_temp=Real_temp;
  display(Disp_temp);

  key_set(); //按键温度设置

  }
第2个回答  2015-05-19
是不是个高低温计数程序追问

有吗???基于pid的

第3个回答  2015-05-19
您好,这样的:
//温控PID程序
#include<reg51.h>
#include<intrins.h>
#include<math.h>
#include<string.h>
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<time;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供DA18B20采样*/
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<<i;
delay(4); /*延时80us以完成此次都时序,之后再读下一数据*/
}
EA=1;
return(value);
}追问

没发完呢吧?

本回答被网友采纳
相似回答