Hi,
Es dreht sich um Bascom auf einem ATMega32.
Ich habe zwei PID-Regler, welche stark unterschiedliche Zeitkonstanten
haben. Regler 1 möchte ich alle 3ms ausführen und Regler 2 sekündlich.
Dazu nutze ich im 1-ms-Timerinterruot aktuell folgende Routine.
Timer_isr:
Incr counter : If counter > 1002 Then counter = 1
Temp = counter Mod 3
If Temp = 0 Then Gosub Regler1 'Ausführung alle 3 ms
If counter = 1000 Then Gosub Regler2 'Ausführung alle Sekunde
return
Mein Gedanke war, nicht beide Regler innerhalb einer ms ausführen zu
lassen, um im worst-case nicht länger zu rechnen als der Timer-Interrupt
her gibt.
Dies funktioniert, aber ich suche nach einer Alternative für die
Modulo-Operation.
Ein Vergleich auf Bit-Ebene mit 3er-Zählerschritt ist mir nicht
gelungen, und auch zwei unabhängige Zähler sind mir
durcheinandergelaufen, so dass beide im selber Timerinterrupt ausgeführt
worden wären.
Wie kann das ohne Division gelöst werden?
Danke
Englisch schrieb:> Wie kann das ohne Division gelöst werden?
Nimm einen zweiten Zähler und lass den von 0..2 laufen...
> und auch zwei unabhängige Zähler sind mir durcheinandergelaufen,> so dass beide im selber Timerinterrupt ausgeführt worden wären.
Wie meinst du das?
> Incr counter : If counter > 1002 Then counter = 1
Warum setzt du den Zähler auf 1 zurück? Üblicherweise beginnt man bei 0
zu zählen.
Englisch schrieb:> Dies funktioniert, aber ich suche nach einer Alternative für die> Modulo-Operation.
Hm, warum?
Alternativ ginge:
In der Initialisierung:
1
temp = startwert (z.B. 3)
in der ISR:
1
temp = temp - 1
2
if Temp = 0 then
3
temp = startwert
4
Gosub Regler1
5
endif
aber ob das schneller/effizienter/kürzer/besser (was ist besser?) ist,
glaube ich nicht.
Einfacher wäre es, den Timer im 3ms-Takt laufen zu lassen.
Oliver
Hi,
mir geht es darum, beide Regler nicht in der selben ms aufzurufen, aber
dennoch äquidistante Aufrufe zu ermöglichen.
Ich möchte also nicht im langsamen Regler2 überprüfen wie der Zähler von
Regler 1 steht und daraufhin das regeln auslassen oder umgekehrt.
Hier mein Versuch dies mit 2 Zählern zu realisieren - die Startwerte
absichtlich auf Primzahlen gestellt um "Kollisionen" zu vermeiden.
Leider erfolglos.
Dies ist nur ein Testbeispiel - die Timer-ISR ist hierbei die Mainloop.
Natürlich erfolglos.
Denn spätestens nach dem x-ten Durchgang, wobei x das Produkt aus den
beiden Zahlen ist, fallen die beiden Zeitpunkte zusammen.
Deine Primzahlen helfen dir da gar nichts. Egal wie du die Zeiten
wählst, es wird immer einen Zeitpunkt in der Zukunft geben, an dem beide
Ereignisse gleichzeitig auftreten. Einzige Ausnahme: die Zeitdifferenzen
sind gleich (bzw. Vielfache voneinander) und du startest schon mit einer
Phasenverschiebung.
Mach dir das mal mit kleineren Zahlen, zb 3 und 5 klar, dass dir
Primzahlen da nicht helfen. Du kannst aber zb 3 und 6 nehmen (weil 6 ein
Vielfaches von 3 ist), wenn du die mit einem Versatz von 1 starten
lässt, werden die Zeitpunkt nie aufeinander fallen.
Glaub mir jetzt aber nicht blind, sondern probiers am Papier aus (denn
ich hab mir das jetzt auch nur im Kopf zusammengereimt :-)
Hallo Karl Heinz,
genau auf diesen Haken - ddas die Vielfachen der Primzahlen ja keine
mehr sind und sich dann gemeinsame Vielfach ergeben bin ich auch
gekommen.
Daher habe ich dann diese Modulo-Lösung herangezogen.
Der Grund dafür einen Ersatz zu finden liegt auch hauptsächlich am Lesen
in diesem Forum - dass Divisionen lange brauchen.
Eine zweite Variante die ich versucht habe, war bitweise Auswertung -
dies klappt problemlos bei allen Potenzen von 2 und verzichtet auf
Division.
Mit der "Drei" hab ichs dann allerdings nicht hinbekommen - hatte die
Idee gegen ein festes und gegen ein toggelndes Bit abzufragen. Finde
aber gerade meine Programmierbemühungen in diese Richtung nicht wieder
Gruß
Englisch schrieb:> Hallo Karl Heinz,>> genau auf diesen Haken - ddas die Vielfachen der Primzahlen ja keine> mehr sind und sich dann gemeinsame Vielfach ergeben bin ich auch> gekommen.
Warum wundert es dich dann, wenn dein Verfahren mit 3 und 997 nicht
funktioniert? 997 ist kein Vielfaches von 3
Es hilft auch nichts, die beiden Zeiten zeitversetzt zu starten, das
verändert nur die Zeitpunkte, wann die beiden Reihen übereinstimmen
1
3-er * * * * * * * * * * * * * *
2
Zeit 01234567890123456789012345678901234567890
3
5-er * * * * * * * * *
4
^ ^ ^
5
| | |
1
3-er * * * * * * * * * * * * *
2
Zeit 01234567890123456789012345678901234567890
3
5-er * * * * * * * * *
4
^ ^ ^
5
| | |
Nach jeweils 15 Zeiteinheiten hast du wieder ein Zusammentreffen. Warum?
Weil 3 * 5 -> 15
Aber: 3 + 6
1
3-er * * * * * * * * * * * * * *
2
Zeit 01234567890123456789012345678901234567890
3
6-er * * * * * * *
jetzt hast du eine fixe "Phasenbeziehung", die immer gleich ist.
Veschiebst du den Anfang der 3-er Reihe, so sorgt diese fixe Phase
dafür, dass die beiden nie wieder gemeinsam auftreten. (Im Grunde ist ja
die 6-er Reihe eine 3-er Reihe, bei der jedes 2-te Ereignis ausgelassen
wird)
1
3-er * * * * * * * * * * * * * *
2
Zeit 01234567890123456789012345678901234567890
3
6-er * * * * * * *
Für dich bedeutet das:
Zb würde 3 und 999 funktionieren, wobei du den ersten Startwert für
Counter1 eben nicht mit Counter1_Startwert nimmst, sondern eine Zahl die
kleiner als das ist. zb Counter1_Startwert - 1 oder auch ganz einfach
nur 1
Warum "umständlich" mit Modulo und Vielfachen rechnen, wenns auch
einfach geht? Man könnte ja Lösungen anbieten, statt ewig auf den
Problemen rum zu reiten. ;)
1
Timer_isr:
2
counter1=counter1+1
3
counter2=counter2+1
4
5
ifcounter1=3then
6
counter1=0;
7
GosubRegler1'Ausführungalle3ms
8
elseifcounter2>=1000then
9
counter2=counter2-1000
10
GosubRegler2'AusführungalleSekunde
11
endif
12
return
Durch das else-if wird verhindert, dass beide Bedingungen gleichzeitig
auftreten/auslösen. Durch das -1000 wird verhindert, dass im Fall wenn
beide gleichzeitig, der Versatz max. 1 Tick ist und sich nicht
aufaddiert.
ziegenpeter schrieb:> Warum "umständlich" mit Modulo und Vielfachen rechnen, wenns auch> einfach geht? Man könnte ja Lösungen anbieten, statt ewig auf den> Problemen rum zu reiten. ;)
Wenn du das Problem bis zum Ende durchdacht hast und die Konklusio am
Ende gelesen hast, hättest du gemerkt, dass das Problem mitlerweile eine
Lösung hat, die (oh Wunder) sogar noch einfacher ist als deine.
Es lohnt sich immer ein Problem im Detail zu verstehen. Und sei es nur
um zu verstehen, warum die Dinge so sind wie sie sind.
1
counter1=1
2
counter2=999
3
4
Timer_isr:
5
counter1=counter1+1
6
counter2=counter2+1
7
8
ifcounter1=3then
9
counter1=0;
10
GosubRegler1'Ausführungalle3ms
11
endif
12
13
ifcounter2=999then
14
counter2=0
15
GosubRegler2'AusführungalleSekunde
16
endif
17
return
Die Zahlen sauber gewählt (basierend auf der Problemanalyse) und das
Problem ist so gelöst, dass es zu keinem gleichzeitigen Auftreten mehr
kommen KANN und damit auch nicht zu einer Verzögerung von 1 Tick!
"Mathematisch" (na ja, da müsste man jetzt noch mehr mathematischen
Aufwand treiben. Sagen wir "mathematisch anschaulich") abgesichert.
Karl Heinz Buchegger schrieb:> Warum wundert es dich dann, wenn dein Verfahren mit 3 und 997 nicht> funktioniert? 997 ist kein Vielfaches von 3
Das war danach kein wundern mehr, sondern nur anfangs unzureichendes
nachdenken. Mein Beispiel diente dann mehr dem Nachweis, dass ich nicht
einfach nur frage, sondern auch zeige, dass es zumindest eigene Versuche
gab.
Ich möchte ja meine Hausaufgaben nicht gelöst bekommen, ohne selber
nachzudenken - auch wenns keine Hausaufgaben sind.