资源描述
#include <reg51.h>
#include <absacc.h>
#include <math.h>
void pid(void) //PID算法子程序
void init(void) //初始化子程序
void display(void) //延时子程序
void clear() //清零子程序
int mmul(int x,int y) //16位乘法,溢出赋极值
int madd(int x,int y) //16位加法,溢出赋极值
int change32_16(int x,int t) //32——16
char change16_8(int wd) //16——8
#define C8255_A XBYTE[0x7F00]
#define C8255_B XBYTE[0x7F01]
#define C8255_C XBYTE[0x7F02]
#define C8255_CON XBYTE[0x7F03]
#define AD0809 XBYTE[0xFEFF] //定义AD0809的地址
sbit P17=P1^7; //PWM的驱动
char TS=0x64; //采样周期
int X=0x80;
char SPEC=0x28; //给定:要求达到的温度值
char IBAND=0x60; //积分分离值:PID算法中积分分离值
int KP=12; //比例系数:PID算法中比例项系数
char KI=20; //积分系数
char KD=32; //微分系数
int CK; //控制量:PID算法产生用于控制的量
int TC; //采样周期变量
char FPWM; //PWM脉冲中间标识位
int CK_1; //控制量变量,用于记录上次控制的值
int AAAA; // PWM高电平脉冲时间计算
int VAA; //AAAA变量
int BBB; //PWM低电平脉冲时间计算
int VBB; //BBB变量
int TKMARK; //采样标志值
int ADMARK;//AD转换结束标志位
int ADVALUE; //AD采样后保存
int YK; //反馈:测量温度值
int EK; //温度误差
int EK_1;
int AEK;
int BEK;
unsigned char dis; //BCD码显示
unsigned char led[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
unsigned char b[]={0x00,0x00,0x00,0x00}; //位选
/********************温度表**************/
unsignedcharcode a[0x100]={0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x15,0x16,0x17,0x18,0x19,
0x1a,0x1b,0x1c,0x1d,0x1e,0x1e,0x1f,0x20,0x21,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,
0x2b,0x2c,0x2d,0x2e,0x2f,0x31,0x32,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,
0x3f,0x40,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x4f,0x50,
0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,0x60,0x61,0x62,0x63,0x64,0x64,0x65,0x65,0x66,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6e,0x6f,0x6f,0x70,0x71,0x72,0x73,0x74,
0x75,0x76,0x77,0x78,0x79,
0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,0x80,0x81,0x82,0x83,0x84,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8e,0x8f,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9b,0x9c,0x9c,0x9d,0x9d,0x9e,0x9e,
0x9f,0x9f,0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,0xb0,0xb0,0xb1,0xb2,0xb3,0xb4,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbd,0xbe,0xbe,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,
0xc8,0xca,0xcc,0xce,0xcf,0xd0,0xd1,0xd2,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xe3,0xe6,0xe9,
0xec,0xf0,0xf2,0xf6,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,}
/**************延时子程序*********************/
void delay(unsigned int time)
{
unsigned int i;
for(i=0;i<time;i++)
}
/*************主程序*************************/
void main()
{
init();
while(1);
{
while(1)
{
if(TRMARK==0x01)
break; //采样周期到否
}
TRMARK==0x00;
while(1)
{
if(ADMARK==0x01)
break; //AD转换是否结束
}
ADMARK=0x00;
YK=a[ADVALUE];
dis=(char)YK; //查温度表
pid(); //PID算法
if(CK<=0x80) //根据CK产生PWM
AAAA=0x00;
else
AAAA=CK-0x80;
BBB=0x7f-AAAA;
}
}
/***********初始化函数*********************/
void init(void)
{
YK=0x00; //变量初始化
EK=0x00;
EK_1=0x00;
AEK=0x00;
BEK=0x00;
CK=0x00;
CK_1=0x00;
BBB=0x00;
VBB=0x00;
ADVALUE=0x00;
TKMARK=0x00;
ADMARK=0x00;
TC=0x00; //采样周期变量
FPWM=0x01;
AAAA=0x7f;
VAA=0x7f;
C8255_CON=0x81;
display();
clear();
TMOD=0x11; //T1 ,T0由外部控制中断控制信号,16位定时器,工作在方式一下
IP=0x02; //设定T0中断优先级最高
IT1=1; //外部中断请求信号方式为脉冲触发方式,外中断1为下降沿有效
EX1=1; //允许INT1中断
TH0=0xd8;
TL0=0xef;
TH1=0xd8;
TL1=0xef;
ET0=ET1=1; //允许T0,T1中断
TR0=TR1=1; //启动T0,T1
EA=1;
AD0809=1; //启动AD转换
}
void myint3(void) interrupt 3 //定时器1 LED显示
{
TH1=0xd8;
TL1=0xef;
ET1=1;
display();
clear();
}
void myint1(void) interrupt 2 //外中断1 读AD转换结果
{
ADVALUE=AD0809;
ADMARK=0x01;
}
void myint2(void) interrupt 1 //定时器0 启动AD转换
{
TH0=0xd8;
TL0=0xef;
ET0=1; //启动定时器0
AD0809=1; //启动AD
if(TC<TS)
TC++; //采样周期变量
else
{
TKMARK=0x01;
TC=0x00;
}
if(FPWM==0x01) //产生PWM ,0x01表示加热模块
{
if(VA!=0x00)
{
VAA=VAA-1;
P17=0; //输出为低 加热
}
else
{
FPWM=0x02;
VBB=BBB/2;
}
}
if(FPWM==0x02) //0x02表示停止加热模块
{
if(VBB!=0x00)
{
VBB=VBB-1;
P17=1; //输出为高 停止加热
}
else
{
FPWM=0x01;
VAA=AAAA/2;
}
}
return;
}
/*****************PID子程序***********/
void pid(void)
{
int K,P,I,D;
K=P=I=D=0;
EK=SPEC-YK; //得到偏差
BEK=EK-EK_1-AEK; //12EK
AEK=EK-EK_1; //偏差变化量
/*********UK=Kp*AEK+Ki*EK+Kd*BEK****/
if(abs(EK)>abs(IBAND))
I=0; //判积分分离
else
I=(EK*TS)/KI; //计算积分项
P=AEK;
D=((KD/TS)*BEK)/10000; //计算微分项
//与书上对照,忽略KP
K=madd(I,P);
K=madd(D,K);
K=mmul(K,KP);
K=K/10;
CK=K+CK_1;
CK=change16_8(CK);
CK_1=CK;
EK_1=EK;
CK=CK+X;
}
int mmul(int x,int y)
{
int t,z;
long s;
s=x*y;
z=(int)(s&0x0ffff);
t=(int)((s>>16)&0x0ffff);
s=change32_16(z,t);
return(s);
}
int change32_16(int z,int t) //t=高字节,z=低字节
{
int s;
if(t==0)
{
if((z&0x8000)==0) s=z;
else s=0x7fff;
}
else if((t&0xffff)==0xffff)
{
if((z&0x8000)==0) s=0x8000;
else s=z;
}
else if((t&0x8000)==0) s=0x7fff;
else s=0x8000;
return(s);
}
int mmad(int x,int y)
{
int t;
t=x+y;
if(x>=0&&y>=0) //同号相乘,符号位变反说明溢出
{
if((t&0x8000)!=0) t=0x7fff;
}
else if(x<=0&&y<=0)
{
if((t&0x8000)==0) t=0x8000;
}
return(t);
}
char change16_8(int wd) //t=高字节,z=低字节
{
char z,t,s;
z=(wd>>8)&0x0ff;
if(t==0x00)
{
if((z&0x80)==0) s=z;
else s=0x7f;
}
else if((t&0xff)==0xff)
{
if((z&0x80)==0) s=0x80;
else s=z;
}
else if((t&0x80)==0) s=0x7f;
else s=0x80;
return(s);
}
void display() //数码管显示函数
{
unsigned char i,j=0xf7;
b[3]=SPEC/10;
b[2]=SPEC%10;
b[1]=dis/10;
b[0]=dis%10;
for(i=0;i<4;i++)
{
C8255_A=j;
C8255_B=led[b[i]];
delay(0x55);
j>>=1;
}
}
void clear()
{
C8255_B=0x00;
}
展开阅读全文