Forum: Compiler & IDEs Merkwürdiges Verhalten bei Variablenaustausch zwischen ISR und Main


von Peter (Gast)


Lesenswert?

Hallo,
ich hab ein Problem, was ich nicht begreife: Ich schalte in einer ISR 
eine Variable und benutze diese, um im Mainloop ein Display alle 100ms 
zu updaten. Das Problem ist nur, das in der Mainloop die Funktion 
zweimal ausgeführt wird, obwohl die Variable zurückgesetzt wird. Als 
Controller verwende ich einen ATmega644 mit 16 MHz Der Code sieht wie 
folgt aus:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include "config.h"
4
#include "uart-routines.h"
5
6
volatile unsigned char disp_update;
7
unsigned char display_updater;
8
9
void timer_init( void )
10
{
11
  setBits(TCCR0A, Bit(WGM01));    
12
  setBits(TCCR0B, Bit(CS01) | Bit(CS00));      
13
  OCR0A = (uint8_t)(XTAL / 64.0 * 1e-3 - 0.5);
14
  TIMSK0 |= 1<<OCIE0A;
15
  #define DISPUP    100L
16
  display_updater = (unsigned char)DISPUP;
17
}
18
19
int main (void)
20
{  
21
  usart_init(9600);
22
  timer_init();
23
  for(;;)
24
  {
25
    if(disp_update == 1)
26
    {
27
      //display_update(menu_count,disp_ebene);
28
      disp_update = 0;
29
      usart_puts("Display Update\n");
30
    }
31
  }  
32
  return 0;
33
}
34
35
ISR( TIMER0_COMPA_vect)
36
{  
37
  if( --display_updater == 0)
38
  {
39
    disp_update = 1;
40
    display_updater = (unsigned char)DISPUP;
41
  }
42
}
Dabei seh ich mittels des UART das die Ausgabe einmal wiederholt wird, 
also zweimal erscheint. Woran liegt das?

Vielen Danke und mit freundlichen Grüßen
Peter

von Peter R. (Gast)


Lesenswert?

Andere Frage:
Warum setzt du deinen Timer nicht gleich so, dass er alle 100ms 
anschlägt und machst die Ausgabe auf das Display in der Timer ISR?
Setze doch mal einen Breakpoint in deine Main-Loop und schaue, was 
passiert.

von Oliver (Gast)


Lesenswert?

Peter schrieb:
> Dabei seh ich mittels des UART das die Ausgabe einmal wiederholt wird,
> also zweimal erscheint. Woran liegt das?

Was verstehst du unter "zweimal"? Die Programm schickt den Text alle 
100ms, das ist 10 mal pro Sekunde. Der müsste daher "dauernd" kommen.


Peter R. schrieb:
> Warum setzt du deinen Timer nicht gleich so, dass er alle 100ms
> anschlägt und machst die Ausgabe auf das Display in der Timer ISR?

Weil man das nicht so macht.

von Floh (Gast)


Lesenswert?

Mach den mal testweise volatile:

> unsigned char display_updater;

von Helfer (Gast)


Lesenswert?

> Warum setzt du deinen Timer nicht gleich so, dass er alle 100ms
> anschlägt und machst die Ausgabe auf das Display in der Timer ISR?

Dann läuft der Displayausgabecode unter den Bedingungen der aufrufenden 
ISR, d.h. mit gesperrten Interrupts. Wenn neben dem Timer-IRQ noch 
andere Interrupts benutzt werden, können diese währenddessen nicht 
abgearbeitet werden. Pro IRQ wird zwar ein Event gespeichert und es wird 
nach dem Verlassen der Timer-ISR ausgeführt. Aber wenn in der Sperrzeit 
mehr IRQs gleicher Sorte auftreten, gehen diese verloren. Es gehen auch 
Timer-IRQs verloren, wenn die Ausführung eines Timer-IRQ länger als 
100ms dauert.

von Peter (Gast)


Lesenswert?

Hallo,
also ich hab testweise:
<c>volatile unsigned char display_updater;</c>
gesetzt, brachte keinen Unterschied.
Wenn ich die Zeit auf 500 ms hochsetze, seh ich, dass jede halbe Sekunde 
2 Ausgaben ueber Uart kommen, damit wird die Bedingung zweimal 
abgearbeitet, dass meine ich.

Gruesse
Peter

von Glaskugel (Gast)


Lesenswert?

Vermutungen:

1. "Zweimal" bedeutet "Display Update" und "Display Update"
2. "Zweimal bedeutet "DDiissppllaayy UUppddaattee"

Was trifft zu?


Fehlende Informationen:

1. Quellcode "uart-routines.h" da Pgm. so für Aussenstehende nicht 
kompilierbar ist.
2. Compiler / IDE?
3. Definition von XTAL
4. Fuses; im besonderen Watchdog
5. Terminalprogramm und Einstellungen


Unschön aber vermutlich nicht Problem verursachend:

"#define DISPUP 100L" eingerückt und innerhalb Funktion; unnötig long; 
deswegen eigentlich unnötiges cast in "display_updater = (unsigned 
char)DISPUP;"


Schlussfolgerung:

Aus dem gezeigten Quellcode allein ist das Verhalten nicht erklärbar.

von idee (Gast)


Lesenswert?

Zähl doch mal nach der UART Ausgabe einen Counter hoch den du mit 
verschickst. Dann siehst du ob das Display wirklich 2mal geupdatet wird 
oder ob ein Fehler in der usart_puts ist.

von Peter (Gast)


Lesenswert?

Bei Vermutung trifft 1. zu, Counter hab ich eingebaut, zaehlt zweimal 
hoch, die uart Routine funktioniert wie gewollt.
xtal wird definiert mittels #define XTAL 16000000L
Watchdog ist abgeschaltet, avr-gcc 4.3.4 wird verwendet makefile kann 
ich morgen mal anhängen und minicom als Terminalprogramm, wenn ich die 
uart Routinen rausschmeisse und den Counter uebers lcd ausgeben lasse, 
trifft das verhalten trotzdem weiterhin auf.

Gruesse Peter

von Oliver (Gast)


Lesenswert?

Ist das oben wirklich der Original-Codeß

Denn ohne ein sei() an geeigneter Stelle gibt es grundsätzliche 
überhaupt keine Interrupts.

Wenn das sei() in usart_init() steckt, nimm das da raus, und setze es 
hinter den Aufruf von timer-init().

Oliver

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.