PID kontrol veri tipi:
typedef struct
{
unsigned int pv; // olculen deger (feedback)
signed int ev; // hata
signed int ev_pre; // bir onceki hata
signed int ev_sum; // hata integrali
signed long int P; // hesaplanan PID komponentleri
signed long int I;
signed long int D;
signed long int out; // hesaplanan cikis
unsigned int controlcounter;
unsigned overloaded: 1; // loadlevel belirlenen esigi asti ise bu bayrak 1 olur.
unsigned restart : 1; // pid ara degerleri baslatilir, akümülatörler sifirlanir
unsigned nocontrol: 1; // MDC = speedref, no pid control.. kullanici sifirlamali
unsigned controlphase: 2; // siradaki speedcontrol cevriminde ne is yapilacak?
} PIDParType;
pv: Process Value
motor encoder’ından örneklenen dönüş hızı değerinin PID çıkış veri tipine göre ölçeklenmiş halidir.
ev: Error Value
Referans değeri ile geçerli değerin farkı. pv çıkış gücü değeri cinsinden ölçekli olduğu için sadece çıkarma işlemi yeterlidir: ev = speedref – pv.
ev_pre:
Previous Error Value, Bir önceki hesaplama çevriminde saklanan hata değeri (türev hesabında kullanılır).
ev_sum:
Sum of Error Values, Hata değerlerinin toplamı (integral hesabında kullanılır)
P,I,D:
Hesaplanan P,I,D bileşenleri
out:
Hesaplanan çıkış. Basitçe, P,I ve D bileşenlerinin toplamından oluşur ancak bu değer fiziksel çıkışın ötesinde olabilir.
controlcounter:
Her SpeedControl( ) çevriminde +1 ilerleyen serbest sayaç. Motor kontrol zamanlamaları sırasında kullanılabilir, PID çevrimiyle eşzamanlı zamanlama sağlar.
overloaded:
Aşırı yüklenme bayrağı. Sürücü thread’i içinde motor akımı izleme ile ya da PID çıkışı üzerinden tetikleniyor olabilir. Kontrol onu sadece set eder. Haricen sıfırlanmalıdır.
restart:
Kontrol biti: Bu bit 1 yapıldığında tüm PID ara değerleri sıfırlanır. İşlem yapılınca bit sıfırlanır.
nocontrol:
Kontrol biti: Bu bit 1 yapıldığında PID kontrol devre dışı olur. speedref = MDC
controlphase
PID scheduling control flag. SpeedControl( ) fonksiyonunun her çağrılmasında hangi PID işlem parçalarının yapılacağını belirler.
Kontrol Çevrimi

// motor hiz kontrolü yapmak için 10ms'de bir çagrilmali:
void SpeedControl(void)
{
LongData w;
PID.controlcounter++;
if (PID.nocontrol)
{
MDC = speedref;
position.i[0] = POS1CNTL; // position update
position.i[1] = POS1HLD;
return;
}
// controlphase scheduling'e gore pv guncellemeleri:
////////////////////////////////////////////////////////////////////////////////////
switch (PID.controlphase)
{
case 0:
position.i[0] = POS1CNTL; // position update
position.i[1] = POS1HLD;
// hiz bilgisini guncelle (40ms'de bir)
rpm = VEL1CNT;
w.ul = abs(rpm);
w.ul *= 5000;
w.ul /= pm;
PID.pv = w.ul;
PID.ev = speedref - PID.pv;
PID.controlphase = 1;
break;
case 1:
// integral icin, errorvalue_sum'i güncelle:
PID.ev_sum += PID.ev;
// ev_sum limitleme (anti windup)
if (PID.ev_sum > 3000) PID.ev_sum = 3000;
else if (PID.ev_sum < -4000) PID.ev_sum = -4000;
// I komponentini hesapla:
PID.I = (signed long*)(KiN * PID.ev_sum);
PID.controlphase = 2;
break;
case 2:
// hiz bilgisini guncelle (40ms'de bir)
rpm = VEL1CNT;
w.ul = abs(rpm);
w.ul *= 5000;
w.ul /= pm;
PID.pv = w.ul;
// hata degerini guncelle:
PID.ev_pre = PID.ev; // simdiki deger onceki deger olarak kaydedilir
PID.ev = speedref - PID.pv;
PID.controlphase = 3;
break;
case 3:
// D komponentini hesapla:
w.i[0] = PID.ev - PID.ev_pre;
if (w.i[0] > 2000) w.i[0] = 2000;
else if (w.i[0] < -2000) w.i[0] = -2000;
PID.D = (signed long*)(KdN * w.i[0]);
PID.controlphase = 0;
break;
}
//////////////////////////////////////////////////////////////////////////////////////////
if (PID.restart)
{
PID.ev = speedref;
PID.ev_pre = 0;
PID.ev_sum = 0;
PID.I = speedref / 3;
PID.D = speedref / 3;
PID.controlphase = 0;
PID.restart = 0;
}
//// P bileseninin hesabi: P = Kp * ev
///////////////////////////////////////////////////////////////////////////////
PID.P = (signed long*) (KpN * PID.ev);
///////////////////////////////////////////////////////////////////////////////
//// cikisin birlestirilmesi:
//////////////////////////////////////////////////////////////////////////////
PID.out = (signed long*)(PID.P + PID.I + PID.D);
PID.out = PID.out / 10;
//////////////////////////////////////////////////////////////////////////////
//// output update: (with limiting)
//////////////////////////////////////////////////////////////////////////////
if (PID.out < -1000)
{
MDC = 2000;
MOTOR_BRK_L;
return;
}
if (PID.out < 0)
{
MDC = 500;
MOTOR_BRK_L;
return;
}
if (PID.out > 5000)
{
MDC = 4900;
SetDir();
return;
}
MDC = PID.out;
SetDir();
/////////////////////////////////////////////////////////////////////////////////
}