#include <intrins.h>
#include"pid.h"
typedef unsigned char uint8;
typedef unsigned int uint16;
typedef unsigned long int uint32;
/*********************************函數聲明******************
結構體設定
***********************************************************/
typedef struct PIDValue
{
uint32 Ek_Uint32[3]; //差值保存,給定和反饋的差值
uint8 EkFlag_Uint8[3]; //差值標誌位符號,1則對應的為負數,0為對應的為正數
uint8 KP_Uint8; //比例系數
uint8 KI_Uint8; //積分系數
uint8 KD_Uint8; //微分顯示
uint16 Uk_Uint16; //上壹時刻的控制電壓
uint16 RK_Uint16; //設定值
uint16 CK_Uint16; //實際值
uint8 Vaule_Flag; //輸出的值正負標誌位,0為正,1為負
}PIDValueStr;
PIDValueStr PID; //定義壹個結P構體
uint16 out ; // 加熱輸出(PID運算後的輸出值)
/***********************************************************************************
增量型PID算式:PID :Uk=KP*[E(k)-E(k-1)]+KI*E(k)+KD*[E(k)-2E(k-1)+E(k-2)]
函數入口: RK(設定值),CK(實際值),KP,KI,KD PID比例參數
函數出口: U(K)
PID運算函數
**************************************************************************************/
uint16 PID_Calc(uint16 PIDinput)
{
uint32 Temp[3]; //中間臨時變量
uint32 PostSum; //正數和
uint32 NegSum; //負數和
Temp[0] = 0; //給儲存中間臨時變量賦初值
Temp[1] = 0;
Temp[2] = 0;
PostSum = 0; //給存儲所有的正數變量賦初值
NegSum = 0; //給存儲所有的負值變量賦初值
PID.RK_Uint16=180; //設定值為180
PID.CK_Uint16=PIDinput; //輸入值
if( PID.RK_Uint16 > PID.CK_Uint16 ) //如果設定值大於實際值,就是當前的值比設定值小
{
if( PID.RK_Uint16 - PID.CK_Uint16 >10 ) //計算偏差是否大於 piancha=10 ( 這裏的10由 piancha 來設定大小,根據實際情況設定)
//if( PID.RK_Uint16 - PID.CK_Uint16 >piancha )
{ //如果偏差大於 piancha=10 不在設定的PID調控範圍之內就全速加熱
out = 100; //偏差大於piancha=10為上限幅值輸出(全速加熱)
// PID.Uk_Uint16 = full_speed; //全速時的加熱值,更具實際情況可自由設定 這裏full_speed=100;
}
else //如果偏差小於 piancha=10 再調節的範圍內就計算儲存起來
{ //下面就是PID算法
Temp[0] = PID.RK_Uint16 - PID.CK_Uint16; // 計算出當前偏差值E(k)
PID.EkFlag_Uint8[1]=0; //E(k)為正數 的標誌位 0為正,1為負
//數值移位
PID.Ek_Uint32[2] = PID.Ek_Uint32[1]; //存儲E(k-2)
PID.Ek_Uint32[1] = PID.Ek_Uint32[0]; //儲存E(k-1)
PID.Ek_Uint32[0] = Temp[0]; //存儲E(k)
/****************************************************************************************/
if( PID.Ek_Uint32[0] >PID.Ek_Uint32[1] ) //E(k)>E(k-1) 為正數
{
Temp[0]=PID.Ek_Uint32[0] - PID.Ek_Uint32[1]; //E(k)-E(k-1) 保存
PID.EkFlag_Uint8[0]=0; // 設定標誌位 0為正,1為負
}
else //E(k)<E(k-1)
{
Temp[0]=PID.Ek_Uint32[1] - PID.Ek_Uint32[0]; //E(k)-E(k-1)為負數
PID.EkFlag_Uint8[0]=1;
}
/*****************************************************************************************/
Temp[2]=PID.Ek_Uint32[1]*2 ; // 2E(k-1)
if( (PID.Ek_Uint32[0]+ PID.Ek_Uint32[2])>Temp[2] ) //E(k-2)+E(k)>2E(k-1)
{
Temp[2]=(PID.Ek_Uint32[0]+ PID.Ek_Uint32[2])-Temp[2]; //E(k-2)+E(k)-2E(k-1)為正數
PID.EkFlag_Uint8[2]=0;
}
else //E(k-2)+E(k)-2E(k-1)為負數
{
Temp[2]=Temp[2]-(PID.Ek_Uint32[0]+ PID.Ek_Uint32[2]); //2E(k-1)-(E(k-2)+E(k))
PID.EkFlag_Uint8[2]=1;
}
/**********************************************************************************************/
Temp[0] = (uint32)PID.KP_Uint8 * Temp[0]; // KP*[E(k)-E(k-1)]
Temp[1] = (uint32)PID.KI_Uint8 * PID.Ek_Uint32[0]; // KI*E(k)
Temp[2] = (uint32)PID.KD_Uint8 * Temp[2]; // KD*[E(k-2)+E(k)-2E(k-1)]
/************************以下部分代碼是講所有的正數項疊加,負數項疊加**************************/
/**************************************KP*[E(k)-E(k-1)]********************************************/
if(PID.EkFlag_Uint8[0]==0)
PostSum += Temp[0]; //正數和
else
NegSum += Temp[0]; //負數和
/*************************************** KI*E(k)*************************************************/
if(PID.EkFlag_Uint8[1]==0)
PostSum += Temp[1]; //正數和
else
; //空操作,E(K)>0
/************************************KD*[E(k-2)+E(k)-2E(k-1)]*************************************/
if(PID.EkFlag_Uint8[2]==0)
PostSum += Temp[2]; //正數和
else
NegSum += Temp[2]; //負數和
/**********************************************U(K)*************************************************/
//PostSum += (uint32)PID.Uk_Uint16;
if(PostSum > NegSum ) // 是否控制量為正數
{
out= PostSum - NegSum;
PID.Vaule_Flag=0; //PID調節值是正值
}
else //控制量輸出為負數
{
out=NegSum-PostSum;
PID.Vaule_Flag=1; //PID調節值是負值
}
}
//return out;
}
else //如果設定值小於實際值,就是當前的值大於設定值,就不進行PID計算直接輸出 0
{
out = 0;
}
return out;
}