基于单片机的温湿度检测及控制的设计,基于单片机和LabVIEW的温湿度监测系统设计
2023-08-13
很多朋友对温控pid算法实例c语言,pid算法温度控制c语言程序不是很了解,每日小编刚好整理了这方面的知识,今天就来带大家一探究竟。
介绍了温度控制PID自整定的原理。调谐PID(三模式)控制器调谐温度控制器包括设置比例、积分和微分值,以获得特定过程的最佳控制。如果控制器不包括自动设置算法,或者自动设置算法不能提供足够的适合于特定应用的控制,则必须通过反复试验来设置该设备。
以下是温度控制器的标准设置步骤。也可以使用其他调整步骤,但使用类似的试错法。请注意,如果控制器使用机械继电器(而不是固态继电器),应在开始时使用长周期时间(20秒)。可能需要以下定义:
周期时间也称为占空比,是控制器完成一个开关周期所用的总时间。例如:对于20秒的周期时间,10秒的开启时间和10秒的关闭时间代表50%的功率输出。当处于比例带时,控制器将循环开启和关闭。
比例带——以满量程的%或度表示的温度范围,在此范围内控制器发生比例动作。比例带越宽,设定值周围发生比例动作的区域就越大。有时也用增益表示,增益是比例带的倒数。积分,也称复位,是根据设定值调整比例带宽以补偿与设定值的偏移(固定偏差)的功能,即在系统稳定后将被控温度调整到设定值。
差分,也称为速率,检测系统温度上升或下降的速率,并自动调整比例带,以尽量减少欠调或过调。
如果设置和使用正确,PID(三模)控制器可以有很好的控制稳定性。通过仔细遵循这些说明,操作员可以实现最快的响应时间和最小的超调量。设置此三模式控制器的信息可能与其他控制器设置步骤不同。对于主输出,通过使用自设定功能,通常不需要使用这种手动设定步骤,但必要时可以调整自设定值。a .设置加热控制的输出,以启用输出并启动过程。
该过程应该在设定点运行,并且温度将随着所需的热量输入而稳定。速度和复位关闭时,温度会比较稳定,设定值和实际温度之间存在稳态偏差或固定偏差。通过观察显示屏上的测量值,密切注意该温度是否有规律的循环或振荡。(振荡可持续30分钟。)
4.如果温度没有规律地振荡,将PB除以2(见图1)。让过程稳定,然后检查是否有温度振荡。如果仍然没有振荡,将PB除以2。重复此操作,直到获得一个周期或振荡。转到步骤5。5.如果立即观察到振荡,将PB乘以2。观察温度几分钟。如果振荡继续,将PB乘以系数2,直到振荡停止。
此时,PB非常接近其临界设置。小心地增加或减少PB设置,直到温度记录中出现一个循环或振荡。如果过程温度即使在最小PB设置为1%时也不波动,请跳过以下步骤6至11,转到条款B.在已经达到的“临界”BP设置下,读取设置值和实际温度之间的稳态偏差或固定偏差。既然温度有一点周期,请用平均温度。)
以单位测量相邻峰或谷之间的振荡时间(见图2)。这种测量最容易用图表记录器进行,但是你可以每分钟读取测量值来记录时间。此时,增加PB设置,直到温度偏差(或固定偏差)增加65%。
所需的最终温度偏差可以通过将在“临界”BP设置下获得的初始温度偏差乘以1.65或方便的线图I(见图4)来计算。通过反复试验,多次尝试PB控制的设置,直到获得所需的最终温度偏差。此时,您已经完成了获得控制器最佳性能所需的所有测量。只需再做两个调整——速度和重置。使用在步骤7中测量的振荡时间,以每分钟重复次数为单位计算重置值,如下所示。
将该值输入复位1。然后,使用步骤7中测量的振荡时间,按如下单位计算速度值。将该值输入到比率1中。如果出现过冲,可以通过减少复位时间来消除。当重置值改变时,速率调整也应相应改变,使速率值等于:即如果重置=2 R/M,则速率=0.08分钟。
如果我们想要在系统扰动的“响应时间”和“设置时间”之间获得正确的平衡,可能需要多次更改设置值,并相应地调整复位和速率控制时间。快速响应往往伴随着较大的超调,过程达到“稳定”所需的时间也较短。相反,如果响应较慢,过程倾向于缓慢滑向最终值,很少或没有超调。由系统的要求来决定采取哪种行动。
当获得令人满意的定时时,应增加周期时间以节省接触器的寿命(适用于只有时间比例输出(TPRI)的设备)。在不导致测量值因负载循环而振荡的情况下,应尽可能增加循环时间。当没有观察到振动时,转到章节C. B .设置步骤。在最小PB设置下,测量设定值和实际温度之间的稳态偏差或固定偏差。
增加PB设置,直到温度偏差(固定偏差)增加65%。线图I(见图4)提供了一种简单的方法来计算所需的最终温度偏差。将复位1设置为高值(10转/分)。将比率1设置为相应的值(0.02点)。此时,由于复位功能,测量值应稳定在设定温度。
因为我们无法确定临界振荡时间,所以必须通过试错法来确定复合位置和速率调整的最优设置。温度稳定在设定值后,将设定温度增加10度。观察伴随实际温度上升的过冲。然后将设定温度的设定值恢复到初始值,然后观察伴随实际温度上升的超调量。过大的过冲表明复位和/或速率值设置得太高。过阻尼响应(无过冲)表示复位和/或速率值设置得太低。请参考图7。
当性能需要提高时,一次改变一个设置参数,观察设置值改变时该参数对性能的影响。让参数逐渐变化,直到性能达到最佳。
当获得令人满意的定时时,应增加周期时间以节省接触器的寿命(适用于只有时间比例输出(TPRI)的设备)。在不导致测量值因负载循环而振荡的情况下,应尽可能增加循环时间。图7:设置重置和/或速率c。设置冷却控制的主输出使用与加热相同的步骤。该过程应该在设定点运行,这需要在温度稳定之前进行冷却控制。d .简化PID控制器的整定步骤。
以下步骤是分析过程对阶跃输入的响应曲线的图解方法。用长图表记录器读取过程变量(PV)更容易。从冷启动(室温下的PV)开始,当控制器不在回路中时(即当回路打开时),过程以最大功率供电。记录这个开始时间。
经过一段时间的延迟(让热量到达传感器),PV将开始上升。延迟后,PV将达到最大变化率(斜率)。记录最大斜率出现的时间和此时的PV。记录最大斜率,单位为度/分钟。关闭系统电源。
从最大斜率点画一条线回到环境温度轴,得到总系统延迟Td(见图8)。延迟也可以通过以下公式获得:Td=达到最大斜率时的时间-(最大斜率时的PV-环境温度)/最大斜率S. PID参数可以通过应用以下公式获得:比例范围=Td x最大斜率x 100/范围=%范围的重置=0.4/Td=次数/分钟速率=0.4 x Td=分钟。
重启系统,在控制器处于回路中的情况下将过程带到设定点,并观察响应。如果响应超调过大或振荡,可以从以下几个方向改变PID参数(稍微改变,一次改变一个参数,观察过程响应):加宽比例带,降低复位值,增加速度值。图8中的图表记录是在加热炉以最大功率运行时获得的。图表比例尺是10?F/cm和5分钟/cm。控制器范围100 ~ 600?f,还是500?f的范围。
示例: 图8中的图表记录是在以最大功率给加热炉供电时获得的。图表比例尺为10F/cm和5分/cm。控制器范围为100 ~ 600F,或者说500F的量程。
最大斜率=18F/5分
=3.6F/分
延时=Td=大约7分
比例带=7分x3.6F/分x 100/500F=5%。
复位=0.4 /7分=0.06次/分
速率=0.4 x 7分=2.8分
图8:系统延时
pid算法温度控制c语言程序基于PID算法的温度控制系统89C51单片机,通过键盘输入预设值,与DS18B20测得的实际值做比较,然后驱动制冷或加热电路。用keil C语言来实现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晶振为准,延时时间为30ustime
***********************************************************/
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;
if(bitval==1)
{
_nop_();
DQ=1;
}
delay(5);
DQ=1;
_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=temp1;
write_bit(temp);
}
delay(7);
//TR0=1;
EA=1;
}
/***********************************************************
读一位数据子程序
***********************************************************/
unsigned char read_bit()
{
unsigned char i,value_bit;
EA=0;
DQ=0;
_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);
}
EA=1;
return(value);
}
/***********************************************************
复位子程序
***********************************************************/
unsigned char reset()
{
unsigned char presence;
EA=0;
DQ=0;
delay(30);
DQ=1;
delay(3);
presence=DQ;
delay(28);
EA=1;
return(presence);
}
/***********************************************************
获取温度子程序
***********************************************************/
void get_temper()
{
unsigned char i,j;
do
{
i=reset();
}while(i!=0);
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)(j0x0f);
s=(s*100)/16;
j=j》4;
temper=i|j;
}
void PIDInit (struct PID *pp)
{
memset ( pp,0,sizeof(struct 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-》SumError //积分项
+ 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
{
}
void disp_1(unsigned char disp_num16)
{
unsigned char n,a,m;
for(n=0;n《6;n++)
{
//k=disp_num1n;
for(a=0;a《8;a++)
{
clk=0;
m=(disp_num1n1);
disp_num1n=disp_num1n》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_num6;
unsigned int k,k1;
k=high_time;
k=k%1000;
k1=k/100;
if(k1==0)
disp_num0=0;
else
disp_num0=0x60;
k=k%100;
disp_num1=numberk/10;
disp_num2=numberk%10;
k=temper;
k=k%100;
disp_num3=numberk/10;
disp_num4=numberk%10+1;
disp_num5=numbers/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;
}
}
//DS18b20 子程序
#include 《REG52.H》
sbit DQ=P2^1; //定义端口
typedef unsigned char byte;
typedef unsigned int word;
//延时
void delay(word useconds)
{
for(;useconds》0;useconds--);
}
//复位
byte ow_reset(void)
{
byte presence;
DQ=0; //DQ低电平
delay(29); //480us
DQ=1; //DQ高电平
delay(3); //等待
presence=DQ; //presence信号
delay(25);
return(presence);
} //0允许,1禁止
//从1-wire 总线上读取一个字节
byte read_byte(viod)
{
byte i;
byte value=0;
for (i=8;i》0;i--)
{
value》=1;
DQ=0;
DQ=1;
delay(1);
if(DQ)value|=0x80;
delay(6);
}
return(value);
}
//向1-wire总线上写一个字节
void write_byte(char val)
{
byte i;
for (i=8;i》0;i--) //一次写一个字节
{
DQ=0;
DQ=val0x01;
delay(5);
DQ=1;
val=val/2;
}
delay(5);
}
//读取温度
char Read_Temperature(void)
{
union{
byte c2;
int x;
}temp;
ow_reset();
write_byte(0xcc);
write_byte(0xBE);
temp.c1=read_byte();
temp.c0=read_byte();
ow_reset();
write_byte(0xCC);
write_byte(0x44);
return temp.x/2;
}
以上知识分享希望能够帮助到大家!
版权声明:本站所有作品图文均由用户自行上传分享,仅供网友学习交流。若您的权利被侵害,请联系我们
推荐阅读
2023-08-13
2023-08-13
2023-08-13
2023-08-13
2023-08-13
2023-08-13
2023-08-13
2023-08-13
2023-08-13
2023-08-13
2023-08-13
2023-08-13
2023-08-13
栏目热点
基于单片机的温湿度检测及控制的设计,基于单片机和LabVIEW的温湿度监测系统设计
LilyGoT手表键盘C3迷你电脑套件
索泰ZBOXEdgeCI342迷你电脑正式上市
谷歌在最新的视频预告片中展示了PixelWatch的独特设计
三星与设计师Juun.J合作推出限量版可折叠产品和配件
从2023年起Fitbit设备将需要Google帐户
TOKKCAMC2+智能WiFi独立日 夜视摄像头
三星正在与全球时尚品牌JUUN.J合作
OnePlusNordWatch的颜色选项通过泄露的渲染揭示
就在第一款Nothing手机发布之前一种新的TWS芽设计浮出水面