Funktion im Main und Interrupt nutzen?

Gast #1289073
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...
#1289100
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
Gast #1289327
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
Gast #1289353
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...
#1289373
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
#1289378
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
Gast #1289392
Lesenswert?

Dann mache ich es mal ganz ordentlich... ;-)

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

3
...
4

5
char not_leap(void)
6
{
7
    if (!(clk_year_long%100))
8
        return (char)(clk_year_long%400);
9
    else
10
        return (char)(clk_year_long%4);
11
}         
12

13
...
14

15
//--- Interrupt Aufruf ---
16
ISR(TIMER2_OVF_vect) {
17
...
18
   if((clk.mon==2) && (not_leap())) {
19
      ...
20
   }
21
...
22
}
23

24
...
25

26
//--- Main Aufruf ---
27
...
28
   if (not_leap()) {
29
      ...
30
   }
31
...


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...

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

5
//--- ISR - UART Dataregister EMPTY
6
ISR(USART0_UDRE_vect)
7
{
8
  if (pos_out_uart_tx == pos_in_uart_tx) {
9
    CLEAR_BIT(UCSR0B,UDRIE0);
10
  }
11
  else {
12
    UDR0 = buf_uart_tx[pos_out_uart_tx];
13
    pos_out_uart_tx ++;
14
    pos_out_uart_tx = pos_out_uart_tx & 0x1FF;
15
  }
16
}
17

18
...
19

20
void tx_char_uart(char chrtx) {
21
  buf_uart_tx[pos_in_uart_tx] = chrtx;
22
  pos_in_uart_tx++;
23
  pos_in_uart_tx = pos_in_uart_tx & 0x1FF;
24
  SET_BIT(UCSR0B,UDRIE0);
25
}


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

Gruß AVRli...
#1289409
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.
Gast #1289552
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.
Gast #1289665
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
Gast #1290023
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...
#1290038
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
Gast #1290191
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...
Gast #1290354
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.
Persönliche Seite #1290355
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.
1
#include <util/atomic.h>
2

3
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
4
{
5
    ....
6
}

gibts auch noch.

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