habe davor nur STM32 Prozessoren programmiert und wollte jetzt für einen Controllino MINI über Microchip Studio einen ATmega programmieren. Jedoch bekomme ich die USB Schnittstelle einfach nicht zum Laufen. Alle anderen Ein- und Ausgänge + ADC funktionieren.
Selbst wenn ich alle anderen Libs auskommentiere und nur die UART lib drin habe, schmiert er ab, sobald ich ein Zeichen sende. Vielleicht sieht ja jemand einen groben Schnitzer oder kann mir weiterhelfen ...
Da ich nur den Controllino da habe, habe ich leider keine debug Schnittstelle und kann das fertige Programm nur über USB aufspielen und testen.
Warum dein Programm "abschmiert" kann ich nicht erkennen. Mir ist aber dies aufgefallen:
Die Methode rund um UART_ZEICHEN_BUFFER_LEER erscheint mir äußerst fragwürdig. Schau dir mal diesen Artikel an, dort ist ein erprobtes Konzept beschrieben, das zuverlässig funktioniert: https://www.mikrocontroller.net/articles/FIFO
Alle Variablen, die sowohl innerhalb als auch außerhalb der ISR benutzt werden, würde ich als volatile kennzeichnen. In deinem Fall betrifft das die Variable UART_Flag_senden_aktiv. Im konkreten Code vernute ich, dass es keinen Unterschied macht, aber ich würde das volatile trotzdem einsetzen um Probleme bei künftigen Änderungen zu vermeiden.
danke für dein Feedback. Volatile hatte ich auch schon probiert, leider ohne Erfolg. Den Ringbuffer verwende ich eigentlich sehr erfolgreich beim ST.
Mit dem Lampen-Spiel hatte ich es auch versucht, jedoch komme ich nur zu dem Ergebnis, dass er einmal in die Funktion USART_UDRE_vect() kommt und ein Zeichen reinschiebt zum Senden. Mit einem Terminalprogramm sieht man auch, dass das eine Zeichen auch übertragen wird. Danach jedoch im Nirvana hängt ...
Nach meinem Verständnis müsste die Funktion USART_UDRE_vect() ein zweites Mal aufgerufen werden, sobald das eine Zeichen übertragen worden ist, jedoch passiert das nicht. Da nichts weiter im Code bzw. main() vorhanden ist, bin ich überfragt, wo ich noch eine Lampe ein oder ausschalten soll, um etwas zu sehen ...
Ich vermute, dass der Interrupt erst dann ausgelöst wird, wenn das UDR Register danach wieder leer wird. Wenn es zu dem Zeitpunkt aber schon leer ist, gibt es keinen Grund für einen erneuten Interrupt. Einen hattest du ja schon vorher aber da war dein Sendepuffer leer.
Das ist ein genereller Unterschied zwischen STM32 und AVR an ganz vielen (nicht allen) Stellen. Bei STM32 musst du jeden Interrupt selbst Quittieren oder Deaktivieren, sonst wird die selbe ISR bei ihrem Ende direkt wieder aufgerufen. Bei AVR werden die Interrupt-Flags beim Eintritt in die ISR automatisch gelöscht, so dass ein Ereignis immer nur zu maximal einem ISR Aufruf führt.
Oder anders formuliert: Ein STM32 würde würde die ISR immer wieder aufrufen, solange du das "UDR ist leer geworden" Flag nicht löschst. Ein AVR ruft die ISR nur einmal auf, wenn das Register leer wird.
In meinen AVR Programmen funktioniert die UART_send() Funktion so:
Wenn der UART sender aktiv ist, dann schreibe ich das Zeichen in den Puffer. Wenn er nicht aktiv ist, schreibe ich es direkt ins UDR Register.
Dadurch entfällt auch die Notwendigkeit, das UDRIE0 immer wieder umzuschalten. Ich schalte es einmal bei der Initialisierung ein, und dann bleibt es dabei.
Ohne Interrupt funktioniert es, wenn man einfach ein Zeichen in UDR schreibt. Jedoch möchte ich bei vielen Zeichen den Mikrocontroller nicht in einer while() warten lassen, bis das nächste Zeichen gesendet werden kann.
Später sollen auch größere Informationspakete an die Schnittstelle gesendet werden, während die Hauptstatemaschine läuft.
Von dem her würde ich es gerne mit Interrupt gesteuert realisieren.
Ohne Interrupt funktioniert es, wenn man einfach ein Zeichen in UDR
schreibt. Jedoch möchte ich bei vielen Zeichen den Mikrocontroller nicht
in einer while() warten lassen, bis das nächste Zeichen gesendet werden
kann.
Später sollen auch größere Informationspakete an die Schnittstelle
gesendet werden, während die Hauptstatemaschine läuft.
Von dem her würde ich es gerne mit Interrupt gesteuert realisieren.
Ich glaube, du hast meinen Vorschlag (direkt ins UDR zu schreiben) nicht verstanden. Du sollst doch nur direkt ins Register schreiben, wenn der Sender nicht aktiv ist. Wenn er hingegen aktiv ist, sollst du nicht warten, sondern wie gehabt den Puffer und die ISR nutzen.
Der eine : UartDataRegisterEmpty bedeutet das UartDataRegister is leer, ist ins Shieberegister kopiert worden und wird raus geschoben. In diesem Interrupt wird das naechste Datenbyte in das TxRegister geladen.
der Andere : TxReady bedeutet das Effektive schieberegister ist leer. Die Uebertragung ist beendet.
Also erst mal : X mal UartDataRegisterEmpty interrupt laufen lassen und zum Schluss den TxReady. Bedeutet beim vorherigen, dem letzten UartDataRegisterEmpty macht man nichts, weil man nichts zum Laden mehr hat.
Eine Library mit Ringbuffer benotigt man eigentlich nicht, laesst grad eine Statemachine das Protokol abspulen. Ich arbeite immer mit linearen buffern, die sind so lange wie die Meldung ist. Natuerlich nicht dynamisch alloziert, sondern fest.
Man braucht es bei jeder halbduplex Kommunikation mit dem UART. Wenn man
zwischen TX und RX umschalten will.
Diesen Fall habe ich mit "rs485-Treiber bespaßen" gemeint. Sonst braucht man das aber nicht; wer macht schon freiwillig Halbduplex, wenn's nicht not tut?
Man braucht es bei jeder halbduplex Kommunikation mit dem UART. Wenn man
zwischen TX und RX umschalten will.
Diesen Fall habe ich mit "rs485-Treiber bespaßen" gemeint. Sonst braucht
man das aber nicht; wer macht schon freiwillig Halbduplex, wenn's nicht
not tut?
Dann wenn man a.) nur 3 Leitungen haben kann oder b.) wenn man mit etwas Kommunizieren will was halbduplex macht.
z.B. Telemetrie-Sensoren im RC Modellbau.
Merke: Dein beschränkter Horizont ist nicht das Maß aller Dinge.
ähnliche, fast gleichlautende Variablennamen, OMG!
missverständliche Variablennamen, das sind Pointer, Indexe
in einem Array oder Ringbuffer
Hallo Wastl,
ich glaube, das ist Ansichtssache. Mir persönlich gefällt es besser etwas zu beschreiben, als einfach mit x, cnt oder gar cryptischen Zeichen so kurze Zeilen wie möglich zu produzieren.
Der Code muss auch nur von mir gelesen werden, also denke ich, kann man da ein Auge zudrücken.
Der Code muss auch nur von mir gelesen werden, also denke ich, kann man
da ein Auge zudrücken.
Du irrst. Du hast deinen unleserliche Code hier reingestellt weil
du um Hilfe gebeten hast. Daher "müssen" sich andere Leute mit
deinem Kauderwelsch auseinandersetzen. In einer Team von
Programmierern in dem du teilnimmst würde man dich auspeitschen.
Mir persönlich gefällt es besser
etwas zu beschreiben, als einfach mit x, cnt oder gar cryptischen
Zeichen so kurze Zeilen wie möglich zu produzieren.
Das ist legitim. Aber "UART_TX_Buffer_Register_Senden" ist irreführend, da das mit "Register" nichts zu tun hat. Das ist ein /Index/.
Die Kombination aus "TX" und "Senden" ist dazu noch redundant, denn "TX" und "Empfangen" kann es nicht geben, ebensowenig wie es "RX" und "Senden" geben kann.
Noch so eine Unsitte ist es Variablen-Namen GROSS zu schreiben.
Grosschreibung ist in einem anständigen Sourcen-Gefüge für
Konstanten (Defines) reserviert. Konstante Variablen dürfen
(sollen) dagegen auch klein geschrieben werden.
Noch so eine Unsitte ist es Variablen-Namen GROSS zu schreiben.
Ich sehe hier gemischte Groß- und Kleinschreibung.
Ja, als an gewisse Standards gewöhnter Mensch denkt man am Anfang automatisch an ein Macro (#define), aber wenn man das zehnte Zeichen (u) sieht, ändert sich was.
Schön finde ich das nicht; ich wollte in meinem Beitrag aber in erster Linie auf die irreführende und redundante Begriffswahl hinweisen, und nicht auf den fünfhundertdrölfzigten Coding-Richtlinien-Flamewar.