水温控制系统
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
设计报告 1. 设计原理
水温控制系统以STC89C52单片机作为控制核心,采用开关控制和PID控制算法相结合,通过控制单位时间内加热
时间所占的比例(即控制波形占空比)来控制水的加热速度,实
现对1L水的全量程(10℃――70℃)内的升温、降温功能
的自动控制。
根据设计要求系统可划分为控制模块、温度测量模块、水温调节模块、键盘输入模块、显示电路模块等。
系统原理
图如图所示
STC89C52首先写命令给DS18B20开始转换数据,将转换后的温度数据送入89C52进行处理,处理后在液
晶屏上实时显示。
并将实际测量温度值与键盘设定值进行比较,
根据比较结果进行温度调节,当温差比较大时采用开关量调节,
既全速加热和制冷,当温差小时采用PID算法进行调节,最终
达到温度的稳定控制。
其中,加热采用内置(水中)电加热器实现,热量直接与水传递,加热效果好,控温方便;降温采用半导
体制冷片实现。
其体积小,安装简单,易于控制,价格便宜,可
短时间内反复启动,但其制冷速率不高,所以设计中配套散热风
扇以达到快速降温的目的。
2.温度控制算法
实际温度控制系统,常采用开关控制或数字PID控制方式。
开关控制的特点是可以使系统以最快的素的向平衡点靠近,但在
实际应用却很容易造成系统在平衡点附近震荡,精度不高;而数
字PID控制具有稳态误差小特点,实用性广泛的特点,但误差
较大时,系统容易出现积分饱和,从而份致系统出现很大的超调
量,甚至出现失控现象。
因此,本设计将开关控制,放积分饱和、防参数突变积分饱和等方法溶入PID控制算法组成复式数字P
ID控制方法,集各种控制策略的优点,既改善了常规控制的动
态过程又保持了常规控制的稳态特性。
2.1控制算法的确定
温度控制过程为 : 当水温温差大时,采用开关控制方式迅速减小温差,以缩短调节时间;当温差小于某一值后采用PID 控制方式,以使系统快速稳定并保持系统无静态误差。
在这种控制方法
中, PID 控制在较小温差时开始进入,这样可有效避免数字积分
器的饱和。
PID参数和被控制对象关系密切,要精确得到被控对象
模型比较困难,为此,采用离线模糊整定的方法来确定PID 参数,即给出一组PID 参数的初值,测得相应的数据,按使这个量减小
的方向调节PID 参数,用整定后的参数控制该系统,并根据输出
的调节时间、超调量及稳态误差,调节PID 参数,如此反复,求
得一组使系统性能最优的PID 参数。
复合PID 控制系统方框图如
图所示。
2.2PID 控制算法
根据设计要求,系统对1L 净水进行加热或降温处理,根据水
的对象特性,会出现惯性温度误差问题,原因如下:
温度控制器采用发热丝对水进行加热。
发热丝通电加热时,
内部温度很高。
当容器内水温升高至设定温度时,温度控制器发
出信号停止加热。
但这时发热丝的温度会高于设定温度,发热丝
还将继续对对水进行加热,导致水的温度还会继续上升几度,然
后才开始下降。
当水温下降到设定温度的下限时,温度控制器又
发出加热信号,开始加热,但发热丝要把温度传递到被加热器件
需要一定的时间,导致水温会继续下降几度。
所以,为了对水温
实现精确控制,使温度测量误差在±0.5 ℃内,必须采用PID 模糊控制算法, 通过Pvar、Ivar 、Dvar(比例、积分、微分)三方面
的结合形成一个模糊控制来解决惯性温度误差问题。
利用数值逼近方法,在采样时刻t=iT(T 为采样周期, i 为正整数) 时,PID 调节规律可通过下式近似计算。
则增量式PID算法的输出量为:
式中,ei 、ei-1 、ei-2 分别为第n 次、n-1 次和 n-2 次的偏差值,Kp、Ti 、Td 分别为比例系数、积分系数和微分系数,T 为
采样周期。
单片机每隔固定时间T 将现场温度与用户设定目标温度的差
值带入增量式PID 算法公式,由公式输出量决定PWM方波的占空
比,后续加热电路根据此PWM方波的占空比决定加热功率。
现场
温度与目标温度的偏差大则占空比大,加热电路加热功率增大,
使温度的实测值与设定值的偏差迅速减少;反之,二者的偏差小
则占空比减小,加热电路加热功率减少,直至目标值与实测值相
等,达到自动控制的目的。
2.3PID 参数的确定
PID 参数的选择是设计成败的关键,它决定了温度控制的准确
度。
由于温度系统是一个具有较大滞后性的系统,所以本系统的
采样周期定为10 秒,加热周期定为 1 秒钟,根据一些文献提供的
经验值,初步确定Kp=2,Ti=2,Td=0.5, 根据公式Ki= Kp*T/ TI ;Kd = Kp * TD /T ;计算得出Ki=1,Kd=1; 然后,由按键对系统设定
一个温度值,在线应用工程整定法中的经验法对P,I,D 各参数进
行调整,经验法是一种凑试法,它通过模拟或闭环运行,观察调
节过程的响应曲线,如果曲线不够理想,则按某种程序将参数反
复凑试,直到调节质量满意为止。
凑试程序通常是先比例后积分,
最后加入微分。
凑试法整定PID 参数的步骤是:
1)首先进行P 整定。
将参数Kp 由小而大慢慢变化,直至得
到反应快,超调小的响应曲线。
若无静差或静差在允许范围内且
响应曲线满意,整定结束,否则继续下步。
2)进行 PI 整定。
略小于Kp 值,将 Ti 由大而小缓慢变化,在保持系统动态性能良好的前提下,消除静差或是静差允许范围
内。
反复改变Kp,Ti 值以求得较好效果,若效果满意,则整定结
束,否则继续下去。
3)进行 PID 整定。
略改变Kp,Ti 的值,使Td 由小而大缓慢变化,以求得较好的响应曲线和较小的静差。
逐步反复的试凑,
直至获得满意效果为止。
对于一定的系统,合理的参数组并不唯一,根据一
些文献的实践经验,在具体实施PID 参数整定时,以下几个结论
比较实用:
1)比例系数Kp是PID 调节中最关键的一个参数,Kp增大,
系统稳定性增加,但调节灵敏度减弱,一般曲线振荡频繁时,要
增大 Kp,而曲线飘浮绕大弯时,要减小Kp.
2)积分时间常数Ti 主要起消除静差的作用,减小Ti ,消除静差快,但稳定性减小,一般曲线偏离恢复慢时,减小Ti, 而曲线波动周期长时,再增大Ki。
3)微分时间常数Td 是加速过程的有力调节,在加速过渡过程,应增加 Td,Td 不宜过小,也不宜太大, Td一般选 Ti 的四分之
一为最佳。
根据以上调节的步骤及调节的方法及经验,经过反复的试验
做后得到最终的P,I,D 的参数为 Kp=30,Ki=5,Kd=0.
3.硬件电路设计
水温控制系统的硬件电路主要包括:主控电路、温度采集电
路、温控电路和显示电路等,下面依次对各部分进行设计。
3.1主控电路
主控电路采用STC89C52单片机作为系统控制器,结合数字 PID 算法完成对温度测量信号的接收、处理,控制加热器和制冷片,
使水温控制达到设计要求。
主控电路包括STC89C52最小系统和键
盘电路两部分, STC89C52最小系统在上一章中已介绍,这里不再
赘述。
本设计键盘采用RF-X1开发板上的 6 个独立按键中的 4 个,各按键经上拉电阻分别接到单片机的P3.2、P3.3、P3.4、P3.5 口上,起到确认、选择、上调和下调的作用,每按上调或下调键一
次,设定温度值加 1 或减 1。
电路图如图所示。
+5V
R61 10K 62 10K R63 10K R65 10K
S1 U1
S2 S3 S4 P32 P33 P34 1 2 3 4 5 6 7 8 P 10 P11 P12 P13 P14
P15 P16 P17
P 00
P01 P02 P03
P04
P05 P06
P07
39 38 37 36 35 34 33 32 C2 22pF C3 P36 Y1 12M HZ 13 12 15 14 31 19 18 I NT1 INT0 T1 T0 EA/VP X1 X2
P 20
P21 P22
P23 P24 P25
P26 P27
21 22 23 24 25 26 27 28 22Pf 9 17 16 R ESET RD WR RXD
TXD
ALE/P PSEN
10 11 30 29
STC89C52
+5V C1 R1
10K 10uF
S19 D9
4001
2.2 温度采集电路
本系统采用 DS18B20单总线可编程温度传感器来实现温度的
采集和转换,温度以 9~12 位数字量读出,可以直接与单片机进
行连接,无需外部器件和电源, 大大简化了电路的复杂度。
DS18B20
应用广泛,测温范围为 -55~+125oC ,温度数字量转换快,性能可
以满足题目的设计要求。
DS18B20的测温电路如图所示。
U2
1
GND
2 P35
DQ
3
GND
R57
2.3K DS18B20
+5V
3.2温度控制电路
温度控制电路采用加热器和制冷片对1L 水实现加热和降温,具体电路如图12-5 所示。
当实测温度高于设定温度时,单片机P0.2 脚输出低电平,光耦管导通输出高电平,进入LM393管脚比较整形,滤除高次谐波,输出高电平,进入 Q3和Q4组成的推挽电路,
Q3导通 Q4截止,输出低电平,晶闸管导通,驱动制冷片降温。
当
实测温度低于设定温度时,P0.3 脚输出低电平,驱动加热器对水
温进行加热,工作原理与降温驱动相同。
CON2 +5V +5V +12V
2 1 R2 1K
R 4 1K R 5 10K R 10 K D N G S +12V 150W Q4 MPS8550 U3 8 U1A P02 3 2 R11 1
20K M2 RF 470 LM393 R6 10K 4 D1
Q3 MPS 8050 D2
P03 U 4 R7 1K 8 Q2 MPS 8550 U2A 3 R12 1
2 20K M1 RF 470
R3 1K 4 LM 393
R8 10K R9 10K R13 K Q1 MPS8050 电热丝 500W
1 +5V D3 4
2 220V/50Hz +12V
BRIDGE1
3 3.
4 显示电路
显示电路采用 LCD12864液晶模块显示系统的设定温度和实测
温度。
LCD12864液晶共有 20 个引脚,管脚名称及功能如表 12-1 所示。
本系统选用单片机 P1 口作为数据输出端与 LCD12864的数 据端(DB0~DB7)相连,进行水温数据传输; P20接串并行模式方 式位 RS ;P21 接并行的读写方式位 R/W ;P22接并行使能端口 E ; P23接并/ 串行接口选择位 PSB ;P24接复位端口 RST 。
具体电路图 如图所示。
2.4软件设计
系统的软件设计应用 C 语言,采用模块化对单片机进行编程实现各项功能。
主要包括:PID 控制程序、按键子程序、温度采集子程序、温度比较子程序和液晶显示程序。
3.3主程序设计
系统上电初始化后,首先进行按键扫描,若有按键按下,则
读取按键值,更新设定温度。
将实测温度与设定温度进行比较,
若实测温度与设定温度差值大于2o C,则对水进行全速加热或降温;若实测温度与设定温度差值小于2o C,则调用PID 子程序,对水温进行微调,达到设计要求。
系统主程序流程图如图所示.
WORD格式
开始
初始化
键盘扫描
是否有N
新参数键入
Y
读按键值并更新各参数
显示当前温度值
温控判断方式
测量值与设定
Y
值差2°以上
N
温差N
2oC以下
加热/制冷子程序
Y
调用PID子程序
附录:
PID 控制程序
PID 控制就是按设定值与测量值之间偏差的比例、偏差的
积累和偏差变化的趋势进行控制。
它根据采样时刻的偏差值计
算输出控制量的增量,调节控制信号的导通时间来控制加热电
路和冷却电路的工作。
当采样周期相当短时,可以用求和代替
积分,用差商代替微分。
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->SumError // 积分项
+ pp->Derivative * dError); // 微分项
}
/************************************************
************************/
按键子程序
本系统采用四个按键,完成
温度的设定。
当选择键 K1每按下一次,K1num加1,根据 K1num
值选择对温度值的百位(预留)、十位、个位进行数值调节。
每按一次按键K2,对应位数值加1,每按一次按键K1,对应位
数值减 1,并将设定温度值写到液晶显示器的相应位置。
按键子程序如下:
/**********************
*** 按键子程序***********************************/
void sheding()
{
if(k1==0)
{
delay1(10);
if(k1==0) // 按键K1按下
while(!k1);// 按键K1
抬起
write_com(0x0f);write_com(0x94);
k1num++;
switch(k1num)
{
case 1: write_com(0x0f);write_com(0x94);// 液晶显示位置,十位
break;
case 2: write_com(0x95);// 液晶显示位置,个位
break;
case 3: write_com(0x96);// 液晶显示位置,小数位
break;
case 4: k1num=0;write_com(0x0c);// 清零
break;
}
}
if(k1num!=0)// 返回
{
// 温度值加处理:
if(k2==0) // 按键K2按
下
{
delay1(10);
if(k2==0)
{
while(!k2);
switch(k1num)
{
case 1: shi++;if(shi==10)shi=0;a=shi;// 十位加 1,到 10 清零
write_com(0x94);write_d
ate(table[shi]);write_com(0x94);
break;
case 2: ge++;if(ge==10)ge=0;b=ge;// 个位加 1,到 10 清零
write_com(0x95);;write_date(table[ge]);write_com(0x95
);
break;
case 3:
xs++;if(xs==10)xs=0;c=xs;// 小数位加 1,到10 清零
write_com(0x96);write_d
ate('.');write_date(table[xs]);write_com(0x96);// 在液
晶对应位置画点
break;
}
}
}
// 温度值减处理:
if(k3==0)
{
delay1(10);
if(k3==0)
{
while(!k3);
switch(k1num)
{
case 1: shi--;if(shi==-1)shi=9;a=shi;
write_com(0x94);write_date(table[shi]);write_com(0x94
);
break;
case 2: ge--;if(ge==-1)ge=9;b=ge;
write_com(0x95);
write_date(table[ge]);write_com(0x95);
break;
case 3: xs--;if(xs==-1)xs=9;c=xs;
write_com(0x96);write_date('.');write_date(table[xs])
;write_com(0x96);
break;
}
}
}
}
}
/**********************
*****************************************************
/
DS18B20温度采集子程序
系统采用DS18B20对 1L 水
的温度进行采集。
首先根据 DS18B20的工作时序对其进行初始
化,并对DS18B20内部寄存器读写操作进行定义。
系统工作时,
单片机读取DS18B20内部寄存器的二进制数值,将其转化为十
进制的真实温度值。
DS18B20温度采集子程序如
下:
/*******************
DS18B20温度采集子程序 ************************/
void init_DS18B20()// 初始化
{
uchar x=0;
DS18B20 = 1; //DQ 复位
delay(8); // 稍做延时
DS18B20= 0; // 单片机将DQ拉低
delay(80); // 精确延时大于 480us
DS18B20= 1; // 拉高总线
delay(14);
x=DS18B20; // 稍做延时后如果x=0 则初始化成功x=1 则初始化失败
delay(20);
}
uchar read_onechar()// 读一个字节
{
uchar i=0;
uchar date = 0;
for (i=8;i>0;i--)
{
DS18B20 = 0;
date>>=1; // 寄存器右移
DS18B20 = 1;
if(DS18B20)
date|=0x80;
delay(4);
}
return(date);
}
void write_onechar(uchar date)// 写一个字节
{
uchar i=0;
for (i=8; i>0; i--)
{
DS18B20 = 0;
DS18B20 = date&0x01;
delay(5);
DS18B20 = 1;
date>>=1;
}
}
uint read_temp()// 读取温度
{ uchar a=0;
uchar b=0;
uint t=0;
float tt=0;
init_DS18B20();
write_onechar(0xcc); //
跳过读序号列号的操作
write_onechar(0x44); //
启动温度转换
init_DS18B20();
write_onechar(0xcc); //
跳过读序号列号的操作
write_onechar(0xbe); //
读取温度寄存器
a=read_onechar(); //
连续读两个字节数据// 读低 8 位
b=read_onechar();
// 读高 8 位
t=b;
t<<=8;
t=t|a; // 两字节合成一个
整型变量。
tt=t*0.0625; // 得到真实十进制温度值,因为DS18B20可以精确到0.0625 度,所以
读回数据的最低位代表的是0.0625 度
//temper12=tt*10;
t= tt*10+0.5; // 放大10 倍,这样做的目的将小数点后第一位也转换为可显示数字,同
时进行一个四舍五入操作。
return(t);
}
void manage_DS18B20()
{
uint num;
num=read_temp();
shi=num/100;
delay(5);
ge=num%100/10;
delay(5);
xs=num%10;
delay(5);
temper=shi*10+ge+0.1*xs ;}
/********************** ****************************************************/
温度比较子程序
系统将DS18B20采集到的实际测量温度值与键盘设定值进行比较,根据比较结果对水温进
行调节。
若设置温度大于实际温度,并且温差在 2 度以上,则
驱动加热器对水温进行全速加热;当温差在 0.8 到 2 度之间时,
则停止加热,开始降温;当温差小于0.8 度时,则启用PID 计
算,控制温差逐渐趋近设定值,最终达到稳态。
若设置温度小
于实际温度,系统驱动制冷片开始全速降温。
当实际温度下降
到低于设定温度时,则马上开启PID 计算,控制温差逐渐趋近
设定值,最终达到稳态。
/**********************
** 温度比较处理子程序****************************/
void compare_temper()
{
unsigned char i;
if(set_temper>temper)
// 是否设置的温度大于实际温度
{
if(set_temper-temper>2) // 设置的温度比实际的温度是否
是大于 2 度
{
high_time=100; // 如果是,则全速加热
low_time=0;
}
else // 如果是在 0.8 到
2 度范围,则开始降温
{
if(set_temper-temper>0.
8)
{
high_time=0;
low_time=100;
}
else // 如果温差小
于0.8 度,运行PID计算
{
for(i=0;i<10;i++)
{
s=read_temp();
rin = s; // Read Input
rout = PIDCalc ( &spid,rin ); // Perform PID Interation
}
if
(high_time<=100)
{
high_time=(unsigned char)(rout/1000);
}
else
{
high_time=100;
low_time= (100-high_time);
}
}
}
}
else
if(set_temper<=temper) // 是否设置的温度小于实际温度
{
if(set_temper-temper<0)
{
high_time=0;
low_time=100; //
全速降温
}
else // 实际温度大于
设定温度,马上开启PID计算
{
for(i=0;i<10;i++)
{
s=read_temp();
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);
}
}
}
}
/********************** ***************************************************/
液晶显示程序
液晶显示器用于显示水温
的实际温度和设定温度。
首先对LCD12864进行初始化,并读
取控制器当前状态,判断是否准备好(空闲)。
然后向液晶模
块写入指令代码,进行显示准备,将要水温以十六进制代码的
形式送入液晶显示缓冲区,最后利用读显示数据指令控制液晶
模块在相应位置显示水温数据。
液晶显示程序如下:
/********************** *****LCD12864 初始化*******************************/
void init_lcd()
{
//lcd_psb=1;
write_com(0x34);// 扩充指令集
delay1(2);
write_com(0x30);// 基本指令集
delay1(2);
write_com(0x02);// 显示归位
delay1(2);
write_com(0x01);// 清屏显示
delay1(2);
write_com(0x0c);// 显示状态开关
delay1(2);
write_com(0x06);// 显示光标移动设置
delay1(2);
}
/**********************
************ 写数据 *********************************/
void write_date(uchar date)
{
read_busy();
lcd_rs=1;
delay(5);
lcd_rw=0;
delay(5);
lcd_date=date;
lcd_en=0;
delay(5);
lcd_en=1;
delay(5);
lcd_en=0;
delay(5);
}
/**********************
************* 写指令 *******************************/
void write_com(uchar com)
{
read_busy();
lcd_rs=0;
delay(5);
lcd_rw=0;
delay(5);
lcd_date=com;
lcd_en=0;
delay(5);
lcd_en=1;
delay(5);
lcd_en=0;
delay(5);
}
/********************** ****** 判断忙闲状态 *******************************/
uchar read_busy()
{
lcd_date=0xff;
lcd_rs=0;
delay(5);
lcd_rw=1;
delay(5);
lcd_en=1;
delay(5);
while(lcd_date&busy);
lcd_en=0;
delay(5);
return(lcd_date);
}
/**********************
*清除液晶 GDRAM中的随机数据 *********************/
void clear_GDRAM()
{
uchar i,j,k;
write_com(0x34);
// 打开扩展指令集
i = 0x80;
for(j = 0;j < 32;j++)
{
write_com(i++);
write_com(0x80);
for(k = 0;k <
16;k++)
{
write_date(0x00);
}
}
i = 0x80;
for(j = 0;j < 32;j++)
{
write_com(i++);
write_com(0x88);
for(k = 0;k < 16;k++)
{
write_date(0x00);
}
}
write_com(0x30);
// 回到基本指令集
}
/****************** 在指定位置显示一串字符(X-- 列;Y-- 行)*******************/
void
display_listchar(uchar X, uchar Y, uchar code *date)
{
uchar ListLength,X2;
ListLength = 0;
X2=X;
if(Y<1)
Y=1;
if(Y>4)
Y=4;
X &= 0x0F; // 限制 X 不能
大于 16,Y在1-4 之内
switch(Y)
{
case
1:X2|=0X80;break; // 根据行数来选择相应地址
case
2:X2|=0X90;break;
case
3:X2|=0X88;break;
case
4:X2|=0X98;break;
}
write_com(X2); // 发送地
址码
while
(date[ListLength]>=0x20) // 若到达字串尾则退出
{
if (X <= 0x0F) //X 坐标应小于 0xF
{
write_date(date[ListLength]);
ListLength++;
X++;
delay1(2);
}
}
}
/**********************
*****************************************************
/
WORD格式。