Hallo, ich bin gerade dabei ein zeitkritisches Programm zur PID-Regelung mittels Mega32 zu erstellen. Zu Testzwecken wollte ich jetzt eine ISR bei Timer Overflow ausführen lassen und mittels USART prüfen, ob auch das Timing so ist wie ichs mir vorgestellt habe. Zugleich lasse ich eine LED blinken. Problem: wenn ich den USART-Teil in der ISR auskommentiere (weglasse) blinkt die LED schneller als wenn ich den USART-Teil drin lasse. Ich vermute die Abarbeitung dieses Abschnitts braucht so lange dass die nächste ISR-Ausführung verzögert wird? (Wenn ich z. B. 20 Interrupts pro Sekunde anstatt 1000 mache blinkt die LED nämlich immer gleich schnell...) Gibt es denn eine Möglichkeit integers über USART auszugeben ohne die Verrenkungen die ich dafür mache? Die scheinen ja ziemlich Rechenzeit zu kosten?! Ziel soll im Endeffekt sein dass die ISR fix und gleichmässig aufgerufen wird und ich trotzdem darin Integers per USART auslesen kann.
> Ich vermute die Abarbeitung dieses Abschnitts braucht so lange dass > die nächste ISR-Ausführung verzögert wird? Ja klar, das geht so nicht. Du wartest brav in den UART-Senderoutinen, bis das jeweils vorhergehende Byte geschrieben ist. Bei 9600 Bd rechnet man mit rund 1 ms pro Zeichen. Du willst aber N Zeichen ausgeben, 5 <= N <= 13. Das Ganze soll dann noch 1000 Mal pro Sekunde passieren -- das kann nicht funktionieren, egal wie du's drehst. Ansonsten der übliche Ratschlag: ISRs kurz halten. Nicht nur die UART-Routinen gehören da nicht rein, auch itoa() dauert viel zu lange (es muss ja mehrere Divisionen ausführen). In der Regel setzt man dort nur ein Flag, ermittelt vielleicht noch eine Timestamp (wobei das beim compare match Interrupt ziemlich wertfrei ist, findest du nicht?), und lässt den Rest im Hauptprogramm abarbeiten. Die Dualität von Zeigern und Feldern hast du auch noch nicht verstanden, sonst könntest du myCharPtr nämlich gleich komplett einsparen. Es macht den Code weder schneller noch verständlicher.
Hi Uli, hier hast ja eine "busy-waiting" Schleife drin: -- void UART_transmit_string(uint8_t *string){ while(!(UCSRA & (1<<UDRE))); while( *string){ UART_transmit (*string++); } } -- d.H. während er auf UDRE wartet treten weitere Interrupts auf (welche aber in der ISR abgeschaltet sind). Es könnte evtl funktionieren, wenn du beim Eintritt in den Timer mit sei() die Ints wieder freigibst. Wahrscheinlich unterbricht sich aber die Timerroutine dann selber und das ganze Prog. geht hops. Besser wäre es, eine ebenfalls interruptgesteuerte Programmierung vorzunehmen. Kurzes Prinzip: Die zu sendenden Daten in einen Fifo schieben und wenn die UART grad nix zu zenden hat, das erste Zeichen senden (NUR das erste). Wenn das Zeichen gesendet wurde, tritt der RX-Complete Interrupt auf, welcher sich das nächste Zeichen aus der Fifo holt. Evtl findest aber auch eine fertige Lib die dir die Arbeit abnimmt. Gruß Roland
Hi Jörg, danke für die Erklärung, die macht sehr plausibel was ich vermutet habe! Ich will während der Regelung gewisse Variablen incl. Timestamp auslesen - sollte ich das also anstatt in der ISR kontinuierlich in der Endlosschleife des Hauptprogrammes zu machen? Geht das konform mit der ISR wenn ich im Hauptprogramm zeitintensive USART-Geschichten mache? Wird z. B. itoa() dann einfach von der ISR unterbrochen, d. h. habe ich die Sicherheit dass eine kompakte ISR wirklich gleichmässig abläuft auch wenn in der Endlosschleife des Hauptprogramms aufwändige Befehle abzuarbeiten sind? Klar, eigentlich sollte der Timestamp beim compare match Interrupt sinnlos sein. Aber durch die USART-Verzögerungen scheint das ganze ja doch so aus dem Takt zu geraten, dass ich immer unterschiedliche Werte erhalte, also ergibt es ja in diesem Fall doch eine Aussage! (Wobei mir nicht einleuchtet wieso ich immer unterschiedliche Time Stamps erhalte - das sollte doch dennoch der gleiche Wert sein, nur dass durch die Verzögerungen halt ein paar Timer-Runden ausgesetzt werden und keine ISR starten, dann aber wieder beim nächsten Overflow?) Danke für weitere Erklärungen!
"habe ich die Sicherheit dass eine kompakte ISR wirklich gleichmässig abläuft auch wenn in der Endlosschleife des Hauptprogramms aufwändige Befehle abzuarbeiten sind?" Genau das ist der Sinn von ISRs. Du darfst bloß nicht elendlangen Code im Main unter Interruptsperre haben. Interruptsperren >100 Zyklen sollte man nochmal überdenken (sind meistens unnötig). Peter
Hi Roland, danke! Ich denke auch mit sei() ISRs während der USART-Geschichte zuzulassen klappt wohl eher nicht, dann wird die Übertragung ja andauernd unterbrochen so dass nicht viel ankommt! Der Vorschlag mit dem FIFO hört sich recht logisch an. Aber ginge es evtl. einfacher (so wie oben geschrieben) alle USART-Kommunikation ohne ISR mit Timestamps in der Hauptschleife durchzuführen? Merci!
>sollte ich das also anstatt in der ISR kontinuierlich in der >Endlosschleife des Hauptprogrammes zu machen du hast es erfasst >Geht das konform mit der ISR wenn ich im Hauptprogramm zeitintensive >USART-Geschichten mache da ist nichts zeitintensives wenn du die UART per Interrupt bedienst Interrupt heisst Unterbrechung, wenn diese klein ist merkst du es nicht, Lies Dir das bitte mal in einem Tutorial oder Buch durch damit du begreifst was du zu beachten hast Deine Regelung muss ein feste Zeitpunkte/Samples haben, darauf stellst du ja die Regelparameter ein. Dein Programm sollte ungefähr so aussehen ISR UARTEmpfang {übernimm Zeichen in UARTpuffer} ISR Timer wird für Zeitraster Regelung aufgerufen {Regelzeitpunkt erreicht=TRUE} main { ... 1.neue Sollwerte einlesen(z.B. aus UARTpuffer) 2.wenn Regelzeitpunkt erreicht-> Regelroutine->Regelzeitpunkterreicht=FALSE 3. zu 1. }
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.