Forum: Mikrocontroller und Digitale Elektronik Switch-Case Anweisung kommt nicht zurück!


von Hans (Gast)


Lesenswert?

Hallo,

kann man AVR Studio beibringen, dass es meckert, wenn man bei einer 
Switch Case Anweisung das Break vergisst? Werror habe ich eingeschaltet. 
Weiter interessier es mich, ob es einen Unterschied macht, den 
Programmteil in der Switch Anweisung einzuklammern oder nicht?:

Case xyz:
{
    ....
    break;
}

ich habe das dumme Problem, wenn ich in einer ISR die Switch-Case 
Anweisung ausführe, das dann das Programm die ISR nicht mehr verlässt 
und wdt greift (wdto60ms).

Mache ich den Programmausschnitt in der main-while(1) Schleife geht 
alles. Jedoch muss die Ausführung der Switch Anweisung unmittelbar nach 
dem adc-Complete Interrupt erfolgen, da es sehr zeitkritisch ist.

Ich habe den Inhalt der Switch-Anweisung in geschweiften Klammern, wie 
oben.
Ich kann's leider im Moment nicht selber testen, bin unterwegs. Bin für 
jeden Tipp dankbar.

MfG Hansi

von Klaus W. (mfgkw)


Lesenswert?

Hans schrieb:
> Programmteil in der Switch Anweisung einzuklammern oder nicht?:
>
> Case xyz:
> {
>     ....
>     break;
> }

Das macht dann einen Unterschied, wenn man noch eine lokale Variable 
darin definiert (oder ähnliches), sonst nicht.

von (prx) A. K. (prx)


Lesenswert?

Hans schrieb:

> kann man AVR Studio beibringen, dass es meckert, wenn man bei einer
> Switch Case Anweisung das Break vergisst?

Meines Wissens nicht.

> Weiter interessier es mich, ob es einen Unterschied macht, den
> Programmteil in der Switch Anweisung einzuklammern oder nicht?:

Nein. Es sei denn im Block sind lokale Variablen definiert.

von Klaus W. (mfgkw)


Lesenswert?

Hans schrieb:
> ich habe das dumme Problem, wenn ich in einer ISR die Switch-Case
> Anweisung ausführe, das dann das Programm die ISR nicht mehr verlässt
> und wdt greift (wdto60ms).

Da würde ich eher tippen, daß du noch etwas anderes falsch machst.

von Ralf S. (spacedog) Benutzerseite


Lesenswert?

Hans schrieb:
> kann man AVR Studio beibringen, dass es meckert, wenn man bei einer
> Switch Case Anweisung das Break vergisst?

Vermutlich nicht, denn wenn man die break-Anweisung weglässt, ist das in 
keiner Weise ein Fehler, sondern wird sogar oft und mit Absicht so 
gemacht.

von Hans (Gast)


Lesenswert?

Ich ändere in der Anweisung globale variablen, die aber als volatile 
deklariert sind.

von max (Gast)


Lesenswert?

Und Zugriffe außerhalb der ISR darauf sind atomar?

Debugger steht dir nicht zur Verfügung um nachzuschauen, wo genau sich 
der AVR in seiner Ausführung befindet?

von Oliver (Gast)


Lesenswert?

Hans schrieb:
> Ich kann's leider im Moment nicht selber testen, bin unterwegs. Bin für
> jeden Tipp dankbar.

Nach Hause kommen, Code hier posten. Bis dahin ist das nur raten auf 
Raten.

Oliver

von asdf (Gast)


Lesenswert?

A. K. schrieb:
> Hans schrieb:
>
>> kann man AVR Studio beibringen, dass es meckert, wenn man bei einer
>> Switch Case Anweisung das Break vergisst?
>
> Meines Wissens nicht.

Nope, sieht nicht so aus, zumindest nicht für gcc:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=7652

Eventuell können einige statische Code-Checker hier aber Warnungen 
werfen (z.B. "splint" o.ä.), hab ich nicht geprüft.

von Uwe (Gast)


Lesenswert?

> Nope, sieht nicht so aus, zumindest nicht für gcc
Ist ja auch ein GEWOLLTES Feature.

von Thomas E. (thomase)


Lesenswert?

Hans schrieb:
> Programmteil in der Switch Anweisung einzuklammern oder nicht?:
Aber sicher.

> Case xyz:
> {   ....
>     break;
> }

Das break gehört jetzt nicht mehr zum switch, sondern zu der Anweisung, 
die unter dem case läuft. Die wird dann mit einem break abgebrochen. Er 
springt also aus dem geklammerten Teil raus und landet dann im 
geklammerten Teil des switch. Da muß dann auch wieder ein break stehen.

Also:
switch(a)
{
  case 0:
     //Mach' was
  break;

  case 1:
    {
     int b;
     //Mach' was
    }
  break;
}

Hans schrieb:
> kann man AVR Studio beibringen, dass es meckert, wenn man bei einer
> Switch Case Anweisung das Break vergisst?
Nein. Das hat mit AVR-Studio nichts zu tun, sondern mit C. Und da ist es 
erlaubt.

mfg.

von (prx) A. K. (prx)


Lesenswert?

Thomas Eckmann schrieb:

> Das break gehört jetzt nicht mehr zum switch, sondern zu der Anweisung,
> die unter dem case läuft. Die wird dann mit einem break abgebrochen. Er
> springt also aus dem geklammerten Teil raus und landet dann im
> geklammerten Teil des switch. Da muß dann auch wieder ein break stehen.

Ein break gehört zum nächsten umgebenden for/while/do/switch Konstrukt, 
egal wieviele {} Klammern zwischendrin stehen. Ob man den zu einem case 
gehörenden Code umklammert oder nicht ändert nichts an der Zugehörigkeit 
vom break.

Die 3 Varianten hier sind also in dieser Hinsicht gleich:
1
case 1:
2
    ...;
3
    break;
4
case 2:
5
  {
6
    ...;
7
    break;
8
  }
9
case 3:
10
  {
11
    ...;
12
  }
13
  break;

von Hans (Gast)


Lesenswert?

Soo, bin grad rein.

Hier die Funtkion, aus der ISR:

ISR(ADC_fertig)
1
...
2
set_brake(brake_state,ON);

dann in der Funktionen.c
1
/* set brake mode */
2
void set_brake (unsigned char brake_mode, unsigned char state)
3
{
4
  switch (brake_mode)
5
  {
6
    case RESISTIVE_BRAKE:
7
    {
8
      if(state==ON)
9
      {
10
        PORTA |= (1<<TRIGGER_RB);
11
      }
12
      else
13
      {
14
        PORTA &= ~(1<<TRIGGER_RB);
15
      }
16
    break;
17
    }
18
    
19
    case SHORTCIRQUIT_BRAKE:
20
    {
21
      /* inverted!!!  */
22
      if(state==OFF)
23
      {
24
        PORTA |= (1<<TRIGGER_SC);
25
      }
26
      else
27
      {
28
        PORTA &= ~(1<<TRIGGER_SC);
29
      }
30
    break;
31
    }
32
    default: break;
33
}
und aus dieser scheint es kein zurück mehr zu geben, da der AVR sich mit 
der im WDT eingestellten Zeit resettet. Wenn ich die Funktion in der 
main ausführen geht es, weil hier keine ISRs gesperrt sind und somit der 
WDT im Timerintterupt (alles 7,nochwas ms) zurückgesetzt wird.

Werds Montag gleich mal an der Hardware ausprobieren, aber daran könnte 
liegen (mit den geschweiften Klammern)?

Hansi

von Hans (Gast)


Lesenswert?

Da fehlt noch ne Klammer, die is aber im Programm vorhanden ;-)

von Josef D. (jogedua)


Lesenswert?

Hans schrieb:
> kann man AVR Studio beibringen, dass es meckert, wenn man bei einer
> Switch Case Anweisung das Break vergisst?

In Eclipse (Indigo) geht das.

von Hans (Gast)


Lesenswert?

A. K. schrieb:
> Ein break gehört zum nächsten umgebenden for/while/do/switch Konstrukt,
> egal wieviele {} Klammern zwischendrin stehen. Ob man den zu einem case
> gehörenden Code umklammert oder nicht ändert nichts an der Zugehörigkeit
> vom break.

Thomas Eckmann schrieb:
> as break gehört jetzt nicht mehr zum switch, sondern zu der Anweisung,
> die unter dem case läuft. Die wird dann mit einem break abgebrochen. Er
> springt also aus dem geklammerten Teil raus und landet dann im
> geklammerten Teil des switch. Da muß dann auch wieder ein break stehen.

Wer hat denn nun Recht?

von Thomas E. (thomase)


Lesenswert?

A. K. schrieb:
> Die 3 Varianten hier sind also in dieser Hinsicht gleich:
Hast recht.

Hans schrieb:
> Wer hat denn nun Recht?
A.K.

mfg.

von Hans (Gast)


Lesenswert?

Gibt es sonst etwas "Auffälliges" an meiner Switch-Case?

von Dummschwaezer (Gast)


Lesenswert?

ich stimme für A.K

von Oliver (Gast)


Lesenswert?

Hans schrieb:
> und aus dieser scheint es kein zurück mehr zu geben

Du weisst aber nicht wirklich, ob die Funktion zurückkehrt, oder?

An der Funktion set_brake() kann es nicht liegen. Was passiert denn noch 
so in der ISR?

Oliver

von Thomas E. (thomase)


Lesenswert?

Hans schrieb:
> void set_brake (unsigned char brake_mode, unsigned char state)

Füg' hier mal ein Watchdog-Reset ein. Vielleicht dödelt er die 8ms ja 
schon vorher ab.

> {
>   switch (brake_mode)

Nachdem wir das jetzt mit den Klammern und dem break geklärt haben, muss 
es ja irgendwo anders liegen.

von Hans (Gast)


Lesenswert?

1
ISR(ADC_vect)
2
{
3
  u_gen = ADC * 1;
4
  
5
  /* Watchdog reset */
6
  wdt_reset();
7
    
8
  /* trigger resistive brake */
9
    /* set brake time counter */
10
    /* lock this function against re trigger */
11
      if
12
    (
13
      /* overvoltage or emergency stop */
14
      (
15
        (u_gen > u_switch_resistive_brake)||
16
        (PINA& (1<<EMERGENCY_STOP))
17
      )
18
      &&
19
      /* triggered yet */
20
      (brake_state == NO_BRAKE)
21
    )
22
    {
23
      /* set brake time */
24
      timer=RESITIVE_BRAKETIME_MAX;
25
      /* lock function against re trigger */
26
      brake_state=RESISTIVE_BRAKE;
27
      /* enable resistive brake */
28
      set_brake(brake_state,ON);
29
    }
30
}
Die Auswertung ist Moment noch mit direkten unskalierten ADC werten, 
nicht wundern.

Wenn ich einmal die if-Passage betrete, verriegelt sich diese 
anschließend durch verändern von brake_state selbst. Gleichzeitig wird 
eine variable (timer) auf einen wert gesetzt und in im 
Timeroverflow-Vektor decrementiert (Zeitfenster). Hier wird auch die 
nächste Messung angestoßen und der wdt zurück gesetzt. Aber das passiert 
alles schon garnicht mehr, da der wdt-reset dazwischen kommt. Ich sehe 
noch wie der Pin PORTA |= (1<<TRIGGER_RB) auf H geht und noch 60ms der 
WDT das Spiel beendet.

von rfv (Gast)


Lesenswert?

Wird das ISR-Flag am Ende restet (von Dir)?

Wenn nicht dann wird deine ISR nur einmal aufgerufen, da ja kein neues 
Setzen des Flags möglich ist.

von Hans (Gast)


Lesenswert?

rfv schrieb:
> Wird das ISR-Flag am Ende restet (von Dir)?
??? Das Flag löscht sich bei Verlassen der ISR selbst... ???!
Wie gesagt, wenn ich den teil unter
1
u_gen = ADC+1;

in die main packe, geht es einwandfrei, nur halt die Reaktion auf einen 
zu hohen ADC-Wert dauert mir zu lange, da die Kiste auch "nur" auf 32kHz 
Uhrenquarz läuft.

von Thomas E. (thomase)


Lesenswert?

Hans schrieb:
> da die Kiste auch "nur" auf 32kHz
> Uhrenquarz läuft.
Dann verlängere mal deinen Watchdog. Das kann doch gar nicht gehen.
Was soll das überhaupt?

mfg.

von Vlad T. (vlad_tepesch)


Lesenswert?

Hans schrieb:
> in die main packe, geht es einwandfrei, nur halt die Reaktion auf einen
> zu hohen ADC-Wert dauert mir zu lange, da die Kiste auch "nur" auf 32kHz
> Uhrenquarz läuft.

wenn ich mich recht erinnere braucht der ADC doch eine Frequenz zwischen 
50kHz und 200kHz.
Was du da also mit deinem ADC misst ist Mist.

Ich denke aber auch, dass das Problem an dem WDT liegt.
weiß ja nicht, was du für einen ADC-Prescaler hast und auf was für eine 
Sample-Dauer du am Ende kommst. Eventuell beißt der Hund vorher in die 
Resetleitung.

von Oliver (Gast)


Lesenswert?

Die ISR wird ja erst aufgerufen, wenn der ADC fertig meldet. Und dann 
bleiben 1920 Zyklen, bis der wdt wieder zuschlägt. Das sollte für die 
paar Anweisungen ausreichen.

Wenn möglich, schalte doch mal LEDs beim ein- und Austritt in die ISR. 
Vielleicht ist der wdt ja auch falsch parametriert, und schlägt viel 
schneller zu.

Oliver

von Thomas E. (thomase)


Lesenswert?

Mit dem Watchdog ist das wie mit dem Sleep. Das wird zuletzt eingebaut. 
Wenn alles andere läuft.
Dann findet man auch schneller den Fehler, wenn es irgendwo mit dem 
Timing doch nicht so passt, wie erwartet.

mfg.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Vermutlich liegt das Problem hier:

Hans schrieb:

> ...

von Hans (Gast)


Lesenswert?

Das Problem tritt nicht auf, wenn ich es mit 1MHz laufen lasse. Folglich 
fange ich mir das Timeout wegen zu langsam ein. Mit 120ms geht's auch 
nicht. Merkwürdig...

von Werner (Gast)


Lesenswert?

Hans schrieb:
> Merkwürdig...

Dann ist es jetzt vielleicht doch mal an der Zeit, den Simulator 
anzuschmeißen, mit den passenden Stimuli zu füttern und zu gucken, womit 
der µC sich denn so die Zeit vertreibt, bis ihn der Hund erwischt.

von Hansi (Gast)


Lesenswert?

Aus dem Datenblatt:
By default, the successive approximation circuitry requires an input 
clock frequency between 50kHz and 200kHz to get maximum resolution.

Und nun??? Internen WDT Oszillator mit 125kHz als Taktquelle nehmen?
Ich will sol wenig Strom wie möglich verbrauchen...

Aber sieht irgendjemand wo er sich ein Timout einfangen könnte?
Hier die Timer ISR:
1
/* System tick with 7,8ms */
2
ISR (TIMER0_COMPA_vect)
3
{
4
  /* Watchdog reset */
5
  wdt_reset();
6
  
7
  /*start new conversation */
8
  ADCSRA |= (1<<ADSC);
9
10
  /* decrement timer */
11
  if(timer)
12
  {
13
    timer--;
14
  }
15
}

Watchdog resetten, neue Messung starten, wenn Wandlung fertig watchdog 
resetten, ergebnis auswerten und von vorn.

was dauert da länger als 60ms (1966 Clocks)?


Hansi

von Karl H. (kbuchegg)


Lesenswert?

Schmeiss endlich den Simulator an und miss es aus!

Dein im Nebel stochern bringt doch nix. Du verplemperst nur deine Zeit.

von Vlad T. (vlad_tepesch)


Lesenswert?

Oliver schrieb:
> Die ISR wird ja erst aufgerufen, wenn der ADC fertig meldet.
ebend.
wird der Wdt zwischendurch resetted?
> Und dann
> bleiben 1920 Zyklen, bis der wdt wieder zuschlägt. Das sollte für die
> paar Anweisungen ausreichen.

Hansi schrieb:
> Und nun??? Internen WDT Oszillator mit 125kHz als Taktquelle nehmen?
> Ich will sol wenig Strom wie möglich verbrauchen...

dann laufe mit 1Mhz und lege dich in den Power Down und lass dich von 
dem WDT wecken.
Ob du jetzt 10s mit 32kHz ackerst oder .3s mit 1Mhz -da  wird 
stromspartechnisch wahrscheinlich letzteres effektiver sein.

von Thomas E. (thomase)


Lesenswert?

Vlad Tepesch schrieb:
> Ob du jetzt 10s mit 32kHz ackerst oder .3s mit 1Mhz -da  wird
> stromspartechnisch wahrscheinlich letzteres effektiver sein.
Sehe ich auch so. Was für ein Controller ist das überhaupt?

mfg.

von Hansi (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Dein im Nebel stochern bringt doch nix. Du verplemperst nur deine Zeit.
Richtig, der Simulator zeigte Klarheit. Ich habe mit dem nur noch nie 
gearbeitet, aber ist ja relativ intuitiv...

Ich habe den Timer, der mit /* System tick with 7,8ms */
läuft falsch initialisiert, sodass der Timer0 im 16Bit Modus gelaufen 
ist und merkwürdigerweise trotzdem irgendwie funktioniert hat. Das es 
mir 1MHz lief, lag daran, dass das Programm eigentlich schon komplett 
ausgeführt worden war, bis der Timeout entstand...

*Schande über mein Haupt, dass is n dummer Anfängerfehler*

Ich benutze einen Tiny861. Nun läuft es im Simulator und auch 
hoffentlich in der Praxis am Montag. Besten Dank für alle Hilfen.



Hansi

von Karl H. (kbuchegg)


Lesenswert?

Und wieder mal zeigt sich.
Der Fehler war ganz woanders als vermutet.

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.