?? 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 + -