Forum: Mikrocontroller und Digitale Elektronik Alternative für Modulo - Bascom


von Englisch (Gast)


Lesenswert?

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

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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.

von Oliver (Gast)


Lesenswert?

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

von Englisch (Gast)


Angehängte Dateien:

Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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 :-)

von Englisch (Gast)


Lesenswert?

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ß

von Karl H. (kbuchegg)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

Beispiel: 3 und 5
1
 3-er  *  *  *  *  *  *  *  *  *  *  *  *  *  *
2
 Zeit  01234567890123456789012345678901234567890
3
 5-er  *    *    *    *    *    *    *    *    *
4
                      ^              ^
5
                      |              |
6
                    mööp           mööp
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

von ziegenpeter (Gast)


Lesenswert?

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
   if counter1 = 3 then
6
      counter1 = 0;
7
      Gosub Regler1       'Ausführung alle 3 ms
8
   else if counter2 >= 1000 then
9
      counter2 = counter2 - 1000
10
      Gosub Regler2 'Ausführung alle Sekunde
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.

von Karl H. (kbuchegg)


Lesenswert?

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
   if counter1 = 3 then
9
     counter1 = 0;
10
     Gosub Regler1       'Ausführung alle 3 ms
11
   endif
12
13
   if counter2 = 999 then
14
     counter2 = 0
15
     Gosub Regler2 'Ausführung alle Sekunde
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.

von Englisch (Gast)


Lesenswert?

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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.