PID温控器系统设计与仿真.docx

上传人:b****4 文档编号:12072748 上传时间:2023-04-16 格式:DOCX 页数:32 大小:494.75KB
下载 相关 举报
PID温控器系统设计与仿真.docx_第1页
第1页 / 共32页
PID温控器系统设计与仿真.docx_第2页
第2页 / 共32页
PID温控器系统设计与仿真.docx_第3页
第3页 / 共32页
PID温控器系统设计与仿真.docx_第4页
第4页 / 共32页
PID温控器系统设计与仿真.docx_第5页
第5页 / 共32页
点击查看更多>>
下载资源
资源描述

PID温控器系统设计与仿真.docx

《PID温控器系统设计与仿真.docx》由会员分享,可在线阅读,更多相关《PID温控器系统设计与仿真.docx(32页珍藏版)》请在冰豆网上搜索。

PID温控器系统设计与仿真.docx

PID温控器系统设计与仿真

PID温控器系统设计与仿真

一、系统概述

PID温控器系统的工作原理图如图1,电炉内的热电阻温度传感器测出的温度信号经运算放大器放大和模/数转换后,由8051单片机读出电阻炉炉温,PID控制程序根据当前炉温和目标温度的偏差,按照一定的控制方法控制开关K的通与断,提供适当的加热功率,以使炉温尽快趋近目标温度。

PID温控器还通过串口与PC通信,以实现远程监控。

LED和键盘用于人机接口,交流电过零检测部分可使8051只在正弦交流电零点附近控制开关K的通与断,以避免对交流电斩波而造成干扰。

图1

二、系统设计及仿真

1.PID温控器存储系统设计

PID温控器的存储系统设计中使用了一片3-8译码器74LS138来产生个芯片所需的片选信号。

6264的

信号来自于74LS138的

输出,要使

为低电平选中6264,则C、B、A的输入应为011,由此可计算出6264的地址范围为0x6000~0x7FFF,2764的地址范围为0x0000~0x1FFF。

在Proteus仿真软件中建立如图2所示的温控器存储系统的Memory.dsn模型文件。

图2

2.人机接口和PID温控器的输入/输出设计及仿真

2.1PID温控器LED显示及仿真

图3是PID温控器LED显示部分的Proteus仿真原理图。

8255A是较复杂的并行接口芯片,在PID控制器主要用作I/O口拓展,用于LED的显示。

在编程时应注意,由于8255A的复位时间较长,在应用程序访问8255A之前,应有足够的延时保证8255A已正确复位,仿真时可不延时,但实际电路中必须加足够的延时。

另外,在Proteus中建立仿真模型时,要保证8255A的器件编号小于8051的编号,否则仿真不能成功。

打开建立的Memory.dsn模型文件,在其中新建一个名为LED的设计页,将图3的内容画在该设计页中,然后将文件保存为Led.dsn。

图3

编写程序,在图3上的6位数码管上循环显示数字0~5。

程序代码如下:

/*display.h*/

/*8255A端口地址*/

#defineBASE0x0000

#definePORT_A(BASE)

#definePORT_B(BASE+1)

#definePORT_C(BASE+2)

#definePORT_CONTROL(BASE+3)

#defineLEDS6//共有6位LED

#defineCA0//共阳

#defineCC1//共阴

//函数声明

voidturn_On(charled,charChNumber,charmode);

voidLedsOff();

voidOneByOne(chardatas[]);

externvoidInit8255();

unsignedcharcodeSelect[];

unsignedcharcodeLED_CODES[];

 

/*display.c*/

#include"absacc.h"

#include"Reg51.h"

#include"display.h"

//led灯选通信号

//高电平位选

unsignedcharcodeSelect[]={0x01,0x02,0x04,0x08,0x10,0x20};

unsignedcharcodeLED_CODES[]={0xc0,0xF9,0xA4,0xB0,0x99,//0-4

0x92,0x82,0xF8,0x80,0x90,//5-9

0x88,0x83,0xC6,0xA1,0x86,//A,b,C,d,E

0x8E,0xFF,0x0C,0x89,0x7F,0xBF//F,空格,P,H,.,-

};

//初始化8255A

//各led位全灭

voidInit8255()

{unsignedchari,j;

for(j=0;j<10;j++)

for(i=0;i<255;i++);//空循环延时,等待8255A复位

//A组,B组工作于方式0,C,B口输出

XBYTE[PORT_CONTROL]=0x90;

//所有的灯全关

LedsOff();

}

//点亮某led

//led:

led灯编号,从右至左为0-5号

//chNumber:

字符在段码表中下标

//mode:

1-共阴,反相Led位选,0-共阳,同相led位选

//段均为同相驱动

voidturn_On(charled,charChNumber,charmode)

{

if(mode==CA)

XBYTE[PORT_C]=LED_CODES[ChNumber];//送字形码;

else

XBYTE[PORT_C]=~LED_CODES[ChNumber];//送字形码;

XBYTE[PORT_B]=Select[led];//送选通信号

}

voidLedsOff()

{//led全关

XBYTE[PORT_B]=0x00;

}

 

/*main.c*/

#include"reg51.h"

#include"display.h"

//循环在0-5位上显示数字0-5

voidmain()

{

unsignedintm;

unsignedchari;

Init8255();

i=LEDS-1;

while

(1)

{

LedsOff();

for(m=50;m!

=0;m--);//延时调整可改变显示效果

turn_On(i,i,CC);

for(m=50;m!

=0;m--);//延时调整可改变显示效果

if(i==0)i=LEDS-1;

elsei--;

}

}

程序运行结果如图4。

图4

2.3PID温控器的键盘设计及其Proteus仿真

打开上小节建立的Led.dsn,删除LED设计页中的ULA2003A驱动部分,在LED设计页中新建一个子电路LED_DRIVER,为该子电路加上图5中的输入/输出端子。

进入子电路设计页,按照图6绘出原ULA2003驱动部分并加上相应端子。

用BUTTON元件绘出图5右上角的键盘部分,并为行扫描线和列扫描线上的端子命名为R0~R3和C0~C3。

转到ExternalMemory设计页,为8051的P1.0~P1.3加上连接端子并命名为R0~R3,为P1.4~P1.7加上连接端子并命名为C0~C3。

将仿真模型文件另存为KeyBoard.dsn仿真模型文件。

图5

 

图6

为仿真模型KeyBoard.dsn编写按键处理程序,将所识别按键的行、列号显示在LED的第1、2位和5、6位上。

程序代码如下:

/*KeyCheck.c按键检测C程序*/

#include"absacc.h"

#include"display.h"

#include"Reg51.h"

voiddelay()

{chari;

for(i=255;i!

=0;i--);

}

//用反转法检查按键的行列号(只检查单键)

//row返回行号,col返回列号

//若有键按下,函数返回1,否则返回0

charkeyCheck(char*row,char*col)

{

unsignedchart1,t2,t3,i;

unsignedcharResult=0;

P1=0xF0;t1=P1;

if(t1==0xf0)gotoexit;//无键按下,返回

for(i=11;i!

=0;i--)//去抖延时约20ms

delay();

t1=P1;

if(t1==0xf0)gotoexit;//无键按下,返回

Result=1;

//求列号

t2=0x80;t1=~t1;

for(i=4;i!

=0;i--)

{t3=t2&t1;

if(t3!

=0){*col=i-1;break;}

elset2=t2>>1;

}

t1=~t1;

t1=t1|0x0f;//低4位置1

P1=t1;

t1=P1;

t2=0x08;t1=~t1;

for(i=4;i!

=0;i--)

{t3=t2&t1;

if(t3!

=0){*row=i-1;break;}

elset2=t2>>1;

}

exit:

returnResult;

}

/*main.c源程序,现实所识别键的行、列号*/

#include"display.h"

#include"absacc.h"

#include"Reg51.h"

externcharkeyCheck(char*row,char*col);

voidmain()

{charrow,col,r;

charstrIndexs[6]={20,20,20,20,20,20};

unsignedchari,k;

Init8255();

while

(1)

{

r=keyCheck(&row,&col);

if(r==0)

{strIndexs[5]=20;strIndexs[4]=20;

strIndexs[1]=20;strIndexs[0]=20;

}

else

{strIndexs[5]=0;strIndexs[1]=0;

strIndexs[4]=row;strIndexs[0]=col;

}

for(k=6;k!

=0;k--)

{LedsOff();

for(i=50;i!

=0;i--);

turn_On(k-1,strIndexs[k-1],CC);

for(i=50;i!

=0;i--);

}

}

}

程序运行结果如图7,当按下图5中第3行第1列上按键时,将在LED上显示键的行列号。

图7

3.PID温控器的炉温采样接口及仿真

图8是PID温控器的仿真原理图。

图中74LS161用于提供ADC0808所需的时钟信号,其Q1、Q2、Q3、Q4输出信号的频率分别是其CLK引脚输入时钟信号频率的1/2、1/4、1/8、1/16,CLK输入信号来自于51单片机的ALE引脚输出,多路开关SW1为ADC0808选取不同的时钟频率。

图中P1为CPU访问片外数据存储空间地址0x2XXX时74LS138的译码输出,当CPU写0x2XXX时,可使ADC0808锁存数据总线上D0、D1、D2的输入通道号;CPU读0x2XXX时,可将A/D转换结果读入到CPU中。

P2为CPU访问片外数据存储空间地址0x4XXX时74LS138的译码输出,当CPU读地址0x4XXX时,可将EOC信号从数据总线D7位读入到CPU中;

信号来自于51单片机的

引脚P3.6、P3.7。

打开前面完成的仿真模型文件KeyBoard.dsn,并另存为Adc.dsn.新建一个名为ADC0808的设计页,将图8的内容画在该设计页中;在进入ExternalMemory设计页,为其中的AT89C51的P3口加上所需的端子并正确命名;在P3.3上加一个端子将其命名为EX1,P3.5加一个端子并将其命名为START,然后保存仿真文件。

图8

用端口查询方式编写程序从图8的ADC0808通道1读取AD转换值并显示在LED上。

程序代码如下:

/*ADC.H*/

#defineADC_08081

#defineADC0808_DATA_PORT0x2000

#defineADC0808_QUERY_PORT0x4000

#defineADC0808_START_PORT0x2000

//function:

getsdatafromADCchip,

//parameters:

//unsignedcharADC_Chip--theadcchipsuchasADC_0808(9),

//AD574andsoon.thechip'sresolutionshouldn'tbehigher

//than12bits

//unsignedcharchannel:

thechannelthatdatafrom

//returnvalue:

ifsucceed,thedatabetween0to4095(12bits)readfromselectedchannelofAdcchip,

//elsereturn-1.

unsignedchargetData1(unsignedcharADC_Chip,unsignedcharchannel);

unsignedchargetData2(unsignedcharADC_Chip,unsignedcharchannel);

 

/*ADC0808.c*/

#include"Adc.h"

#include"absacc.h"

#include"Reg51.h"

//端口(P3.3)查询方式

unsignedchargetData2(unsignedcharADC_Chip,unsignedcharchannel)

{unsignedcharflag=0;

unsignedcharvalue=-1;

unsignedxdataale;

switch(ADC_Chip)

{caseADC_0808:

P3=P3|0x08;//读入端口前相应位先置1

XBYTE[ADC0808_START_PORT]=channel;//输入通道锁存

//P3.4低--高--低脉冲启动AD转换

P3=P3&0xdf;//P3.4置低

P3=P3|0x20;//P3.4置高

P3=P3&0xdf;//P3.4置低

//查询转换是否完成(P3.3是否为0)

flag=P3;

while

(1)

{ale=1;//注意:

Proteus中8051模型有问题,在不访问片外RAM时ALE无输出,

//故在此加入了一条访问片外RAM的语句ale=1,

//以产生ADC0808所需的时钟信号,实际的应用程序是不需要这条语句的

flag=flag&0x08;

if(flag==0)break;

flag=P3;

}

//step3:

readdataandreturnit

value=XBYTE[ADC0808_DATA_PORT];

returnvalue;

break;

}

}

 

/*main.c*/

#include"Adc.h"

#include"display.h"

#include"Reg51.h"

voiddispStr(charstrIndexs[],unsignedcharvalue,charchannel)

{chari,k;

for(i=0;i<3;i++)

{strIndexs[i]=value%10;

value=value/10;

}

strIndexs[4]=channel;

LedsOff();

for(i=50;i!

=0;i--);

for(k=6;k!

=0;k--)

{LedsOff();

for(i=50;i!

=0;i--);

turn_On(k-1,strIndexs[k-1],CC);

for(i=50;i!

=0;i--);

}

}

//端口查询读取通道1的值并显示

voidmain()

{unsignedcharvalue;

unsignedintk;

charstrIndexs[6]={20,20,20,20,1,12};//待显示字符下标

Init8255();

while

(1)

{

value=getData2(ADC_0808,1);

for(k=100;k!

=0;k--)

dispStr(strIndexs,value,1);

LedsOff();

}

}

运行程序结果如图9,数码管左边两位表示通道号,右边三位为读入的数据。

图9

4.PID温控器的温度测量电路设计及仿真

PID温控器的测温放大电路原理图如图10。

图10

打开以上所建立的Adc.dsn仿真图,在其中LED_KeyBoard设计页上建立如图(a)所示的放大子电路Amp,用以封装测温放大电路(b)。

Amp子电路和模仿热电阻阻值变化的R

放置道0。

进入子电路设计页,将图(b)绘制在子电路设计页,最后将仿真图保存为Measure.dsn。

图(b)中的R

用于调整放大电路的倍数,使电路在测温上限200℃时输出Uto刚好为5V;R

用于调节电桥的初始平衡,即在测温下限0℃时使电桥平衡,Uto为零。

实际电路调整时,Uto的上下限与5V、0V有微小偏差。

在Measure.dsn温度测量仿真模型上编写程序,将ADC0808输入通道0上读入的数据转换为温度后显示在LED上。

程序代码如下:

/*main.c源程序*/

#include"Adc.h"

#include"display.h"

#include"Reg51.h"

//读取通道0输入并换算成温度(保留一位小数)显示并显示

//量程:

0--200度

voidmain()

{unsignedcharvalue;//通道0读入的数据

unsignedlongt;//标度换算出的温度值

unsignedchari,m,n;

Init8255();

while

(1)

{

value=getData1(ADC_0808,0);

//标度变换时,为避免浮点运算,将算出的温度放大10倍,并对第二位小数四舍

//五入,结果保留一位小数,如读入的value为103,则200*103*100)/255=8078

//t=(8078+5)/10=808(注意:

C整除运算只取商的整数部分)

//则算出的温度为80.8度

t=((200*(unsignedlong)value*100)/255+5)/10;

LedsOff();

for(i=200;i!

=0;i--)

for(m=100;m!

=0;m--);//延时

for(i=0;;i++)

{m=t%10;

if(i==1)

turn_On_WithDot(i,m,CC);

else

turn_On(i,m,CC);

for(n=50;n!

=0;n--);

t=t/10;

if(t==0)break;

}

}

}

程序仿真结果如图11。

图11

1、PID温控器上/下位机串口通信及仿真

PID温控器串口通信的原理如图12所示。

图12

虚线边框内是PID温控器的串行通信口设计部分;黑色边框内部分用于模拟PC,便于调试通信程序,在PID温控器的实际电炉中是不需要的。

打开前面建立的Adc.dsn仿真原理图,进入ExternalMemory设计页,为AT89C51的TXD、RXD引脚各连上一个接线端子并取名为T和R。

将图12的内容画在ExternalMemory设计页中,将AT89C51的时钟频率设为12MHz,两个虚拟终端的波特率设为2400。

然后将仿真原理图另存为Comm.dsn。

运行如下程序。

/*--------------------------------------------------------------------------

INTRINS.H

IntrinsicfunctionsforC51.

Copyright(c)1988-2010KeilElektronikGmbHandARMGermanyGmbH

Allrightsreserved.

--------------------------------------------------------------------------*/

#ifndef__INTRINS_H__

#define__INTRINS_H__

externvoid_nop_(void);

externbit_testbit_(bit);

externunsignedchar_cror_(unsignedchar,unsignedchar);

externunsignedint_iror_(unsignedint,unsignedchar);

externunsignedlong_lror_(unsignedlong,unsignedchar);

externunsignedchar_crol_(unsignedchar,unsignedchar);

externunsignedint_irol_(unsignedint,unsignedchar);

externunsignedlong_lrol_(unsignedlong,unsignedchar);

externunsignedchar_chkfloat_(float);

#if!

defined(__CX2__)

externvoid_push_(unsignedchar_sfr);

externvoid_pop_(unsignedchar_sfr);

#endif

#endif

/*KeyCheck.c*/

#include"display.h"

#include"Reg51.h"

#include"intrins.h"

voiddelay()

{chari;

for(i=255;i!

=0;i--);

}

//用扫描法检查按键的行列号(只检查单键)

//按仿真图设计,无键按下时行信号为低电平

//有键按下时,行信号为高电平

//row返回行号,col返回列号

//若有键按下,函数返回1,否则返回0

sbitP1_0=0x90;//第0行信号

sbitP1_1=0x91;//第1行信号

sbitClear=0x92;//74LS164清零信号

charkeyCheck(char*row,char*col)

{charResult=0;

chari,mask=0x7f;

charcolumn=0;

P1_0=1;P1_1=1;//读之前先置1

Clear=0;Clear=0;//74LS清全零

Clear=1;

if(P1_0&P1_1)//无键按下,两行信号均为高电平

gotoexit;

for(i=11;i!

=0;i--)//去抖延时约20ms

delay();

if(P1_0&P1_1)//无键按下,两行信号均为高电平

gotoexit;

//记录行号

if(P1_0==0)*row=0;

else*row=1;

Result=1;

//求列号

Clear=1;Clear=1;//允许74LS164串入并出

whil

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 经管营销 > 经济市场

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1