智能化压力控制系统设计
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
《过程控制系统》课程设计智能化压力控制系统设计
院别
专业名称
班级学号
学生姓名
指导教师
2014.7.8-2014.7.19
一、前言
在科技飞速发展的今天,智能化已经成为这个时代的主旋律,大到工业生产,小到手机、家具。
其中,压力是不可或缺的一个重要参数。
为实现锅炉气压的准确地自动检测与控制,我们基于51单片机,设计了气压自动控制系统。
它通过实时采集气压传感器电压进行PID 运算,输出PWM,从而控制固态继电器对锅炉进行加热,使锅炉气压快速准确的达到设定值。
与其它同类系统相比,本系统具有经济、方便等特点,适合小型控制。
关键词:锅炉气压、51单片机、自动控制、PID
二、任务书
1、系统构成:
系统主要由压力传感器,单片机控制系统、对象、执行器(查找资料自行选择)等组成。
压力传感器、控制器、对象、执行器可查找资料自行选择,控制器选择单片机为控制器。
单片机型号自选。
2、写出压力测量与控制过程,绘制压力控制系统组成框图。
3、(1)系统硬件电路设计自选。
(2)编制压力测量控制程序:软件采用模块化程序结构设计,由压力采集程序、压力校准程序、压力控制程序等部分组成。
三、选型
1、传感器:HL-DQ1气压传感器
HL-DQ1气压传感器采用进口高精度压力芯片,测量精度高、稳定性好。
精密信号处理电路可根据用户的不同需求将大气压力转换为电压或电流等其它输出信号。
具有体积小巧,性能可靠,精度高,负载能力强,传输距离长,抗干扰能力强等特点。
可广泛用于气象、海洋、环境、机场、港口、实验室、工农业及交通等领域。
产品特点:连接简便、体积小巧、性价比高,专业级大气压力应用范围各类自动气象站的大气压力专业测量
测量范围:500~1060hPa
输出:频率/电压/智能
分辨率:0.1hPa
2、控制器:51单片机
外接串行AD转化芯片ADC0832将传感器电压转换成数字量,通过1602显示屏显示实时数据,
使用定时器模拟一路PWM控制执行器。
3、被控对象:普通锅炉
4、执行器:固态继电器
四、主体设计
1、系统框图
给定值气压
说明:本系统根据单闭环自动控制系统的特点,以89C51单片机作为调节器,通过对传感器输出的电压信号进行AD转换,与给定值进行作差比较,单片机程序中进行相应的PID运算,在1602显示屏上显示采集到的电压值,转化后的气压值,输出相应占空比的PWM信号控制固态继电器加热,使锅炉气压快速准确到达并稳定在设定值。
2、系统操作说明
启动系统之后,显示屏显示默认的PID参数和设定值,通过按键ADD,SUB,NEXT,OK可实现参数加减修改,参数选择,参数确认操作,之后系统进行自动运行,无需人干预,当压力值高于设定值110%的时候能够自动报警。
3、硬件电路设计
proteus仿真电路图
说明:
按键:ADD、SUB、NEXT、OK按键依次接单片机P2.1、P2.2、P2.3、P2.4引脚,低电平触发。
ADC0832:DI、DO接单片机P3.4引脚,CS接P3.5,CLK接P3.3
显示屛1602:RS接P2.6,RW 接P2.5,LCDEN接P2.7,数据口D0~D7接P0口,为提高稳定性和引脚驱动能力,P0口接上拉电阻。
4、程序设计
①显示屏显示字符代码
init_lcd1602();//液晶1602显示初始化
write_cmd(0x81);
write_date('K');
write_date('p');
write_date(':');
write_cmd(0x89);
write_date('K');
write_date('i');
write_date(':');
write_cmd(0xc1);
write_date('K');
write_date('d');
write_date(':');
write_cmd(0xc9);
write_date('A');
write_date('i');
write_date('m');
write_date(':');
②参数修改代码
while(1)
{
if(add==0)
{
delay(10);
if(add==0)
{
while(add==0);
switch(choose)
{
case 1:kp+=0.1;break;
case 2:ki+=0.1;break;
case 3:kd+=0.1;break;
case 4:aim+=0.1;break;
}
}
}
if(sub==0)
{
if(sub==0)
{
while(sub==0);
switch(choose)
{
case 1:kp-=0.1;break;
case 2:ki-=0.1;break;
case 3:kd-=0.1;break;
case 4:aim-=0.1;break;
}
}
}
if(next==0)
{
delay(10);
if(next==0)
{
while(next==0);
choose++;
if(choose==5)
choose=1;
}
}
if(ok==0)
{
delay(10);
if(ok==0)
}
pidshow();
}
pidshow子程序
void pidshow()
{
int dt,dt1,dt2,dt3;
dt=kp*10;
dt1=dt/100+0x30;
dt2=dt%100/10+0x30;
dt3=dt%10+0x30;
write_cmd(0x84);
//write_date(dt1);
write_date(dt2);
write_date('.');
write_date(dt3);
dt=ki*10;
dt1=dt/100+0x30;
dt2=dt%100/10+0x30;
dt3=dt%10+0x30;
write_cmd(0x8c);
//write_date(dt1);
write_date(dt2);
write_date('.');
write_date(dt3);
dt=kd*10;
dt1=dt/100+0x30;
dt2=dt%100/10+0x30;
dt3=dt%10+0x30;
write_cmd(0xc4);
//write_date(dt1);
write_date(dt2);
write_date('.');
write_date(dt3);
dt=aim*10;
dt1=dt/100+0x30;
dt2=dt%100/10+0x30;
dt3=dt%10+0x30;
write_cmd(0xcd);
//write_date(dt1);
write_date(dt2);
write_date('.');
write_date(dt3);
switch(choose)
{
case 1:
{
write_cmd(0x80);
write_date(0x7e);
write_cmd(0x88);
write_date(0x20);
write_cmd(0xc0);
write_date(0x20);
write_cmd(0xc8);
write_date(0x20);
break;
}
case 2:
{
write_cmd(0x80);
write_date(0x20);
write_cmd(0x88);
write_date(0x7e);
write_cmd(0xc0);
write_date(0x20);
write_cmd(0xc8);
write_date(0x20);
break;
}
case 3:
{
write_cmd(0x80);
write_date(0x20);
write_cmd(0x88);
write_date(0x20);
write_cmd(0xc0);
write_date(0x7e);
write_cmd(0xc8);
write_date(0x20);
break;
}
case 4:
{
write_cmd(0x80);
write_date(0x20);
write_cmd(0x88);
write_date(0x20);
write_cmd(0xc0);
write_date(0x20);
write_cmd(0xc8);
write_date(0x7e);
break;
}
}
}
③、串行ADC0832转换程序
uchar ADC0832(uchar CH)
{
uchar dis0,dis1;
Clk=0; //拉低时钟
DI=1; //初始化
_nop_();
CS=0; //芯片选定
_nop_();
Clk=1; //拉高时钟
_nop_();
if(CH==0) //通道选择
{
Clk=0; //第一次拉低时钟
DI=1; //通道0的第一位
_nop_();
Clk=1; //拉高时钟
_nop_();
Clk=0; //第二次拉低时钟,ADC0832 DI接受数据 DI=0; //通道0的第二位
_nop_();
Clk=1;
_nop_();
}
else
{
Clk=0;
DI=1; //通道1的第一位
_nop_();
Clk=1;
_nop_();
Clk=0;
DI=1; //通道1的第二位
_nop_();
Clk=1;
_nop_();
}
Clk=0; //第三次拉低时钟,此前DI两次赋值决定通道 DI=1; //DI开始失效,拉高电平,便于DO数据传输
for(i= 0;i<8;i++) //读取前8位的值
{
_nop_();
dis0<<= 1;
Clk=1;
_nop_();
Clk=0;
if (DO)
dis0|=0x01;
else
dis0|=0x00;
}
for (i=0;i<8;i++) //读取后8位的值
{
dis1>>= 1;
if (DO)
dis1|= 0x80;
else
dis1|= 0x00;
_nop_();
Clk=1;
_nop_();
Clk=0;
}
if(dis0==dis1) //两次结束数据比较,若相等
date=dis0; //则赋值给dat
_nop_();
CS=1; //释放ADC0832
DO=1; //拉高输出端,方便下次通道选择DI端有效
Clk=1; //拉高时钟
return date;
}
五、参考文献
[1]邵裕森、戴先中.过程控制工程.北京:机械工业出版社,2000.5
[2]萧德云译.过程控制系统——应用、设计与整定(第3版).清华大学出版社,2004.5
[3]金以慧.过程控制.清华大学出版社,2002.3
六、结束语
在本次课设过程中,我主要工作是运用Proteus软件进行连接电路图和仿真。
通过这次课设,我对Proteus软件的使用更加熟悉。
这次课设是大学最后一个课设了,所以团队成员分工合作、共同讨论疑难点时也都非常积极主动,同时也不乏一些快乐。
七、附录
1、仿真结果
2、完整程序代码
#include <reg52.h>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char
sbit lcdrs=P2^6;
sbit lcdrw=P2^5;
sbit lcden=P2^7; //1602控制端口
sbit DI=P3^4;
sbit DO=P3^4; //DI和DO与单片机共接口
sbit Clk=P3^3;
sbit CS=P3^5;//ADC0832控制端口
sbit pwm=P2^0;
sbit add=P2^1;
sbit sub=P2^2;
sbit next=P2^3;
sbit ok=P2^4;
sbit beep=P1^0;
uchar dis[3]={0x00,0x00,0x00}; //显示缓冲区电压值uchar dis1[3]={0x00,0x00,0x00}; //显示缓冲区压强值uchar dis2[3]={0x00,0x00,0x00}; //显示缓冲区输出占空比uchar date=0; //AD值
int press=0;//压力值
int out=50;
int choose=1;
uchar i;
uchar CH; //ADC0832通道值
uchar timer1;
float kp=6;
float ki=0.1;
float kd=0.2;
float aim=5;
void system_Ini()
{
TMOD|= 0x11;
//PWM
TH0 = 0xff; //11.0592
TL0 = 0x9a;
TR0 = 1;
IE =0x8A;
}
/*****************************************
AD0832转换程序
******************************************/
uchar ADC0832(uchar CH)
{
uchar dis0,dis1;
Clk=0; //拉低时钟
DI=1; //初始化
_nop_();
CS=0; //芯片选定
_nop_();
Clk=1; //拉高时钟
_nop_();
if(CH==0) //通道选择
{
Clk=0; //第一次拉低时钟
DI=1; //通道0的第一位
_nop_();
Clk=1; //拉高时钟
_nop_();
Clk=0; //第二次拉低时钟,ADC0832 DI接受数据 DI=0; //通道0的第二位
_nop_();
Clk=1;
_nop_();
}
else
{
Clk=0;
DI=1; //通道1的第一位
_nop_();
Clk=1;
_nop_();
Clk=0;
DI=1; //通道1的第二位
_nop_();
Clk=1;
_nop_();
}
Clk=0; //第三次拉低时钟,此前DI两次赋值决定通道 DI=1; //DI开始失效,拉高电平,便于DO数据传输
for(i= 0;i<8;i++) //读取前8位的值
{
_nop_();
dis0<<= 1;
Clk=1;
_nop_();
Clk=0;
if (DO)
dis0|=0x01;
else
dis0|=0x00;
}
for (i=0;i<8;i++) //读取后8位的值
{
dis1>>= 1;
if (DO)
dis1|= 0x80;
else
dis1|= 0x00;
_nop_();
Clk=1;
_nop_();
Clk=0;
}
if(dis0==dis1) //两次结束数据比较,若相等
date=dis0; //则赋值给dat
_nop_();
CS=1; //释放ADC0832
DO=1; //拉高输出端,方便下次通道选择DI端有效
Clk=1; //拉高时钟
return date;
}
/***********************************************
数据转换程序
功能:将0-255级换算成0.00-5.00的电压数
***********************************************/
void convert(uchar a)
{
uint temp; //特别注意这里需定义int型(余数将大于255)dis[0]=a/51; //取个位
temp=a%51;
temp=temp*10;
dis[1]=temp/51; //取小数点后第一位
temp=temp%51;
temp=temp*10;
dis[2]=temp/51; //取小数点后第二位
press=(dis[0]+dis[1]*0.1+dis[0]*0.01)*1000/4;
dis1[0]=press/100;
dis1[1]=press%100/10;
dis1[2]=press%10;
dis2[0]=out/100;
dis2[1]=out%100/10;
dis2[2]=out%10;
}
/*****************************************
LCD1602驱动程序
******************************************/
void delay(uchar z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=122;y>0;y--);
}
void write_cmd(uchar cmd)//lcd1602写命令函数
{
lcdrs=0;
lcdrw=0; //选择指令寄存器
lcden=1;
P0=cmd; //写数据
delay(5);
lcden=0; //使能拉低
lcden=1;
}
void write_date(uchar date)//lcd1602写数据函数{
lcdrs=1;
lcdrw=0; //选择数据寄存器
lcden=1;
P0=date; //写数据
delay(5);
lcden=0; //使能拉低
lcden=1;
}
void init_lcd1602()//lcd1602初始化
{
write_cmd(0x01); //清屏
write_cmd(0x38); //功能设置
write_cmd(0x0c); //显示设置
write_cmd(0x06); //输入方式从左到右
delay(1);
}
/*****************************************
显示函数
*****************************************/ void display(void)
{
uchar i;
write_cmd(0x80);
write_date('V');
write_date(':');
for(i=0;i<3;i++)
{
if(i==1) write_date('.'); //第二位显示小数点write_date (0x30+dis[i]);
delay(5);
}
write_date('V');
write_cmd(0x88);
write_date('P');
write_date(':');
for(i=0;i<2;i++)
{
if(i==1) write_date('.'); //第二位显示小数点write_date (0x30+dis1[i]);
delay(5);
}
write_date('k');
write_date('p');
write_date('a');
write_cmd(0xc0);
write_date('O');
write_date('U');
write_date('T');
write_date(':');
for(i=0;i<3;i++)
{
write_date (0x30+dis2[i]);
delay(5);
}
}
void pidshow()
{
int dt,dt1,dt2,dt3;
dt=kp*10;
dt1=dt/100+0x30;
dt2=dt%100/10+0x30;
dt3=dt%10+0x30;
write_cmd(0x84);
//write_date(dt1);
write_date(dt2);
write_date('.');
write_date(dt3);
dt=ki*10;
dt1=dt/100+0x30;
dt2=dt%100/10+0x30;
dt3=dt%10+0x30;
write_cmd(0x8c);
//write_date(dt1);
write_date(dt2);
write_date('.');
write_date(dt3);
dt=kd*10;
dt1=dt/100+0x30;
dt2=dt%100/10+0x30;
dt3=dt%10+0x30;
write_cmd(0xc4);
//write_date(dt1);
write_date(dt2);
write_date('.');
write_date(dt3);
dt=aim*10;
dt1=dt/100+0x30;
dt2=dt%100/10+0x30;
dt3=dt%10+0x30;
write_cmd(0xcd);
//write_date(dt1);
write_date(dt2);
write_date('.');
write_date(dt3);
switch(choose)
{
case 1:
{
write_cmd(0x80);
write_date(0x7e);
write_cmd(0x88);
write_date(0x20);
write_cmd(0xc0);
write_date(0x20);
write_cmd(0xc8);
write_date(0x20);
break;
}
case 2:
{
write_cmd(0x80);
write_date(0x20);
write_cmd(0x88);
write_date(0x7e);
write_cmd(0xc0);
write_date(0x20);
write_cmd(0xc8);
write_date(0x20);
break;
}
case 3:
{
write_cmd(0x80);
write_date(0x20);
write_cmd(0x88);
write_date(0x20);
write_cmd(0xc0);
write_date(0x7e);
write_cmd(0xc8);
write_date(0x20);
break;
}
case 4:
{
write_cmd(0x80);
write_date(0x20);
write_cmd(0x88);
write_date(0x20);
write_cmd(0xc0);
write_date(0x20);
write_cmd(0xc8);
write_date(0x7e);
break;
}
}
}
void pidcal()
{
out=(aim-press/100)*kp+50;
}
/************************************************ 主函数
***************************************************/ void main(void)
{ beep=0;
system_Ini();
CH=0; //选择通道0或1
init_lcd1602();//液晶1602显示初始化 write_cmd(0x81);
write_date('K');
write_date('p');
write_date(':');
write_cmd(0x89);
write_date('K');
write_date('i');
write_date(':');
write_cmd(0xc1);
write_date('K');
write_date('d');
write_date(':');
write_cmd(0xc9);
write_date('A');
write_date('i');
write_date('m');
write_date(':');
while(1)
{
if(add==0)
{
delay(10);
if(add==0)
{
while(add==0);
switch(choose)
{
case 1:kp+=0.1;break;
case 2:ki+=0.1;break;
case 3:kd+=0.1;break;
case 4:aim+=0.1;break;
}
}
}
if(sub==0)
{
delay(10);
if(sub==0)
{
while(sub==0);
switch(choose)
{
case 1:kp-=0.1;break;
case 2:ki-=0.1;break;
case 3:kd-=0.1;break;
case 4:aim-=0.1;break;
}
}
}
if(next==0)
{
delay(10);
if(next==0)
{
while(next==0);
choose++;
if(choose==5)
choose=1;
}
}
if(ok==0)
{
delay(10);
if(ok==0)
break;
}
pidshow();
}
write_cmd(0x01);
while(1) //主循环
{
date=ADC0832(CH);//启动ADC0832转换并接受数据
delay(1);
convert(date); //数据转换成BCD码
pidcal();
display(); //显示数值
CS=0;
delay(5);
CS=1;
if((press/100)>=(aim*1.1))
beep=1;
else beep=0;
}
}
/*************************************
[ t1 (0.5ms)中断] 中断中做 PWM 输出
------------1000/(0.02ms*250)=200Hz
*************************************/
void T1zd(void) interrupt 1 //3 为定时器1的中断号 1 定时器0的中断号 0 外部中断1 2 外部中断2 4 串口中断
{
TH0 = 0xff; //11.0592
TL0 = 0x9a;
timer1++;
if(timer1>100) timer1=0;
if(timer1<out) pwm=1;
else pwm=0;
}。