mikrocontroller.net

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


Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
#include <avr/io.h>
#include <avr/interrupt.h>
#include "config.h"
#include "uart-routines.h"

volatile unsigned char disp_update;
unsigned char display_updater;

void timer_init( void )
{
  setBits(TCCR0A, Bit(WGM01));    
  setBits(TCCR0B, Bit(CS01) | Bit(CS00));      
  OCR0A = (uint8_t)(XTAL / 64.0 * 1e-3 - 0.5);
  TIMSK0 |= 1<<OCIE0A;
  #define DISPUP    100L
  display_updater = (unsigned char)DISPUP;
}

int main (void)
{  
  usart_init(9600);
  timer_init();
  for(;;)
  {
    if(disp_update == 1)
    {
      //display_update(menu_count,disp_ebene);
      disp_update = 0;
      usart_puts("Display Update\n");
    }
  }  
  return 0;
}

ISR( TIMER0_COMPA_vect)
{  
  if( --display_updater == 0)
  {
    disp_update = 1;
    display_updater = (unsigned char)DISPUP;
  }
}
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

Autor: Peter R. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Floh (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mach den mal testweise volatile:

> unsigned char display_updater;

Autor: Helfer (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Glaskugel (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: idee (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.