Hi, ich habe nun meine ersten Zeichen erfolgreich zum PC übertragen. Das ganze mit einer einfachen Warte Abfrage auf das UCSRA Register und das UDRE Bit. Da ich aber lange Texte (bis zu 82 Zeichen...) übertragen möchte und das leider nur in 4800 Baud würde das ja wohl bedeuten wenn man es mit der Schleifen MEthode macht das ich mir mein Hauptprogramm abbremse. ;-( Nun habe ich gelesen das es auch für die TX Seite Interrupt Vektoren gibt nur steige ich noch nicht ganz dahinter wie es funktionieren soll. Ich habe meinen String den ich sende möchte im SRAM abgelegt. Wie ist denn nun der Ablauf wenn man es mit Hilfe der Interrupts senden möchte? RX macht mir keine Probleme das habe ich begriffen... :-) Für jeden Tip danbar... AVRli...
Hallo AVRLi, wenn ich das jetzt richtig im Kopf habe, dann mußt Du nur den Sendebuffer füllen und auf den dazu passenden Interrupt warten. Der Code sollte irgendwie so aussehen. Allerdings weiß ich jetzt nicht welchen AVR Du benutzt, somit ist der Code jetzt etwas allgemeiner gefaßt. Gruß Marcus char tx_buffer[82]; char tx_send = 0; char tx_end = 0; void init_UART(void) { //Parameter entsprechend Datenblatt einstellen! } void init_transmission(void) { tx_send = 0; //Die Position, die gesendet werden soll, zum //start erstmal auf Null stellen tx_end = strlen(tx_buffer); // Länge des Buffers ermitteln sei(); //interrupts aktivieren } SIGNAL (SIG_UART_TRANS) { if (tx_send < tx_end) //tx_send ist innerhalb des Datenstrings UCSRA = tx_buffer[tx_send++]; else cli(); //andernfalls Interrupt deaktivieren, denn es gibt nix mehr für die serielle Schnittstelle zu senden }
Hi Marcus, danke für den Tip! Leider habe ich es mal wieder verpennt zu schreiben was meine "Spielsachen" sind. ATmega8 und in Assembler... Mir ist nicht ganz klar wozu die beiden Interrupts da sind. Und wie man die eigendlich Übertragung dann anschubst... Gruß AVRli...
Hi AVRli der "transmittierende" Teil des USART am Mega 8 hat zwei mögliche Interrupts. Der eine wird ausgelöst, wenn ein neues Zeichen ins Datenregister gepackt werden kann (UDRE). Der zweite, wenn die Übertragung komplett ist (TXC). In deinem Fall kannst du in der ISR zum UDRE beispielsweise immer ein neues Zeichen aus deinem String im Datenregister ablegen. Dieses wird dann automagisch übertragen. Viele Grüße
Hi, danke... ist es dann so das man wenn ich im SRAM meine Daten abgelegt habe dann im UCSRB das BIT UDRIE setze um die Übertragung zu starten und wenn alle Zeichen übertragen sind das BIT wieder lösche? Im Moment springt es ja nun immer wierde in den Vector rein... Ist das korekt? Gruß AVRli...
Hi. du musst erstmal TXEN und RXEN setzen, aber das musstest du für die Interruptlose Kommunikation ja auch. Dann setzt du noch UDRIE, was bewirkt, dass immer wenn ein Byte fort ist (d. h. aus dem UDR Register raus) dieser Interrupt ausgelöst wird. Wenn alle Zeichen übertragen wurden, wird das UDRIE wieder gelöscht, sonst wird die ISR immer wieder aufgerufen... Grüße
Hi AVRli, Du solltest Dir erstmal überlegen, woran Du das Ende Deiner Zeichenfolge erkennen willst. Es gibt 2 Möglichkeiten: 1. Counter 2. Null am Ende des Strings In Deiner Sende-IR-Routine sendest Du also einfach solange Zeichen, bis die Ende-Bedingung erfüllt ist. Dann schaltest Du den TXD-IR ab mit: UCSRB &= ~_BV(UDRIE); // disable the transmitter-IR Wenn Du einen String senden willst, schreibst Du den Ptr auf den String in die IR-Ptr-Variable und gibst den TXD-IR frei: UCSRB |= _BV(UDRIE); // enable the transmitter-IR Bevor das alles so einfach funktioniert, musst Du den UART initialisieren. Und da geht das Henne-Ei-Problem los: Das Flag UDRE ist nach dem Reset Null und kann auch nicht manuell gesetzt werden. Die einzige Möglichkeit, die ich kenne: ein erstes Byte manuell (ohne IR) in das TXD-Register schreiben. @Marcus: Mit cli und sei beeinflusst Du alle IRs gleichzeitig. Wenn Du also auch andere IR benutzen willst, solltest Du unbedingt das spezifische IR-Enable-Register der entsprechenden Hardware (in diesem Fall UDRIE) benutzen. Stefan
Hi Stefan, "Das Flag UDRE ist nach dem Reset Null und kann auch nicht manuell gesetzt werden. Die einzige Möglichkeit, die ich kenne: ein erstes Byte manuell (ohne IR) in das TXD-Register schreiben." Da das so nicht im Datenblatt steht, habe ich das grad' auch noch mal ausprobiert ;-> Und es ist wirklich so, dass der UDRE - data register empty interrupt - sofort ausgelöst wird, sobald UDRIE und natürlich das globale Interruptflag gesetzt sind. Man muss also das erste Byte nicht selbst schreiben... Viele Grüße
Hallo Thomas, danke für den Tip. Ich verwende bei meinem eigenen Code nicht das UDRIE-Flag, sondern das TXCIE-Flag. Bei dem läuft es so wie ich beschrieben habe, und ich habe das dem UDRIE-Flag ohne zu testen auch unterstellt. Normalerweise ist die Verwendung des UDRIE besser. Weil ich bei meiner Appl. aber XON/XOFF-Handshake benutze, verwende ich das TXCIE. Dadurch ist der Ausgangspuffer des UART beim Senden immer leer (doppelte Pufferung). Der Recieve-IR kann also XOFF-Bytes direkt in den Transmitter schreiben, ohne eine laufende Ausgabe zu stören. Stefan
Hi Stefan, die Verwendung des UDRIE hat halt den einen Vorteil, dass man schon ein neues Byte zum Transfer abgeben kann, während das andere noch durch die serielle Übertragung geschoben wird. Aber das war's doch auch schon?! :) Viele Grüße
Hi Thomas, bei manchen Sachen sind die beiden unterschiedlichen Flags schon ganz hilfreich, z.B. bei RS485: der letzte macht das Licht aus ;-) Viele Grüße, Stefan
Hi, also ich habe es mit dem UDRE Interrupt gelöst. Alles super so! ;-) Also meine Daten liegen im SRAM und enden mit der 0. Wenn die Daten im SRAM gespeichert sind wird das UDRIE Bit gesetzt. In dem Interrupt wird nun immer das nächste Zeichen geleaden und ausgesendet. Ist er bei der 0 angekommen dann wird das UDRIE Bit wieder gelöscht. Funktioniert wirklich gut. Ich danke für die Infos. Es macht es schon leichter wenn man sich austauscht. Gruß AVRli...
Hi, nun bin ich dabei die Anwndersoft auf dem PC zu schreiben und da ist mir aufgefallen das ich was in der Software vom ATMEL (ATmega8, Assembler) was übersehen haben muss. Ich schicke meine Abfragen zyklisch zum AVR... kurze Antworten von 3 Zeichen kommen richtig an zum PC. Längere die dazwischen sind werden nach halber aussendung von der Antwort der nächsten Anfrage überschrieben. Mit einer Pause zwischen den Befehlen kann ich nicht leben... Also Sende 1 Sek warten sende ... Wie würdet ihr sowas lösen? Die Möglichkeiten die mir einfallen sind wohl nicht ideal. 1. Doch nicht im Interrupt aussenden und das ganze AVR Programm abbremsen 2. keine Zeichen annehemen solange nicht die komplette Antwort raus ist. (hier gehen dann Zeichen verloren oder) Gruß AVRli...
Hi AVRli, kannst du mir das nochmal anders erklären :-> irgendwie stehe ich aufm Schlauch und kapier nicht so recht, was du meinst. Wenn deine Abfragen nicht schneller kommen, als die Übertragung des Strings anhand seiner Länge und Baudrate dauert, leuchtet mir nicht ein, warum nur ein Teil übertragen werden sollte... Mir wird nicht klar, warum dies ein Problem der Übertragung mittels Interrupt sein soll.
Hi AVRli, das macht es etwas komplizierter. Du brauchst einen Ausgangs-Puffer, analog zum Eingangspuffer des RXD-Teils. Zum Verschicken reicht es dann nicht mehr, einfach den Pointer des Strings zu kopieren, sondern Du musst alle Zeichen aus dem String in den Puffer kopieren. Nicht vergessen: Beim Kopieren in den Puffer und auch beim Auslesen die obere Puffergrenze und den Puffer-Füllstand kontrollieren. Du brauchst also: * den Puffer selbst, Größe je nach Anforderung * einen Puffer-Index für die Füll-Routine * einen Puffer-Index für den TXD-IR Viele Grüße, Stefan
Hi, @Thomas Ja das Problem ist folgendes... Ein Befehl PC>AVR sieht bei mir so aus das er mit einem CR endet. Also so... SET1 wenn alle Zeichen im AVR sind dann schreibt der in den SRAM die Zeichen rein die er aussenden soll. Soweit ok... Sendet man nun aber SET1 SET2 SET3 hintereinander zum AVR dann bekommt man nur die Antwort vom letztem Befehl richtig zum PC gesendet. Grund dafür dürfte sein das die Antwort auf den letzten Befehl noch nicht fertig ist und dann die neue einfach begonnen wird. :-( Ok? @Stefan Danke für den Tip... werde erstmal darüber schlafen.... :-D Gruß AVRli...
du brauchst einfach einen eingangspuffer von was weiss ich wievielen befehlen den dein programm dann der reihe nach abarbeitet
Hi AVRli also gut, dann wirds wohl ein Eingangspuffer im AVR tun oder noch einfacher: dafür sorgen, dass der PC keine Kommandos schickt, solange die Abarbeitung eines anderen Befehls noch läuft.
Hi, > also gut, dann wirds wohl ein Eingangspuffer im AVR tun Ja habe ich hinbekommen so eine Art "Ringbuffer"... Die Antwort vom AVR wird nun temporär im SRAM abgelegt diese darf max. 82 Zeichen haben. Anschließend werden die neuen Zeichen in den Ringbuffer (255 Zeichen) geladen. Nun wird der TX int. aktiviert. Und er sendet fleißig los. Kommt nun einen neue Anfrage dann wird diese im Ringbuffer angehangen. Das ganze funktioniert so lange einwandfrei bis man ein Dauerfeuer an Kommandos gibt. Der Ringbuffer ist hier nun 255 Byte groß. Da knallt es wenn man also 4 mal eine Antwort mit 80 Zeichen bekommen will... aber das ist total nebensächlich !!!! ;-) Das kommt in der Praxis nie vor !!! In der Praxis werden alle 500ms eine Antwort von ca. 50 Zeichen erwartet. > oder noch einfacher: dafür sorgen, dass der PC keine Kommandos > schickt, solange die Abarbeitung eines anderen Befehls noch läuft. Ja die Lösung hatte ich auch in Betracht gezogen da man ja einen neuen Befehl hätte blöcken können solange nicht die ganze Antwort da ist... ;-I Aber geschickt ist das nicht... hahahahaha Kostet unnötig Resourcen... Ich freue mich riesig das ich es, dank eurer Hilfe, auf die Reihe bekommen habe. Gruß AVRli...
Hi, >> oder noch einfacher: dafür sorgen, dass der PC keine Kommandos >> schickt, solange die Abarbeitung eines anderen Befehls noch läuft. >Aber geschickt ist das nicht... hahahahaha >Kostet unnötig Resourcen... Wie jetzt, was ist daran ungeschickt :-P Und was kostet das für Resourcen? Du sollst da ja an dem Steuerrechner kein "Busy-Wait" draus machen :)
Hi Thomas, ja na ungeschickt in der Form das man auf der PC Seite damit beschäftigt ist ständig zu schauen ob die Schaltung fertig ist mit der Abarbeitung. Nun kann ich ganz sorglos meine Befehle an einem Stück absenden und tu dies nun alle 500ms der Atmel hingt zwar etwas hinter her aber das stört nicht weiter. Die Befehle hat er locker nach 500ms beantwortet. ;-) Ohne nur eine Antwort zu zerstückeln. Finde es eleganter und das wird es leichter machen wenn Software anderer Entwickler mit meiner Schaltung "spielen" wollen. Gruß AVRli...
Hi, der PC hat ja auch sowas wie Interrupts :) muss man also nicht ununterbrochen pollen, um rauszufinden, was der µC tut. Aber es ist schon richtig, ein Puffer im µC schadet nicht. Nur muss man sich der Grenzen trotzdem bewusst sein... irgendwann ist der nämlich auch voll. Grüße
übrigens: Baudrate hochsetzen verringert solche Probleme oft extrem. Bei 115kbaud brauchen 80 Zeichen keine 8ms mehr. Happy praogramming, Stefan
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.