www.mikrocontroller.net

Forum: Compiler & IDEs Funktion im Main und Interrupt nutzen?


Autor: AVRli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo! :-)

Ich vermute das ich einen Ablauffehler habe durch die Nutzung eines 
Unterprogrammes im Interrupt und im Main Programm.

Ich arbeite mit AVR Studio/GGC und einem ATmega 644.

Die Funktion macht einen Vergleich von Variablen und gibt mit 1 oder 0 
zurück.

Nun nutze ich diese einmal im Interrupt und in einem bestimmten Zustand 
brauche ich den Vergleich auch im Main Programm.

Kann es passieren das da irgenwas aus dem Ruder läuft? Gleizeitiger 
Zugriff oder der gleichen?

Wenn ja, muß ich dieses Unterprogramm zur Sicherheit einmal extra für 
das Main und einmal für das Interrupt Programm schreiben oder gibt es 
einen anderen Weg?


Vielen Dank für Eure Hilfe.

Gruß AVRli...

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@  AVRli (Gast)

>Nun nutze ich diese einmal im Interrupt und in einem bestimmten Zustand
>brauche ich den Vergleich auch im Main Programm.

>Kann es passieren das da irgenwas aus dem Ruder läuft? Gleizeitiger
>Zugriff oder der gleichen?

Ja, siehe Interrupt, atomarer Zugriff.

>Wenn ja, muß ich dieses Unterprogramm zur Sicherheit einmal extra für
>das Main und einmal für das Interrupt Programm schreiben oder gibt es
>einen anderen Weg?

Man kann die Interrupts kurzzeitig sperren.

MFG
Falk

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Kann es passieren das da irgenwas aus dem Ruder läuft? Gleizeitiger
>Zugriff oder der gleichen?

Ja, siehe ausserdem Reentranz.

http://de.wikipedia.org/wiki/Eintrittsinvarianz

Wenn du z.B. statische Variablen in der Funktion nutzt, geht es schief, 
ebenso bei vielen library-Funktionen.

>Die Funktion macht einen Vergleich von Variablen und gibt mit 1 oder 0
>zurück.

Das klingt jetzt nicht so kompliziert, als daß sich das, falls 
erforderlich, nicht auch zweimal implementieren ließe.

Oliver

Autor: AVRli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo und danke für Eure Antworten,

ich werde den Vergleich zweimal schreiben. Einmal für den INT und einmal 
für das MAIN Programm. Den Platz habe ich schon (nehme ich mir eben)...

Was mich aber viel mehr erschrecken ließ ist folgenes:

Ich habe ebend mir den Abschnitt Interrupt im Beitrag GGC 
AVR-GCC-Tutorial durchgelesen. Da stolperte ich über die Aussage das man 
Variablen als volatile deklarieren muß um diese gleichzeitig im INT als 
auch im MAIN Programm zu nutzen. Ok das habe ich auch immer gemacht! Nur 
funktioniert es nach dem was da steht nicht bei Werten die "breiter" als 
8 bit sind. Also ein 16 bit Zähler oder einen Struct Variable???

Ohh man da muß ich wohl mein ganzen Programm nochmal durchgehen. :-( Ich 
habe schon einige 16bit Zähler die im INT und im MAIN Programm benutzt 
werden.

Ist mir bis jetzt auch nie aufgefallen das es zu Problemen führt.
Wie handelt man das nun... :-(

Gruß AVRli...

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
AVRli schrieb:
> Die Funktion macht einen Vergleich von Variablen und gibt mit 1 oder 0
> zurück.

Schreib doch einfach mal die Funktion hin, dann kann man leicht sehen, 
obs Probleme geben könnte.

Ein Quelltext sagt mehr als 1000 Worte !!!

Warum die Leute immer ihr Problem erstmal umständlich umschreiben 
müssen, statt einfach nur copy&paste.


Peter

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
AVRli schrieb:
> Ist mir bis jetzt auch nie aufgefallen das es zu Problemen führt.
> Wie handelt man das nun... :-(

Benutze mal den neuesten WINAVR, da gibt es ne hübsche "atomic.h", das 
ist genau die richtige Medizin für alle diese Probleme.

Aber drauf achten, daß man nicht versehentlich langsame 
Funktionsaufrufe, Divisionen, float o.ä. in das atomic mit einpackt, 
also wirklich nur die Parameterübergabe.


Peter

Autor: AVRli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dann mache ich es mal ganz ordentlich... ;-)

als erstes meine Funktion mit dem Vergleich...
volatile uint16_t clk_year_long;    // Int/Main use

...

char not_leap(void)
{
    if (!(clk_year_long%100))
        return (char)(clk_year_long%400);
    else
        return (char)(clk_year_long%4);
}         

...

//--- Interrupt Aufruf ---
ISR(TIMER2_OVF_vect) {
...
   if((clk.mon==2) && (not_leap())) {
      ...
   }
...
}

...

//--- Main Aufruf ---
...
   if (not_leap()) {
      ...
   }
...


Die Abfrage ist die, die man zweimal schreiben könnte wenn man es dann 
muß.
Und nun noch ein Beiepiel wo ich einen 16bit Zähler verwende...

volatile  uint8_t buf_uart_tx[512];    // UART TX-Buffer
volatile uint16_t pos_in_uart_tx;    // UART TX-Buffer Position bis wo Zeichen eingefügt wurden
volatile uint16_t pos_out_uart_tx;    // UART TX-Buffer Position bis wo Zeichen gesendet wurden

//--- ISR - UART Dataregister EMPTY
ISR(USART0_UDRE_vect)
{
  if (pos_out_uart_tx == pos_in_uart_tx) {
    CLEAR_BIT(UCSR0B,UDRIE0);
  }
  else {
    UDR0 = buf_uart_tx[pos_out_uart_tx];
    pos_out_uart_tx ++;
    pos_out_uart_tx = pos_out_uart_tx & 0x1FF;
  }
}

...

void tx_char_uart(char chrtx) {
  buf_uart_tx[pos_in_uart_tx] = chrtx;
  pos_in_uart_tx++;
  pos_in_uart_tx = pos_in_uart_tx & 0x1FF;
  SET_BIT(UCSR0B,UDRIE0);
}


Mit tx_char_uart() wird das Zeichen in den Buffer übertragen.
Nun bleibt zu hoffen das man versteht was ich da mache...

Gruß AVRli...

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Die Abfrage ist die, die man zweimal schreiben könnte wenn man es dann
> muß.

Das bringt aber nicht wirklich viel, denn auch bei zwei Funktionen muss 
der Zugriff auf clk_year_long geschützt werden. Der einzige Vorteil ist, 
dass dieser Schutz dann nur in einer Funktion nötig ist (in der, die von 
main aufgerufen wird), und der Interrupt dadurch geringfügig schneller 
ist. Ich würde nur eine Funktion machen, die dann aber inlinen 
(insbesondere im Interrupt).

> char not_leap(void)

"char" solltest du nur nehmen, wenn es tatsächlich um Zeichen geht. 
Ansonsten "unsigned char" oder "signed char". Oder warum nicht uint8_t? 
uint16_t benutzt du doch auch.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mein Vorschlag für die Funktion:
#include <util/atomic.h>
...
uint8_t not_leap (void) {

    uint16_t year;

    ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
        year = clk_year_long;
    }

    if (!(year % 100))
        return year % 400;
    else
        return year % 4;
}         

Autor: Ahem (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Äh, ich frage mich ob eine Berechnung bezüglich eines Jahres nun 
wirklich in einem Interrupt geschehen muss. Die Jahreszahl ändert sich 
sooooo langsam. Das kann man entweder vorher, so zur Teezeit am 31.12. 
berechnen oder irgendwann am 1.1. wenn der Kater verflogen ist.
Das alles scheint mir eher auf einen Designfehler hinzudeuten, wenn es 
auch als Lehrstück bzg. volatile usw. hiflreich sein kann.

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Die Abfrage ist die, die man zweimal schreiben könnte wenn man es dann
> muß.

Muß man nicht. Probleme gäbe es, wenn die Funktion interne Zustände 
speichern würde, die dann bei "parallelem" Aufruf überschrieben würden. 
Das ist bei den paar Zeilen aber nicht der Fall.

Oliver

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was spricht dagegen einen einfachen 32 Bit Timestamp im Timerinterrupt 
hochzuzählen, statt so ne "Orgie" zu veranstalten? Interruptroutinen 
sollten so klein wie möglich sein.

Autor: AVRli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für Eure Antworten!

Kann jemand noch ein Statement zu meiner 16bit Zähler Nutzung geben?
Ich habe auch meine Literatur nochmal durchgeblättert. (C Buch für AVR 
controller), da werden 16bit Zähler auch im Main und Interrupt genutzt 
und werden auch nur mit volatile "geschützt".

Hmm ich glaube ja bald das ich noch nicht ganz begriffen habe wann es zu 
Problemen kommen kann und wann nicht.

Wo kann man sich über die atomic funktion informieren?

Gruß AVRli...

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@  AVRli (Gast)

>Kann jemand noch ein Statement zu meiner 16bit Zähler Nutzung geben?

siehe Interrupt.

>Ich habe auch meine Literatur nochmal durchgeblättert. (C Buch für AVR
>controller), da werden 16bit Zähler auch im Main und Interrupt genutzt
>und werden auch nur mit volatile "geschützt".

Ist unter BESTIMMTEN Umständen möglich, z.B. im Zusammenhang mit dem 
Sleep Mode, kann aber auch schief gehen.

>Wo kann man sich über die atomic funktion informieren?

In der Doku der libc, ist irgendwo im WinAVR Verzeichnis is drinnen.

MfG
Falk

Autor: AVRli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

na dann werde ich mal meine ganzen Programme durchforsten wo ich 16 bit 
Zähler im Int und Main verwende.

Ziel ist es dann immer die Int zu sperren wenn man auf die Zähler im 
Main Programm zugreift.

Danke und Gruß AVRli...

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Ziel ist es dann immer die Int zu sperren wenn man auf die Zähler im
>Main Programm zugreift.

Vorher ein CLI und hinterher ein SEI...
So behandelt man doch immer Variablen, die "atomic" behandelt werden 
müssen.

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
STK500-Besitzer schrieb:
>>Ziel ist es dann immer die Int zu sperren wenn man auf die Zähler im
>>Main Programm zugreift.
>
> Vorher ein CLI und hinterher ein SEI...
> So behandelt man doch immer Variablen, die "atomic" behandelt werden
> müssen.
#include <util/atomic.h>

ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
{
    ....
}

gibts auch noch.

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.