温度PID控制源码基于51单片机.docx
《温度PID控制源码基于51单片机.docx》由会员分享,可在线阅读,更多相关《温度PID控制源码基于51单片机.docx(15页珍藏版)》请在冰豆网上搜索。
温度PID控制源码基于51单片机
/************************************************************
类型:
温度传感器液晶综合运用。
现象:
在液晶上面显示当前环境温度。
编写:
铁牛电子
时间:
2009.3
修改:
无
【版权】Copyright(C)铁牛电子AllRightsReserved
【声明】此程序仅用于学习与参考,引用请注明版权和作者信息!
************************************************************/
#include//52单片机头文件,一般不要改动,里面包含特殊功能寄存器的定义
#include
#include
#include
#defineucharunsignedchar//将unsignedchar定义为uchar,简化输写。
提高编程速度
#defineuintunsignedint//将unsignedchar定义为uint,简化输写。
提高编程速度
uintshi,ge,xiaoshu;
uintmiao,fen,shi0;
uchari,x,c,crout,d,high_time,low_time;
uintnum;
uintset_temp;
sbitlcdrs=P1^0;//数据命令选择控制
sbitlcdrw=P1^1;//读/写选择控制
sbitlcden=P1^2;
sbits1=P0^0;
sbits2=P0^1;
sbits3=P0^2;
sbitrd=P0^7;
sbitjdq=P3^5;
structPID{
uintSetPoint;//设定目标DesiredValue
uintProportion;//比例常数ProportionalConst
uintIntegral;//积分常数IntegralConst
uintDerivative;//微分常数DerivativeConst
uintLastError;//Error[-1]
uintPrevError;//Error[-2]
uintSumError;//SumsofErrors
};
structPIDspid;//PIDControlStructure
uintrout;//PIDResponse(Output)
uintrin;//PIDFeedback(Input)
uintNextPoint;
uinttemper;
unsignedcharj;
ucharcount,s1num;
ucharcodet0[]="Thetemperature";
ucharcodet1[]="isC";
ucharcodet2[]="Thetemperature";
ucharcodet3[]="isC";
ucharcodewendu[]="0123456789";//利用一个温度表解决温度显示乱码
sbitDS=P3^3;//定义温度DS18B20接口,详情见原理图
voiddelay(ucharz)
{
ucharx,y;
for(x=100;x>1;x--)
for(y=z;y>1;y--);
}
voidwrite_com(ucharcom)//写指令码
{
lcdrs=0;
lcden=0;
P2=com;//送指令码
delay(5);
lcden=1;
delay(5);
lcden=0;
}
voidwrite_date(uchardate)
{
lcdrs=1;
lcden=0;
P2=date;
delay(5);
lcden=1;
delay(5);
lcden=0;
}
voidinit_lcd()//初始化程序
{
//dula=0;
//wela=0;//关掉数码管
lcden=0;
lcdrw=0;
write_com(0x38);//显示模式设置
write_com(0x01);
write_com(0x0c);
write_com(0x06);
write_com(0x80);
for(i=0;i<16;i++)
{
write_date(t0[i]);
delay(0);
}
write_com(0x80+0x40);
for(i=0;i<16;i++)
{
write_date(t1[i]);
delay(0);
}
}
/*************DS18B20温度读取模块*************/
voidtmpDelay(intnum)//延时函数
{
while(num--);
}
voidInit_DS18B20()//初始化ds1820
{
unsignedcharx=0;
DS=1;//DS复位
tmpDelay(8);//稍做延时
DS=0;//单片机将DS拉低
tmpDelay(80);//精确延时大于480us
DS=1;//拉高总线
tmpDelay(14);
x=DS;//稍做延时后如果x=0则初始化成功x=1则初始化失败
tmpDelay(20);
}
unsignedcharReadOneChar()//读一个字节
{
unsignedchari=0;
unsignedchardat=0;
for(i=8;i>0;i--)
{
DS=0;//给脉冲信号
dat>>=1;
DS=1;//给脉冲信号
if(DS)
dat|=0x80;
tmpDelay(4);
}
return(dat);
}
voidWriteOneChar(unsignedchardat)//写一个字节
{
unsignedchari=0;
for(i=8;i>0;i--)
{
DS=0;
DS=dat&0x01;
tmpDelay(5);
DS=1;
dat>>=1;
}
}
unsignedintReadtemp()//读取温度
{
unsignedchara=0;
unsignedcharb=0;
unsignedintt=0;
floattt=0;
Init_DS18B20();
WriteOneChar(0xCC);//跳过读序号列号的操作
WriteOneChar(0x44);//启动温度转换
Init_DS18B20();
WriteOneChar(0xCC);//跳过读序号列号的操作
WriteOneChar(0xBE);//读取温度寄存器
a=ReadOneChar();//连续读两个字节数据//读低8位
b=ReadOneChar();//读高8位
t=b;
t<<=8;
t=t|a;//两字节合成一个整型变量。
tt=t*0.0625;//得到真实十进制温度值,因为DS18B20可以精确到0.0625度,所以读回数据的最低位代表的是0.0625度
t=tt*10+0.5;//放大十倍,这样做的目的将小数点后第一位也转换为可显示数字,同时进行一个四舍五入操作。
return(t);
}
voiddisplay()//显示函数
{
write_com(0x80);
for(i=0;i<16;i++)
{
write_date(t2[i]);
delay(5);
}
write_com(0x80+0x40);//更改数据指针,让字符换行
for(i=0;i<16;i++)
{
write_date(t3[i]);
delay(5);//增加延时可以达到动态的效果
}
write_com(0x80+0x40+5);
write_date(wendu[shi0]);
write_com(0x80+0x40+6);
write_date(wendu[fen]);
write_com(0x80+0x40+7);
write_date(0x2e);
write_com(0x80+0x40+8);
write_date(wendu[miao]);
write_com(0x80+0x40+9);
write_date(0xa1);
}
voiddisplay1()
{
uintnum;//定义的时候用uchar宏定义就会出错
uintshi,ge,xiaoshu;//这里的num,shi,ge,xiaoshu必须用uint无符号整数来表示,用uchar字符型则显示错误
num=Readtemp();
shi=num/100;
ge=num/10%10;
xiaoshu=num%10;
write_com(0x80+0x40+5);
write_date(wendu[shi]);
write_com(0x80+0x40+6);
write_date(wendu[ge]);
write_com(0x80+0x40+7);
write_date(0x2e);
write_com(0x80+0x40+8);
write_date(wendu[xiaoshu]);
write_com(0x80+0x40+9);
write_date(0xa1);
}
/*voidwrite_sfm(ucharadd,uchardate)
{
ucharge;
//shi=date/10;
ge=date%10;
//xiaoshu=num%10;
write_com(0x80+0x40+add);
//write_date(0x30+shi);
write_date(0x30+ge);
//write_date(0x30+xiaoshu);
}*/
voidint0()interrupt0
{
EX0=0;
display();
while
(1)
{
rd=0;
if(s1==0)
{
delay(5);
if(s1==0)
{s1num++;
while(!
s1);
if(s1num==1)
{
TR0=0;
write_com(0x80+0x40+8);
write_com(0x0f);
}
}
if(s1num==2)
{
write_com(0x80+0x40+6);
}
if(s1num==3)
{
write_com(0x80+0x40+5);
}
if(s1num==4)
{
s1num=0;
write_com(0x0c);
TR0=1;
set_temp=shi0*100+fen*10+miao;
break;
}
}
if(s1num!
=0)
{
if(s2==0)
{
delay(5);
if(s2==0)
{
while(!
s2);
if(s1num==1)
{
miao++;
if(miao==10)
miao=0;
write_date(wendu[miao]);
write_com(0x80+0x40+8);
}
if(s1num==2)
{
fen++;
if(fen==10)
fen=0;
write_date(wendu[fen]);
write_com(0x80+0x40+6);
}
if(s1num==3)
{
shi0++;
if(shi0==10)
shi0=0;
write_date(wendu[shi0]);
write_com(0x80+0x40+5);
}
}
}
}
}
EX0=1;
}
voidPIDInit(structPID*pp)
{
memset(pp,0,sizeof(structPID));
}
floatPIDCalc(structPID*pp,NextPoint)
{
unsignedintdError,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->SumError+pp->Derivative*dError);
}
compare_temper()
{
spid.SetPoint=set_temp;//SetPIDSetpoint
temper=Readtemp();
set_temp=shi0*100+fen*10+miao;
if(set_temp>temper)
{
if(set_temp-temper>50)
{
jdq=0;
}
elseif(set_temp-temper<=50)
{
for(j=0;j<10;j++)
{
temper=Readtemp();
rin=temper;//ReadInput
rout=PIDCalc(&spid,rin);//PerformPIDInteration
}
if(high_time<=100)
high_time=(unsignedchar)(rout/800);
else
high_time=100;
low_time=(100-high_time);
}
elseif(set_temp<=temper)
{
jdq=1;
}
}
}
voidmain()
{
c=0;
d=0;
PIDInit(&spid);//InitializeStructure
spid.Proportion=10;//SetPIDCoefficients
spid.Integral=8;
spid.Derivative=6;
spid.SetPoint=set_temp;
init_lcd();
set_temp=330;
shi0=set_temp/100;
fen=set_temp%100/10;
miao=set_temp%10;
EA=1;
EX0=1;
IT0=1;
while
(1)
{
//keyscan();
display();
delay(10);
compare_temper();
for(c>0;c{
jdq=0;
delay(5);
low_time=15750-high_time;
}
for(d=0;d{
jdq=1;
delay(5);
}
display();
}
}