Hilfe2010
26.01.2010, 19:37
Hallo zusammen ich habe einen PID Regler mit einem Atmega128 realisiert.
Damit regel ich die Drehzahl eines Lüfter.
Für die Parameter des Reglers habe ich Kp=4.8 Tn=2 und Tv=0.13 gewählt.
Mein Problem ist jetzt. Die Sprungantwort des Regelkreises sieht immer
gleich aus egal ob Tv=0 oder Tv=0.13.
Der D-Anteil ist immer Null. Wenn ich das mit dem AVR Studio simuliere, kommt für D=Kd/Ta=624, das Problem liegt halt daran , dass e-ealt=0 bei mir ist. Hat jemand einen Vorschlag oder Idee warum das so ist.
Im Anhang mein Code.
Danke für eure Unterstützung
Das ist die main:
#include <avr/io.h>
#include "ADC.h"
#include "timer.h"
#include "adc.h"
volatile float temp1;
volatile float temp2;
volatile float x;
volatile float w;
volatile float y;
volatile float z;
volatile float i;
volatile float e;
volatile float ealt;
volatile float esum;
volatile float Kd;
volatile float Ki;
volatile float Kp=4.8;
volatile float Tn=2;
volatile float Tv=0;
volatile float Ta=0.001;
int main (void)
{
if (Tn == 0)
{
Ki=0;
}
else
{
Ki=Kp/Tn;
}
if (Tv == 0)
{
Kd=0;
}
else
{
Kd=Tv*Kp;
}
timer1_init();
sei();
DigitalAnalogWandlerInit();
while (1)
{
temp1 = ReadAdcChannel(1)-512; // Sollwert einlesen
temp2 = ReadAdcChannel(0)-512; // Istwert einlesen
cli();
w=temp1;
x=temp2;
sei();
SetDigitalAnalogWandler(DACA, y+512);
}
return 0;
}
#include <avr/interrupt.h>
#include "timer.h"
Das ist Timer.c
#define Anzahl 16;
/*
jede 1 ms wird ein Interrupt ausgeführt, wenn CPU_F=16MHz,anzahl=16 und Vorteiler=1024
16MHz/1024=15625Hz
=> 15625Hz/Durchläufe=Timer_Fre
15625Hz/16=976Hz
=> Abtastzeit_Ta =1/Timer_Fre
Ta=1/967Hz=1ms=0,001s
jede 10 ms wird ein Interrupt ausgeführt, wenn CPU_F=16MHz,Durchläufe=156 und Vorteiler=1024
16MHz/1024=15625Hz
=> 15625Hz/Durchläufe=Timer_Fre
15625Hz/156=100Hz
=> Abtastzeit_Ta =1/Timer_Fre
Ta=1/100Hz=10ms=0,01s
jede 0,256 ms wird ein Interrupt ausgeführt, wenn CPU_F=16MHz,Durchläufe=16 und Vorteiler=256
*/
void timer1_init()
{
TCNT0 = 256-Anzahl; // TCNT0 = Register in dem man den Startwert festlegt.
TCCR0 = (1 << CS02)|(1 << CS00); // Timer Takt
// Bei CSO0=1 und CSO2=1 16MHz/1024=15625Hz
// Bei Nur CS02 vorteiler gleich 256
// Bei Nur CS01 vorteiler gleich 8, DURCHLÄUFE=8 => 4µs
/* Interrupt aktiveren, falls Overflow, z.B. , falls Timer von 0 bis 255 gezählt hat */
/* Oder hier im Bsp.von 99 bis 255 */
TIMSK = (1<< TOIE0); // Deshalb TOIE0 (Timer/Counter0 Overflow Interrupt Enable) = 1
/* Alle Interrupts erlauben mit der Funktion sei () */
sei ();
}
ISR (TIMER0_OVF_vect)
{
// Regeldifferenz bilden
e = w - x; // aktuelle Regelabweichung bestimmen
//if ((y < 511)&&(y > -512)) // bei Übersteuertem stellglied Integration einfrieren
//{ // (Anti-Windup)
esum = esum + e; // Summe der Regelabweichung aktualisieren
//}
y = (Kp*e)+(Ki*Ta*esum)+(Ka/Ta*(e-ealt)); //Reglergleichung
ealt = e;
//Regelabweichung für nächste Abtastung merken
if (y > 511) // Stellgröße auf -511...+512 begrenzen (10 bit DAC)
{
y = 511;
}
if (y < -511)
{
y = -512;
}
// Neu laden, damit Timer nicht bei 0 beginnt
TCNT0 = 256-Anzahl;
}
Damit regel ich die Drehzahl eines Lüfter.
Für die Parameter des Reglers habe ich Kp=4.8 Tn=2 und Tv=0.13 gewählt.
Mein Problem ist jetzt. Die Sprungantwort des Regelkreises sieht immer
gleich aus egal ob Tv=0 oder Tv=0.13.
Der D-Anteil ist immer Null. Wenn ich das mit dem AVR Studio simuliere, kommt für D=Kd/Ta=624, das Problem liegt halt daran , dass e-ealt=0 bei mir ist. Hat jemand einen Vorschlag oder Idee warum das so ist.
Im Anhang mein Code.
Danke für eure Unterstützung
Das ist die main:
#include <avr/io.h>
#include "ADC.h"
#include "timer.h"
#include "adc.h"
volatile float temp1;
volatile float temp2;
volatile float x;
volatile float w;
volatile float y;
volatile float z;
volatile float i;
volatile float e;
volatile float ealt;
volatile float esum;
volatile float Kd;
volatile float Ki;
volatile float Kp=4.8;
volatile float Tn=2;
volatile float Tv=0;
volatile float Ta=0.001;
int main (void)
{
if (Tn == 0)
{
Ki=0;
}
else
{
Ki=Kp/Tn;
}
if (Tv == 0)
{
Kd=0;
}
else
{
Kd=Tv*Kp;
}
timer1_init();
sei();
DigitalAnalogWandlerInit();
while (1)
{
temp1 = ReadAdcChannel(1)-512; // Sollwert einlesen
temp2 = ReadAdcChannel(0)-512; // Istwert einlesen
cli();
w=temp1;
x=temp2;
sei();
SetDigitalAnalogWandler(DACA, y+512);
}
return 0;
}
#include <avr/interrupt.h>
#include "timer.h"
Das ist Timer.c
#define Anzahl 16;
/*
jede 1 ms wird ein Interrupt ausgeführt, wenn CPU_F=16MHz,anzahl=16 und Vorteiler=1024
16MHz/1024=15625Hz
=> 15625Hz/Durchläufe=Timer_Fre
15625Hz/16=976Hz
=> Abtastzeit_Ta =1/Timer_Fre
Ta=1/967Hz=1ms=0,001s
jede 10 ms wird ein Interrupt ausgeführt, wenn CPU_F=16MHz,Durchläufe=156 und Vorteiler=1024
16MHz/1024=15625Hz
=> 15625Hz/Durchläufe=Timer_Fre
15625Hz/156=100Hz
=> Abtastzeit_Ta =1/Timer_Fre
Ta=1/100Hz=10ms=0,01s
jede 0,256 ms wird ein Interrupt ausgeführt, wenn CPU_F=16MHz,Durchläufe=16 und Vorteiler=256
*/
void timer1_init()
{
TCNT0 = 256-Anzahl; // TCNT0 = Register in dem man den Startwert festlegt.
TCCR0 = (1 << CS02)|(1 << CS00); // Timer Takt
// Bei CSO0=1 und CSO2=1 16MHz/1024=15625Hz
// Bei Nur CS02 vorteiler gleich 256
// Bei Nur CS01 vorteiler gleich 8, DURCHLÄUFE=8 => 4µs
/* Interrupt aktiveren, falls Overflow, z.B. , falls Timer von 0 bis 255 gezählt hat */
/* Oder hier im Bsp.von 99 bis 255 */
TIMSK = (1<< TOIE0); // Deshalb TOIE0 (Timer/Counter0 Overflow Interrupt Enable) = 1
/* Alle Interrupts erlauben mit der Funktion sei () */
sei ();
}
ISR (TIMER0_OVF_vect)
{
// Regeldifferenz bilden
e = w - x; // aktuelle Regelabweichung bestimmen
//if ((y < 511)&&(y > -512)) // bei Übersteuertem stellglied Integration einfrieren
//{ // (Anti-Windup)
esum = esum + e; // Summe der Regelabweichung aktualisieren
//}
y = (Kp*e)+(Ki*Ta*esum)+(Ka/Ta*(e-ealt)); //Reglergleichung
ealt = e;
//Regelabweichung für nächste Abtastung merken
if (y > 511) // Stellgröße auf -511...+512 begrenzen (10 bit DAC)
{
y = 511;
}
if (y < -511)
{
y = -512;
}
// Neu laden, damit Timer nicht bei 0 beginnt
TCNT0 = 256-Anzahl;
}