PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Asuros SerWrite(..) - Verständnisproblem



Rakke
23.12.2005, 00:00
Guten Abend allerseits,

ich hab' heut mal ein bisschen in die Funktion SerWrite der asuro.c 'reingeguckt:


/* function for serial communication */
void SerWrite(unsigned char *data,unsigned char length)
{
unsigned char i = 0;
UCSRB = 0x08; // enable transmitter
while (length > 0) {
if (UCSRA & 0x20) { // wait for empty transmit buffer
UDR = data[i++];
length --;
}
}
while (!(UCSRA & 0x40));
for (i = 0; i < 0xFE; i++)
for(length = 0; length < 0xFE; length++);
}

Kann mir jemand den Sinn der letzten beiden Zeilen der Funktion erklären?
Was ich noch verstehe: alle Zeichen werden erfolgreich gesendet, und der ATmega meldet schließlich "Transmit Complete" (UCSRA wird = 0x40).
Was ich nicht verstehe: anschließend wird noch einmal i von 0 bis 0xFE durchlaufen und unterlagert length von 0 bis 0xFE. Dabei wird aber keinerlei Aktion ausgeführt; und da beide eh' nur lokale Variable bzw. lokale Kopie eines Argumentes sind, werden sie auch nicht beeinflusst.
Was ich gern wüsste: warum das, übersehe ich was? Was macht da der Compiler draus, wird sowas wegoptimiert (zumindest sofern ich nix übersehen habe...)?

Interessant fand ich, dass der Prozessor sich beim Schreiben auf die serielle Schnittstelle tatsächlich ausschließlich auf das Senden "konzentriert", während nebenher z. B. die Motoren und irgendwelche Regler laufen. Wenn Zeit also knapp ist, besser keine oder nur ganz kurze Ausgaben über die serielle Schnittstelle - oder gibts andere Trix, die ich nicht kenne?

Schlaut mich bitte auf!

Gruß,
Rakke

m.a.r.v.i.n
23.12.2005, 10:38
Hallo Rakke,

die beiden letzten Zeilen sollen eine Warteschleife darstellen.
Wie du schon richtig vermutest wird sowas der Compiler wegoptimieren.
Sieht zumindest so aus, wenn man ins Asm Listing schaut (spreche allerdings nicht fließend Assembler).
Einfach mal die beiden Zeilen weglöschen und sehen ob beim Senden Zeichen verloren gehen.

Besser wäre es, die SerWrite und SerRead Funktionen auf Interrupt Betrieb umstellen, dann wird nicht unnötigt Zeit vertrödelt.
Wäre doch ne hübsche Aufgabe?

Gruß Peter

Rakke
23.12.2005, 11:15
Hei Peter,

hm, Warteschleife: warten worauf? (Christkind ;-)?) Die Funktion wird ja danach beendet... Habe jetzt auch mal das Assemblerzeug angeguckt, verstehe aber nur Bahnhof.

Ansonsten: au ja Interrupt! Jetzt kommen ja ein paar ruhigere Tage, da könnte wohl etwas mehr Zeit übrigbleiben als in der "oh-je-was-schenke-ich-Doris"-Vorweihnachtszeit.

Bloß muss ich dafür erstemal den CVS-Kram fürs Sourceforge ans Laufen bringen, damit ich nicht wieder quer zu existierenden asuro.c/h arbeite. Das müsste doch bei dir schon laufen (als SF-Admin...) - wie kann ich mich am geschicktesten informieren? Muss ich fürs SSH irgendwas installieren? Gibts da an zentraler Stelle eine Info, die man im asuro-lib-thread verlinken könnte?

Alaaf,
Rakke

m.a.r.v.i.n
23.12.2005, 12:03
Hallo Rakke,

Vielleicht braucht der IR Transceiver noch eine Zwangspause zwischen einzelnen Zeichen?

ich benutze smartcvs als CVS client. Gibt es bei http://www.smartcvs.com.
Die Einrichtung und der Zugriff auf Sourceforge ging damit problemlos.
SSH Client ist auch dabei.
Die Demoversion sollte für den normalen Gebrauch ausreichen.
Werde mal eine Doku zum Einrichten dafür schreiben.

Gruß Peter

Rakke
23.12.2005, 12:48
Hei Peter,

danke für die fixe Antwort, ich mach mich mal dran (wenn die Tanne geschmückt ist usw.).

Über eine Stichpunktdoku würde sicher nicht nur ich mich freuen!

Alaaf,

Rakke

m.a.r.v.i.n
26.12.2005, 13:54
Hallo Rakke,

im CVS ist jetzt auch eine Doku zur Einrichtung des CVS Clients (http://cvs.sourceforge.net/viewcvs.py/*checkout*/asuro/asuro/doc/CVS_Einrichtung.html) (für SmartCVS).

Ich habe mich noch mal mit der Warteschleife in der SerWrite Funktion befaßt. Der Code wird nicht wegoptimiert sondern tatsächlich ausgeführt.
Das heißt, diese Wartezeit scheint doch notwendig zu sein, damit es mit der IR-Schnittstelle funktioniert.
Vielleicht ist das auch der Grund warum der BootLoader von linux_80 (https://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=9426) bei einer Drahtverbindung funktioniert, nicht aber über die IR-Schnittstelle.

Das macht das Umstellen der Sendefunktion auf Interrupt Betrieb natürlich um einiges aufwändiger.

Gruß Peter

Sternthaler
30.12.2005, 17:50
Hallo zusammen,
zum Thema mit der Warteschleife: Ich habe sie weggelassen und habe keinen Datenverlust beim Senden.
Die Funktion überprüft ja nach dem letzten gesendenen Byte, ob es gesendet wurde und damit der Buffer wieder frei ist. --> while (!(UCSRA & 0x40)); <---


INTERRUPT-BETRIEB
Ich bin gerade dabei die Schnittstelle, und alle anderen Sensoren, auf Interrupt-Betrieb umzustellen.
Ist aber noch nicht spruchreif, so dass ich noch keinen Code posten kann.

Eins vorweg:
Ich werden wohl nur das Senden über Interrupt gesteuert ausführen. Das Empfangen werde ich im Moment erst mal im pollenden Betrieb lassen.
Begriffe:
-> Senden: Asuro sendet.
-> Empfangen: Asuro empfängt

Grund:
Wenn beides per Interrupt läuft, dann hat das aufrufende Programm nicht mehr die Kontrolle in Bezug auf gleichzeitiges Senden und Empfangen. (Sendepuffer noch gefüllt [Interrupt sendet auch lustig weiter], aber es soll auch gleich noch der Empfänger aktiv sein) Hier tritt bei mir grundsätzlich das Problem auf, dass ich meine eigenen gesendeten Zeichen als Echo selbst empfange. Dies macht 'leichte' Probleme, bzw. macht es auch für einen echten Sender (PC) unmöglich, in den geechoten Datentransfer vom Asuro zum PC korrekte Infos vom PC zum Asuro zu bringen.

Weiteres Problem:
Wenn die zu sendenen Daten vom Hauptprogramm nur 'abggegeben' werden, um sie per Interrupt auf die Reise zu bringen, dann muss das Interruptsystem dafür einen Puffer bereitstellen.
Genau hier haben wir etwas zu wenig Speicher im Asuro um großzügig damit umzugehen.
Als Anzatz habe ich eine feste Pufferlägne gewählt, damit man nicht noch mit malloc hantieren muss. (Die Funktion ist OK, aber viel zu groß)
Wenn jetzt also dieser statischte Puffer voll ist, soll meine Funktion, wie gehabt, in den pollenden Betrieb wechseln. Genau hier bin ich jetzt bei der Software.

Viele Grüße vom Sternthaler.

P.S.: Ich wünsche allen einen guten Rutsch ins Neue Jahr.

Rakke
31.12.2005, 15:11
Hei Sternthaler,

an die Geschichte will ich ja auch noch 'rangehen. Habe bislang nix codiert, nur gedacht:
wenn der Funktion "Senden" nur ein Zeiger auf den Sendetext übergeben wird, und die Funktion selbst nur ein Feld mit Zeigern verwaltet (z. B. Platz für fünf Zeiger), dann müsste der Speicherbedarf überschaubar klein bleiben (die Sendetexte sind ja eh' schon vorhanden im Speicher, keine zusätzliche Belastung also, und je char* sollten nur zwei Byte belegt werden, bei fünf Pointern also ca 10 Byte - geht, oder?).

Auch ich würde zunächst nur die Sendefunktion modifizieren.

Wie wärs, wenn wir uns mit der Bearbeitung abstimmen, z. B. Schnittstellendef., Kompatibilität mit vorhandener Funktion etc.?

Egal wie, guten Rutsch,

Rakke

Sternthaler
31.12.2005, 18:54
Hallo Rakke,
die Idee mit dem Zeiger gefällt mir nicht so recht.

Wenn das Hauptprogramm also den Speicher zur Verfügung stellt, und z.B. eine Variable mit den zu sendenen Daten nutzt, und nur die Adresse/den Zeiger an die Interrupt-Funktion gibt, dann kann das Hauptprogramm ja schliesslich weitermachen und neue Daten in diese Variable schreiben.
Jetzt kommt die 'langsame' sendende Interruptfunktion und liest die vom 'schnellen' Hauptprogramm schon wieder geänderten Daten.
Somit ist der erste Inhalt dieser Variablen noch gar nicht komplett gesendet worden.

Wenn du, wie du vorschlägst, mehrere Zeiger in der Interruptfunktion verwalten möchtest, dann muss auch das Hauptprogramm 'wissen' wann diese Zeiger wieder benutzt werden dürfen, nachdem die dort hinterlegten Daten komplett gesendet wurden. Ich glaube, dass damit die Verwaltung im Hauptprogramm wieder zu groß wird. (Glauben heist aber nicht wissen.)

Zur Abstimmung bei der Bearbeitung:
Ich möchte den in der originalen asuro.c-Library angegeben Funktionsaufruf exakt weiter so benutzten.
Zum einen ist die Funktion ja schon bei allen ASURO-Freaks im Einsatz, und zum anderen habe ich mir überlegt, dass es keinen Sinn macht z.B. die lenght-Variable wegzulassen und nur Strings als data-Variable in die Funktion zu geben. Möglich wäre es, wenn wir immer nur Daten mit dem in C notwendigen '\0' als Endekennung eines Strings hätten.
Ich selbst nutze die Sendefunktion aber auch um 'pure' Daten zu senden. Also z.B. einzelne Messwerte der Sensoren, die ich dann mit einem kleine Programm am PC empfange und auswerte.

Wenn hier aber andere Ideen kommen, z.B. doch ein Ansatz mit den Zeigern, dann immer her damit.

Viele Grüße vom Sternthaler

Nicht mehr lang, und wir rutschen.

Rakke
01.01.2006, 19:31
Guten Abend zusammen,

erstmal frohes neues Jahr allerseits!

@Sternthaler: leider kenne ich mich mit dem tiefsten inneren von einem C-Programm nicht sooo genau aus. Ich hatte das immer so verstanden: wenn ich irgendeinen String senden möchte, muss der irgendwo im Flash abgelegt sein und entsprechend kann man einen Pointer übergeben. Da im Flash, kann nix nicht überschrieben werden. Dabei habe ich nicht mit "echten" Variablenwerten gerechnet, und funktioniert auch bei lokalen (automatischen) Variablen ganz schlecht.
Hm, bleibt nur die übliche Vorgehensweise mit einem Puffer, in den die Daten geschrieben werden und damit vor Veränderungen sicher sind. Das kostet aber wieder Bytes...

Du sprichst noch einen anderen Punkt an: die zeitliche Zuordnung zwischen UART-Ausgabe und Hauptprogramm geht bei Interruptnutzung flöten. Heute wartet das Hauptprogramm mit der weiteren Arbeit, bis die Daten versendet sind. Fürs debugging ist das sicherlich einfacher als wenn ("in Zukunft") die Daten zwar zeitnah, aber nicht notwendigerweise synchron verschickt werden. Außerdem könnte das Hauptprogramm soviel Fahrt haben, dass es Sendedaten schneller in einen Puffer schreibt, als gesendet werden kann - noch so etwas, worauf man heute nicht achten muss.

Die Sendefunktion sollte also auf jeden Fall einen Rückgabewert besitzen wie "Puffer voll"; vielleicht wäre auch eine "Prüfen ob Puffer voll"-Funktion nicht schlecht. Mit der ließe sich dann die zeitliche Kopplung wieder herstellen: einfach warten, bis der Puffer leer ist, dann schreiben und weitermachen.
Auf diese Weise lässt sich die Interruptgeschichte dann flexibel nutzen: wenn nötig, wird auf die serielle Schnittstelle gewartet, wenn nicht erforderlich, nicht.

Mal weiter drüber nachdenken...

Gruß

Rakke

Sternthaler
03.01.2006, 23:52
einfach warten, bis der Puffer leer ist, dann schreiben und weitermachen.
Auf diese Weise lässt sich die Interruptgeschichte dann flexibel nutzen:
wenn nötig, wird auf die serielle Schnittstelle gewartet, wenn nicht erforderlich, nicht.


Ja, genau das habe ich versucht in meinem letzten Beitrag zu sagen.

Hab leider immer noch nix zum posten, da mein Pegel jetzt erst so langsam abklingt. (War auch leckere Whiskey von Weihnachten bis zum Jahreswechsel dabei ;-))
Ich werde versuchen einen funktionsfähigen Ausschnitt aus meinem Zeug mal nur zum Thema Senden zusammenzustellen.

Viele Grüße vom Sternthaler

RedBaron
04.01.2006, 01:13
Hallo,

vor einigen Jahrzehnten, als auch PCs nur wenige KB RAM hatten, kannte ich solche Dinger 'mal auswendig :-k. Mal schauen, an was ich mich noch erinnern kann:

Das Stichwort heißt "Ringpuffer". Es handelt sich um eine beliebige Anzahl Bytes im RAM und zwei Zeiger. Der eine dient als Schreibzeiger, der andere als Lesezeiger.
Beim Schreiben wird an die Stelle geschrieben, auf die der Schreibzeiger zeigt. Danach wird der Zeiger inkrementiert. Kommt er ans Ende des Puffers, wird er auf den Anfang gesetzt (daher der Name Ringpuffer). Trifft der Schreibzeiger auf den Lesezeiger, ist der Puffer voll.

Asynchron hierzu (z.B. durch Interrupt) kann gelesen werden (und z.B. dann an die USART geggeben werden). Es wird das Zeichen gelesen, auf das der Lesezeiger zeigt. Anschließend wird der Lesezeiger inkrementiert. Trifft der Lesezeiger auf den Schreibzeiger, ist der Puffer leer.

Solch einen Puffer kann man sowohl zum Senden als auch zum Empfangen einsetzen. Nützlich sind ein paar Routinen zum Lesen oder Schreiben aus dem Puffer und solche, die Auskunft über seinen Zustand, z.B. Anzahl freie Bytes, Anzahl noch zu sendender Bytes, etc.

Mögliche Interrupts wären:
Serial Transfer Complete
USART, Rx Complete
USART Data Register Empty
USART, Tx Complete
Hier müsste man nachschauen, welches die geeigneten sind.

Zu beachten: jedesmal wenn man eneut beginnt, Zeichen in den Puffer zu schreiben, d.h. es läuft gerade keine Übertragung, muss das Senden durch die schreibende Funktion erneut angestossen werden. Die nächsten Byte werden dann per Interrupt gesendet.

Zum Echo: Man muss schon eindeutig zwischen Sende- und Empfangzustand unterscheiden (halbduplex). Wenn man sendet, kann man nicht empfangen und während des Empfangens, muss man strikt das Senden unterbinden. Die Kommunikationspartner müssen sich per Protokoll darüber einigen, wer senden und wer empfangen soll.

Man muss auch damit rechnen, dass beide Stationen gleichzeitig mit dem Senden beginnen. Deshalb ist eine Kollisionserkennung sinnvoll.

Aber solange man nur mit der IR-Ausrüstung arbeitet, ist das sowieso nicht besonders prickeld (Reichweite 20-100 cm (max.) und 2400 Baud). Oder habt ihr da eine andere Technik?

Gruß Red Baron

m.a.r.v.i.n
04.01.2006, 11:13
Hallo,

Es gibt ja auch die avrlib (http://hubbard.engr.scu.edu/embedded/avr/avrlib/), eine sehr gut dokumentierte Bibliothek für die AVR-Familie.
Dort gibt es auch fertige interruptgesteuerte Sende-Emfangs Routinen mit Ringbuffern. Die Funktionen kann man sich sicher anpassen.

Als Alternative zur IR-Schnittstelle kommen eigentlich nur Funkmodule in Frage.
Mein persönlicher Favorit sind die iDwaRF Funk-Module (http://www.chip45.com/index.pl?page=iDwaRF&lang=de). Die sind aber leider noch nicht lieferbar.

Gruß Peter

Sternthaler
13.01.2006, 00:17
Hallo zusammen,

wie versprochen, kommt nun eine 'halbwegs' funktionsfähige INTERRUPT-getrieben Sendefunktion.

Ich habe auf der ursprünglichen asuro.c/asuro.h aufgesetzt und liefer im ZIP-File aber eine vom Namen geänderte Version asuro-st.c/asuro-st.h, damit bei euch keinesfalls das Original, oder eine LIB hier aus dem Forum übermangelt wird. IST ALSO NICHT ALS LIB-ERSATZ ZU SEHEN.

'Halbwegs funktionsfähig' soll hier heißen, dass es noch einen Bug gibt.
Wenn ich aus der Test-Funktion den Button 6 gedrückt hatte (sendet sehr viele Daten), dann funktioniert der Fall Button 1 (genau ein Zeichen senden) danach nicht mehr.

Zum Testen habe ich mal so einige hier im Thread aufgeführte Probleme auf die einzelnen Button gelegt. Kommentar sind im Source.

Ich bin mal auf eure Reaktion gespannt. Ich hoffe, dass ihr den letzten Bug finden werdet. (So weit ICH weiss ist es der Letzte. Ihr müsst die anderen finden)

EDITIERT vom Sternthaler am 15.01.06
Entfernen des fehlerhaften Atachments, da ich etwas weiter unten eine FEHLERKORREKTUR gepostet habe.

m.a.r.v.i.n
13.01.2006, 11:12
Hallo Sternthaler,

klasse, das sieht doch sehr gut aus.

Was den letzten Bug betrifft habe ich auch eine Vermutung.
Liegt wohl an der PollSwitch Abfrage.
PollSwitch 2x aufrufen und die beiden Ergebnisse vergleichen, hilft eigentlich immer. :wink:



...
unsigned char tmp;
...
tmp = PollSwitch ();
v_taster = PollSwitch ();

if (v_taster > 0 && v_taster == tmp)
...


Btw. die iDwaRF Module sind jetzt endlich erhältlich. Gestern habe ich 5 Stück bekommen. O:)
Leider kann ich die Module noch nicht flashen, weil mein AVR910 Programmer den mega168 nicht kennt. :evil:

Gruß Peter

dgrobot
14.01.2006, 08:14
Hallo M.a.r.v.i.n, hallo Sternthaler,
als Neuling, der gerade den ASURO zusammengebaut hat (alle Tests OK), habe ich eure Diskussion mit Interesse gelesen und sofort den Verbesserungsvorschlag von M.a.r.v.i.n eingebaut:

Nutzt leider nichts, weiterhin wird nach Taste 6 der Punkt von Taste 1 nicht angezeigt.

Gruß
Dieter

Sternthaler
14.01.2006, 18:31
Hallo dgrobot,
ersteinmal herzlich willkommen im Forum.

Leider kann ich da nur zustimmen, dass die Tastenabfrage da wohl diesmal nicht die Schuld hat.
Ich hatte auch versucht die beiden Funktionen von Taste 1 und 6 auf andere Tasten zu legen, da ich den Vorschlag von m.a.r.v.i.n nicht unversucht lassen wollt. Hat aber leider tatsächlich keine Auswirkung.

Ich bin zur Zeit der Überzeugung, dass ich selbst Schuld bin, und irgendwo im Programm doch noch mit den Zeigern auf Tail und Head schlamper. Oder die Variable mit der Anzahl im Buffer vorhandener Zeichen ist noch nicht ganz sauber.

Sternthaler
14.01.2006, 18:37
Der Vollständigkeit halber:

Unter https://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=12790 hat Winne im Thread auch Source zu Interrupt-Thema gepostet.
Das hatte ich gestern Nacht gefunden, aber noch nicht ausprobiert.
Ich habe wohl schon gesehen, dass seine Sendefunktion nur C-Strings entgegen nehmen kann, was ich persöhnlich ja nicht für ausreichend halte. Das ist aber das kleinere Problem da etwas zu Ändern. Dafür hat er aber eine Funktion um ein einzelnes Byte zu senden. Das gefällt mir schon ganz gut.

dgrobot
15.01.2006, 14:18
Hallo Sternthaler,
nach einigen Versuchen bin ich zu dem Schluss gekommen, dass die Anzahl der von TASTE 6 gesendeten Zeichen zu hoch ist, es wird im Speicher des ASURO gerade das erste Zeichen des Textes von TASTE 1 gelöscht; da TASTE 1 nur 1 Zeichen sendet, sieht man gar nichts mehr!
Das lässt sich sehr schön demonstrieren, wenn man im Programm die if-Anweisungen von TASTE 1 mit der von TASTE 2 in der Reihenfolge tauscht, dann fehlt nämlich das erste Zeichen von TASTE 2.
Ohne mich da genau auszukennen, vermute ich, dass eine Art Buffer-Ueberlauf die Ursache ist. Der Buffer ist mit 30 Zeichen definiert, es werden aber viel mehr erzeugt.

Bei der Gelegenheit: Bei mir scheint TASTE 6 den Code 0x21 zu senden. Dadurch wird wegen
if (v-Taster & 0x01) immer auch SerWrite() der TASTE 1 erzeugt. Abhilfe:
if (v-Taster == 0x01)

Gruß
Dieter

Sternthaler
15.01.2006, 23:42
@dgrobot
Ja, du hast absolut Recht mit deiner Vermutung das da ein Speicherbereich zu klein ist.
P.S.: Der Sendebuffer ist in der Datei asuro_st.h am Ende mit #define UART_TX_BUF_LEN 50 nicht auf 30 Zeichen, sondern auf 50 angegeben.
(Im übrigen ist dein angegeben Code für die Tastenabfrage für Testzwecke tatsächlich der sichere. Für eine echte Tastenabfrage vor einer 'angerumsten' Wand müsstest du dann aber ALLE Kombinationen der Tastewerte in einem Case abfragen.)

Es liegt aber nicht an dem Sendebuffer mit seiner begrenzten Länge, sondern an meinem eigenen Testprogramm.
Dort ist die Variable v_text mit 100 Zeichen definiert und ich Trottel schreibe beim Testfall auf Taste 6 102 Zeichen in diese Variable.

Nun also im Anhang eine korrigiert UND MIT WINNE-CODE VERSCHMOLZENE funktionsfähige Version. Kommentar wie gehabt in den Sourcen (Kopf und Funktion)

Ich hoffe ihr schaut alle nochmal genau nach was ich diesmal kaputt gemacht habe. ;-)

Vogon
10.05.2006, 23:24
... hoffe ihr schaut alle nochmal genau nach was ich diesmal kaputt gemacht habe. ;-)

Ist ja schon eine Weile her - aber es hat mir keine Ruhe gelassen.
Ich habe die serielle IO jetzt komplett mit Interrupt zum laufen bekomme. O:)

In der asuro.c habe ich mal eine Debug-Anzeige stehen gelassen.

BackLED((tx_aktiv) ? ON : OFF, (rx_aktiv) ? ON : OFF); //Debug Debug Debug Debug Debug Debug

Da kann man sehen wie ich das Problem mit dem Empfang der selbt gesendeten Zeichen gelöst habe.

dgrobot
11.05.2006, 09:52
@Vogon
Zunächst einmal meine Anerkennung für die Weiterverarbeitung des Themas.
Was ich mir allerdings wünschen würde, ist eine weniger trickreiche C-programmierung. (Wie mir wird es sicher noch manchem anderen gehen, der in C nicht sattelfest ist.)
Ich meine die Zeile

if (rx_aktiv) if (! --rx_aktiv) ;

in SIGNAL (SIG_ADC).

Mit freundlichem Gruß
Dieter Groß

Vogon
11.05.2006, 11:51
.. eine weniger trickreiche C-programmierung. ..

if (rx_aktiv) if (! --rx_aktiv) ;


Ich habe mir das so angewöhnt weil es für mich so besser zu lesen ist.

Um mein Gewissen zu beruhigen hab ich mal im "Kernigan + Ritchi" nachgelesen.

Zitat aus dem Kapitel:
2.6 Vergleiche und logische Verknüpfungen
Der Negationsoperator !, der wie ein Vorzeichen verwendet wird, liefert 0, wenn sein Operand nicht 0 ist, und 1, wenn sein Operand 0 ist. (in C gilt jeder numerische Wert, der von 0 verschieden ist, in Bedingungen als wahr, und der numerische Wert 0 gilt in Bedingungen als falsch.) Der Operatur ! wird häufig bei

if (!inword)
verwendet, anstelle von
if (inword == 0)

Man kann nicht völlig verallgemeinern, welche Schreibweise besser ist. Angaben wie !inword sind gut verständlich ("wenn nicht innerhalb eines Wortes"), aber kompliziertere Formulierungen sind oft scher verständlich.


Der letzten Satz drückt es ja schon aus. Das war den Erfindern schon 1977 klar. (Meine Ausgabe ist von 1983)

dgrobot
11.05.2006, 13:15
@Vogon,
danke für die schnelle Antwort; aber:


if (rx_aktiv) if (! --rx_aktiv) ;
Meine Frage bezieht sich nicht auf das Negations-Zeichen allein, sondern auf die zweite if-Bedingung, nach der ja nichts kommt. Das übersetze ich so, dass eigenlich nur rx_aktiv dekrementiert wird, wenn es vorher nicht 0 war;
also könnte es doch einfach so heissen:

if (rx_aktiv) rx_aktiv-- ;

Arexx-Henk
11.05.2006, 13:17
Hallo,

Ich glaube die Losung vom Warteschleife Ratsel ist eigentlich ganz einfach.
Mir begegnete es weil es Tx Probleme gab.


Vorbild:

- die Asuro sendet einige Daten mittels den

SerWrite() Funktion

- die Asuro schaltet direkt um nach empfangen mittels den

SerRead() Funktion

ohne diesen Warteschleiffe in die SerWrite() Funktion werden
die letzten drei Karakter vom transmitter nicht mehr
ausgestrahlt.

Warum nicht?

Guck mal in die SerRead() Funktion.

Dort steht u.a.

UCSRB = 0x10; //enable receiver

Mit diesen Kode wird die receiver eingeschaltet ABER
damit wird auch die transmitter direkt AUSgeschaltet.

Die Warteschleife ist lange genug um 3 Karakter zu versenden,
damit die zwei Karakter im UDR Puffer und das eine Karakter
im Tx-Schieberegister nach aussen geschieben sind wenn dass
Program die SerWrite() Funktion verlasst.


Eine schonere losung ware es die Warteschleife zu ersetzen
mit Folgendes:

//warte bis UDR und Schieberegister leer sind

while ( ! ( UCSRA | (1<<TXC) ) );

//reset handmassig den TXC bit durch schreiben einen '1' !
UCSRA |= (1<<TXC);


Dies alles hab ich ausprobiert und mit einem Oszi recherchiert.

Funktioniert Tadelos!


Gruss

Henk

Vogon
11.05.2006, 23:38
if (rx_aktiv) rx_aktiv-- ;

if (tx_aktiv) if (! --tx_aktiv) UCSRB |= ( 1 << RXEN ) ; // enable receiver interrupt + receiver
Hier, eine Zeile höher hat das if dann doch einen Sinn.

Du hast ja recht, da brauchts das nicht.
Aber die Zeile hatte ich kopiert und angepasst. (bin nicht nur denkfaul sondern auch schreibfaul!)

Arexx-Henk: Ich bin jetzt am überlegen wie du das meint ????
Wenn du eine Lösung ohne die Umschaltverzögerung kennst, dann baue es doch mal ein.
Es ist ja auch noch das Problem, das sich durch die gegenseitige Störung, nur der Transmitter oder der Receiver arbeiten darf.

Warum das alles ?
Ich möchte mit einem anderen ASURO oder Roboter und mit einem PC Daten austauschen können, ohne den eigentlichen Programmablauf zu unterbrechen. Da kann es nur von Vorteil sein, wenn der Datenaustausch per Interrupt und ausreichendem Puffer ablaufen kann.
https://www.roboternetz.de/phpBB2/viewtopic.php?p=176551#176551

Ich habe aber gerade einen ernsten Fehler gefunden für den ich noch keinen Ursache und Lösung gefunden habe.
Durch Zufall habe ich mal auf eine IR-Fernbedienung gedrückt - und das Testprogramm bleibt hängen ? ! ? ! ?
Edit: Habe den Fehler gefunden.
Ein ungültiges Zeichen muss von der UART abgeholt werden. Sonst wird der Interrupt ja nicht gelöscht ? ! ?

SIGNAL(SIG_UART_RECV)
{
int head_next;
head_next = rx_buf_head;
if ((UCSRA & ((1 << FE) | (1 << DOR) | (1 << PE ))) == 0)
{
rx_buf[head_next++] = UDR; // Das Zeichen im Buffer speichern
if (head_next >= UART_RX_BUF_LEN) head_next = 0; // Buffergrenze beachten
if (head_next != rx_buf_tail) rx_buf_head = head_next; // Überlauf ? noch Platz im Buffer ?
}
else head_next = UDR;
rx_aktiv = 5; // Transmitter erst einschalten wenn die Wartezeit abgelaufen ist.
}