/////////////////////////////////////////////////////////////////
pid.h
/////////////////////////////////////////////////////////////////
#ifndef __PID_H
#define __PID_H
#include "sys.h"
struct PID
{
float Kp; // 比例常數 Proportional Const
float Ki; // 積分常數 Integral Const
float Kd; // 微分常數 Derivative Const
float Keep; // 設定保持溫度 基本PWM 輸出量
float TargetTemp; //輸入設定溫度
float NowTemp; //現在量測到溫度 Temperature
float NowTemp1; //上次1量測到溫度 Temperature
float NowTemp2; //上次2量測到溫度 Temperature
float NowTemp3; //上次3量測到溫度 Temperature
float NowTemp4; //上次4量測到溫度 Temperature
float NowTemp5; //上次5量測到溫度 Temperature
u8 Flag; //升溫或降溫旗標 升溫=1; 降溫=0
u8 TempCount; //溫度取樣計數器
float TargetValue; //PID 控制 設定溫度
float NowValue; ///PID 控制 目前溫度
float Pre1Value; ///PID 控制 上次溫度記錄,
float Pre2Value; ///PID 控制 上上次溫度記錄,
float Error0; //本次誤差值
float Error1; //上次誤差值
float Error2; //上上次誤差值
float SumError; //累積誤差總合值
float vError0; //目前有變化 誤差溫度值
float vError1; //上1次有變化 誤差溫度值
float vError2; //上2次有變化 誤差溫度值
float vError3; //上3次有變化 誤差溫度值
float vError4; //上4次有變化 誤差溫度值
float vError5; //上5次有變化 誤差溫度值
float KpValue; //運算比例量暫存值
float KiValue; //運算積分量暫存值
float KdValue; //運算微分量暫存值
float ResultValue; //PID Kp+Ki+Kd 運算結果 暫存值
float OutputValue; //PID 運算後 輸出值 暫存值
float PWMResult; //PWM 輸出量 暫存值
float PWMOut; // PWM 輸出量 實際輸出值
};
extern struct PID PID1,PID2,PID3,PID4;
void PID1_Init( void); //PID1初始化程式
void PID1_Control(void); //PID1 控制程式
void PID1_Calculate(void); //PID1 運算程式 (位置計算式)
void PID2_Init( void); //PID2初始化程式
void PID2_Control(void); //PID2 控制程式
void PID2_Calculate(void); //PID2 運算程式 (位置計算式)
void PID3_Init( void); //PID3初始化程式
void PID3_Control(void); //PID3 控制程式
void PID3_Calculate(void); //PID3 運算程式 (位置計算式)
void PID4_Init( void); //PID4初始化程式
void PID4_Control(void); //PID4 控制程式
void PID4_Calculate(void); //PID4 運算程式 (位置計算式)
#endif
////////////////////////////////
pid.c
//////////////////////////////
#include "pid.h"
#include "stdio.h"
#include "lcd.h"
#include "s11059.h"
#include "max31855.h"
#include "myhmi.h"
/*
变量名
Pp(K) ;比例输出
Pi(K) ;积分输出
Pd(K) ;微分输出
Kp ;比例系数
Ki ;积分系数
Kd ;微分系数
E(K) ;本次误差值
R(K) ;本次设定值
M(K) ;本次测量值
E(K-1);上次误差值
E(K-2);上上次误差值
Pi(K-1);上次积分输出
;位置型PID算法:
E(K)=R(K)-M(K) ;本次误差=本次设定值-本次测量值
Pp(K)=Kp*E(K) ;本次比例输出=比例系数×本次误差值
Pi(K)=Ki*E(K)+Pi(K-1) ;本次积分输出=积分系数×本次误差值+上次积分输出值
Pd(K)=Kd[E(K)-E(K-1)] ;本次微分输出=微分系数×(本次误差值-上次误差值)
P(K)=Pp(K)+Pi(K)+Pd(K) ;输出值=本次比例输出+本次积分输出+本次微分输出
位置型PID计算公式
;增量型PID算法:
E(K)=R(K)-M(K) ;本次误差=本次设定值-本次测量值
Pp(K)=Kp[E(K)-E(K-1)] ;本次比例输出=比例系数×(本次误差值-上次误差值)
Pi(K)=Ki*E(K) ;本次积分输出=积分系数×本次误差
Pd(K)=Kd[E(K)-2E(K-1)+E(K-2) ;本次微分输出=微分系数×(本次误差值-2×上次误差值+上上次误差值)
P(K)=Pp(K)+Pi(K)+Pd(K) ;输出值=本次比例输出+本次积分输出+本次微分输出
//增量法计算公式:
//Pdt=Kp*[E(t)-E(t-1)]+Ki*E(t)+Kd*[E(t)-2*E(t-1)+E(t-2)]
增量式PID算法的输出量为
ΔUn = Kp[(en-en-1)+(T/Ti)en+(Td/T)(en-2*en-1+en-2)]
*/
/************************************************************************
**位置PID的 KP,KI,KD参数;
**在调试过程中,只对KP,KI,进行了调节,对KP,KI有了一点认识,但对KD仍然没有什么认识
**在本组参数中,只设置了KP。
**同时现在给定的理想值是实际的电机转动过程中输出的脉冲数。
*************************************************************************/
struct PID PID1,PID2,PID3,PID4;
//////////////////////////////////////////////////////////////////////////////////////
/*====================================================================================================/
 

ID1 PWM1 TIM4 CH1 PB6 Temp.13~17 Heater
=====================================================================================================*/
void PID1_Init(void)
{ //PID=100000 PWM=1000 =1/100
PID1.TargetTemp =9700; //設定目標溫度值
PID1.Keep=1000; //設定保持最低輸出值 //[100/1000 (0.1)]
PID1.Kp=100; // 比例常数Proportional Const //[100x100=10000 /100=100 (0.15)]
PID1.Ki=3; // 积分常数Integral Const //[2000*5=10000/100=100 (0.1)] (0.5 20=10s )
PID1.Kd=50; // 微分常数Derivative Const //[25*200=5000 /100=50 (+_0.05)] Max=0.1
PID1.Error0=0.0; //目前誤差值
PID1.Error1=0.0; // Error[-1] 上次误差
PID1.Error2=0.0; // Error[-2] 上上次误差
PID1.SumError =0.0; //累積誤差總合值
PID1.OutputValue=0.0 ; //实际输出量
PID1.TargetValue =PID1.TargetTemp ; // 设定目标值Desired value Target
}
void PID1_Control(void) //Temp.13~17 Heater
{
//PID1.NowValue=PID1.NowTemp; //控制現在溫度值
PID1.TargetValue=PID1.TargetTemp; //控制目標溫度值
PID1_Calculate(); // float PID_calculate( struct PID *pid_1,float NowValue ); //位置PID计算
if (PID1.NowTemp<

ID1.TargetTemp-1000) PID1.PWMResult=10000; //(0~1000) 溫度過低 PID運算範圍外 , PWM 輸出量 暫存值
else if (PID1.NowTemp<

ID1.TargetTemp-500) PID1.PWMResult=7000;
//溫度過低 PID運算範圍外 , PWM 輸出量 暫存值
else if (PID1.NowTemp<

ID1.TargetTemp -200) PID1.PWMResult=5000;
//溫度過低 PID運算範圍外 , PWM 輸出量 暫存值
else if (PID1.NowTemp>

ID1.TargetTemp +100) PID1.PWMResult=0;
//溫度過高 PID運算範圍外 , PWM 輸出量 暫存值
else
 

ID1.PWMResult=(PID1.OutputValue/10)+PID1.Keep;
//溫度上升中; PID 運算 (0~100000/0~1000)=100 //PID 運算範圍內 輸出值 // PID運算範圍內
PID1.PWMOut=PID1.PWMResult; // PWM 輸出量 實際輸出值
}
/*====================================================================================================/
 

ID1计算部分
=====================================================================================================*/
/*
位置型PID算法:
E(K)=R(K)-M(K) ;本次误差=本次设定值-本次测量值
Pp(K)=Kp*E(K) ;本次比例输出=比例系数×本次误差值
Pi(K)=Ki*E(K)+Pi(K-1) ;本次积分输出=积分系数×本次误差值+上次积分输出值
Pd(K)=Kd[E(K)-E(K-1)] ;本次微分输出=微分系数×(本次误差值-上次误差值)
P(K)=Pp(K)+Pi(K)+Pd(K) ;输出值=本次比例输出+本次积分输出+本次微分输出
*/
void PID1_Calculate(void) //位置PID计算
{
PID1.Error0 = PID1.TargetValue-PID1.NowValue ; //目前誤差值 本次误差=本次设定值-本次测量值
/*===PID1比例項 計算式===*/
//PID1.KpValue = PID1.Kp*PID1.Error0 ; //比例項 本次比例输出=比例系数×本次误差值 pError=Error-pp->LastError;
PID1.KpValue = PID1.Kp*(PID1.Error0+50) ; //比例項 本次比例输出=比例系数×本次误差值 pError=Error-pp->LastError;
/*===PID1 積分項 計算式===*/
PID1.SumError += PID1.Error0; //累積誤差總合值 本次积分输出=积分系数×本次误差值+上次积分输出值
if(PID1.SumError>2000) PID1.SumError=2000; //累積誤差總合最大值
if(PID1.SumError<-200) PID1.SumError=-200; //累積誤差總合最小值
if((PID1.NowTemp>

ID1.TargetTemp+25)&&(PID1.SumError>1000)) PID1.SumError=0;
//升溫超過正誤差設定值 累積誤差歸零
if((PID1.NowTemp<

ID1.TargetTemp)&&(PID1.SumError<-25)) PID1.SumError=0;
//降溫超過負誤差設定值 累積誤差歸零
PID1.KiValue = PID1.Ki*PID1.SumError; //積分項 本次积分输出=积分系数×本次误差值+上次积分输出值 E(t) //pp->SumError += Error
/*===PID1 微分項 計算式===*/
if(PID1.NowValue!=PID1.Pre1Value) //檢查溫度有無變化
{
if(PID1.NowValue<

ID1.Pre1Value) PID1.Flag=0;
//降溫=目前溫度 <上次溫度記錄,
if(PID1.NowValue>PID1.Pre1Value) PID1.Flag=1; //升溫=目前溫度 >上次溫度記錄,
PID1.vError5=PID1.vError4; //上5次有變化 誤差溫度值
PID1.vError4=PID1.vError3; //上4次有變化 誤差溫度值
PID1.vError3=PID1.vError2; //上3次有變化 誤差溫度值
PID1.vError2=PID1.vError1; //上2次有變化 誤差溫度值
PID1.vError1=PID1.vError0; //上1次有變化 誤差溫度值
PID1.vError0=PID1.Error0; //目前有變化 誤差溫度值
PID1.Pre2Value=PID1.Pre1Value;
PID1.Pre1Value=PID1.NowValue; //目前溫度記錄=上次溫度
}
//PID1.KdValue = PID1.Kd*(PID1.Error0 - PID1.Error1 ); //微分项 本次微分输出=微分系数×(本次误差值-上次误差值)dError = pp->LastError - pp->PrevError
PID1.KdValue = PID1.Kd*(3*((PID1.vError0-PID1.vError1))+(2*(PID1.vError1-PID1.vError2))+(PID1.vError2-PID1.vError3)+(PID1.vError3-PID1.vError4)+(PID1.vError4-PID1.vError5)); //微分項 本次微分输出=微分系数×(本次误差值-上次误差值)dError = pp->LastError - pp->PrevError
/*===PID1 誤差值儲存===*/
PID1.Error2 = PID1.Error1;//保存上2次誤差
PID1.Error1 = PID1.Error0;//保存上1次誤差
/*===PID1 輸出值 ===*/
PID1.ResultValue = PID1.KpValue + PID1.KiValue + PID1.KdValue; //Kp+Ki+Kd 運算結果暫存值
PID1.OutputValue=PID1.ResultValue; //PID 運算後 輸出值
if( PID1.OutputValue>100000) PID1.OutputValue=100000; //PWM 實際輸出最大值限幅
if (PID1.OutputValue<0) PID1.OutputValue=0; //PWM 實際輸出最最小值限幅
}
/*====================================================================================================/
PID2 PWM2 TIM3 CH1 PC6 Temp. 1~6 Fan1,2
=====================================================================================================*///////////////////////////////////////////////////////////////////////////////
void PID2_Init(void)
{
PID2.TargetTemp =6100; //設定目標溫度值
PID2.Keep=100; //設定保持最低輸出值
PID2.Kp=100; // 比例常数Proportional Const
PID2.Ki=1; // 积分常数Integral Const
PID2.Kd=1; // 微分常数Derivative Const
PID2.Error0=0.0; //目前誤差值
PID2.Error1=0.0; // Error[-1] 上次误差
PID2.Error2=0.0; // Error[-2] 上上次误差
PID2.SumError =0.0; //累積誤差總合值
PID2.OutputValue=0.0 ; //实际输出量
PID2.TargetValue =PID2.TargetTemp ; // 设定目标值Desired value Target
}
void PID2_Control(void) //Temp. 1~6 Fan1,2
{
PID2.NowValue=PID2.NowTemp; //控制現在溫度值
PID2.TargetValue=PID2.TargetTemp; //控制目標溫度值
PID2_Calculate(); // float PID_calculate( struct PID *pid_1,float NowValue ); //位置PID计算
if(PID2.NowTemp>PID2.TargetTemp+500) PID2.PWMResult=1000; //PWMResult
else if(PID2.NowTemp<PID2.TargetTemp-500) PID2.PWMResult=0;
else PID2.PWMResult=PID2.OutputValue/100; //0~100000
PID2.PWMOut=PID2.PWMResult+PID2.Keep;
TIM_SetCompare1(TIM3,PID2.PWMOut); // TIM3_CH1 PB6 PWM2 PWM2.OutValue Rate = 0~1000
}
/*====================================================================================================/
PID2计算部分
=====================================================================================================*/
void PID2_Calculate(void)//位置PID计算
{
PID2.Error0 =PID2.NowValue-PID2.TargetValue; //目前誤差值
PID2.KpValue = PID2.Kp*PID2.Error0 ; //比例项 本次比例输出=比例系数×本次误差值 pError=Error-pp->LastError;
PID2.SumError += PID2.Error0; //累積誤差總合值
if(PID2.SumError>2000) PID2.SumError=2000;
if(PID2.SumError<-2000) PID2.SumError=-2000;
PID2.KiValue = PID2.Ki*PID2.SumError; //积分项 本次积分输出=积分系数×本次误差值+上次积分输出值 E(t) //pp->SumError += Error
PID2.KdValue = PID2.Kd*(PID2.Error0 - PID2.Error1); //微分项 本次微分输出=微分系数×(本次误差值-上次误差值)dError = pp->LastError - pp->PrevError
PID2.Error2 = PID2.Error1;//保存二次谐波
PID2.Error1 = PID2.Error0;//保存一次谐波
PID2.ResultValue = PID2.KpValue + PID2.KiValue + PID2.KdValue;//输出值计算,注意加减
PID2.OutputValue=PID2.ResultValue;
if( PID2.OutputValue>100000) PID2.OutputValue=100000; //限幅
if (PID2.OutputValue<0) PID2.OutputValue=0;
}
//////////////////////////////////////////////////////////////////////////////////////
/*====================================================================================================/
PID3 PWM3 TIM4 CH1 PB8 Temp. 13~17
=====================================================================================================*/
void PID3_Init(void)
{
PID3.TargetTemp =6100; //設定目標溫度值
PID3.Keep=100; //設定保持最低輸出值
PID3.Kp=100; // 比例常数Proportional Const
PID3.Ki=1; // 积分常数Integral Const
PID3.Kd=1; // 微分常数Derivative Const
PID3.Error0=0.0; //目前誤差值
PID3.Error1=0.0; // Error[-1] 上次误差
PID3.Error2=0.0; // Error[-2] 上上次误差
PID3.SumError =0.0; //累積誤差總合值
PID3.OutputValue=0.0 ; //实际输出量
PID3.TargetValue =PID3.TargetTemp ; // 设定目标值Desired value Target
}
void PID3_Control(void)
{
PID3.NowValue=PID3.NowTemp; //控制現在溫度值
PID3.TargetValue=PID3.TargetTemp; //控制目標溫度值
PID3_Calculate(); // float PID_calculate( struct PID *pid_1,float NowValue ); //位置PID计算
if (PID3.NowTemp>PID3.TargetTemp +500) PID3.PWMResult=1000; //PWMResult
else if (PID3.NowTemp<PID3.TargetTemp -500) PID3.PWMResult=0;
else PID3.PWMResult=PID3.OutputValue/100;
PID3.PWMOut=PID3.PWMResult+PID3.Keep;
TIM_SetCompare2(TIM3,PID3.PWMOut); // TIM3_CH2 PC7 PWM3 PWM3.OutValue Rate = 0~1000
}
/*====================================================================================================/
PID3计算部分
=====================================================================================================*/
void PID3_Calculate(void)//位置PID计算
{
PID3.Error0 = PID3.NowValue-PID3.TargetValue ; //目前誤差值
PID3.KpValue = PID3.Kp*PID3.Error0 ; //比例项 本次比例输出=比例系数×本次误差值 pError=Error-pp->LastError;
PID3.SumError += PID3.Error0;
if(PID3.SumError>2000) PID3.SumError=2000;
if(PID3.SumError<-2000) PID3.SumError=-2000;
PID3.KiValue = PID3.Ki*PID3.SumError; //积分项 本次积分输出=积分系数×本次误差值+上次积分输出值 E(t) //pp->SumError += Error
PID3.KdValue = PID3.Kd*(PID3.Error0 - PID3.Error1); //微分项 本次微分输出=微分系数×(本次误差值-上次误差值)dError = pp->LastError - pp->PrevError
PID3.Error2 = PID3.Error1;//保存二次谐波
PID3.Error1 = PID3.Error0;//保存一次谐波
PID3.ResultValue = PID3.KpValue + PID3.KiValue + PID3.KdValue;//输出值计算,注意加减
PID3.OutputValue=PID3.ResultValue;
if( PID3.OutputValue>100000) PID3.OutputValue=100000; //限幅
if (PID3.OutputValue<0) PID3.OutputValue=0;
}
//////////////////////////////////////////////////////////////////////////////////////
void PID4_Init(void)
{
PID4.TargetTemp =4000; //設定目標溫度值
PID4.Keep=300; //設定保持最低輸出值
PID4.Kp=10; // 比例常数Proportional Const
PID4.Ki=0; // 积分常数Integral Const
PID4.Kd=0; // 微分常数Derivative Const
PID4.Error0=0.0; //目前誤差值
PID4.Error1=0.0; // Error[-1] 上次误差
PID4.Error2=0.0; // Error[-2] 上上次误差
PID4.SumError =0.0; //累積誤差總合值
PID4.OutputValue=0.0 ; //实际输出量
PID4.TargetValue =PID4.TargetTemp ; // 设定目标值Desired value Target
}
void PID4_Control(void)
{
PID4.NowValue=PID4.NowTemp; //控制現在溫度值
PID4.TargetValue=PID4.TargetTemp; //控制目標溫度值
PID4_Calculate(); // float PID_calculate( struct PID *pid_4,float NowValue ); //位置PID计算
if (PID4.NowTemp>PID4.TargetTemp +500) PID4.PWMResult=1000; //PWMResult
else if (PID4.NowTemp<PID4.TargetTemp-500) PID4.PWMResult=0;
else PID4.PWMResult=PID4.OutputValue/100;
PID4.PWMOut=PID4.PWMResult+PID4.Keep;
TIM_SetCompare3(TIM3,PID4.PWMOut); // TIM3_CH3 PC8 PWM4.OutValue Rate = 0~1000
}
/*====================================================================================================/
PID4计算部分
=====================================================================================================*/
void PID4_Calculate(void)//位置PID计算
{
PID4.Error0 = PID4.NowValue-PID4.TargetValue ; //目前誤差值
PID4.KpValue = PID4.Kp*PID4.Error0 ; //比例项 本次比例输出=比例系数×本次误差值 pError=Error-pp->LastError;
PID4.SumError += PID4.Error0; //累積誤差總合值
if(PID4.SumError>2000) PID4.SumError=2000;
if(PID4.SumError<-2000) PID4.SumError=-2000;
PID4.KiValue = PID4.Ki*PID4.SumError; //积分项 本次积分输出=积分系数×本次误差值+上次积分输出值 E(t) //pp->SumError += Error
PID4.KdValue = PID4.Kd*(PID4.Error0 - PID4.Error1); //微分项 本次微分输出=微分系数×(本次误差值-上次误差值)dError = pp->LastError - pp->PrevError
PID4.Error2 = PID4.Error1;//保存二次谐波
PID4.Error1 = PID4.Error0;//保存一次谐波
PID4.ResultValue = PID4.KpValue + PID4.KiValue + PID4.KdValue;//输出值计算,注意加减
PID4.OutputValue=PID4.ResultValue;
if( PID4.OutputValue>100000) PID4.OutputValue=100000; //限幅
if (PID4.OutputValue<0) PID4.OutputValue=0;
}
pid.c