Hallo,
wie schon im Betreff beschrieben, möchte ich itoa in der ISR verwenden
und bekomme die Warnung wegen des volatile-Qualifiers des
string-pointers, der an itoa übergeben wird. Itoa möchte ich nicht
unbedingt ändern.
Ich abe aber gelesen, dass man das volatile beim Aufruf wegcasten kann.
Wie sähe das denn aus?
Mein Aufruf ist uart0_puts (itoa(i, tmp_str, 10));
wie müsste ich das schreiben mit weggecastetem volatile?
Wenn ich das in der ISR ohne volatile für tmp_str mache, was könnte an
Fehlern passieren?
Gruß und Danke, Alex
Alex schrieb:> Wenn ich das in der ISR ohne volatile für tmp_str mache, was könnte an> Fehlern passieren?
Warum machst du es denn mit volatile?
volatile brauchst du nur, wenn du eine Variable in der ISR und im
Hauptprogramm verwendest. Der Name "tmp_str" könnte darauf hinweisen,
daß das nicht so ist.
Alex schrieb:> Mein Aufruf ist uart0_puts (itoa(i, tmp_str, 10));> wie müsste ich das schreiben mit weggecastetem volatile?
(char *)tmp_str
Aber: Wenn uart0_puts eine Ausgabe über UART ist, ist das in einer ISR
gar keine gute Idee. Da drüber solltest du nochmals nachdenken.
Oliver
Hallo Oliver,
danke für die schnelle Antwort. Ich weiß, dass es nicht optimal ist in
der ISR was zu senden, aber da es zeitgenau geschehen muss, weiß ich
gerade keinen besseren Weg und es sind nur wenige Zeichen pro
Ineterrupt, der alle 500ms ausgelöst wird. Und ich schreibe es auch nur
in den Sendepuffer und schicke es nicht direkt mir der UART weg. Ich
hatte noch überlegt, den in der ISR verwendeten tmp_str lokal in der ISR
anzulegen, wäre das dann ohne volatile i.O.? Momentan benutze ich einen
globalen tmp_str für alles mögliche im Programm, auch außerhalb der ISR.
Was sagst Du dazu?
Danke, Alex
Alex schrieb:> Momentan benutze ich einen> globalen tmp_str für alles mögliche im Programm, auch außerhalb der ISR.> Was sagst Du dazu?
Das ist eine ganz schlechte Idee. Wie synchronisierst Du Zugriffe
darauf? Deine ISR hat bei Aufruf keine Ahnung davon, ob nicht
zufälligerweise Dein Hauptprogramm irgendwas mit diesem Puffer anfängt
und überschreibt gnadenlos das, was da möglicherweise schon drinsteht.
Das wiederum dürfte Dein Hauptprogramm aus dem Tritt bringen, das ja
wohl nicht ohne Grund etwas dort hingeschrieben hat.
Je nach Größe dieses Puffers: Mach daraus eine automatische Variable,
die nur zur Laufzeit der ISR existiert (also auf dem Stack liegt).
Andererseits: Statt die per itoa ermittelten Zeichen in den
UART-Sendepuffer einzutragen, könntest Du auch einfach den Wert in einen
dem UART-Sendepuffer vorgeschalteten Puffer eintragen, und die
Aufbereitung und Ausgabe erfolgt dann außerhalb der ISR.
In Deinem Beispiel ist zwar der itoa-Aufruf in der ISR recht harmlos (da
die ISR so selten auftritt und die Chose anscheinend auch nicht extrem
zeitkritisch ist), aber so etwas sollte man vermeiden.
Hallo Rufus,
Rufus t. Firefly schrieb:> Andererseits: Statt die per itoa ermittelten Zeichen in den> UART-Sendepuffer einzutragen, könntest Du auch einfach den Wert in einen> dem UART-Sendepuffer vorgeschalteten Puffer eintragen, und die> Aufbereitung und Ausgabe erfolgt dann außerhalb der ISR.
Das mache ich ja. Ich habe eine Ringpuffer, in den ich die Werte
schreibe und der dann im UART Interrupt gelesen und gesendet wird.
Ansonsten danke für die Tipp, leuchtet mir alles ein und ich werde das
so umsetzten. Das mit dem tmp_str ist wirklich dumm so und auch
offensichtlich dumm, trotzdem ist mir das so noch gar nicht den Sinn
gekommen.
Grüße, Alex
Alex schrieb:> Hallo Rufus,>> Rufus t. Firefly schrieb:>> Andererseits: Statt die per itoa ermittelten Zeichen in den>> UART-Sendepuffer einzutragen, könntest Du auch einfach den Wert in einen>> dem UART-Sendepuffer vorgeschalteten Puffer eintragen, und die>> Aufbereitung und Ausgabe erfolgt dann außerhalb der ISR.>> Das mache ich ja. Ich habe eine Ringpuffer, in den ich die Werte> schreibe und der dann im UART Interrupt gelesen und gesendet wird.
Ist trotzdem immer noch eine ganz schlechte Idee.
Das Problem:
Dein Hauptprogramm möchte zb ausgeben "Hallo World"
Dazu beginnt es den String in den Sendepuffer zu übertragen. Es wird
zeichenweise in den Sendepuffer eingetragen H a l l
Und wie es der Zufall so haben will, kommt ausgerechnet jetzt dein
anderer Interrupt daher. Der seinerseits 123 in den Sendepuffer stellt.
Irgendwann ist auch dieser Interrupt beendet und es geht zurück zum
Hauptprogramm welches immer noch Zeichen in den Sendepuffer einstellt o
W o r l d
Dein Empfänger bekommt damit den Text
Hall123o World
zu Gesicht. Und das dürfte in den meisten Fällen für Verwirrung sorgen.
Halte dich an die klassischen Methoden und du hast weniger Probleme:
* In einer ISR wird ein Flag gesetzt, vielleicht noch ein bischen
Arbeit gemacht
* In der Hauptschleife werden alle Flags reihum abgearbeitet und der
zugehörige Job ausgeführt, wenn das Flag richtig steht
* Kein Job darf lange dauern. Länger andauernde Prozesse werden in
Einzelteile zerlegt, für jeden Einzelteil gibt es ein Flag und
die Einzelteile aktivieren sich nacheinender selber, indem sie das
jeweilige Flag setzen.
Es hat schon seinen Grund, warum manche Programm-Systematiken es zum
Klassiker schaffen und andere nicht.
Oder noch schöner:
Im Hauptfluß wird ein Zeichen geschrieben, aber bevor der
zugehörige Zähler oder Zeiger erhöht wird, kommt der Interrupt.
Der gibt dann etwas aus (wobei er das letzte zuvor geschriebene Zeichen
überschreibt), und anschließend geht es an der unterbrochenen Stelle
weiter - dann wird der Zähler wiederum fälschlicherweise
weiter gesetzt.
(Du schwächelst! Sonst kommen die düsteren Beispiele doch immer von
Dir...)
Das lohnt nicht, wenn nicht wirklich Daten ausgetauscht werden sollen.
Wenn ich das richtig mitbekommen habe, braucht er den tmp_str aber
gar nicht zum Austausch. Mit einem Feld im Hauptprogramm und einem
im Interrupt gibt es keine Kollisionen, und die aufwendige
Abstimmung entfällt.
Klaus Wachtler schrieb:> (Du schwächelst! Sonst kommen die düsteren Beispiele doch immer von> Dir...)
LOL.
Ich hab da ein 'nebenbei' ein saublödes Problem zu bearbeiten. Wird ein
Fenster mit einem hochgezogenen Fensterbrett in eine Mauer gesetzt, so
dass das Fenster am Fertigfussboden unten ansteht, der auch noch von der
Mauervorderkante zurückgesetzt ist, dann verhaut sich die
Schnittberechnung, die einen Querschnitt durch das Geschoss berechnet
und dieser Mauerteil wird nicht richtig schraffiert. Ich denke mal, es
ist irgendwo ein Epsilon in einem schleifenden Schnitt, welches zu klein
ist. Kann auch sein, dass die Urgeometrie schon nicht sauber ist und die
boolsche Operation Mist gebaut hat. (Datenstrukturdumps deuten in diese
Richtung).
Sitzt jetzt schon den 2. Tag daran und finde das Problem einfach nicht.
Auf zur nächsten Debug-Session und rund 15tausend Zeilen Code erneut
durchsteppen :-)
Alex schrieb:> zeitgenau geschehen muss, weiß ich> Und ich schreibe es auch nur> in den Sendepuffer
Das beißt sich...
Annahme:
Deine Main schreibt den Sendepuffer mit irgendwas voll... und dann kommt
dein ISR....
Also das ablegen der Daten geht vielleicht zeitgenau aber das Senden nie
und nimmer...
Speicher einfach die Daten aus der ISR (ohne vorher itoa zu wandeln)
irgendwohin und setzt dann ein Flag und dann holt die main die Daten ab
und wandelt die um
Ich hab das Programm jetzt so geändert, wie von euch vorgeschlagen.
Keine zeitintensiven Geschichten in der ISR und mit Flags. Es
funktioniert. Und der Rest der Codes, der vorher schon lief, auch ;-)
Toll!
Danke...