Forum: Compiler & IDEs Variable laezst sich in SIG_UART_RECV nicht veraendern


von Thomas Plos (Gast)


Lesenswert?

Hallo,

habe da ein Problem, zu dem ich weder ueber Google noch ueber Faq's zu
einer brauchbaren Loesung gekommen bin:

Eine globale Variable, welche ich als 'static volatile' deklariert
habe, wird bei mir in einem kleinen Testprogramm beim Auftreten von
Interrupts (SIG_INTERRUPT0 und SIG_UART_RECV) jedesmal um eins erhoeht.
Bei SIG_INTERRUPT0 funktioniert das auch genauso wie erwartet - nur bei
SIG_UART_RECV eben nicht. Hier wird die Variable jedesmal auf null
zurueckgesetzt und dann erhoeht, wodurch sie bei eins haengen bleibt.
Ich kann da irgendwie keinen Denkfehler meinerseits sehen. Eigentlich
sollten doch alle Interruptaufrufe eine Variable gleich behandeln.
Nachdem ich fuer die Interrupts 'Signal' verwende, koennen sie sich
auch nicht gegenseitig beeinflussen.

Ach ja, es handelt sich um einen Atmega8 (real device) und compiliert
wird unter WinAvr.


Bin fuer jeden Hinweis/Vorschlag dankbar!

m.f.G.
Thomas

von Peter D. (peda)


Lesenswert?

Du hast das Problem beschrieben, aber den Code vergessen (als
Dateianhang).


Peter

von Marcus M. (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Peter,

da ich im Moment echt das gleiche Problem habe, hoffe Du mir vielleicht
bereit bist zu helfen.

Ich dachte bisher, das Problem würde an dem nicht richtig erkannten
<CR> liegen. Aber der Code hat ne Macke!

Was soll der Code machen?
Ich möchte die empfangen Daten bis zum <CR> (0xD) in einen 32 Byte
großen Puffer per Interrupt schreiben und danach diesen Auswerten.
Dazu dient die Funktion:

unsigned char* UART_recv (void);

Die Funktionen:
void UART_init(void) ;
void UART_transmitt (unsigned char* Transmitt);

funktionieren bereits einwandfrei.

Um meine Vermutung zu validieren habe ich das Backlight des LCD's
innerhalb der Interrupt Routine ausschalten lassen. Es wird eigentlich
nach Beendigung von UART_recv wieder eingeschaltet.
Der Code erzeugt aber folgendes Phänomen:
wenn ich die SIGNAL Funktion benutze wird erst nach dem dritten
Datentransfer das Display dunkel, aber aus irgendeinem Grund wird es
permanent aus und wieder eingeschaltet. Das ist aber etwas, das mein
Code nicht zulassen sollte, denn nach Ende der Übertragung sollte die
Interrupt Routine nicht mehr durchlaufen werden, also das Display
wieder an sein.
Eigentlich sollte entweder UART_global.recv_pos den Wert 0 oder >0
aufweisen, warum die Variable permanent hin und her schwingt, ist mir
schleierhaft.

Hoffe Dir kann das ganze mehr sagen, als mir.

Gruß Marcus

von Malte Marwedel (Gast)


Lesenswert?

Also ich vermisse in dem Quellcode irgendwo vor einer Variable ein
volatile.

von Thomas Plos (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

hier nun der Code. Ist nur ein kleines Testprogramm um das Problem,
welches ich habe (und nicht verstehe) zu demonstrieren.

m.f.G.
Thomas

von Marcus M. (Gast)


Lesenswert?

Hallo Marvel,

Sorry, wenn mein Code im Moment sehr durcheinander ist - und
unkommentiert arg.
Ich bastelle da nun schon seit zwei Tagen dran und somit sind einige
zugegeben unnötige überprüfungen und LCD_Light Befehle drin.

Du brauchst die Variable IMHO nicht unbedingt als static volatile zu
deklarieren, wenn Du sie wie ich an ein bestimmtest Register bindest.
Ich habe dies damals bei der Entwicklung auf dem Tiny26 lernen müssen.


@Thomas:
Versuchs mal bitte mit folgender Deklaration:

register unsigned char value asm ("r3);

Dann wird die Variable definitiv an ein bestimmtes Register gebunden
und niemand wird dieses Register wieder anpacken. So ähnliche Probleme
habe ich mit dem Tiny auch gehabt.

BTW:
Ich bin mit meinem Problem auch ein ganzes Stück weiter.
Wüßte von Euch jemand, warum diese Routine nach ihrer Beendigung
jedesmal wieder einen SIG_UART_RECV Interrupt auslöst?
Das Problem, was ich nur noch habe, ist das die Schnittstelle permanent
SIG_UART_RECV Interrupts auslöst arg
Im Pollbetrieb funktioniert alles einwandfrei!


SIGNAL (SIG_UART_RECV) {

  LCD_Light_off;
  temp_recv = UDR;
  if (temp_recv == 0xc)
    status |= (1 << RECV);
  else
    rec_buff[temp++] = temp_recv;

}

von Thomas Plos (Gast)


Lesenswert?

Hallo Markus,

danke fuer deinen Hinweis. Leider hat dies mein Problem nicht behoben.

m.f.G.
Thomas

von Marcus M. (Gast)


Lesenswert?

Hallo Marvel,

ich habe leider irgendwie ein ähnliches Problem, wie Du.

Leider schaffe ich es nicht mehr, das jetzt alles noch durchzutesten -
Jörg hoffe Du hilfst uns -.

Versuch mal folgendes:

erzeuge einen Pointer:
static volatile unsinged char value;

void init_UART(void) {

....


  value_ptr = &value;

....

SIGNAL (SIG_UART_RECV) {

   unsinged char* value_ptr = &value;
   (*value_ptr)++;



}

Hier passiert folgendes:
dein Object value hat eine Adresse. Diese Adresse weißt Du nun dem
Pointer value_ptr zu. Damit hast Du nun zwei möglichkeiten Dein Object
zu manupilieren. Entweder du greift direkt drauf zu:
value++;
oder indirekt über Deinen Pointer:
(*value)++;
Was nun in der Signalroutine passiert ist folgendes:
Du erzeugst einen lokalen Pointer, der defaultmäßig auf das Object
value verweißt. Da ich bisher herausgefunden habe, das innerhalb der
SIGNAL_ROUTINE, alle Variablen korrekt behandelt werden, aber leider
Ihren Wert nicht behalten, da sie ja nicht vom Stack geholt sondern
vorher gesichert werden, benutzt du nun diesen Pointer um das Problem
zu umgehen. Du bearbeitest also direkt die Speicherzellen, ohne Dich
irgendwie um den Aufenthaltsort zu scheren.
Meiner Meinung nach müßte value in dem Moment auf dem Heap gesichert
worden sein.
Vielleicht hilft dies.

Gruß Marcus

von Thomas Plos (Gast)


Lesenswert?

Hallo Markus,

auch dieser Tipp fuehrt leider nicht dazu, dass ich einen Wert aus dem
SIG_UART_RECV-Interrupt 'heraustransportieren' kann. Mit anderen
Interrupts funktioniert es wieder (wie erwartet) problemlos :-(.

Habe es mit einem globalen Pointer versucht, dessen 'Inhalt' in
SIG_UART_RECV veraendert wird => kein Erfolg.

Habe es auch mit einem lokalen Pointer in SIG_UART_RECV probiert,
welcher direkt auf die Adresse von 'value' zeigt => kein Erfolg.


Schoen langsam bin ich ratlos...


Vielleicht liest ja jemand mit, der schon einmal erfolgreich aus dem
SIG_UART_RECV-Interrupt einen Wert nach 'auszen' gebracht hat, und
koennte mir diesbezueglich einen Tipp geben.

m.f.G.
Thomas

von Marcus M. (Gast)


Lesenswert?

Hallo Thomas,

mitlerweile habe ich es geschafft Daten über aus dem SIG_UART_RECV
heraus zu transportieren.
Leider sind die aber nie ganz vollständig und teilweise lückenhaft.

Ich schicke Dir heute NAchmittag aber mal den Code.

Gruß Marcus

von Peter D. (peda)


Lesenswert?

@Thomas,

versuch doch mal die Interrupts erstmal einzeln zu testen und nicht
miteinander zu verwursteln.

Schreib z.B. das "PORTC = value;" in die Mainloop und disable erstmal
den externen Interrupt.

Wenn was nicht funktioniert und man weiß nicht wo es klemmt, dann immer
schön in gleichgroße Brocken unterteilen und diese separat testen.

Denn bei der Programmierung gilt immer:

Der Fehler liegt nie dort, wo er sich bemerkbar macht.


Peter

von Marcus M. (Gast)


Angehängte Dateien:

Lesenswert?

So,

hier ist mein Code, der zwar etwas einließt, aber meist irgendwie mit
dem Zeichen durcheinander gerät.
Vielleicht weiß jemand von Euch, was da so falsch läuft... .

Gruß und auf Hilfe hoffend!!

Marcus

von Marcus M. (Gast)


Lesenswert?

Hallo Thomas,

ich habe den Fehler gefunden, zugegeben erst nach viel Probieren, weil
ich schon lange mit meinem Latein am Ende war.
Der folgende Code füllt Dir den rec_buff:

unsigned char  rec_buff[16];
volatile unsigned char temp_recv;

SIGNAL(SIG_UART_RECV)
{
  while ((UCSRA & (1 << RXC)) && (temp_recv < 16)) {
---Fehler----->  *&rec_buff[temp_recv] =  UDR;
    temp_recv ++;
  }
  if (temp_recv > 15) {
    temp_recv = 0;
    status |= (1 << RECV);
  }
}

Die Zeile
  *&rec_buff[temp_recv] = UDR;
besagt eigendlich folgendes:
Zuerst wird die Adresse von rec_buff[temp_recv] nachgeschlagen und
anschließend wird dieses Register, auf das diese Adresse zeigt mit dem
Inhalt von UDR gefüllt.
Laut Standart-C ist die equvalent mit:
   rec_buff[temp_recv] = UDR;

Warum ich nun aber diesen Umweg gehen muß, kann mir nur der gcc sagen.
Vielleicht weiß uns Gott Jörg Wunsch dazu etwas zu sagen. Ich hab keine
Ahnung, warum dieser Code funktionert und der andere nicht.

Gruß Marcus

von Jörg Wunsch (Gast)


Lesenswert?

Davon abgesehen, daß ich von "*&foo[bar]" einen Knoten im Gehirn
bekomme :-), nein, ich kann da genausowenig einen Unterschied zu
"foo[bar]" feststellen wie mein Compiler.

von Peter D. (peda)


Lesenswert?

Ich bekomme auch nen Knoten davon, daß Marcus diesen Thread gehijackt
hat.

Sowas macht man nicht.

Wer blickt jetzt noch durch, was sich worauf bezieht.


Peter

von Marcus M. (Gast)


Lesenswert?

Hallo Peter,

Sorry, da wir beide das gleiche Problem haben, wollte ich deswegen
nicht nochmal einen Thread aufmachen.

<OT>
Die Sprüche a là schau Dir den Thread, der gerade läuft an, haben mich
schon ziemlich genervt in der letzten längeren Vergangenheit.
Werd aber demnächst immer einen zweiten Thread aufmachen. Dann nehmts
mir bitte auch nciht übel, wenn ich dann auch pampisch reagiere
</OT>

Trozdem hoffe ich, das meine letzten schlaflosen Nächte Thomas
irgendwie helfen konnten.

Sorry nochmals, hatte eben gedacht diesmal etwas besser zu machen.

Marcus

von Marcus M. (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Tobias,

falls Du noch Probleme mit der SIGNAL hast, versuch mal den beigefügten
Code zu testen.

Gruß Marcus

von Thomas Plos (Gast)


Lesenswert?

Hallo zusammen,

danke an alle, die mir bis jetzt Tipps zur Loesung des Problems gegeben
haben!

@Marcus
Ich habe deinen Loesungsansatz in mein Mini-Testprogramm eingebaut -
erhalte aber noch immer kein brauchbares Ergebnis (es will mir einfach
nicht gelingen :-( ). Aus, mir unerklaerlichen Gruenden, wird nach
einem Aufruf von SIG_UART_RECV die Variable 'value' wieder auf ihren
Initialisierungswert zurueckgesetzt. Schoen langsam habe ich die
Vermutung, dass dieser Interrupt-Aufruf irgendwie einen Reset
ausloest.

Vielleicht koennte sich ja jemand die Muehe machen und das Programm auf
seinem uC kurz testen und mir dann mitteilen ob es dort funktioniert
oder nicht. Dies wuerde dann zumindest jeglichen Verdacht von meiner
Hardware nehmen

Danke!

m.f.G.
Thomas

von Thomas Plos (Gast)


Angehängte Dateien:

Lesenswert?

Upps - Datei vergessen!

von Peter D. (peda)


Lesenswert?

"...da wir beide das gleiche Problem haben..."

???

Also ich sehe da Welten zwischen Deinem und Thomas Code.
Ich glaub deshalb nicht, daß er mit Deinem Code überhaupt etwas
anfangen kann.


Aber auch bei ähnlichen Problemen sollte man einen Fragethread erst
hijacken, wenn die Ursprungsfrage schon gelöst ist.

Man schiebt sonst den Erstfrager nach hinten weg und seine Chancen auf
eine Antwort sinken (wie man hier ja gut sieht).

Ich würde es daher Thomas nicht übelnehmen, wenn er seine Frage nochmal
in einem neuen Thread stellt.



Peter

von Jörg Wunsch (Gast)


Lesenswert?

Thomas, Du aktivierst alle möglichen UART-Interrupts, hast aber nur
einen Handler für einen (von dreien)!?  Das kann nicht gut gehen.
Sowie einer der beiden anderen ausgelöst wird, wird der default Vektor
angesprochen, der einen [r]jmp 0 ausführt.

von Marcus M. (Gast)


Lesenswert?

Hallo Thomas,

nachdem ich einen Handler für

SIGNAL(SIG_UART_TRANS) {

}

SIGNAL (SIG_UART_DATA) {

}

hinzugefügt und die Zeile:

unsigned char value = 7;

in

unsigned char value;

geändert habe, läuft bei mir immer alles nach Plan.
Letztere Änderung glaube ich nicht, das irgendwas ausmacht.
Getestet habe ich auf Mega32, Mega16 Nega8535. Einen Mega8 habe ich
leider nicht hier. Sorry :-(

Gruß Marcus

PS: Sorry fürs hijacken und thx für die Infos

von Thomas Plos (Gast)


Lesenswert?

@Joerg und Marcus
Habt vielen Dank - jetzt funktioniert es!

Ich habe beim vielen Herumprobieren vergessen die nicht verwendeten
Interrupts wieder zu deaktivieren. In weiterer Folge hab ich den Fehler
dann krampfhaft an anderer Stelle gesucht, also sprichwoertlich den Wald
vor lauter Baeumen nicht mehr gesehen ;-).

Nochmals Danke!

m.f.G.
Thomas

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.