Hallo Forumsleute, ich habe ein C Programm mit UART interrupts gemacht und moechte es in AVR Studio simulieren. Ich sende das erste byte, dabei wird ein ISR-Signal erzeugt und die naechsten Zeichen werden dann in der ISR rausgeschickt. while (!(UCSRA & (1<<UDRE))) ; UDR = cmd[0]; Dieser Befehl (UDR = ...) erzeugt doch das ISR-Signal SIG_UART_TRANS. Der Simulator springt aber nicht in diese ISR. Das TXCIE bit in UCSRB ist gesetzt, der interrupt muesste doch funktionieren. was mach ich falsch? oder kann man UART-Interrupts in AVR Studio nicht simulieren. ganz "nebenbei": meine Hilfe im AVR Studio funktioniert nicht. Click auf "AVR-GCC plug-in Help" ruehrt sich ueberhaupt nicht, alle anderen links zu User Manual und User Guide funktionieren auch nicht. Ich hab das SP2 zur Version 4.12 installiert, geht aber auch nicht. vielen Dank fuer Tips, Johannes
Du musst Dich schon entscheiden, ob Du nen Interrupt auslösen oder ob Du die Flags im Polling-Verfahren abfragst. Beides gleichzeitig geht garantiert in die Hose. BTW: hast Du die Interrupts auch global freigegeben?
Hi Johnny, danke fuer die Antwort. gobale interrupts sind enabled, sei(); Ich will nicht polling-Verfahren sondern ISR. Den Code, den ich verwende hat bisher auf meinen AVRs funktioniert. Ich hab den Code jetzt einfach kopiert und Variablen etc. angepasst. sorry die Frage: was bedeutet "BTW" - bin kein AKS (Abkuerzungsspezialist) :-) mg, Johannes
btw = by the way manche haben einen Aküfi... Zeigt doch mal deinen Code.
BTW heißt 'By the way' (auf deutsch: 'übrigens'...:-) Du fragst mit 'while (!(UCSRA & (1<<UDRE)));' das UDRE ab (Das nennt man Polling). Wenn Du nen Interrupt aktiviert hast, kannst Du Dir das aber sparen, weil das UDRE, sobald es gesetzt wird, eh den Interrupt auslöst. Deshalb meine Vermutung, dass es da zu ner Kollision kommt. Mit dem kurzen Codeschnipselchen kann ich aber nicht mehr anfangen, da der Kontext fehlt. Gruß Johnny
1.: Mach mal ein Update von Deinem WINAVR und benutze ISR anstatt SIGNAL 2.: Du wertest einen Interrupt aus, der ausgelöst wird, sobald UDR leer ist (also UDRE = 1)(Vermute ich jedenfalls, habe die alten Vektorbezeichnungen von WINAVR nicht mehr parat). UDRE wird afaik beim Einsprung in die ISR gelöscht, so dass der µC sich in der Abfrage 'while (!(UCSRA & (1<<UDRE)));' für immer und ewig aufhängt, weil UDRE nie wieder gesetzt wird. Was soll diese Abfrage überhaupt bewirken?
Sorry, hab grad gesehen, dass Du den normalen Transmit Interrupt aktiviert hast. Also vergiss 2. von oben.
Ich würde das eher mit dem UDRE-Interrupt lösen. Das TXC-Interrupt wird erst ausgelöst, wenn ein Byte komplett gesendet wurde. Das nutzt aber nicht den Doppelpuffer der USART aus... Das UDRE-Interrupt darf man natürlich erst freigeben, wenn man wirklich senden will... Man könnte send_cmd auch als void deklarieren... In die ISR springt der Controller sobald das Byte komplett gesendet wurde... und das kann einen Moment dauern (breakpoint setzen und dann den Simulator laufen lassen). TXC benutze ich, um RS485-halbduplex-Kommunikation zu realsisieren (bei TXC wird der Bus wieder freiggeben bzw. der TRansceiver auf Empfang geschaltet).
> bytecountSen==0;
Das dürfte nix bringen. Ein '=' muss vermutlich weg...
Abgesehen davon wird der Sende-Interrupt nicht beim Schreiben des UDR
ausgelöst, sondern dann, wenn der Sendevorgang abgeschlossen ist.
Hallo, Danke fuer die Muehe. UDRE ist laut Datenblatt nur lesbar, nicht beschreibbar. Sobald das UDR leer ist - also bereit neue Daten zu empfangen, die abgeschickt werden sollen, wird dieses Bit automatisch gesetzt. Die Abfrage stammt aus dem Tutorial hier auf der Seite und bewirkt, dass solange gewartet wird bis das UDRE bit gesetzt ist, also bis man neue Daten losschicken kann, indem man sie ins UDR schreibt. Diese Sachen funktionieren seit Jahren. Auch meine Struktur mit den ISRs haben bisher immer gut funktioniert. Ich simuliere allerdings zum erstenmal mit AVR Studio, hier will es offenbar nicht so wie ich... ich vermute das AVR Studio hinter dem Problem, dass es nicht jedwelche interrupts Interrupts simulieren kann. Wie kann man pruefen ob ein Interrupt tatsaechlich erzeugt wird? Offensichtlich ist das nicht der Fall und das TXC flag wird auch nicht gesetzt wenn ich etwas ins UDR schreib... Johannes
sorry! es geht ja schlag auf schlag :-) ich muss etliches zuruecknehmen... Johannes
Bis jetzt hatte ich bei der Simulation von seriellen Interrupts im AVR-Studio noch keine Probleme. Wenn ich heute abend dazu komme, probiere ich deinen Code mal zu simulieren.
Ich bin die Sache Schritt fuer Schritt durchgegangen. nachdem "UDR = cmd[0]" Befehl geht das Programm einfach weiter ohne in die ISR zu springen. Das TXC flag, das den Interrupt ausloest, wird nie danach gesetzt. Fuers Ausprobieren danke! Falls ich dahinter komm meld ich mich natuerlich. Gruss, Johannes
> UDRE ist laut Datenblatt nur lesbar, nicht beschreibbar.
Dem hat hier auch niemand widersprochen.
AVRStudio hat zwar tatsächlich einige Macken was die Simulation
bestimmter Hardware-Ereignisse angeht, aber UART ist afaik davon nicht
betroffen.
(Ach ja, bevor Du fragst: 'afaik' heißt 'as far as I know', auf
deutsch 'soweit ich weiß'. Sorry, abkürzen ist so ne Gewohnheit;-)
Hast Du die falsche Zuweisung korrigiert? Andere Frage: Denkst Du daran, dass die Simulation in AVRStudio nicht in Echtzeit ist? Bei 9600 Baud dauert eine Übertragung ne Weile. Wenn Du da ungeduldig wirst... Außerdem: Warum benutzt Du unten nicht cli() und sei()?
Jawohl Herr Kapitaen. ... genau das meinte ich mit "zuruecknehmen": meine belehrenden Ausfuehrungen mit leicht pedagogischen touch. danke fuer die Erklaerung zum "afaik"! BTW "mg" bedeutet mit Gruss ;) mg, Johannes
...Mal eben nachgerechnet: Bei 9600 Baud und einem Oszillatortakt von 16 MHz dauert die Übertragung eines Bytes über 13000 Taktzyklen...
sach ich doch: Breakpoint in die ISR setzen, F5 drücken und warten, bis der Simulator am Breakpoint stehen bleibt. Wenn er das nach einer Weile nicht gemacht hat, kann man ihn mit STRG-F5 anhalten, um zu sehen, womit sich der "Controller" gerade beschäftigt. Wenn man dann noch ein paar sinnvolle watches setzt, kann man sich angucken, wo der Hund begraben ist.
Jawohl, Spass muss sein. Deswegen bist du wohl auf die 13 gekommen. Tatsache ist aber, dass ich noch immer nicht check, warum mein Simulator nicht funzt. Ich werd mich mal ein wenig bilden = "Datenblatt lesen", vielleicht gibts dort einen tip. mg, Johannes
Nö, die 13(tausend) sind mathematisch fundiert (zumindest in grober Näherung). Ist nur so'n Zahlenwert, damit Du ne Ahnung davon hast, was der µC bis zum Auftreten eines einzigen Sende-Interrupts fürn Unfug machen kann (in 13000 Zyklen kann der ne Menge Mist bauen. Ist für den ne halbe Ewigkeit.) Und dass Du nicht auf die Idee kommst, das ganze mit Einzelschritten durchzuspielen. Könnte sein, dass danach Deine Maus bzw. Tastatur ihre Nenn-Lebensdauer erreicht haben und Du immer noch keinen Interrupt hast...;-) mFg Johnny
Was hast du denn gerechnet? 1/16Mhz*13000*9600 = 7.4 bei 1MHz=1/(1024hoch2). Die 13000 Zuklen sind die Zeit zwischen zwei zu sendenden bits. Woher weist du, dass das Senden selber tatsaechlich diese Zeit in Anspruch nimmt? das glaube ich naemlich nicht. Ich denke eher das senden eines bits dauert wenige zuklen und alle anderen bis zu 13000 werden vom uC (hoffentlich vernuenftig) verwendet. Allerdings stimmt es, dass beim zweitenmal in der Schleife das UDRE bit nicht mehr gesetzt ist, offensichtlich also Daten im UDR sind, die noch nicht gesendet wurden. Diese Situation aendert sich allerdings auch nach ueber 500000 Takten nicht. Der uC springt nicht in die ISR; dort incrementier ich ein Variable um das zu testen, aber die bleibt ewig Null...
Wenn Du das UDR schreibst, werden die 8 Bits aus UDR der Reihe nach mit der eingestellten Baudrate (9600 Baud, also 9600 Bit/s) ausgegeben. Da der µC pro Sekunde 16000000 Taktzyklen hinlegt, macht er während der Übertragung (16000000 / 9600) * 8 Zyklen (ungefähr). Vom Moment des sendens (durch Schreiben von UDR) bis zum Auslösen des Transmit Complete-Interrupt vergehen also ungefähr 13000 Taktzyklen, die der µC großenteils mit Warten verbringt. Diese Taktzyklen müssen aber trotzdem in der Simulation berücksichtigt werden, auch wenn der µC in einer Endlosschleife rumeiert...
Was mir grad noch auffällt: Du rufst in der Endlosschleife am Ende des Hauptprogramms immer wieder die Funktion 'send_cmd(AS_nr);' auf. So wie ich das verstehe (korrigiere mich, wenn ich daneben liege) soll diese Funktion aus dem Programm nur am Anfang einmal aufgerufen werden, um die ganze Sache anzustoßen. Den Rest der Übertragung macht doch die ISR, oder nicht???? So wie es da steht kann es eigentlich nur Probleme geben. Gruß Johnny
Naja, wenn man erst die Werte mit get...(); vom Sensor holt, sollte man sie danach auch verschicken.
Das ist schon korrekt, aber für das Versenden muss man sich schon auf eine Methode einigen. Die beiden im Programm kollidieren garantiert...
...hmmm. Ich bin mir nicht sicher, ob der uC die Zeit nicht doch ausnuetzen kann. Ist der UART-Block nicht unabhaengig? Sprich er wird konfiguriert/initialisiert und erhaelt dann seine Daten und verrichtet sich damit ohne, dass der uC warten muss - quasi parallel. Ganz unabhaengig natuerlich nicht, zB Takt nimmt das UART Modul schon ueber den uC. Sprich der uC kann 1+2=3 rechnen und speichern waehrend zB bit 6 und 7 am USART mit der Geschwindigkeit von 9600buad abgeschickt werden. stimmt das nicht? mg, Johannes
Da liegst du richtig. Deswegen ist es auch so schön, mit Interrupts zu arbeiten...
Hallo Rahul, hallo Johnny, also meine Software ist noch in der Testphase, wer haette das gedacht :)... Ich will jetzt am Anfang erst einmal den Sensor auslesen und dann die Daten abschicken wie Rahul richtig erkannt hat. Spaeter einmal werd ich nur dann senden, wenn es erwuenscht ist, zB auf Knopfdruck oder Commando vom host etc... Ich hab mal mein UART Modul in die Codesammlung gestellt. Das Programm ist getestet. Es lief auf meinem ATMega16 richtig und ohne Probleme. der Link: http://www.mikrocontroller.net/forum/read-4-274151.html#new Ich hab dieses kleine Programm auch ausprobiert und es tritt das gleiche Phaenomen auf wie in meinem jetzigen Programm: Beim ersten Sprung in die send_cmd() Funktion ist das UDRE bit gesetzt. Ich schreibe in UDR, das bit bleibt gesetzt (?!). Das Programm lauft weiter ohne in die ISR zu springen. Beim zweitenmal komm ich auch dazu ins UDR zu schreiben, aber diesmal wird das UDRE bit geloescht, und das Programm lauft weiter. Da das TXC flag nie gesetzt wird, geht meine ISR nie los. Aber dieses Programm hatte auf dem uC funktioniert. Ich vermute immer noch, dass der Bug nicht bei mir ist. Kann es aber auch nicht ausschliessen. mg, Johannes
Das eigentliche Problem ist ja gerade, dass der µC beschäftigt werden will, während er auf den Interrupt wartet, der ihm mitteilt, dass der letzte Wert weg ist und der nächste gesendet werden kann. Wenn Du aber, während er noch am senden ist (was, wie gesagt, mehr als 13000 Taktzyklen pro Byte beansprucht) schon wieder was neues senden willst und die entsprechende Funktion aufrufst, dann gibts Komplikationen. Dann wartet er nämlich in der Funktion send_cmd(), bis UDRE gesetzt wird (also bis der letzte Sendevorgang abgeschlossen ist). Sobald UDRE 1 wird, springt er aber auch schon in die ISR und sendet von dort aus den nächsten Wert, dann wieder in die Funktion. Dort wird dann (diesmal ohne zu warten, denn die Warteschleife wurde ja bereits abgebrochen) nochmal gesendet. Das ist dann der Punkt, an dem es kollidiert.... Das eigentliche Problem Deines Programms ist, dass Du die Funktion send_cmd() sowohl aus der Funktion als auch aus der ISR heraus aufrufst. Da dürfte nicht viel Sinnvolles beim Empfänger ankommen. Warum in der Simulation kein Interrupt auftritt, kann ich nicht sagen, solange Du nicht sagst, wie Du das simulierst. Wie gesagt, die Simulation ist nicht in Echtzeit...
>Ich schreibe in UDR, das bit bleibt gesetzt (?!). Das liegt daran, dass die meisten AVR ein doppelt gepuffertes UART haben. Es ist also noch ein UDR (unter der gleichen Adresse) frei. >Sobald UDRE 1 wird, springt er aber auch schon in die ISR und sendet >von dort aus den nächsten Wert, dann wieder in die Funktion Nee, die ISR reagiert auf das Ende eines gesendeten Bytes, wenn also ein Byte komplett gesendet wurde. Das kann man (wie oben schon erwähnt) hervorragend für halbduplex-Übertragungen benutzen (RS485-2wire). Um interrupt-gesteuert eine Reihe von Bytes über das UART zu den senden, benutzt man (z.B. ich) das UDRE-Interrupt. Dieses Interrupt wird immer dann ausgelöst, wenn das (mindestens ein) UDR leer ist. Deswegen sollte man das Interrupt-flag erst dann setzen, wenn man wirklich senden will. SIGNAL(SIG_UART_EMPTY) // ich gehe mal davon aus, dass der UDRE-Vektor so heisst...nachgucken! //ISR for transmitting via serial Interface { if (bytecountSen >= PLENGTH) //bytes 0 bis PLEGNTH sind gesendet { bytecountSen=0; UCSRB &= ~(1<<UDRIE); // UDRE-Interrupt wieder sperren } else { UDR = cmd[bytecountSen++]; // Daten senden } } void send_cmd(uint8_t AS_nr) { cmd[0] = STX; // start of text cmd[1] = AS_nr; // sensor number cmd[2] = position >> 8; // position high byte cmd[3] = position & 0xFF; // position low byte cmd[4] = flags; // flags cmd[5] = 0; // Error code; 0 --> OK cmd[6] = ETX; // end of text bytecountSen = 0; // start sending UCSRB |= (1<<UDRIE); // UDRE-Interrupt freigeben // UDR = cmd[0]; // Das kann man sich durch die Freigabe des Interrupts sparen... }
Aha! danke Rahul, verstehe das Prinzip. Ehrlich gesagt scheint mir das logischer als meines. Ich hatte das in meinen Anfaengen bei einem Freund so gesehen und es uebernommen. Bisher hat es immer seinen Dienst getan. Aber man kann ja auch mal was aendern, was jahrelang funzte. Der USART vector heisst: SIG_USART_DATA (falls hier mal jemand nachliest). Johannes
an den Anfang von send_cmd sollte noch while (bytecountSen>0){} sonst könnte das Paket verstümmelt werden
Hallo, also die Sache mit dem Interrupt funktioniert jetzt. Um ein byte zu senden braucht er ca. 16000 Zyklen (bei 9600baud)!! Allerdings muss ich jetzt noch ueberpruefen ob er die richtigen bytes sendet... mg, Johannes
>Allerdings muss ich jetzt noch ueberpruefen ob er die richtigen >bytes
sendet...
Kann schon sein...
Wo liegt das Problem?
Das Problem ist, dass ich die sendeFunktion aufruf, bevor die 7 byte des Protokolls gesendet sind, und dabei wird byteCountSen zu Null gesetzt. Das problem liegt mal wieder beim Programmierer :) "trozdem ist natuerlich der Computer schuld, dass es nicht funktioniert hat" Ich habs geschnallt, jetzt funktioniert es sowie ich es will, und wie es mir logisch vorkommt. Vorher hats wahrscheinlich auch logisch funktioniert, aber ich hatte es nicht verstanden, also war der Computer schuld... Ich schreib gleich noch einmal das Programm in der funktionierenden Version. Ich musste eine Variable sendComplete einfuegen um zu testen ob alles gesendet war oder nicht. Aber es funktioniert damit. Im Schnitt werden 16639 Zyklen benoetigt um 1 byte bei 9600 rauszuschieben. In dieser Zeit warte ich einfach (vorlaeufig, spaeter werd ich was sinnvolles damit machen) bis gleich, Johannes
Du könntest auch per "if (UCSRB & (1<<UDRIE)) ..." abfragen, ob die Schnittstelle "noch belegt ist". Eine andere Möglichkeit hast du ja schon beschrieben.
> >Sobald UDRE 1 wird, springt er aber auch schon in die ISR und sendet > >von dort aus den nächsten Wert, dann wieder in die Funktion > Nee, die ISR reagiert auf das Ende eines gesendeten Bytes Eben. Das ist (oder besser: war) ja das eine Problem. Er löst auf TXC einen Interrupt aus, fragt aber GLEICHZEITIG in einer anderen Routine das UDRE ab. Und genau da hats ja auch geknallt. Wenn er UDRE in einer Warteschleife abfragt und es '1' wird, wird u.U. quasi im selben Moment auch TXC '1' und er springt in die ISR. Danach wird möglicherweise alles Mögliche gesendet, nur nicht in der richtigen Reihenfolge... Aber hat sich ja anscheinend erledigt...
hallo, hier also das Funktionierende Programm. BTW: Die Auslesefunktion liest die Daten eines Sensors aus: Es handelt sich um den AS5045 von www.austriamicrosystems.com. Nicht das jemand denkt, ich wuerde es nicht sagen wollen. Hab die Funktion nur herausgeholt um ein wenig uebersichtlicher zu bleiben. Wer daran interessiert ist schreibt ne email an johannesphilippi{bei}web{punkt}de. Danke an Johnny und Rahul! mg, Johannes
Das "sendComplete = 0" würde ich schon in die "send_cdm()" packen. Dann greift es schon früher und verhindert einen neuen Zugriff auf die Messung und die Datensendung. Ist aber eher eine Schönheitskorrektur. In der ISR würde ich sowenig wie möglich machen.
solange du keine RX-Interruptroutine hast solltest du diese nicht aktivieren.
Hallo, unter folgendem Link ist eine Version des Programms mit einer groben Zusammenfassung der Ergebnisse(im Header) aus diesem Thread zu finden. http://www.mikrocontroller.net/forum/read-4-358508.html?reload=yes#358508 Korrekturen natuerlich weiterhin gerne willkommen falls notwendig. von fern der Heimat gruesst, Johannes
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.