#include/*---------------定义绘图坐标---------------*/
#defineox8/*-原点横坐标-------*/
#defineoy440/*------原点纵坐标------*/
#definexx620/*------x轴顶点横坐标--*/
#definexy440/*-----x轴顶点纵坐标---*/
#definelenx580
#defineleny400
#defineyx8/*-----y轴顶点横坐标----*/
#defineyy15/*------y轴顶点纵坐标----*/
/*-----------------定义绘图区域----------------*/
#defineleft20
#definetop20
#defineright620
#definebottom460
/*----------------坐标轴注释---------------------*/
#definextext1x450
#definextext1y450
#defineytext1x10
#defineytext1y60
#definextext2x610
#definextext2y450
#defineytext2x10
#defineytext2y20
/*--------------理想PID运算式----------*/
floatlxpid(floatkp,floattd,floatti,floate[3],floatu1)
{
intt=1;
floatu;
floatq0=kp*(1+t/ti+td/t);
floatq1=-kp*(1+2*td/t);
floatq2=kp*td/t;
u=q0*e[0]+q1*e[1]+q2*e[2]+u1;
returnu;
}
/*-------------------------实际PID运算式--------------------------*/
floatsjpid(floatkp,floattf,floattd,floatti,floate[3],floatdu1,floatu1)
{
intt=1;
floatu2;
floatc1=tf/(t+tf);
floatc2=kp*t*(1+t/ti+td/t)/(t+tf);
floatc3=-kp*t*(1+2*td/t)/(t+tf);
floatc4=kp*td/(t+tf);
u2=c1*du1+c2*e[0]+c3*e[1]+c4*e[2]+u1;
returnu2;
}
/*-------------------------绘图初始化--------------------------*/
voidInitial_Sys(void)
{
intGraphDriver;
intGraphMode;
detectgraph(&GraphDriver,&GraphMode);
initgraph(&GraphDriver,&GraphMode,"C:\\TC201E\\BGI");
cleardevice();
}
/*-------------------------绘制坐标系------------------*/
voidDrawAxis(void){
inti;
setbkcolor(15);
setcolor(5);
line(ox,oy,xx,xy);/*x_axis*/
line(xx-5,xy-5,xx,xy);
line(xx,xy,xx-5,xy+5);
line(ox,oy,yx,yy);/*y_axis*/
line(yx-5,yy+10,yx,yy);
line(yx+5,yy+10,yx,yy);
for(i=0;i<51;i++) /*-x轴刻度-*/
{
line(ox+10*i,oy,ox+10*i,oy-10);
line(ox+10*i+5,oy,ox+10*i+5,oy-5);
}
for(i=1;i<=8;i++) /*-y轴刻度-*/
line(ox,oy-50*i,ox+10,oy-50*i);
outtextxy(ox+50*0-7,oy+20,"0");
outtextxy(ox+50*1-7,oy+20,"5");
outtextxy(ox+50*2-7,oy+20,"10");
outtextxy(ox+50*3-7,oy+20,"15");
outtextxy(ox+50*4-7,oy+20,"20");
outtextxy(ox+50*5-7,oy+20,"25");
outtextxy(ox+50*6-7,oy+20,"30");
outtextxy(ox+50*7-7,oy+20,"35");
outtextxy(ox+50*8-7,oy+20,"40");
outtextxy(ox+50*9-7,oy+20,"45");
outtextxy(ox+50*10-7,oy+20,"50");
outtextxy(ox-10,oy-50*1,"1");
outtextxy(ox-10,oy-50*2,"2");
outtextxy(ox-10,oy-50*3,"3");
outtextxy(ox-10,oy-50*4,"4");
outtextxy(ox-10,oy-50*5,"5");
outtextxy(ox-10,oy-50*6,"6");
outtextxy(ox-10,oy-50*7,"7");
outtextxy(ox-10,oy-50*8,"8"); /*坐标轴刻度标识*/
settextstyle(SMALL_FONT,HORIZ_DIR,5); /*坐标轴标示字体 方向 大小*/
outtextxy(xtext1x,xtext1y,"Time");
outtextxy(xtext2x,xtext2y,"t\/s");
settextstyle(SMALL_FONT,VERT_DIR,5);
outtextxy(ytext1x,ytext1y,"Theoutput(Response)");
outtextxy(ytext2x,ytext2y,"U(t)\/V");
}
}
main()
{
floatkp,ti,td,tf,e[3]={0},ee[3]={0},u[6]={0},au1=0;
intr=1,k=1;
Initial_Sys();
DrawAxis();
while(k<100)
{
u[0]=lxpid(1,3.0,10,e,u[1]);
e[0]=r;
u[3]=sjpid(1,5,3.0,10,ee,au1,u[4]);
setcolor(5);
line((k-1)*10,130-u[1]*100,k*10,130-u[1]*100);
line(k*10,130-u[1]*100,k*10,130-u[0]*100);
delay(10000);
u[1]=u[0];
e[2]=e[1];
e[1]=e[0];
ee[0]=r;
setcolor(3);
line((k-1)*10,150-u[4]*100,k*10,150-u[4]*100);
line(k*10,150-u[4]*100,k*10,150-u[3]*100);
delay(10000);
u[5]=u[4];
u[4]=u[3];
ee[2]=ee[1];
ee[1]=ee[0];
au1=u[4]-u[5];
k++;
}
}
/*---------------头文件定义---------------*/
#include"stdio.h"
#include"math.h"
#include"graphics.h"
#include"string.h"
#include"dos.h"
#include"bios.h"
#include"conio.h" /*中断程序头文件定义*/
#include"stdlib.h"
#include"io.h"
/*--------------按键地址区定义--------------------*/
/*statements*/
doublekey_ESC=0x011b; /*退出*/
doublekey_E=0x1265;
doublekey_A=0x1e61; /*自动*/
doublekey_H=0x2368; /*手动*/
doublekey_U=0x1675; /*自动时增SP,手动时增手操器输出*/
doublekey_D=0x2064; /*自动时减SP,手动时增手操器输出*/
doublekey_I=0x1769; /*理想PID*/
doublekey_P=0x1970; /*实际PID*/
doublekey_up=0x4800; /*手动时,增Kp*/
doublekey_down=0x5000; /*手动时,减Kp*/
doublekey_left=0x4b00; /*手动时,减Ti*/
doublekey_right=0x4d00; /*手动时,增Ti*/
doublekey_pgup=0x4900; /*手动时,增Td*/
doublekey_pgdown=0x5100; /*手动时,减Td*/
/*--------------PLCD780基址定义--------------------*/
#defineBASE0x220 /*------------PCL812Gneed16addressesinarow,from220Hto3F0H*/
#defineREG0
/*---------------定义绘图坐标---------------*/
#defineox40/*------------原点横坐标-------------*/
#defineoy440/*------------原点纵坐标------------*/
#definexx600/*------------x轴顶点横坐标--------*/
#definexy440/*------------x轴顶点纵坐标--------*/
#defineyx40/*------------y轴顶点横坐标--------*/
#defineyy40/*------------y轴顶点纵坐标---------*/
/*---------------PID参数定义---------------*/
floatKp=1.0;
floatTi=10.0;
floatTd=3.0;
floatTf0=15.0;
floatTf=0;
floatT=0.1;/*---------------采样时间------------*/
floatad,e,pv0;
floatu=0.0;
floatpv=0.0; /*反馈值*/
floatsp=0.0; /*设定值*/
charA_H=H; /*手动-自动,开始为手动*/
charmanu; /*用于调节u_m的增减*/
intkey=0; /*存键盘扫描结果*/
inttime_counter=0; /*中断计数*/
intcj_counter=0;/*采样计数器*/
intQ_counter=800;/*采集步长赋初始值*/
intstepdata[800];
intslopedata[800];
interror[800];
/*--------------函数声明-----------------*/
voidinterrupt(*fadd1C)(void); /*中断*/
voidloop(); /*主程序循环*/
floatAD(unsignedcharchannal);/*A/D*/
voidDA(floatpv1);/*D/A*/
voidinterruptINT_1C(void);/*8259,resetinterruptcontroller*/
intscankey(); /*扫描键盘,判断是否有建按下*/
floatDelayAction(floaty0); /*软件延迟*/
voidPIDset(void); /*PID设置*/
floatPID(floatsp1,floatpv1,floatKp1,floatTi1,floatTd1,floatTf1,charA_H1,floatT1);
floatObject(floatu1,floatT1); /*仿真对象*/
voidInitial_Sys(void);/*初始化为图形模式*/
voidaxis(void); /*画坐标轴*/
voidDrawline(intcj,floatpv1,floatsp1,floatu1,floate1); /*画线*/
/*主函数*/voidmain(void)
{
inti;
for(i=0;i<500;i++)
{ stepdata[i]=10; slopedata[i]=i; error[i]=0;}
/*SetnewINT_1Candsaveold*/
disable(); /*保存旧中断,设置新中断*/
fadd1C=getvect(0x1C);/*1C为定时器控制的软中断,平均一秒发生18.2次,即周期为55ms中断程序*/
/*开启中断服务*/
setvect(0x1C,INT_1C);
enable();
axis();
loop();
}
/*主函数结束下面为定时采值输出程序*/
voidloop()
{do
{
if((cj_counter*T)0)
printf("Parallal,Mode:%c,sp=%.1f,pv=%2.1f,u=%.1f,error=%.1f,Kp=%.1f,Ti=%.1f,Td=%.1f\t\r",A_H,sp,pv,u,e,Kp,Ti,Td);
elseprintf("\t\tTfgotawrongvalue!Pleaseexitandrestartthisprogram.\r");
cj_counter++;
}
}while(cj_counter<500);
/*恢复中断*/
disable();
setvect(0x1C,fadd1C);
enable();
}
/*D/Aconversionprogram,0to4095--0to+5*/
floatAD(unsignedcharchannal)
{
floatresult=0;
inti;
unsignedcharhb=0,lb=0,poll=0x10;
outportb(BASE+11,REG);/*软件程序触发*/
for(i=0;i<10000;i++);
outportb(BASE+10,channal);/*进行通道设置.选择通道0*/
for(i=0;i<10000;i++);
outportb(BASE+9,0);/*设置增益通道增益*/
for(i=0;i<10000;i++);
outportb(BASE+12,0);/*触发A/D转换*/
for(i=0;i<10000;i++);
do{ /*查询法读PV*/
poll=inportb(BASE+5);
}while(poll&0x10);
hb=inportb(BASE+5);
for(i=0;i<10000;i++);
lb=inportb(BASE+4);
result=lb+((hb&0x0F)<<8);/*0to4095*/
result=result*5/4096;/*0Vto+5V*/
returnresult;
}
/*A/Dconversionprogram,0to+5--0to4095*/
voidDA(floatpv1){
inttemp,i;
unsignedcharhb,lb; /*限幅 */
if(pv1>5)/*maketheoutputreal*/
pv1=5;
elseif(pv1<0)pv1=0;temp=(int)(4095*pv1/5.0);
hb=temp<<8;
lb=temp-(hb<<8);
outportb(BASE,1); /*启动DA转换*/
for(i=0;i<10000;i++);
outportb(BASE+4,lb);/*low8*/
for(i=0;i<10000;i++);
outportb(BASE+5,hb);/*high4*/
}
/*00----------------------------中断子程序-------------------------*/
voidinterruptINT_1C(void)
{time_counter++;
outportb(0x20,0x20);
}
/*键盘控制*/
intscankey(void)
{
intkey0; /*扫描键盘,判断是否有建按下*/
key0=bioskey(1);/*1:无键按下则返回0*/
if(key0!=0)
key0=bioskey(0);/*0:返回按下的键*/
returnkey0;
}
/*DelayAction*/
/*tao=(int)(18.2*2)Delayaction=2seconds*/
floatDelayAction(floaty0) /*软件延迟*/
{
floaty_out;
staticfloaty_old[36]={0};/*将ad延迟2s作为PV,T=0.2s,于是延迟36步*/
intcyc;
y_out=y_old[36-1];
for(cyc=1;cyc<36;cyc++)
y_old[36-cyc]=y_old[36-cyc-1];
y_old[0]=y0;
returny_out;
}
/*PID主程序*/
voidPIDset(void) /*PID设置*/
{
key=scankey(); /*扫描键盘,并将按键存为key*/
if(A_H==H)/*手动状态*/
{if(key==key_up)
Kp+=0.2;
elseif(key==key_down)
Kp-=0.2;
elseif(key==key_left)
Ti-=0.2;
elseif(key==key_right)
Ti+=0.2;
elseif(key==key_pgup)
Td+=0.2;
elseif(key==key_pgdown)
Td-=0.2;
elseif(key==key_U)/*控制u_m增减*/
manu=+;
elseif(key==key_D)
manu=-;
}
if(A_H==A) /*自动状态*/
{if(key==key_U) /*设定值增减*/
sp+=10;
if(key==key_D)
sp-=10;
}
if(key==key_E||key==key_ESC)/*退出*/
exit(1);
if(key==key_A)/*设为手动*/
A_H=A;
if(key==key_H)/*设为自动*/
A_H=H;
if(key==key_I)/*理想PID*/
Tf=0;
if(key==key_P)/*实际PID*/
Tf=Tf0;
}
/*PID-default:IdealPID*/
floatPID(floatsp1,floatpv1,floatKp1,floatTi1,floatTd1,floatTf1,charA_H1,floatT1){
floatdelta_u,u0,e,C1,C2,C3,C4; /*离散化后PID参数 当前时刻,u0为返回值*/
staticfloate1,e2,u1,delta_u1;/*前一时刻的值*/
if(Kp1<0)
printf("Kpbecomesanegativenumber,pleaserestart.");
elseif(Ti1<0) printf("Tibecomesanegativenumber,pleasepressrestart.");
elseif(Td1<0) printf("Tdbecomesanegativenumber,pleasepressrestart.");
else
{
C1=Tf1/(T1+Tf1);
C2=Kp1*T1*(1+T1/Ti1+Td1/T1)/(T1+Tf1);
C3=-Kp1*T1*(1+2*Td1/T1)/(T1+Tf1);
C4=Kp1*Td1/(T1+Tf1);
/*自动控制*/
if(A_H1==A)
{e=sp1-pv1;
delta_u=C1*delta_u1+C2*e+C3*e1+C4*e2; /*delta_u1是delta_u前一时刻的值*/
u0=u1+delta_u; /*当前时刻控制器输出*/
e2=e1;
e1=e;
delta_u1=delta_u;
u1=u0; /*自动时,手操器输出跟踪自动输出*/
error[cj_counter]=sp1-pv1;
returnu0;
}
/*手动控制*/
elseif(A_H1==H)
{
if(manu==+) /*调节手操器输出*/
u+=10;
if(manu==-)
u-=10;
sp1=pv1;
u1=u;
sp=pv1; /*sp跟踪pv保证偏差e为0*/
e1=0;
e2=0;
delta_u1=0; /*将前两时刻的偏差赋值为0*/
error[cj_counter]=sp1-pv1;
returnu;
}
}
}
/*显示与画图*/
/*初始化CRT*/
voidInitial_Sys(void){
intGraphDriver;
intGraphMode;
detectgraph(&GraphDriver,&GraphMode);
initgraph(&GraphDriver,&GraphMode,"C:\\TC201E\\BGI");}
/*drawbasiccoordinateaxis*/
voidaxis(void)
{
inti;
Initial_Sys();
setbkcolor(15);/*white0/black15*/
setcolor(9);/*linghtblue*/
rectangle(10,20,630,470);/*zoneofdrawing*/
line(ox,oy,xx,xy);/*axisandarrow*/
line(xx-5,xy-5,xx,xy);
line(xx,xy,xx-5,xy+5);
line(ox,oy,yx,yy);
line(yx-5,yy+5,yx,yy);
line(yx+5,yy+5,yx,yy);
settextstyle(2,1,5);/*Smallfont,vert,5timesbigger*/
outtextxy(20,100,"TheOutput(Response)");
outtextxy(20,40,"U(t)");
settextstyle(2,0,5);/*Smallfont,horiz,5timesbigger*/
outtextxy(300,455,"Time");outtextxy(590,455,"t/sec");
setlinestyle(1,0,1);/*dotline,none,width*/
for(i=1;i<4;i++)/*eachinportstartingposition*/
line(ox,oy-100*i,ox+500,oy-100*i);
outtextxy(ox-16,oy-100*0,"0");outtextxy(ox-16,oy-100*1,"1");
outtextxy(ox-16,oy-100*2,"2");outtextxy(ox-16,oy-100*3,"3");
for(i=1;i<=500/50;i++)/*scale*/
{
line(ox+50*i,oy,ox+50*i,oy-400); /*1/T=10,thatis10px=1sec*/
line(ox+50*i-25,oy,ox+50*i-25,oy-10);
}
setlinestyle(0,0,1);/*realline,none,width*/
outtextxy(ox-4+50,oy+2,"5");
outtextxy(ox-8+100,oy+2,"10");
outtextxy(ox-8+150,oy+2,"15");
outtextxy(ox-8+200,oy+2,"20");
outtextxy(ox-8+250,oy+2,"25");
outtextxy(ox-8+300,oy+2,"30");
outtextxy(ox-8+350,oy+2,"35");
outtextxy(ox-8+400,oy+2,"40");
outtextxy(ox-8+450,oy+2,"45");
outtextxy(ox-8+500,oy+2,"50");
}
/*line-drawingandnotes*/
voidDrawline(intcj1,floatpv1,floatsp1,floatu1,floate1) /*画线*/
{staticintcj_0=0,cj_1=0,pv_0=0.0,pv_1=0.0,sp_0=0.0,
sp_1=0.0,u_0=0.0,u_1=0.0,e_0=0.0,e_1=0.0;cj_1=cj1; /*Xcoordinate*/
pv_1=(int)(pv1*10);
sp_1=(int)(sp1*10);
u_1=(int)(u1*10);
e_1=(int)(e1*10);
setcolor(2);/*green*/
line(ox+cj_0,oy-pv_0,ox+cj_1,oy-pv_1);outtextxy(590,30,"pv");
setcolor(8);/*darkgray*/
line(ox+cj_0,oy-sp_0,ox+cj_1,oy-sp_1);outtextxy(590,45,"sp");
setcolor(3);/*cyan*/
line(ox+cj_0,oy-u_0,ox+cj_1,oy-u_1);
outtextxy(590,60,"u");
setcolor(4);/*red*/
line(ox+cj_0,oy-e_0,ox+cj_1,oy-e_1);
outtextxy(590,75,"error");
cj_0=cj_1;pv_0=pv_1;sp_0=sp_1;u_0=u_1;e_0=e_1;
}