Forum: Mikrocontroller und Digitale Elektronik switch / case macht etwas was ich nicht verstehe


von Attila C. (attila)


Lesenswert?

Hallo!

Ich habe folgendes "Konstrukt" :

ISR (TIMER2_OVF_vect)
{
  pause=pause+1;

  switch  (pause)
  {
    case 1:
      PORTC=0b11111110;
      break;
    case 3:
      PORTC=0b11111101;
      break;
    case 5:
      PORTC=0b11111011;
      break;
usw usw usw bis:


      case 11:
      PORTC=0b11011111;
      pause=0;
      break;

    default:
    PORTC=0xFF;
    break;
  }
}

Wenn ich mir jetzt Port 0 und Port 1 auf dem Oszilloskop anschaue sehe 
ich das auf das "low" von Port 0 unmittelbar das "low" von Port 1 folgt. 
Ich beabsichtige aber das zwischen den beiden "lows" ein Abstand ist. 
Daher nehme ich bei den case Anweisungen ungerade Zahlen.

Was übersehe ich?

Danke schonmal!

von bitte löschen (Gast)


Lesenswert?

Ich sehe nur, dass auf das Low von Bit 5 das Low auf Bit 0 folgt, was Du 
verhindern kannst, indem Du in "case 11" Pause auf -1, statt auf 0 
setzt.

von Floh (Gast)


Lesenswert?

Attila Ciftci schrieb:
> Ich beabsichtige aber das zwischen den beiden "lows" ein Abstand ist.
> Daher nehme ich bei den case Anweisungen ungerade Zahlen.

Wie schnell läuft denn dein Timer? Und wie lange willst du pausieren 
zwischne den Zusänden?
Schon gerechnet?

von Attila C. (attila)


Lesenswert?

Ich betrachte nur Bit 0 und Bit 1 (im Moment!)

Wie schnell der Timer läuft ist ja eigentlich nicht wesentlich. "pause" 
wird bei jedem interrupt eins hochgezählt. Daher sollte ja bei pause = 
2, 4, 6 ,8  und 10 der "default" Fall eintreten und alle Pins "high" 
sein. Dem ist aber laut meinem Oszilloskop nicht so sondern case 3 folgt 
unmittelbar case 1.

Pullups sind deaktiviert. Es ist ein Atmega 8.

von Karl H. (kbuchegg)


Lesenswert?

Dann zeig mal dein komplettes Programm.
Irgendwo wirst du wohl die Variable pause noch zusätzlich vrändern.

von Achim M. (minifloat)


Lesenswert?

Geht das nicht auch kürzer?
1
ISR (TIMER2_OVF_vect)
2
{
3
   PORTC = ~(1 << (pause/2));
4
   pause = (pause == 11) ? (0) : (pause + 1);
5
}
mfg mf

PS: Oder so?
1
ISR (TIMER2_OVF_vect)
2
{
3
   PORTC = ~(1 << (pause >> 1));
4
   pause += (pause == 11) ? -11 : 1;
5
}

von Knut (Gast)


Lesenswert?

Jepp, sollte so auch gehen, is auf jeden Fall wesentlich kompakter!


Knut

von Attila C. (attila)


Lesenswert?

@Karl Heinz: Die Variable pause kommt nur in der ISR vor.
@Mini Float: Danke! Sehr interessanter Ansatz den ich aber erst 
vollständig verstehen muss.

Zur weiteren Verdeutlichung: An den Ports hängen 6 LEDs die im Prinzip 
so Multiplexing-mässig angefahren werden. Funktioniert auch und hätte 
ich mir das im Oszi nicht angeschaut hätte ich garnicht bemerkt das der 
default-Fall nicht ausgeführt wird.

von Achim M. (minifloat)


Lesenswert?

Bitte zerfleischt mich!!

Die "Shift"werte sehen so aus:
1
pause| 0 1 | 2 3 | 4 5 | 6 7 | 8 9 |10 11
2
-----+-----+-----+-----+-----+-----+--------
3
shift|  0  |  1  |  2  |  3  |  4  |  5

Bei elftem Durchlauf wäre pause noch 10.

So müsste es jetzt passen:
1
//So
2
ISR (TIMER2_OVF_vect)
3
{
4
   PORTC = ~(1 << (pause/2));
5
   pause = (pause == 10) ? (0) : (pause + 1);
6
}
7
8
mfg mf
9
10
//Oder eben
11
ISR (TIMER2_OVF_vect)
12
{
13
   PORTC = ~(1 << (pause >> 1));
14
   pause += (pause == 10) ? -10 : 1;
15
}

mfg mf

PS: Informatiker am Bahnhof-Problem:
Er zählt seine Koffer: "Null, Eins, Zwei...Sh“¡¶¢ wo ist mein DRITTER 
KOFFER???"

von Karl H. (kbuchegg)


Lesenswert?

Attila Ciftci schrieb:
> @Karl Heinz: Die Variable pause kommt nur in der ISR vor.

Zeigs trotzdem.


> Zur weiteren Verdeutlichung: An den Ports hängen 6 LEDs die im Prinzip
> so Multiplexing-mässig angefahren werden. Funktioniert auch und hätte
> ich mir das im Oszi nicht angeschaut hätte ich garnicht bemerkt das der
> default-Fall nicht ausgeführt wird.

Er wird ausgeführt. Verlass dich drauf. Wenn du am Oszi nichts erkennen 
kannst, dann gibt es noch einen Fehler in deinem Programm.

von Tom K. (ez81)


Lesenswert?

Mini Float schrieb:
> Bitte zerfleischt mich!!

Gerne :).


Attila Ciftci schrieb:
> @Mini Float: Danke! Sehr interessanter Ansatz den ich aber erst
> vollständig verstehen muss.

Das sollte Dir zeigen, dass dieser Ansatz in real-world-Programmen, die 
nicht write-only sind, großer Mist ist. Deine Lösung vom Anfang kann 
jeder halbwegs brauchbare Programmierer ohne Stift+Papier durch 
Draufsehen verstehen und ändern, das Macho-C von Mini-Float eher nicht.

von Attila C. (attila)


Angehängte Dateien:

Lesenswert?

Lieber Karl Heinz!

Wenn ich hier mein Programm veröfentliche dann wird es (wie schon einige 
male passiert) dazu führen dass hier ein blutiger C Anfänger demontiert 
wird und , wie man ja bereits sehen kann, am Thema vorbei gepostet wird.

Wetten? ;-)

Nur damit alle Beteiligten noch einmal wissen worum es mir geht: Warum 
wird der default -Fall (scheinbar?) nicht ausgeführt?

von Attila C. (attila)


Lesenswert?

Danke Tom! :-)

von Karl H. (kbuchegg)


Lesenswert?

Attila Ciftci schrieb:
> Lieber Karl Heinz!
>
> Wenn ich hier mein Programm veröfentliche dann wird es (wie schon einige
> male passiert) dazu führen dass hier ein blutiger C Anfänger demontiert
> wird

demontiert würde ich nicht sagen.
Letzten Endes wirst da ja aus solchen Diskussionen immer etwas 
mitgenommen haben.

> Nur damit alle Beteiligten noch einmal wissen worum es mir geht: Warum
> wird der default -Fall (scheinbar?) nicht ausgeführt?

Ein Messfehler ist von deiner Seite her ausgeschlossen?
(Du musst es fir zur Gewohnheit machen, dass deine erste Annahme nie 
darin besteht, dass der Compiler oder der µC Mist macht. In 99% der 
Fälle sitzt das Problem immer vor dem Bildschirm)
In deinem Programm ist kein Grund erkennbar, warum der default Zweig 
nicht ausgeführt werden sollte.


PS: Bist du daran interessiert, wie du dein Programm vereinfachen 
kannst? Du bist nämlich reif für Arrays.

von ... ... ... (Gast)


Lesenswert?

Attila Ciftci schrieb:
> Wenn ich hier mein Programm veröfentliche dann wird es (wie schon einige
> male passiert) dazu führen dass hier ein blutiger C Anfänger demontiert
> wird und , wie man ja bereits sehen kann, am Thema vorbei gepostet wird.
>
> Wetten? ;-)
Steh drüber und lerne:
1
  volatile long dimm1=2000,dimm2=2000,dimm3=2000,dimm4=2000,dimm5=2000,dimm6=2000,dimm7=2000,dimm8=2000;
2
  int direct1,direct2,direct3,direct4,direct5,direct6,direct7,direct8;
3
  int eins,zwei,drei,vier,fuenf,sechs,sieben,acht;

1
  volatile long dimm[8]={2000};
2
  int direct[8];
3
  int rand[8];
Der Zugriff erfolgt aber mit rand[0] bis rand[7], da die Indexierung mit 
0 beginnt.

von Attila C. (attila)


Lesenswert?

@Karl Heinz: Ja natürlich! Darum habe ich mich auch bei Mini Float 
(ehrlich und NICHT zynisch) bedankt und auch zu verstehen gegeben das 
meine C Kenntnisse nicht ausreichen um vollständig zu verstehen was er 
da eigentlich gemacht hat.Die Idee etwas davon abhängig zu machen ob es 
durch 2 teilbar ist finde ich spannend.

Auf meinem Oszi sehe ich zwei Rechtecke von etwa 100us Dauer die einen 
Abstand von 10 us haben um es einfach auszudrücken und eine 
"Missbedienung" meinersets auszuschliessen.

von Karl H. (kbuchegg)


Lesenswert?

Attila Ciftci schrieb:

> Auf meinem Oszi sehe ich zwei Rechtecke von etwa 100us Dauer die einen
> Abstand von 10 us haben um es einfach auszudrücken

Bitte nicht einfach ausdrücken!
Drück dich präzise aus!

Also doch ein Abstand dazwischen?


So?
 -------+       +---------------------------
        |       |
        +-------+


 --------------------+        +-------------
                     |        |
                     +--------+


        | 100   | 10 |  100   |

von Attila C. (attila)


Lesenswert?

@... ... ...: Danke! Das mit Arrays zu lösen ist natürlich ein guter 
Tip!

von Attila C. (attila)


Lesenswert?

@Karl Heinz: Ja genau!

von Karl H. (kbuchegg)


Lesenswert?

Attila Ciftci schrieb:
> @Karl Heinz: Ja genau!


Also wird der default auch ausgeführt. Er ist der einzige Code, der 
dafür sorgt, dass am Port C alle Pins auf 1 gehen.

von Attila C. (attila)


Lesenswert?

@Karl Heinz: So gesehen hast Du recht. Aber warum nur so kurz? Die Dauer 
bis zum interrupt sollte doch immer gleich sein? Egal ob der case-Fall 
oder der default-Fall gilt?

von Karl H. (kbuchegg)


Lesenswert?

Attila Ciftci schrieb:
> @Karl Heinz: So gesehen hast Du recht. Aber warum nur so kurz? Die Dauer
> bis zum interrupt sollte doch immer gleich sein? Egal ob der case-Fall
> oder der default-Fall gilt?

richtig.
Aber an dem Rätsel grüble ich noch :-)

von Attila C. (attila)


Lesenswert?

10us sind für einen AVR zuviel um das als "systembedingt" zu betrachten 
oder? Also im Sinne von: Verarbeitungszeit bis der nächste Pin 
geschaltet wird?

von Karl H. (kbuchegg)


Lesenswert?

Tu mir einen Gefallen.
Ändere dein Programm mal so um.
1
ISR (TIMER2_OVF_vect)
2
{
3
  static unsigned int delay = 0;
4
5
  delay++;
6
  if( delay < 31250 )
7
    return;
8
  delay = 0;
9
10
  // ab hier so wie es vorher auch war
11
12
  pause=pause+1;
13
14
  ...
15
}

das verlangsamt das Umschalten, so dass nur etwa jede 1 Sekunde pause um 
1 weitergeschaltet wird. Dann kann man an den LED selber sehen, wie 
lange sie leuchten und wie lange die Dunkelphase dazwischen ist.

von Niemand (Gast)


Lesenswert?

Hi,
Du änderst die switch() variable innerhalb des "switch". Könnte mir 
vorstellen, dass einige Compiler da Mist generieren.

von Karl H. (kbuchegg)


Lesenswert?

Attila Ciftci schrieb:
> 10us sind für einen AVR zuviel um das als "systembedingt" zu betrachten
> oder?

10us = 10 * 10E-6
viel zu viel

Bei 8 Mhz arbeitet den µC da immerhin 80 Befehle ab.

von Karl H. (kbuchegg)


Lesenswert?

Niemand schrieb:
> Hi,
> Du änderst die switch() variable innerhalb des "switch". Könnte mir
> vorstellen, dass einige Compiler da Mist generieren.

Du meinst im case 15?

Nö, das ist in Ordnung. Das bringt keinen Compiler in Schwierigkeiten.

von Attila C. (attila)


Lesenswert?

@Karl Heinz: Hab ich gemacht. Jetzt gehen die LEDs etwa im 
2-Sekundentakt nacheinander an.

von Karl H. (kbuchegg)


Lesenswert?

Attila Ciftci schrieb:
> @Karl Heinz: Hab ich gemacht. Jetzt gehen die LEDs etwa im
> 2-Sekundentakt nacheinander an.

ohne Pause dazwischen?

IMHO müsste es so sein.

LED 0 leuchtet
         1 Sekunde
LED 0 geht aus
         1 Sekunde
LED 1 leuchtet
         1 Sekunde
LED 1 geht aus
         1 Sekunde
....

von Attila C. (attila)


Lesenswert?

Eher etwa 2 Sekunden an und 2 Sekunden aus. Ansonsten so wie Du es 
beschreibst.

von Patrick (Gast)


Lesenswert?

Kommentiere mal bitte alles, was im while(1)-Block steht, aus. Du 
verwendest da munter (vermutlich) vorzeichenbehaftete Variablen 
unterschiedlicher Länge und weist sie dann einem (vorzeichenlosen) 
Register (8 Bit? 16 Bit? Konnte keinen CPU-Typ finden; hab ich ihn 
überlesen?) zu, ohne irgendwelche Prüfungen auf Über-/Unterläufe bei 
Deinen Additionen und Subtraktionen.

von Attila C. (attila)


Lesenswert?

@Patrick: Mache ich sobald ich wieder nüchtern bin ;-) Könnte denn das 
was in der while Schleife passiert Einfluss auf den default-Fall in der 
ISR haben?  Ich kann es mir nicht recht vorstellen.

von Karl H. (kbuchegg)


Lesenswert?

Attila Ciftci schrieb:
> Eher etwa 2 Sekunden an und 2 Sekunden aus. Ansonsten so wie Du es
> beschreibst.

OK. Die 2 Sekunden sind mir zwar nicht klar, rein rechnerisch müssten 
sich bei 8Mhz 1 Sekunde ergeben (*), aber wenn die Pause gleich lang wie 
das Leuchten ist, dann ist alles in Ordnung.


(* ausser ich hab mich verrechnet. Mag sein)

von Patrick (Gast)


Lesenswert?

Nicht im default-Fall, aber in case 1 beschreibst Du ja OCR2 mit 
dimm1/1000. D. h. wenn Timer 2 8 Bit breit ist, kriegt OCR2 nur die 8 
LSB ab; das kann natürlich zu witzigen Effekten führen.

von Attila C. (attila)


Lesenswert?

@Karl Heinz: Hast recht, Wirklich merkwürdig. Hab grade die Fuses 
gecheckt und probeweise den Quarz rausgezogen. Daran scheint es nicht zu 
liegen.

von Attila C. (attila)


Lesenswert?

@Patrick: Ich habe grade vor das while ein weiteres while(1) gesetzt. 
Alle LEDs leuchten ganz leicht (Alle dimm=2000) aber wesentlich ist dass 
das Bild sich auf meine Oszi nicht geändert hat.

von Attila C. (attila)


Lesenswert?

@Patrick: Was natürlich (!!!) nicht heissen soll das ich deine Anmerkung 
zu den Variablen ignoriere sondern dankend wahrnehme! Es scheint aber 
nicht das Problem zu sein.

von GS_Gast (Gast)


Lesenswert?

Könnte sein, dass die Divisionen durch 1000 in der ISR zu lange dauern. 
Ist immerhin eine long-Division. Vielleicht zum Test mal die OCRx-Werte 
in main innerhalb der while(1)-Schleife bei jeder Veränderung berechnen 
und in neu zu definierende Variablen ocrnew1 .. ocrnew8, je nach 
OCR-Breite unsigned char oder unsigned short, und in der ISR auf diese 
Variablen statt der dimmX zugreifen.

von Attila C. (attila)


Lesenswert?

@GS_Gast: Treffer! Versenkt! Ich habe das Teilen durch 1000 in der ISR 
gelöscht und siehe da: Das Oszilloskop zeigt was ich erwartet habe.
Es ist jetzt (was schlüssig ist) 60 us Pin 0 low, 60 us beide pins high 
und 60 us Pin 1 low.

von GS_Gast (Gast)


Lesenswert?

Eine weitere Verbesserung wäre, den Faktor 1000 durch 1024 zu ersetzen. 
Damit könnten die Divisionen jeweils durch ocrnewX = dimmX>>10; ersetzt 
werden. Natürlich müssen dann die Konstanten entsprechend angepasst 
werden, also 2048 statt 2000, 206848 (=1024*(202000/1000)) statt 202000 
usw. Mit dieser Maßnahme bleibt in der while(1)-Schleife wesentlich mehr 
Rechenzeit übrig.

von Attila C. (attila)


Lesenswert?

@GS_Gast: ocrnewX=dimmX>>10; ???

Das kenne und verstehe ich nicht ">>10" tut was? Und wie heisst die 
Operation damit ich sie suchen und nachlesen kann?

von ... ... ... (Gast)


Lesenswert?

Attila Ciftci schrieb:
> @GS_Gast: ocrnewX=dimmX>>10; ???
>
> Das kenne und verstehe ich nicht ">>10" tut was? Und wie heisst die
> Operation damit ich sie suchen und nachlesen kann?
die Lektüre liefere ich bleich mit -> Bitmanipulation

von Attila C. (attila)


Lesenswert?

Danke!

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.