Servus, ich habe ein Problem mit meiner Ampelsteuerung(s.u.) Es ist eine normale Kreuzung, an der einen Seite ist dabei ein Fußgängerüberweg der per Taster ausgelöst werden kann. Die Zeitschleife für die jeweiligen Phasen muss ich mit einem Timer umsetzen, das verlangt die Aufgabe. Den Taster muss ich mehr oder weniger mit einem Interrupt0 bearbeiten, da es sich nur um einen Drucktaster und keinen Schalter handelt(also wie real). Dabei liegt bei mir das Problem. Einen Timer0 arbeitet ebenso mit einem Interrupt und es scheint, als würden die sich nicht mögen. Man kann ja die Prioritäten verändern. Wenn ich nun die Priorität des Timers höher setze als die des Interrupts funktioniert nur noch der Timer, andersrum funktioniert nur noch der Interrupt, was kann ich da tun? Wo liegt bei mir da der Fehler? Also der Controller ist von Atmel, T89C51RD2 so weit ich weiß.
mfg
Servus, ich habe ein Problem mit meiner Ampelsteuerung(s.u.)
Hallo,
dazu gäbe es an vielen Stellen etwas zu beanstanden, nur das Wichtigste:
Soweit ich das verstehe, ohne extra nachzuschlagen, wird in der Interrupt-Service-Routine für den Taster der Timer angehalten. Damit läuft aber die ganze Maschine wahrscheinlich in einer Endlosschleife, weil das Zählerende nicht mehr erreicht wird.
Erstmal danke für die Antwort. Eigentlich sollte das Programm soweit in Ordnung sein, bis auf den Fehler mit dem Interrupt. Sollte die Priorität des Tasters dann höher gestellt sein und falls er dann in den Taster-Interrupt springt, danach den Timer erneut starten?
mfg
sei froh, wenn sich keine unbeabsichtigten Nebenwirkungen ergeben, und führ nicht noch selbst welche ein. Die Taster-ISR soll den Tastendruck erfassen und sonst nichts. Regel: Probleme separieren. Die Zeitsteuerung sollte ebenfalls ganz unabhängig laufen, es ist eigentlich schon nicht gut, den Timer ständig anzuhalten und neu zu starten, das gibt nur zusätzliche Fehler.
Wenn die Programmierung korrekt ist, hat die Priorität praktisch keinen Einfluss: man könnte damit nur erreichen, dass der Tastendruck ein paar µsec früher erfasst wird, aber bei Handeingaben kommt es auf Zehntelsekunden nicht an. Und an einer Ampel muss man u.U, eine Minute warten, bis es grün wird, da nützen mich die paar Microsekunden garnichts.
Gruss Reinhard
[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]
Und wie genau sollte ich das dann umsetzen? Sollte ich den Timer zu Beginn starten und in der Zeitschleife den Akku auf 0 setzen, danach den Akku auf die bestimmte Konstante abfragen? Was meinen Sie mit den vielen kleinen Problemen???
mfg
Den Taster muss ich
mehr oder weniger mit einem Interrupt0 bearbeiten, da es sich
nur um einen Drucktaster und keinen Schalter handelt(also wie
real).
Versteh ich nicht. Frag den Zustand des Tasters fortlaufend z. B. alle 20 ms ab (*) und speichere ihn in einer Variablen – fertig. Der Glaube, dass man Taster über Interrupts betreiben muss (warum denn?) , ist Anfängerdenken. Das muss man nämlich (fast) nie.
(*) Nein, Du brauchst nicht für jeden Taster einen eigenen Timer, sondern wahrscheinlich nur einen Timer (ja: nur einen einzigen Timer!) für Dein komplettes Programm (einverstanden?).
Und wie genau sollte ich das dann umsetzen? Sollte ich den
Timer zu Beginn starten
Du richtest einen Timer ein, der z. B. mit 20 ms vor sich hin „tickt“. Dieser Timer wird niemals angehalten oder sein Zählerstand verändert oder irgendwie anderweitig „manipuliert“. Er läuft während der gesamten Programmlaufzeit. Dein komplettes Programm „hängst“ Du an diesem 20 ms-Timertick auf. Dazu zählst Du Variablen (für jede Aufgabe eine) bei jedem Timertick rauf oder runter und führst bei Erreichen bestimmter Zählerstände die zugehörigen Aktionen aus (diese Zähler stellen sozusagen „Software-Timer“ dar).
Und wie genau sollte ich das dann umsetzen? Sollte ich den
Timer zu Beginn starten und in der Zeitschleife den Akku auf 0
setzen, danach den Akku auf die bestimmte Konstante abfragen?
Was meinen Sie mit den vielen kleinen Problemen???
mfg
Hallo,
wie schon gesagt, der Timer wird auf einen festen Wert programmiert und läuft dann endlos, wobei er z.B. alle 1 msec einen Interrupt auslöst. Dann kann man in der ISR bis 1000 zählen und dann die Uhrzeit um eine Sekunde erhöhen, usw. usw. Starten und Stoppen des Timers ist von Zufällen abhängig und ergibt ungenaue Zeitmessungen.
Ein Beispiel dafür, wie man es nicht macht: eine Schleife mit der Abfrage auf Equal zu beenden, ist ein Anfängerfehler. Es kann in einem System mit Interrupt vorkommen, dass ein Schritt nicht erfasst wird, oder man ändert was am Programm und zählt immer gleich um 2 hoch. Wenn man also auf 100 testet und das zufällig überspringt, so dass also auf 99 gleich 101 folgt, so zählt die Schleife bis in alle Ewigkeit weiter oder zumindest bis zum Überlauf des Zählers. Die korrekte Abbruchbedingung muss heissen Greater or Equal, das ist eine Frage der defensiven Programmierung. Man darf einfach keinen Platz für Fehler lassen, von 0 bis 100 läuft die Schleife, jeder beliebige andere Wert muss zum Abbruch führen. Einfach zu behaupten, > 100 kommt nicht vor, ist schlechte Programmierarbeit und irgendwann wird man von der Realität eines anderen belehrt.
Meiner Meinung nach kann man den Timer gar nicht beeinflussen, also keinen festen Wert für den auszulösenden Interrupt festlegen. Wir haben das in der Schule mal ausgerechnet, da kam was von 65,ms raus. Ich habe das jetzt auf jeden Fall so hinbekommen. Ich zähle bei jedem Timer-Überlauf den Akku um eins hoch und lösche dann einfach beim Start des UP der Zeitschleife den Akku wieder bis er den Wert erreicht hat. Habs ausprobiert und es hat geklappt. Bin euch auf jeden Fall mal dankbar für die Hilfe.
Bin jetzt nur froh, dass das Programm geht, da es schließlich meine GFS wird ^^
dankeschön mal
Meiner Meinung nach kann man den Timer gar nicht beeinflussen,
also keinen festen Wert für den auszulösenden Interrupt
festlegen. Wir haben das in der Schule mal ausgerechnet, da
kam was von 65,ms raus.
Das gilt nur, wenn Du den Timer einfach durchlaufen lässt. Du kannst aber den Startwert des Timers setzen auf 0-x. Dann wird nach x-maligem Erhöhen des Timerwertes der Interrupt ausgelöst. Und damit kannst Du dann jede beliebige Interruptzeit erreichen, sofern das mit den möglichen Zählfrequenzen zu machen ist.
Gruß
Axel
ah, ok, wusste ich bisher noch nicht, habe dazu auch leider die betreffenden Zeilen auch nicht. Aber so passt dat ja auch. Wenn ich sowieso den Timer mit einer Variablen vergleichen muss, bzw die Interrupts, die der Timer dann ausführt.
mfg
soweit klar, aber wie würde programmtext aussehen, wenn du alle 20ms den Taster abfragen würdest? Bei einem längeren Programmtext, der dazu noch verschachtelt ist wird es dann nicht gerade einfach, bzw. logisch.
mfg
soweit klar, aber wie würde programmtext aussehen, wenn du
alle 20ms den Taster abfragen würdest? Bei einem längeren
Programmtext, der dazu noch verschachtelt ist wird es dann
nicht gerade einfach, bzw. logisch.
Doch, der wird gerade dann einfach und logisch.
Du richtest einen Timer ein, der mit 20 ms vor sich hin tickt. Das heißt, es gibt eine Interrupt-Service-Routine (Timer-Overflow-Interrupt, oder Timer-Output-Compare-Interrupt), die fortwährend im Abstand von 20 ms aufgerufen wird (während der gesamten Programmlaufzeit). Dort hinein schreibst Du die Tastenabfrage. Und nicht nur die, sondern alles (!) andere auch.
In dem Programm darf es dann natürlich keine einzige „Delayschleife“ nach Art von „tue 100000 mal {}“ mehr geben, oder so Geschichten wie „warte solange bis jemand die Taste drückt“. Aber wenn Du deine Software timergesteuert aufziehst, besteht dazu auch gar keine Notwendigkeit mehr.
Du musst nur dafür sorgen, dass die Gesamtheit aller Aufgaben, die Dein µC alle 20 ms erledigen muss, auch im schlimmsten Fall nicht mehr Rechenzeit als ebendiese 20 ms in Anspruch nehmen (sonst würden Timerinterrupts „verlorengehen“). Diese Forderung stellt aber meistens überhaupt kein Problem dar, denn während 20 ms kann der µC schließlich noch verdammt viele Instruktionen abarbeiten (rechne doch mal aus, wieviele es bei der von Dir gewählten Taktfrequenz sind).