Guten Abend, Ich habe mal eine Frage bzgl. des Bits U2X im Usart Register beim 328P. Ich habe für mein Flugsimulator ein VHF Radio gebaut welches mir ermöglicht die Frequenzen für die Flugsicherung einzudrehen und dann über USART zum PC zu senden, wo dann eine Software mit mein Flug Simulator interagiert und die Frequenz im Simulator eindreht. Ich benutze für das darstellen der Frequenzen 7 Segment Anzeigen. 5 Stück pro Frequenz also insgesamt 10. Diese tute ich per 74HC595 Shift Register Multiplexen um Pins zu sparen. Angesteuert werden die 7 Segment Anzeigen mit 100Hz, so das kein Flackern zu erkennen ist. Jede 1ms setze ich ein Flag in einer ISR um im Hauptprogramm dann die Segmente anzusteuern. Das ganze funktioniert auch ohne Probleme. Bis dann die Kommunikation mit dem USART kam. Ich arbeite normaler weiße nur mit 9600 Baud Rate. Da aber das Senden dann so lange gedauert hat das der Controller sich dort ein bisschen verzögert hat sich auch die ISR verzögert was dazu führt das die Multiplex Frequenz auf 15 Hz abfiel und ein Flackern erkennbar war. Ich habe dann bei mir in Datenblatt geschaut unter "Table 20-7" UBBRn Settings für fosc=16.00000 MHz. Da nur relativ hohe Baudraten in frage kamen um den Sendevorgang vorher zu beenden bevor die ISR ins Stocken gerät. Habe ich mir auf 230.4k, 250k, 0.5M Baudraten begrenzt. 230.4k hat zu viele Fehler bei 16 MHz. Bei 250k kann man immer noch ein flackern erkennen. Bei 0.5M ist das flackern weg. In meiner Initialisierung des Usart ist eine abfrage mit USE_2X drin. Wenn ich das richtig verstanden habe wird dort die Teiler von 16 auf 8 gesetzt und somit die Baudrate verdoppelt? Also bei 250k Baudraten wären es dann 500k? Was wäre dann besser 500K ohne U2X oder 250K mit U2X oder macht das am Ende immer noch kein Unterschied weil die gleiche Menge an Daten mit der gleichen Geschwindigkeit durchs Kabel jagen? Ich habe ein bisschen Sorgen das, wenn ich 0,5M Baudrate dauerhaft nehme das "Daten-Pakete" auf der 45cm langen Kabelstrecke zum USB Wandler aufgrund der hohen Baudrate verloren gehen, oder kann man das getrost vergessen, den laut Datenblatt sind es ja immerhin 0% Fehler @ 16 MHz. Oder sollte man lieber den 328P über ein anderes Interface mit einem anderen Prozessor kommunizieren lassen(bzp. Attiny) der dann als USART dient? Was aber wiederum auch Verschwendung wäre, weil der 328P das auch selbst erledigen könnte. Mfg
Sende und empfange via Interrupt und all deine Probleme sind vergessen.
H.Joachim S. schrieb: > Sende und empfange via Interrupt und all deine Probleme sind > vergessen. Hallo Joachim! Im UCRS0B Register habe ich im Moment nur das RXCIE0 Bit gesetzt. Alle Daten die vom PC aus an meinen Controller gesendet werden in der USART RX ISR wieder zu einem String zusammengesetzt und dann von einer Funktion weiterverarbeitet bzw. darauf entsprechend reagiert. Ich weiß das es auch das TXCIE0 Bit für das UCRS0B Register existiert. Wenn ich das richtig verstanden habe wird das USART TX vect nachdem erfolgreich inkl. Stopp Bit erfolgreich gesendet wurde, ausgelöst. Also bringt Sie mir nix? Oder verstehe ich da was falsch? Meine Funktion die ich im Moment fürs Senden nutze sieht so aus:
1 | void sendToSerial(char c[]) { |
2 | for (int i = 0; i < strlen(c); i++){ |
3 | if(c[i] != 0) { |
4 | while (( UCSR0A & (1<<UDRE0)) == 0){}; |
5 | UDR0 = c[i]; |
6 | }else{ |
7 | break; |
8 | } |
9 | } |
10 | } |
Mfg
Felix N. schrieb: > Meine Funktion die ich im Moment fürs Senden nutze sieht so aus Diese Zeilen enthalten nicht das Problem. Denn prinzipiell ist diese Routine unterbrechbar. > Also bringt Sie mir nix? Oder verstehe ich da was falsch? Wenn Interruptquellen nichts bringen würden, dann hätte man sie nicht eingebaut. Der Trick ist dann letztendlich, eine Interruptroutine so kurz wie irgend möglich zu halten. Die Empfangsroutine empfängt nur, sie wertet aber nicht aus. Eine Anzeigeroutine zeigt nur das an, was in der Hauptschleife berechnet und schon passend "vorverdaut" und zurecht gerechnet wurde. Die ganze Arbeit wird letztlich in der Hauptschleife erledigt. Und die wird aus diesem Grund auch nicht mit einem "while" angehalten. Sondern es wird nur abgefragt, ob das Senderegister frei ist. Falls ja, dann wird das nächste Zeichen gesendet, falls nein, wird mit dem Hauptprogramm weitergemacht. Irgendwas gibt's immer zu tun. Aber häng doch einfach mal deine C Dateien hier an...
Lothar M. schrieb: > Diese Zeilen enthalten nicht das Problem. Denn prinzipiell ist diese > Routine unterbrechbar. Das würde ich nicht so sagen. Denn der Code enthält ja eine while abfrage:
1 | while (( UCSR0A & (1<<UDRE0)) == 0){}; |
in der er wartet bis er neue Daten senden kann. Und dort wird sich der Controller dann verzögern, oder nicht? Lothar M. schrieb: > Wenn Interruptquellen nichts bringen würden, dann hätte man sie nicht > eingebaut. Ja aber laut Datenblatt wird USART_TX_vect erst ausgelöst wenn alle Daten inkl. das Stopp Bit gesendet wurden. Dann muss ich ja trotzdem die Daten mit der while Schleife senden und bekomme so gesehen nur das "ok" später in der ISR. Lothar M. schrieb: > Der Trick ist dann letztendlich, eine Interruptroutine so kurz wie > irgend möglich zu halten. Hab ich schon öfters gehört. Ich versuche dort nur mit Flags zu arbeiten, und Integer zu inkrementieren(Präzises Timing). Lothar M. schrieb: > Aber häng doch einfach mal deine C Dateien hier an... Klar mache ich gerne.(Und ja ich weiß ich habe viele Globale Variablen, die brauche ich später noch, mein Programm ist noch nicht mal zur Hälfte fertig) RotaryEncoder.c/h kommen hier aus dem Forum, sind nur so abgeändert das ich zwei Encoders ansteuern kann. ADC.c/h ist nur zum init des ADCs und zum auslesen. Usart.c/h erklärt sich glaubig selbst :) Mfg
Ich stimme H.Joachim S. zu. Du brauchst einen Sende-Puffer, der Interruptgesteuert abgearbeitet wird.
Felix N. schrieb: > Dann muss ich ja trotzdem die > Daten mit der while Schleife senden und bekomme so gesehen nur das "ok" > später in der ISR. Nein, du schreibst alle Daten in einen Puffer und die ISR sendet im Hintergrund Byte für Byte raus. Der Puffer sollte wenn möglich so groß sein, dass deine längste zu sendende Nachricht reinpasst. Weit verbreitet und gut ist die UART-Lib von Peter Fleury: http://homepage.hispeed.ch/peterfleury/avr-software.html lg Chris
Felix N. schrieb: > Diese tute ich per 74HC595 Shift > Register Multiplexen um Pins zu sparen. Dazu frage ich mich allerdings: Wenn du schon Schieberegister einsetzt, warum dann nicht gleich für jede 7-Segmentanzeige ein separates? Dann musst du nicht multiplexen, und sparst außerdem noch mehr Pins, da du die Schieberegister kaskadieren kannst. Die Anzeigehelligkeit kannst du dann auch noch komfortabel mit PWM am OE-Pin der 595er steuern.
Wenn du ein Schieberegister aus der CD40xxBE Reihe verwendest und sie mit maximal 5V betreibst, kannst du sogar auf die Vorwiderstände verzichten, wei die IC's den Strom schon passend begrenzen.
chris schrieb: > Wenn du schon Schieberegister einsetzt, > warum dann nicht gleich für jede 7-Segmentanzeige ein separates? Hi. Wenn ich für jedes Segment ein Schieberegister nehmen würde bräuchte ich 10 Stücke dafür, das wäre wiederum viel Arbeit die auf einer Platine platzsparend unterzubringen. Deswegen nutze ich 2x 74HC595 und 2x Pins vom PortC Register. Die Ausgänge des ersten Registers liegen über 510 Ohm Widerstände an den Anode der Segment LED an. Q0 bis Q6 sind dabei für die einzeln Segmente und Q7 ist für den Dot Punkt. Das zweite Schieberegister bekommt die Daten vom Q7S vom ersten. Und steuert die Transistoren an. Da mir am zweiten Register aber 2 Pins fehlen und ich noch ein paar frei hatte an meinem Mikrocontroller nutze ich diese einfach so spare ich mir ein dritten 74HC595. chris schrieb: > Die Anzeigehelligkeit kannst du dann auch noch komfortabel mit PWM am > OE-Pin der 595er steuern Bin mir gerade nicht ganz sicher ob das geht. Sollte aber am zweiten Register möglich sein, so das dann der Transistor als Spannungsregler wirkt. chris schrieb: > Nein, du schreibst alle Daten in einen Puffer und die ISR sendet im > Hintergrund Byte für Byte raus. Könnte das was mit dem USART UDRE ISR zutun haben? Wenn ich das richtig lese ist das das Datenregister des USART wenn ich dort Daten rein schiebe und dann das Interrupt Bit für UDRE setze müsste er ja dort rein gehen und kann könnte ich die Daten doch mit UDR0 = ... rüber senden? mfg
Felix N. schrieb: > Bis dann die Kommunikation mit dem USART kam. Ich arbeite normaler weiße > nur mit 9600 Baud Rate. Da aber das Senden dann so lange gedauert Man darf eben NICHT auf das Ende der Übertragung. > hat > das der Controller sich dort ein bisschen verzögert hat sich auch die > ISR verzögert was dazu führt das die Multiplex Frequenz auf 15 Hz abfiel > und ein Flackern erkennbar war. Konzeptfehler. > Ich habe dann bei mir in Datenblatt geschaut unter "Table 20-7" UBBRn > Settings für fosc=16.00000 MHz. Da nur relativ hohe Baudraten in frage > kamen um den Sendevorgang vorher zu beenden bevor die ISR ins Stocken > gerät. Konzeptfehler. > Oder sollte man lieber den 328P über ein anderes Interface mit einem > anderen Prozessor kommunizieren lassen(bzp. Attiny) Nein. du mußt dich mit dem Thema Multitasking befassen, dann klappt das auch.
Felix N. schrieb: > Könnte das was mit dem USART UDRE ISR zutun haben? Wenn ich das richtig > lese ist das das Datenregister des USART wenn ich dort Daten rein > schiebe und dann das Interrupt Bit für UDRE setze müsste er ja dort rein > gehen und kann könnte ich die Daten doch mit UDR0 = ... rüber senden? Ich weiss nicht, ob man auf diese Art einen Interrupt auslösen kann. Normalerweise macht man das so: Wenn das UDRE leer ist, schreibt man das erste Byte hinein und den Rest in den Puffer. Ansonsten kommt alles in den Puffer, welcher von der ISR abgearbeitet wird.
Hallo TO, ich verwende die von Peter Dannegger (peda) mal veröffentliche Routine, als Vorlage für weitere Implementierungen. Auch außerhalb von C. Beitrag "AVR-GCC: UART mit FIFO"
Falk B. schrieb: > Man darf eben NICHT auf das Ende der Übertragung. Weil der Controller auf das Ende Wartet, im Moment wie ich es habe. Falk B. schrieb: > Nein. du mußt dich mit dem Thema Multitasking befassen, dann klappt > das auch. Ich habe mir den Betrag mal durchgelesen, auf Delays aus der Delay.h verzichte ich ja schon komplett, und wenn ich doch ein Delay brauche löse ich das über ein ISR Timer Overflow der zb. alle 1ms sich erhöht und ein uin16_t hoch zählt und dann halt was auslöst ... Im Moment ist nur ein delay aus der delay.h enthalten das ist aber nur zum testen und wird wieder entfernt. Wie oben bereits geschrieben von Joachim S, kann man das ja per Interrupt beheben das Problem ich bin hier auf diesen Artikel gestoßen: https://www.mikrocontroller.net/articles/Interrupt#UART_mit_Interrupts Da erklärt sich auch wie ich mir das vorgestellt habe mit dem UDRE ISR Event. Das werde ich nachher mal ausprobieren. Mal was anderes was mir so aufgefallen ist: Warum müssen eigentlich manche Wert die in einer ISR vorkommen vom Typ "static" sein? Zb:
1 | static uint8_t uart_rx_counter = 0; |
Eben habe ich ein paar variablen erst mit dem Wort "static" im Variablennamen erstellt und habe dann später mit der Such und Ersetzenfunktion der IDE das "static" wieder entfernt. Dadurch hat er natürlich auch das static vor dem uart_rx_counter entfernt. Nachdem das static weg war funktionierte die Kommunikation beim Empfangen von Daten vom PC nicht mehr richtig. Erst wieder als ich das static wieder vor das uint8_t schreibe. Wieso? Mfg
static Variablen innerhalb einer Funktion verlieren ihren Wert zwischen zwei Funktionsaufrufen nicht.
Hallo, das sind doch C Grundlagen! static können Variable oder Funktionen sein. Bei static innerhalb von Funktionen wird der Speicherplatz einer Variable nicht auf dem Stack angelegt und anschließen - bei beenden der Funktion - wieder freigegeben und somit das Datum ungültig/ gelöscht. Man kann also Daten über Funktionsaufrufe hinweg immer wieder nutzen, hier der Index auf einen Speicherbereich (Array). Felix N. schrieb: > Warum müssen eigentlich manche Wert die in einer ISR vorkommen vom Typ > "static" sein? Zb:
Karl M. schrieb: > Bei static innerhalb von Funktionen wird der Speicherplatz einer > Variable nicht auf dem Stack angelegt und anschließen - bei beenden der > Funktion - wieder freigegeben und somit das Datum ungültig/ gelöscht. Ah ja stimmt ohne Static wäre die Variable in der Funktion sinnlos weil sie jedesmal beim neuen Durchgang wieder mit 0 neu initialisiert werden würde. Danke für die Erklärung! Felix N. schrieb: > Das werde ich nachher mal ausprobieren. Ich habe jetzt mal alle "sendToSerial" durch "sendToISR" ersetzt, wie in dem Artikel beschrieben, werden die Daten nun über die ISR(UDRE) zum PC gesendet, das klappt schon mal wunderbar! Empfangen wird auch über eine ISR also sollte der Kommunikation zwischen PC - AVR ohne Störungen laufen. Eins ist mir aufgefallen wenn ich in der Main Funktion ohne Delay dazwischen dauerhaft Sende(hier die Spannung die der ADC Misst um die Knöpfe zu erkennen) dann fällt die Multiplex Frequenz von 100Hz auf circa. 96-98 Hz ab also eigentlich kaum ein Unterschied. Wenn man sich aber die Multiplexen Anzeigen ganz genau anschaut, sieht man das ein leichtes flackern zu erkennen ist. Bzw. wenn man sich an einen Transistor dran klemmt mit dem Oszilloskop dann sieht man zwar das es kein so schönes Rechteck ist aber das es während des schnellen Senden an Daten leicht ins Schwanken nach rechtes und linkes kommt(+/-3Hz). Müsste ich in diesem Fall die Baudrate erhöhen, oder ist so dauerhaftes Senden eh er Problematisch? Mfg
:
Bearbeitet durch User
Wenn du dauerhaft schneller sendest, als es die serielle Schnittstelle zulässt, ist irgendwann der Puffer voll und dann muss doch gewartet werden. Hast du das bedacht? Falls das nicht die Problemursache ist, musst du herausfinden, welchen Programmteil du optimieren kannst, damit deine Hauptschleife innerhalb der gewünschten Intervalle ausgeführt werden kann. Wenn ich mir deine bisherigen Beiträge so anschaue würde ich Dir raten, das Debugging und Profiling zu üben. In diesem Fall geht es um die Frage, welcher Programmteil wie viel Zeit benötigt und warum das so ist. Du fragst uns und bekommst Hilfe. besser wird es aber sein, wenn du weniger auf unsere Erfahrungswerte aufbaust, sondern es selbst durch Messungen heraus findest. Wir kann man das messbar machen? Überlege Dir das. Kleiner Tipp: Ein Oszilloskop oder ein Logic Analyzer kann dabei serh hilfreich sein. Die billigen Produkte unter 50€ sind hier immer noch hilfreicher, als gar keins zu haben.
Felix N. schrieb: > Jede 1ms setze ich ein Flag in einer ISR um im > Hauptprogramm dann die Segmente anzusteuern. Das ganze funktioniert auch > ohne Probleme. Genau das schreit geradezu nach Problemen und Du hast sie ja schon. Multiplexen macht man immer im Timerinerrupt. Du legst ein 10 Byte Array an, in dem speicherst Du die 10 Digitmuster und der Timerinterrupt gibt sie aus. Felix N. schrieb: > 230.4k hat zu viele Fehler bei 16 MHz. Na dann nimm doch einfach nen 14,7456MHz Quarz. Für alle anderen Sachen ist der exakte Wert vollkommen egal. Die Frequenzberechnungen macht man eh in float, d.h. Kommazahlen sind erlaubt.
Felix N. schrieb: > Eins ist mir aufgefallen wenn ich in der Main Funktion ohne Delay > dazwischen dauerhaft Sende(hier die Spannung die der ADC Misst um die > Knöpfe zu erkennen) dann fällt die Multiplex Frequenz von 100Hz auf > circa. 96-98 Hz ab also eigentlich kaum ein Unterschied. > Müsste ich in diesem Fall die Baudrate erhöhen, oder ist so dauerhaftes > Senden eh er Problematisch? Nein. 100Hz bedeutet alle 10ms ein Refresh. Das sind bei 16MHz 160.000 (Hundertsechzig Tausend) Instruktionen dazwischen. Wenn dir diese 160.000 Instruktionen nicht reichen, dann machst du irgendetwas falsch.
Marc V. schrieb: > Wenn dir diese 160.000 Instruktionen nicht reichen, dann machst du > irgendetwas falsch. Projekte haben es an sich, daß sie wachsen und wachsen. Man sollte daher vorausschauend programmieren. Zeitkritische Sachen haben in der Mainloop nichts verloren.
Felix N. schrieb: > Hi. Wenn ich für jedes Segment ein Schieberegister nehmen würde bräuchte > ich 10 Stücke dafür, das wäre wiederum viel Arbeit die auf einer Platine > platzsparend unterzubringen. Ab 13 mm Ziffernhöhe kann man beide Seiten effektiv nutzen. Ob es dann drei Stellen oder 20 Stellen sind - man kann einfach kaskadieren. Beitrag "7-Segm.-LED-Anzeige, 6-stellig, statische Ansteuerung mit (74HC)4094"
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.