📄 88888pid.c
字号:
//********************************
//max6675 温度采集
//lp 2007.12.06
//********************************
#include <AT89x52.h>
#include <intrins.h>
#include <string.h>
#include "stdio.h"
//#include "sio.h"
#include "stc89c58_eeprom.h"
#define uchar unsigned char
#define uint unsigned int
//********************
//模拟串口
#define RXD P2_7
#define TXD P2_6
//********************************
// 164显示用的变量
data uchar dis_data0=10;
data uchar dis_data1=10;
data uchar dis_data2=10;
data uchar dis_data3=10;
data uchar dis_data4=10;
data uchar dis_data5=10;
data uchar dis_data6=10;
data uchar dis_data7=10;
data uchar dis_data8=10;
data uchar dis_data9=10;
data uchar dis_data10=10;
data uchar dis_data11=10;
data uchar dis_data12=10;
data uchar dis_data13=10;
data uchar dis_data14=10;
data uchar dis_data15=10;
data uint disp_cx=200; //计数到显示标志树起
bit DISP_FLAG=1; //显示标志
//********************************
//串口通信用
float lnwd;
float cywd;
float czhi;
float eczhi;
float EII;
float EI=0;
//float bzhi;
uint yxsj;
//********************************
// 按键用的变量
data uchar key_data;key_state=0xff;
bit sk_flag=0;
bit KEY_FLAG=1; //按键抖动标志
data uchar KeyFunIndex=0; //状态号
bit SERRIES_FLAG; //连加时间计数
bit SCANKEY_FLAG=1; //10ms 中断树标志 进入按键扫描程序
data uchar key_long_cx=0;key_serries_cx=0;//长按键、连加时间计数用
//********************************
uchar code led_segment[12]={0x21,0xF9,0x45,0x51,0x99,0x13,0x03,0xF1,0x01,0x11,0xff,0xdf} ;
//********************************
//热电偶数字转换器MAX6675
sbit SCK=P1^0;
sbit CS=P1^1;
sbit SO=P1^2;
sbit out=P1^3; //pwm输出
bit COV_FLAG=1; //转换标志
uint aver0,aver1=0,aver2=0; //采样后求平均得到的温度也扩大了十倍 aver0 当前的 aver1 前一次 aver2 前二次的
uint samping_temper; //采样的温度扩大了十倍
int s_t0, s_t1=0; //计算理论温度当前的和前一次的 也扩大了十倍
uchar data pmw_out=0;
uchar data pmw_cx=0;
bit SAVE_FLAG=1,SET_FLAG=0,PID_FLAG=0;
uint a[7]; //软件滤波用
//********************************
bit SEC5_FLAG=0; //按键是否是由5-0mode 标志
int set_temper=25; //设定温度
char set_hour=0;set_min=0; //设定时间
data int temper1;temper2;temper3;temper4;temper5;
data char hour1;min1;hour2;min2;hour3;min3;hour4;min4;hour5;min5;
uint min_cx=0; //分计数
uint ln_min;
//uint xs_xs=20;
//uint xsxs;
uint cjsj=0;
bit jr_flag;
uint min=0; //分钟
char sect=0; //设置段数
uint t0; //保存开始的温度
//********************************
typedef struct //多级菜单
{
uchar KeyStateIndex; //index
uchar KeyCrState; //mode
uchar KeyUpState; //up
uchar KeyDnState; //down
uchar KeyBackState; //enter
void (*CurrentOperate)();
}KbdTabStruct;
//********************************
//函数申明:
void set(); //按键用
void up();
void down();
void enter();
void normal(); //正常模式
void sec_1_temper(); //第一段的 设定温度
void sec_1_temper_up(); //第一段的 设定温度+
void sec_1_temper_down(); //第一段的 设定温度-
void sec_1_min(); //第一段的 设定时间min
void sec_1_min_up(); //第一段的 设定时间min+
void sec_1_min_down(); //第一段的 设定时间min-
void sec_1_hour(); //第一段的 设定时间hour
void sec_1_hour_up(); //第一段的 设定时间hour+
void sec_1_hour_down(); //第一段的 设定时间hour-
void sec_2_temper(); //第2段的 设定温度
void sec_2_temper_up(); //第2段的 设定温度+
void sec_2_temper_down(); //第2段的 设定温度-
void sec_2_min(); //第2段的 设定时间min
void sec_2_min_up(); //第2段的 设定时间min+
void sec_2_min_down(); //第2段的 设定时间min-
void sec_2_hour(); //第2段的 设定时间hour
void sec_2_hour_up(); //第2段的 设定时间hour+
void sec_2_hour_down(); //第2段的 设定时间hour-
void sec_3_temper(); //第3段的 设定温度
void sec_3_temper_up(); //第3段的 设定温度+
void sec_3_temper_down(); //第3段的 设定温度-
void sec_3_min(); //第3段的 设定时间min
void sec_3_min_up(); //第3段的 设定时间min+
void sec_3_min_down(); //第3段的 设定时间min-
void sec_3_hour(); //第3段的 设定时间hour
void sec_3_hour_up(); //第3段的 设定时间hour+
void sec_3_hour_down(); //第3段的 设定时间hour-
void sec_4_temper(); //第4段的 设定温度
void sec_4_temper_up(); //第4段的 设定温度+
void sec_4_temper_down(); //第4段的 设定温度-
void sec_4_min(); //第4段的 设定时间min
void sec_4_min_up(); //第4段的 设定时间min+
void sec_4_min_down(); //第4段的 设定时间min-
void sec_4_hour(); //第4段的 设定时间hour
void sec_4_hour_up(); //第4段的 设定时间hour+
void sec_4_hour_down(); //第4段的 设定时间hour-
void sec_5_temper(); //第5段的 设定温度
void sec_5_temper_up(); //第5段的 设定温度+
void sec_5_temper_down(); //第5段的 设定温度-
void sec_5_min(); //第5段的 设定时间min
void sec_5_min_up(); //第5段的 设定时间min+
void sec_5_min_down(); //第5段的 设定时间min-
void sec_5_hour(); //第5段的 设定时间hour
void sec_5_hour_up(); //第5段的 设定时间hour+
void sec_5_hour_down(); //第5段的 设定时间hour-
void theory_count();
//********************************
//E_0: 当前测量值
//E_1: 前一次测量值
//E0 :当前理论值
//E1 :前一次理论值
//kp : 比例系数
//ki : 积分系数
//kd : 微分系数
//--------------------------------
//fun: PID计算输出
//********************************
char kp; // pid 系数
char ki;
char kd;
bit CT_FLAG=0;
float E_1=0,E_2=0;
char code DKP[7][7]={{40,40, 40,40,40,40, 40},
{40,40, 40,40,40,40, 40},
{30,30, 30,30,30,30, 30},
{0,0, 0,0,0,0,0},
{-10,0,-10,-10,-10,-10,-10},
{-10,0,-10,-10,-10,-10,-10},
{-20,0,-20,-20,-30,-30,-30}};
char code DKI[7][7]={{20,20, 20,20,20,20,20},
{20,20, 20,20,20,20,20},
{20,20, 20,20,20,20,20},
{20,20, 20,20,20,20,20},
{20,20, 20,20,5,5,5},
{5,5,5,5,5,5,5},
{0,0,0,0,0,0,0}};
char code DKD[7][7]={ {7,-7,-21,-21,-21,-14,7},
{7,-7,-21,-14,-14,-7,0 },
{0,-7,-14,-14,-7,-7,0},
{0,-7,-7,-7,-7,-7,0},
{0,-7,-14,-14,-7,-7,0},
{7,-7,-21,-14,-14,-7,0},
{7,-7,-21,-21,-21,-14,7},};
#define ENB -7 //N是负,B是很大,M是中等,S是很少
#define ENM -5 //P是正,EC是偏差变化率,E是偏差
#define ENS -1
//#define EZO 0
#define EPS 1
#define EPM 2
#define EPB 3
#define ECNB -3
#define ECNM -2
#define ECNS -1
//#define ECZO 0
#define ECPS 1
#define ECPM 2
#define ECPB 3
float pidprocess(int rn,yn) //rn理论值,yn采样值
{
float dp,di,dd,E_0,EC,kpp,kii,pdsj,ycjw;
static float pidout=0;
uchar i,j;
ycjw=pdsj-rn;;
E_0=rn-yn; //当前偏差
EI=EI+E_0;
// if(E_0>8) {EI=0;}
EII=EI/10.0;
if(E_0==0){EII=0;}
EC=E_0-E_1; //偏差的变化率
eczhi=(E_0-E_1)/10.0;
if(E_0<ENB) {i=0;} //负的比较多 //负=超调
else if(E_0>ENB&&E_0<ENM) {i=1;} //负的中
else if(E_0>ENM&&E_0<ENS) {i=2;} //负的比较小
else if(E_0>ENS&&E_0<EPS) {i=3;} // 0
else if(E_0>EPS&&E_0<EPM) {i=4;} //正的比较小 //正超调
else if(E_0>EPM&&E_0<EPB) {i=5;} //正的比较中
else {i=6;} //正的比较大
if(EC<ECNB) {j=0;} //负的比较多 //负=下降趋势
else if(EC>ECNB&&EC<ECNM) {j=1;} //负的中
else if(EC>ECNM&&EC<ECNS) {j=2;} //负的比较小
else if(EC>ECNS&&EC<ECPS) {j=3;} // 0
else if(EC>ECPS&&EC<ECPM) {j=4;} //正的比较小 //正=上升趋势
else if(EC>ECPM&&EC<ECPB) {j=5;} //正的比较中
else {j=6;} //正的比较大
kp=(45-DKP[i][j]);
if(rn<600){kp=kp-20-rn/100;}
if(rn<700&&rn>600){kp=kp-10-rn/500;}
if(rn<1200&&rn>700){kp=kp-5500/rn;}
if(rn>1200&&rn<1500){kp=kp-1000/rn;}
if(rn>1501&&rn<1800){kp=kp+rn/2000;}
if(rn>1800){kp=kp+5+rn/450;}
kpp=kp/10.0;
ki=(80-DKI[i][j]);
kii=ki/100.0;
kd=(130-DKD[i][j]);
dp=kpp*E_0;
di=kii*EII; //(E_0-E_1);
dd=kd*EC;
pidout=dp+di+dd+pidout; // 对输出要累加
// if(E_0>-3){pidout=0;}
if(E_0<1){pidout=0;}
E_2=E_1;
E_1=E_0;
pdsj=rn;
if(pidout<0){pidout=0;} //输出限幅
if(pidout>200){pidout=200;} //输出限幅
dis_data4=dp/100;
dis_data11=((int)dp%100 )/10;
dis_data12=(int)dp%10;
//dis_data13=(k%100)/10; //个位
//dis_data14=k%10;
dis_data13=dd/100;
dis_data14=((int)dd%100)/10;
dis_data15=(int)dd%10;
return (pidout);
// return (EI);
}
//********************************
//fun:定时器0 1 ms 定时 初始化子程序
//********************************
void time0_init()
{
TMOD=0x11;
TH0 =(65536-1000)>>8;
TL0 =(65536-1000)&0xff;
EA=1;
ET0=1;
TR0=1;
}
//********************************
//fun:定时器1 50 ms 定时 初始化子程序
//********************************
void time1_init()
{
TH1 =(65536-50000)>>8;
TL1 =(65536-50000)&0xff;
ET1=1;
TR1=1;
}
//********************************
//fun:定时器2 设置单片机的频率
//********************************
void time2()
{
T2CON=0x14;
RCAP2H=0xff;
RCAP2L=0xb4;
SCON=0x7a;
// ET2=1;
// ES=1;
EA=1;
TI=1;
printf("%.2f ",lnwd);
printf("%.2f ",cywd);
// printf("%.2f ",min);
// printf("%.2f ",yxsj);
printf("%.2f\n",czhi);
// printf("%d\n",yxsj);
TI=0;
// ET2=0;
}
//********************************
//fun: 定时器0服务子程序
//********************************
void time0_sever() interrupt 1 using 1
{
//EA=0;
TH0 =(65536-10000)>>8;
TL0 =(65536-10000)&0xff;
SCANKEY_FLAG=1; //10ms 扫描按键1次
sk_flag=1;
disp_cx--;
if(disp_cx==0)
{
disp_cx=100;
DISP_FLAG=1; //1秒显示标志树起
COV_FLAG=1; //1秒转换标志树起
}
EA=1;
}
//********************************
//fun: 定时器1服务子程序
//********************************
void time1_sever() interrupt 3
{
//EA=0;
TH1 =(65536-49900)>>8;
TL1 =(65536-49900)&0xff;
//--------------------------------
min_cx+=1;
cjsj+=1;
if(min_cx==120) //要改成1200(1 min);
{
min_cx=0; //1分钟到计数清零
min+=1; //分钟计数
yxsj=min;
{
if(sect==1) //sec 在按键设置的时候设为1 为0则不进行PID运算
{}
else if(sect==2) //
{min1=min2;hour1=hour2;} // 计算理论温度时,计算理论温度的斜率要分段
else if(sect==3) //
{min1=min3;hour1=hour3;} //
else if(sect==4) //
{min1=min4;hour1=hour4;} //
else if(sect==5) //
{min1=min5;hour1=hour5;} //
else
{
sect=0; // sect=0;表示不进行PID计算
dis_data4=10; //
dis_data5=10; //
dis_data6=10; //
dis_data7=10; //
dis_data8=10; //
dis_data9=10; //
dis_data10=10; //
out=1;
}
}
}
if(sect)
{
theory_count();
if(min==min1*10+hour1*600) //时间到进行第二段计算
{
sect++;
if(sect==6) sect=0;
min=0; //时间清0
}
if(min%10==0) //十分钟写保护
{
write_eeprom(SECT_ADDR,sect);
write_eeprom(MIN_ADDR,min);
}
}
//--------------------------------
if(sect) //sect!=0 则有进行PWM输出
{ //中断输出
if(pmw_cx<pmw_out) //加热时间到
{ //输出加热
out=0;
}
else
{
if(pmw_cx<=200) //不加热时间到
{ //停止加热
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -