Switch-Case Anweisung kommt nicht zurück!

Gast #2521568
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
Gast #2521637
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.
#2521674
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.
#2521687
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;
Gast #2521690
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
Gast #2521703
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?
Gast #2521726
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.
Gast #2521743
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.
#2521780
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.
Gast #2521810
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
Gast #2521949
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
#2521995
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.
Gast #2522037
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren