Forum: Compiler & IDEs Pointer in ISRs


von Hundertvolt (Gast)


Lesenswert?

Hallo,

bin mir nicht sicher, aber für mich sieht das folgende fast nach einem 
Compilerbug aus...

Ich hab versucht, eine interruptgesteuerte UART auf einem Mega32 zu 
machen, die Strings bis zu einem definierten Endzeichen empfängt / 
sendet.

Das ganze sollte so funktionieren: Ich lege globale Variablen für 
Eingangspuffer (RXBUF) und Ausgangspuffer (TXBUF) an und stoße dann das 
Senden / Empfangen über eine Funktion an, die die Pointer übergibt und 
die Interrupts freigibt, dann läuft alles von alleine weiter.

So weit, so gut. Ich rufe die Funktion auf und übergebe ihr einen 
Pointer, am Beispiel "senden":

1
void uart_puts (unsigned char *t)

in der Funktion weise ich dann die Adresse dem Sendepuffer zu:
1
TXBUF=t;
 (TXBUF ist ein Pointer vom Typ char).

und dann sende ich irgendwo die Sache weg mit:
1
UDR = TXBUF;
2
TXBUF++;
und warte, bis es weg ist, wieder von vorne, und so weiter, also fast 
wie im Beispiel im Tutorial.

Klappt auch wunderbar - so lange ich das außerhalb der Interrupt Service 
Routine mache. Sobald ich UDR=TXBUF in der ISR mache, kommt nur noch 
Datenmüll heraus, oder gar nichts, mal so, mal so.

Folgende Definitionen von TXBUF habe ich schon versucht:
1
unsigned char *TXBUF;
2
unsigned char *volatile TXBUF;
3
volatile unsigned char *TXBUF;
4
volatile unsigned char *volatile TXBUF;
alle mit dem gleichen Ergebnis - außerhalb der ISR lässt sich die 
Pointeradresse anderen Variablen über mehrere Ecken zuweisen, 
hochzählen, und es stimmt immer alles. In der ISR geht genauso 
zuverlässig alles daneben.

In meinem Buch (C für Mikrocontroller) steht drin, dass es so 
funktioniert, im Tutorial auch. Wo hakt es denn jetzt noch???

von P. S. (Gast)


Lesenswert?

Es hakt beim fehlenden Sourcecode. So ist dir nicht zu helfen.

von Ahem (Gast)


Lesenswert?

>TXBUF ist ein Pointer vom Typ char
Sicherlich ist es das nicht. Sowas gibt es nämlich in C nicht.
Vielmehr ist TXBUF, wenn überhaupt ein Zeiger auf eine Variable vom Typ 
char.
Ein Pointer hat keinen Typ.

Als ich das hier:

UDR = TXBUF;

las, wurde mir kariert vor den Augen. ;-)
Falls und wenn TXBUF ein Zeiger ist, was steht dann danach in UDR?
Ein Zeiger? Was soll der dort?

Wenn, dann also

UDR = *TXBUF;

Die ganze Zeigerei in C ist etwas schwierig. Das Kapitel in K&R lesen, 
und ein halbes Jahr unters Kopfkissen tun, wäre angemessen.

von Hundertvolt (Gast)


Lesenswert?

>Als ich das hier:

>UDR = TXBUF;

>las, wurde mir kariert vor den Augen. ;-)

Klar, war ja auch n Tippfehler im Beitrag... ^^

So, aber nu zum Sourcecode der Routine:
1
 volatile unsigned char *TXBUF;    // Sendepuffer
2
3
4
 
5
 ISR(USART_UDRE_vect)         //Interrupt: UART UDR empty
6
{
7
  if (*TXBUF)            //anderes Zeichen als NULL zu senden
8
    {
9
    UDR = *TXBUF;        //Zeichen aus aktueller Pufferstelle an TX-Register
10
    TXBUF++;          //Pufferstelle auf nächstes Zeichen
11
    }
12
  else
13
    {
14
    UCSRB &= ~(1<<UDRIE);    //Wenn NULL (Stringende erreicht), Interrupt ausschalten
15
    }
16
} 
17
 
18
  
19
 
20
21
unsigned char uart_puts (unsigned char *Ausgang)  //Zeichen über UART senden
22
{  
23
  if (UCSRB & (1<<UDRIE))    //schon eine Übertragung am Laufen, d.h. Interrupt aktiviert?
24
    {
25
    return 1;          //Fehler: Bereits am Senden
26
    }
27
  else
28
    {
29
    TXBUF=Ausgang;          //zu übertragenden String in Puffer schreiben
30
    UCSRB |= (1 << UDRIE);   //Interrupt einschalten zum Sendestart
31
    return 0;          //TX beginnt fehlerfrei
32
    }
33
}

...und wenn ich den Inhalt aus der ISR unverändert in eine "normale" 
Funktion übernehme, geht es. Nur so wie hier gezeigt kommt Datenmüll 
raus.

von Ahem (Gast)


Lesenswert?

>Klar, war ja auch n Tippfehler im Beitrag... ^^

Deswegen steht ja auch in allen möglichen Foren und Beiträgen im 
Internet zum Posten, das man Code NICHT abtippt sonder kopiert.

Und als ich das las, wurden aus den Karos bunte Kreise:

TXBUF=Ausgang; //zu übertragenden String in Puffer schreiben

Das kopiert eigentlich nur den Zeiger aber nicht den String aus einem 
Puffer in den anderen.

Was heisst "Datenmüll"? Kannst Du das mal genauer beschreiben?

Und poste bitte kompletten Code. Hier fehlt die Initialisierung des 
UARTs und main.

Und bitte nicht alles einzeln aus der Nase ziehen lassen, ja? Danke.

von Ahem (Gast)


Lesenswert?

Was ist das überhaupt? Wenn schon eine Übertragung läuft, dann kommt die 
Funktion mit Fehler zurück?
Und was macht dann Dein Programm?
Mit zusammengekniffenen Beinen herumhopsen?

Mach lieber einen gescheiten Ringpuffer.

von Mark B. (markbrandis)


Lesenswert?

Du hast also einen Zeiger auf den Sendepuffer. Und wo legst Du den 
Sendepuffer selbst an? Welche Größe hat er?
Bevor man einen Zeiger inkrementiert oder dekrementiert, sollte man sich 
vergewissern, dass er danach nicht ins Nirvana zeigt. ;-)
Beliebt ist auch der Fehler, einen Zeiger anzulegen, ihn aber nicht 
vernünftig zu initialisieren. Also z.B. nach

volatile unsigned char *TXBUF;

hat man einen Zeiger, der noch überhaupt nichts kann. Besser wird's mit 
z.B.

TXBUF = &Mein_Puffer;

von Hundertvolt (Gast)


Lesenswert?

Das Programm soll so funktionieren:
1. schicke String vom Typ Char an Funktion uart_puts
2. kopiere den Pointer auf den String an TXBUF, d.h. TXBUF soll an die 
gleiche Adresse zeigen wie der übergebene Pointer auf den String.
3. Interrupt einschalten, damit die ISR den String Zeichen für Zeichen 
sendet.
4. wenn fertig, Interrupt wieder ausschalten und Senden stoppen.

Während des Sendens soll uart_puts keine weiteren Daten annehmen, damit 
der Inhalt von *TXBUF sich nicht mitten in einer Übertragung ändern 
kann, und dann gibt es den Returncode 1, damit die aufrufende Funktion 
Bescheid bekommt, es später nochmal zu versuchen.

>TXBUF=Ausgang; //zu übertragenden String in Puffer schreiben

>Das kopiert eigentlich nur den Zeiger aber nicht den String aus einem
>Puffer in den anderen.

Keine bunten Kreise, sondern genau das, was ich will!

Nochmal, um es zu verdeutlichen. Ich möchte NICHT den String kopieren, 
ich möchte einen Pointer auf die Anfangsadresse des bereits im Speicher 
vorhandenen Strings in TXBUF schreiben und damit der ISR übergeben.

Das kann nicht so "schlimm" sein, weil ich es 1. in vielen Beispielcodes 
so gesehen habe und 2. es klappt ja!!! Außerhalb der ISR!

Übrigens, wenn ich in der ISR ein fest definiertes Zeichen statt dem 
String schicke, klappt es auch, also die ISR wird einwandfrei 
angesprochen.


>hat man einen Zeiger, der noch überhaupt nichts kann. Besser wird's mit
>z.B.

>TXBUF = &Mein_Puffer;

laut meinem Buch sehe ich das auch so. GCC schluckt das "&" bei mir aber 
nicht, der erwartet immer einen zweiten Operanden.


Hier nochmal das gaze Programm, nicht über die komische Initialisierung 
von "Line" wundern, das war Teil meiner Testerei. Es soll die Zeichen 
"abc" einmal in der Sekunde über die UART ausgeben.
1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <avr/interrupt.h>
4
#include <util/setbaud.h>
5
6
#define BAUD 38400
7
8
 
9
 volatile unsigned char *TXBUF;    // Sendepuffer
10
11
12
 
13
 ISR(USART_UDRE_vect)         //Interrupt: UART UDR empty
14
{
15
  if (*TXBUF)            //anderes Zeichen als NULL zu senden
16
    {
17
    UDR = *TXBUF;        //Zeichen aus aktueller Pufferstelle an TX-Register
18
    TXBUF++;          //Pufferstelle auf nächstes Zeichen
19
    }
20
  else
21
    {
22
    StatusBits.TX_Active = 0;   //Merkerbit zurücksetzen
23
    UCSRB &= ~(1<<UDRIE);    //Wenn NULL (Stringende erreicht), Interrupt ausschalten
24
    }
25
} 
26
 
27
  
28
 
29
30
unsigned char uart_puts (unsigned char *Ausgang)  //Zeichen über UART senden
31
{  
32
  if (UCSRB & (1<<UDRIE))    //schon eine Übertragung am Laufen, d.h. Interrupt aktiviert?
33
    {
34
    return 1;          //Fehler: Bereits am Senden
35
    }
36
  else
37
    {
38
    TXBUF=Ausgang;          //zu übertragenden String in Puffer schreiben
39
    UCSRB |= (1 << UDRIE);   //Interrupt einschalten zum Sendestart
40
    return 0;          //TX beginnt fehlerfrei
41
    }
42
}
43
 
44
 
45
 
46
 
47
int main (void) {      
48
     
49
   unsigned char Line[22];      // String zum Senden
50
   
51
   UBRRH = UBRRH_VALUE;
52
   UBRRL = UBRRL_VALUE;
53
   
54
   
55
   UCSRB |= ((1<<TXEN)|(1<<RXEN));                 // UART TX + RX einschalten
56
   UCSRC |= (1<<URSEL)|(1 << UCSZ1)|(1 << UCSZ0); // Asynchron 8N1 
57
  
58
   sei();
59
 
60
   while(1) {                
61
62
63
 _delay_ms(1000);
64
  
65
66
Line[0]='a';
67
Line[1]='b';
68
Line[2]='c';
69
Line[3]='\0';
70
71
72
uart_puts(Line);
73
74
75
      }                        
76
  
77
   return 0;                
78
}

von Stefan E. (sternst)


Lesenswert?

1
volatile unsigned char *TXBUF;
Nicht der Inhalt deines Puffers muss volatile sein, sondern der Pointer.
Also:
1
unsigned char * volatile TXBUF;

von Hundertvolt (Gast)


Lesenswert?

Wie gesagt, ich habe diese 4 Deklarationen versucht:
1
unsigned char *TXBUF;
2
unsigned char *volatile TXBUF;
3
volatile unsigned char *TXBUF;
4
volatile unsigned char *volatile TXBUF;

alle erfolglos. Muss ich vielleicht auch den Übergabepointer (*Ausgang) 
als volatile machen, damit es alles richtig von den Registern ins RAM 
kommt?

von Mark B. (markbrandis)


Lesenswert?

Hundertvolt wrote:
>>TXBUF = &Mein_Puffer;
>
> laut meinem Buch sehe ich das auch so. GCC schluckt das "&" bei mir aber
> nicht, der erwartet immer einen zweiten Operanden.

Der Adressoperator ist C-Standard... was für eine Meldung bringt denn 
der Compiler? Vielleicht will er ein
1
TXBUF = &Mein_Puffer[0];

sehen.

von Gast (Gast)


Lesenswert?

Ist Mein_Puffer ein char array, so sind Mein_Puffer und &Mein_Puffer[0] 
identisch. &Mein_Puffer macht keinen sinn, da es ja die Adresse von der 
Adresse wäre, die der Compiler hier aber in den meisten Fällen wohl fest 
einsetzen kann, da er weis wo die Variable liegt.

Ich würde dir mal dazu raten mit Single Stepping im Simulator 
dadurchzugehen, dann siehst du wo die Daten verloren gehen.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Hundertvolt wrote:

> Hier nochmal das gaze Programm, nicht über die komische Initialisierung
> von "Line" wundern, das war Teil meiner Testerei. Es soll die Zeichen
> "abc" einmal in der Sekunde über die UART ausgeben.
>
> #include <avr/io.h>
> #include <util/delay.h>
> #include <avr/interrupt.h>
> #include <util/setbaud.h>
>
> #define BAUD 38400
1
./lib/gcc/../../avr/include/util/setbaud.h:117:4: error: #error "setbaud.h requires BAUD to be defined"
2
./lib/gcc/../../avr/include/util/setbaud.h:125:4: error: #error "BAUD must be a constant value"
3
./lib/gcc/../../avr/include/util/setbaud.h:197:11: error: division by zero in #if
4
./lib/gcc/../../avr/include/util/setbaud.h:212:10: error: division by zero in #if
5
./lib/gcc/../../avr/include/util/setbaud.h:217:10: error: division by zero in #if

>     StatusBits.TX_Active = 0;   //Merkerbit zurücksetzen
1
./lib/gcc/../../avr/include/util/delay.h:85:3: warning: #warning "F_CPU not defined for <util/delay.h>"
2
./lib/gcc/../../avr/include/util/setbaud.h:213:4: warning: #warning "Baud rate achieved is higher than allowed"
3
n function '__vector_14':
4
error: 'StatusBits' undeclared (first use in this function)
5
error: (Each undeclared identifier is reported only once
6
error: for each function it appears in.)


> unsigned char uart_puts (unsigned char *Ausgang)  //Zeichen über UART
> senden
> {
>   if (UCSRB & (1<<UDRIE))    //schon eine Übertragung am Laufen, d.h.
> Interrupt aktiviert?
>     {
>     return 1;          //Fehler: Bereits am Senden
>     }
>   else
>     {
>     TXBUF=Ausgang;          //zu übertragenden String in Puffer
> schreiben
>     UCSRB |= (1 << UDRIE);   //Interrupt einschalten zum Sendestart
>     return 0;          //TX beginnt fehlerfrei
>     }
> }

Setze ein Flag der ISR, und zwar wenn die Kommunikation fertig ist; 
nicht wenn das Datenregister leer ist!

>    unsigned char Line[22];      // String zum Senden

Line ist nach Verlassen von main ungültig.

Die UART-Initialisierung ist unvollständig (TXC löschen, evtl. Flush 
receive buffer)


Johann

von P. S. (Gast)


Lesenswert?

Hundertvolt wrote:

>     StatusBits.TX_Active = 0;   //Merkerbit zurücksetzen

Und woher ist StatusBits? Das ist doch schon wieder nicht das echte 
Programm, du verarschst hier die Leute :-(

von Peter D. (peda)


Lesenswert?

Hundertvolt wrote:
> Das kann nicht so "schlimm" sein, weil ich es 1. in vielen Beispielcodes
> so gesehen habe und 2. es klappt ja!!! Außerhalb der ISR!

Kannst Du mal nen Link auf solche Beispiele angeben, ich hab sowas noch 
nie gesehen.
Ich hab auch noch nie gesehen, daß Ausgabefunktionen nen Returnwert 
abprüfen und die Sendung später wiederholen.


UART-Ausgaben benutzen üblicher Weise einen Ringpuffer und nen Funktion 
putchar, mit der man Bytes in den Ringpuffer stellt. Ist kein Platz mehr 
im Puffer, wartet putcher.
Geprüft wird nix, nachdem putchar beendet ist, geht man davon aus, daß 
die Bytes auch gesendet werden.
Dem Ringpuffer ist es auch egal, ob es Text- oder Binärdaten sind.


Ein funktionierender Ringpuffer:

Beitrag "AVR-GCC: UART mit FIFO"

Er benutzt mit Absicht keine Pointer, da die auf nem 8-Bitter nicht 
atomar zugegriffen werden können. Es wären also mit Pointer in den 
Main-Funktionen an mehreren Stellen CLI/SEI-Sequenzen nötig.


Peter

von Philipp B. (philipp_burch)


Lesenswert?

Häng' doch mal das Disassembly an. Besonders das Kompilat der ISR wäre 
interessant.

von peterguy (Gast)


Lesenswert?

@TE: Ich kenn mich jetzt weder mit dem Mega32, noch mit der UART 
Schnittstelle gut aus, aber sollte man nicht üblicherweise das 
Interruptflag zurücksetzten, nachdem die ISR abgearbeitet wurde?

So in etwa:
1
ISR(USART_UDRE_vect)         //Interrupt: UART UDR empty
2
{
3
  if (*TXBUF)            //anderes Zeichen als NULL zu senden
4
    {
5
    UDR = *TXBUF;        //Zeichen aus aktueller Pufferstelle an TX-Register
6
    TXBUF++;          //Pufferstelle auf nächstes Zeichen
7
    }
8
  else
9
    {
10
    StatusBits.TX_Active = 0;   //Merkerbit zurücksetzen
11
    UCSRB &= ~(1<<UDRIE);    //Wenn NULL (Stringende erreicht), Interrupt ausschalten
12
    }
13
    USART_UDRE_Interruptflag = 1; // Interruptflag zurücksetztn. Üblicherweise durch schreiben einer 1
14
}

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

peterguy wrote:
> @TE: Ich kenn mich jetzt weder mit dem Mega32, noch mit der UART
> Schnittstelle gut aus, aber sollte man nicht üblicherweise das
> Interruptflag zurücksetzten, nachdem die ISR abgearbeitet wurde?
1
When the Data Register empty Interrupt Enable (UDRIE) bit in
2
UCSRB is written to one, the USART Data Register Empty Interrupt
3
will be executed as long as UDRE is set (provided that global
4
interrupts are enabled). UDRE is cleared by writing UDR. When
5
interrupt-driven data transmission is used, the Data Register
6
Empty Interrupt routine must either write new data to UDR in
7
order to clear UDRE or disable the Data Register empty Interrupt,
8
otherwise a new interrupt will occur once the interrupt routine
9
terminates.

von Falk B. (falk)


Lesenswert?

Ein funktionierendes Beispiel gibt es im Artikel Interrupt

von Hundertvolt (Gast)


Lesenswert?

> Und woher ist StatusBits? Das ist doch schon wieder nicht das echte
> Programm, du verarschst hier die Leute :-(

Ein übersehenes Überbleibsel aus der Testerei. Genau, und weil meine 
Seele so tiefschwarz ist, mache ich das alles nur, um Leuten Böses zu 
tun - und an ganz schlechten Tagen schieße ich mit Absicht Hochspannung 
in Mikrocontroller ;-)

Okay, Spaß beiseite, das im Artikel "Interrupt" ist ja fast sowas wie 
meins. Die Idee bei mir war halt, mir das strcpy zu sparen und damit RAM 
zu sparen.

Was mich bei dem Beipiel wundert, da sind Strings als globale char 
definiert, die auch ohne "volatile" in den ISRs benutzt werden - das 
geht gut?? Bei der RX-Routine wird direkt draufgeschrieben, bei der 
TX-Routine wird zusätzlich ein lokaler Pointer erzeugt. Warum?

Und um es nochmal kurz zu machen, ich will bei mir in einer globalen 
Variablen einen lokalen Pointer auf char speichern, der dann von einer 
ISR benutzt wird und der nach der Rückkehr aus der ISR wieder lokal - 
aber sein Ziel gefüllt mit den Daten - verfügbar ist. Dann muss ich nur 
einmal das RAM belegen, nicht 2mal. Geht das prinzipiell?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Hundertvolt wrote:
>> Und woher ist StatusBits? Das ist doch schon wieder nicht das echte
>> Programm, du verarschst hier die Leute :-(
>
> Ein übersehenes Überbleibsel aus der Testerei. Genau, und weil meine
> Seele so tiefschwarz ist, mache ich das alles nur, um Leuten Böses zu
> tun

Immerhin versuchen andere deine Probleme nachzuvollziehen. Man sollte 
daher soweit entgegenkommend sein, daß sich die Probleme auch möglichst 
git reproduzieren/nachvollziehen lassen. Siehe
   Beitrag "Re: Pointer in ISRs"

Wenn im Code private Header sind, Pünktchen ... (ausser in 
varargs-Funktionen), oder sonstige unbekannte 
Makros/Deklarationen/Funktionen kann das irgendwas sein. Ebenso 
mysteriös ist oft die verwendeten Privat-Hardware, der verwendete 
Compiler, seine Optionen, Version, etc.

> Und um es nochmal kurz zu machen, ich will bei mir in einer globalen
> Variablen einen lokalen Pointer auf char speichern, der dann von einer
> ISR benutzt wird und der nach der Rückkehr aus der ISR wieder lokal -
> aber sein Ziel gefüllt mit den Daten - verfügbar ist. Dann muss ich nur
> einmal das RAM belegen, nicht 2mal. Geht das prinzipiell?

Nein, auch wenn es hier in dem Beispiel keine Probleme macht: Du legst 
eine Kopie eines lokalen Zeigers an. Die Kopie bleibt auch noch dann 
bestehen, wenn der Zeiger selbst ungültig ist, weil die Funktion (main) 
in der der Zeiger (Line), und das worauf er zeigt (der Text) verlassen 
wurden.

Johann

von Hundertvolt (Gast)


Lesenswert?

Also in anderen Worten, ich komme um strcopy nicht herum, hab ich das 
richtig verstanden?

Ich dachte halt, es gäbe vielleicht irgendeine Möglichkeit, beim 
Empfangen clever die empfangenen Bytes direkt in einen String einer 
Funktion reinschreiben, ohne sie nochmal zwischenpuffern zu müssen. 
Wirklich keine Chance...?

Danke so weit!

von Peter D. (peda)


Lesenswert?

Hundertvolt wrote:
> Ein übersehenes Überbleibsel aus der Testerei. Genau, und weil meine
> Seele so tiefschwarz ist, mache ich das alles nur, um Leuten Böses zu
> tun - und an ganz schlechten Tagen schieße ich mit Absicht Hochspannung
> in Mikrocontroller ;-)


Es gibt nen ganz einfachen simplen Trick, wenn man Code in Foren posten 
will, man compiliert ihn.
Und wenn er dann mit 0 Error/Warnings durchläuft, postet man ihn genauso 
(als Anhang).
Natürlich prüft man auch, ob er das Fehlerverhalten immer noch zeigt.

Damit hat man schonmal mindestens 80% an unnötigen Rückfragen und 
Mißverständnissen erschlagen.


Und wenn man zu diesem kleinen Schritt zu faul ist, muß man eben 
unwirsche Reaktionen oder Schweigen im Walde ertragen können.


Peter

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Hundertvolt wrote:
> Also in anderen Worten, ich komme um strcopy nicht herum, hab ich das
> richtig verstanden?
>
> Ich dachte halt, es gäbe vielleicht irgendeine Möglichkeit, beim
> Empfangen clever die empfangenen Bytes direkt in einen String einer
> Funktion reinschreiben, ohne sie nochmal zwischenpuffern zu müssen.
> Wirklich keine Chance...?

Verwende als Puffer keine auto, sondern ne statische Variable. Die ist 
unabhängig vom Aufrufer deiner Ausgabefunktion gültig. Du must 
allerdings sicherstellen, daß vor Beendigung der Sendung niemand in der 
Puffer schreibt. D.h. nicht ver Versenden ist zu prüfen, ob noch eine 
Transaktion läuft, sondern beim Befüllen des Puffers.

Johann

von Peter D. (peda)


Lesenswert?

Hundertvolt wrote:
> Ich dachte halt, es gäbe vielleicht irgendeine Möglichkeit, beim
> Empfangen clever die empfangenen Bytes direkt in einen String einer
> Funktion reinschreiben, ohne sie nochmal zwischenpuffern zu müssen.
> Wirklich keine Chance...?

Es gibt noch die Möglichkeit, anstelle eines Ringpuffers einen 
Linearpuffer zu verwenden. Dann stehen alle Zeichen am Anfang und man 
kann direkt im Puffer die Zeichen auswerten.
Man muß allerdings nach der Auswertung alle zwischenzeitlich empfangenen 
Bytes wieder an den Anfang zurückkopieren, damit der Linearpuffer nicht 
überläuft.
Der RAM-Bedarf sinkt etwas, aber der Code wird komplexer.

Ich hab das früher mal gemacht, benutze jetzt aber doch lieber den 
Ringpuffer.


Peter

von Hundertvolt (Gast)


Lesenswert?

Nach reichlich Überlegung bin ich inzwischen dazu gekommen, das auch als 
Ringpuffer zu machen.

Erstmal großes Dankeschön an alle!

Eine Frage hätte ich aber noch: Im Tut und im Interrupt-Artiklel steht, 
alle globalen Variablen sowie Pointer und / oder deren Ziele, die sowohl 
in ISRs als auch in Funktionen benutzt und verändert werden, sollte man 
als volatile anlegen.

Jetzt werden im Interrupt-Artikel die Status-Flags als volatile, die 
Puffer als auto angelegt. Im Ringpuffer von Peter sind die Puffer 
static. So wie ich das verstanden habe, werden volatile Variablen nicht 
in Registern gehalten, sondern immer direkt ins RAM geschrieben. Will 
ich das nicht mit meinen Pointerzielen machen??

Was stimmt denn nun, bzw. wann ist welche Deklaration nötig?

von Peter D. (peda)


Lesenswert?

Hundertvolt wrote:
> Eine Frage hätte ich aber noch: Im Tut und im Interrupt-Artiklel steht,
> alle globalen Variablen sowie Pointer und / oder deren Ziele, die sowohl
> in ISRs als auch in Funktionen benutzt und verändert werden, sollte man
> als volatile anlegen.

Das ist erstmal vollkommen korrekt.

Allerdings kann es dann passieren, daß dadurch der Interrupt-Code größer 
und länger wird.

Das volatile wird eigentlich nur im Main gebraucht, da der Interrupt die 
Variable zwischendurch ändern kann, aber nicht umgekehrt.
Daher habe ich mir Macros definiert, die eine Variable als volatile 
casten.
Das habe ich mir von Jörg Wunsch abgeschaut, der hatte das mal gepostet.

Der Puffer selber muß nicht volatile sein. Wenn der Index oder Pointer 
volatile ist, darf trotzdem kein Zugriff wegoptimiert werden.
Eine Ausnahme wäre, wenn man eine feste Adresse (d.h. ohne Pointer oder 
Index) in dem Puffer liest, dann muß man wieder das Macro nehmen.


Peter

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.