www.mikrocontroller.net

Forum: Compiler & IDEs Pointer in ISRs


Autor: Hundertvolt (Gast)
Datum:

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

void uart_puts (unsigned char *t)

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

und dann sende ich irgendwo die Sache weg mit:
UDR = TXBUF;
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:
unsigned char *TXBUF;
unsigned char *volatile TXBUF;
volatile unsigned char *TXBUF;
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???

Autor: P. S. (Gast)
Datum:

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

Autor: Ahem (Gast)
Datum:

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

Autor: Hundertvolt (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
 volatile unsigned char *TXBUF;    // Sendepuffer


 
 ISR(USART_UDRE_vect)         //Interrupt: UART UDR empty
{
  if (*TXBUF)            //anderes Zeichen als NULL zu senden
    {
    UDR = *TXBUF;        //Zeichen aus aktueller Pufferstelle an TX-Register
    TXBUF++;          //Pufferstelle auf nächstes Zeichen
    }
  else
    {
    UCSRB &= ~(1<<UDRIE);    //Wenn NULL (Stringende erreicht), Interrupt ausschalten
    }
} 
 
  
 

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

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

Autor: Ahem (Gast)
Datum:

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

Autor: Ahem (Gast)
Datum:

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

Autor: Mark Brandis (markbrandis)
Datum:

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

Autor: Hundertvolt (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <util/setbaud.h>

#define BAUD 38400

 
 volatile unsigned char *TXBUF;    // Sendepuffer


 
 ISR(USART_UDRE_vect)         //Interrupt: UART UDR empty
{
  if (*TXBUF)            //anderes Zeichen als NULL zu senden
    {
    UDR = *TXBUF;        //Zeichen aus aktueller Pufferstelle an TX-Register
    TXBUF++;          //Pufferstelle auf nächstes Zeichen
    }
  else
    {
    StatusBits.TX_Active = 0;   //Merkerbit zurücksetzen
    UCSRB &= ~(1<<UDRIE);    //Wenn NULL (Stringende erreicht), Interrupt ausschalten
    }
} 
 
  
 

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
    }
}
 
 
 
 
int main (void) {      
     
   unsigned char Line[22];      // String zum Senden
   
   UBRRH = UBRRH_VALUE;
   UBRRL = UBRRL_VALUE;
   
   
   UCSRB |= ((1<<TXEN)|(1<<RXEN));                 // UART TX + RX einschalten
   UCSRC |= (1<<URSEL)|(1 << UCSZ1)|(1 << UCSZ0); // Asynchron 8N1 
  
   sei();
 
   while(1) {                


 _delay_ms(1000);
  

Line[0]='a';
Line[1]='b';
Line[2]='c';
Line[3]='\0';


uart_puts(Line);


      }                        
  
   return 0;                
}


Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
volatile unsigned char *TXBUF;
Nicht der Inhalt deines Puffers muss volatile sein, sondern der Pointer.
Also:
unsigned char * volatile TXBUF;

Autor: Hundertvolt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie gesagt, ich habe diese 4 Deklarationen versucht:
unsigned char *TXBUF;
unsigned char *volatile TXBUF;
volatile unsigned char *TXBUF;
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?

Autor: Mark Brandis (markbrandis)
Datum:

Bewertung
0 lesenswert
nicht 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
TXBUF = &Mein_Puffer[0];

sehen.

Autor: Gast (Gast)
Datum:

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

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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
./lib/gcc/../../avr/include/util/setbaud.h:117:4: error: #error "setbaud.h requires BAUD to be defined"
./lib/gcc/../../avr/include/util/setbaud.h:125:4: error: #error "BAUD must be a constant value"
./lib/gcc/../../avr/include/util/setbaud.h:197:11: error: division by zero in #if
./lib/gcc/../../avr/include/util/setbaud.h:212:10: error: division by zero in #if
./lib/gcc/../../avr/include/util/setbaud.h:217:10: error: division by zero in #if

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

Autor: P. S. (Gast)
Datum:

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

Autor: Peter Dannegger (peda)
Datum:

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

Autor: Philipp Burch (philipp_burch)
Datum:

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

Autor: peterguy (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
ISR(USART_UDRE_vect)         //Interrupt: UART UDR empty
{
  if (*TXBUF)            //anderes Zeichen als NULL zu senden
    {
    UDR = *TXBUF;        //Zeichen aus aktueller Pufferstelle an TX-Register
    TXBUF++;          //Pufferstelle auf nächstes Zeichen
    }
  else
    {
    StatusBits.TX_Active = 0;   //Merkerbit zurücksetzen
    UCSRB &= ~(1<<UDRIE);    //Wenn NULL (Stringende erreicht), Interrupt ausschalten
    }
    USART_UDRE_Interruptflag = 1; // Interruptflag zurücksetztn. Üblicherweise durch schreiben einer 1
} 

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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?
When the Data Register empty Interrupt Enable (UDRIE) bit in
UCSRB is written to one, the USART Data Register Empty Interrupt
will be executed as long as UDRE is set (provided that global
interrupts are enabled). UDRE is cleared by writing UDR. When
interrupt-driven data transmission is used, the Data Register
Empty Interrupt routine must either write new data to UDR in
order to clear UDRE or disable the Data Register empty Interrupt,
otherwise a new interrupt will occur once the interrupt routine
terminates.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ein funktionierendes Beispiel gibt es im Artikel Interrupt

Autor: Hundertvolt (Gast)
Datum:

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

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

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

Autor: Hundertvolt (Gast)
Datum:

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

Autor: Peter Dannegger (peda)
Datum:

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

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

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

Autor: Peter Dannegger (peda)
Datum:

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

Autor: Hundertvolt (Gast)
Datum:

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

Autor: Peter Dannegger (peda)
Datum:

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

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.