Ich möchte mich nun daran wagen einen Timer zu programmieren. Jedoch
weiß ich nicht genau, wie ich abfrage, ob das TF - Bit(Timer Überlauf
Bit gesetzt) gesetzt ist. Weiters wäre es noch sehr hilfreich, wenn mir
jemand die folgenden Fragen beantworten könnte:
1. Muss ich um dies zu prüfen unbedingt einen Interrupt verwenden?
2. Wie sehe ich am besten, ob der Timer tatsächlich funktioniert(habe
ein µC - Kit von Silabs mit 2 leds).
3. Wie lange ist die maximale Zeit, die mit einem 8051er mit einem Timer
bei 12MHz erreicht werden kann?
4. Reicht diese Zeit aus um eine Änderung bei den Leds zu erkennen?
Ich freue mich auf eure Antworten!
MfG
tom51
Tom B. schrieb:> 1. Muss ich um dies zu prüfen unbedingt einen Interrupt verwenden?
Du mußt Dich entscheiden, entweder Interrupthandler oder das Bit testen
und rücksetzen.
Beides zusammen geht nicht.
> 2. Wie sehe ich am besten, ob der Timer tatsächlich funktioniert(habe> ein µC - Kit von Silabs mit 2 leds).
Vermutlich gibts nicht nur ein Kit.
Zu nennen, welcher konkrete 8051 bei Dir drauf sitzt, wäre daher recht
hilfreich.
> 3. Wie lange ist die maximale Zeit, die mit einem 8051er mit einem Timer> bei 12MHz erreicht werden kann?
Datenblatt und Taschenrechner sind Dein Freund.
> 4. Reicht diese Zeit aus um eine Änderung bei den Leds zu erkennen?
Bei den Silabs 1-clocker mit Sicherheit nicht.
Du mußt dann noch ne Variable im Interrupthandler runterzählen.
Peter
Ich habe einfach mal zu programmieren begonnen ...
Wollte ein Programm schreiben, welches eine LED blinken lässt und
während der Zeitschleife soll der Interrupt durch den Timer Überlauf
ausgelöst werden. Leider habe ich bisher noch nie mit Interrupts
programmiert.
Das von mir programmierte Programm macht leider nichts
Ich verwende das F320 Kit von Silabs.
Das Datenblatt dazu gibt es hier:
http://www.silabs.com/Support%20Documents/TechnicalDocs/C8051F32x.pdf
Es wäre wirklich sehr hilfreich, wenn sich jemand der sich mit dem
8051er auskennt etwas Zeit nehmen würde.
Mit freundlichen Grüßen
tom
Ich habe den Eindruck, daß Du überhaupt noch nicht verstanden hast, wie
das mit den Interupts funktioniert.
Du kannst in dem Ablauf des Hauptprogramms nicht bestimmen, wann Du in
den Interupt springst, und wann Du wieder - und wohin - zurückkehrst.
Im Hauptprogramm Initialisierst Du nur das, was Du initialisieren
möchtest. U.a. auch Timer0.
Bei jedem Überlauf soll ein Interupt ausgelöst werden. D.h. Du musst
Interupts (SETB EAL) und den Timerinterupt (SETB ET0) erlauben.
Vor allem musst Du aber auch den Timerinterupt bedienen. Sprich: ab
Adresse 0x000B steht zumindest ein Sprung auf die Serviceroutine - und
nicht ein Neustart des Prozessors.
Nachdem das Hauptprogramm das alles angestossen hat, kann es sich selber
in einer Endlosschleife aufhängen:
1
SJMP $
Wie häufig nun die Serviceroutine aufgerufen wird, hängt von Deinem
Prozessortakt, Teilung bzw. Auswahl der Taktquelle und natürlich von dem
Wert, den Du in TH0 geschrieben hast, ab.
Das können aber immernoch einige 1000-male pro Sekunde sein!
Also musst Du die Aufrufe (in 2 Bytes) mitzählen. Also immer 1 dazu
Addieren, wenn die Routine aufgerufen wird. Wird ein bestimmter Wert
erreicht, muss der Ausgang umgeschaltet werden und der Zähler wieder auf
0 gesetzt werden.
Wenn Du keine Speichergeschichten (MOVX, MOVC) machst, kannst Du auch
den DPTR benutzen. Mit
1
INC DPTR
hast Du Deinen 16-Bit-Zähler dann um 1 erhöht. DPH kannst Du dann
einfach auf einen kompletten Port kopieren und hast an diesem
verschiedene Blinkfrequenzen.
... erzeugt auf einem mit 18.432MHz getakteten 12-cycler ca. 12 - 0,1 Hz
an den Portpins P1.0 - P1.7
Könnte bei Dir also bis Faktor 16 schneller sein. Sollte aber noch etwas
blinkendes dabei sein ...
Hexfile dazu - falls Du meinen Kram nicht kompilieren kannst ...
Mal eine kleine Veranschaulichung:
Du stehst in der Küche und kochst. Aktuell schälst Du Kartoffeln.
Nun klingelt es an der Tür.
Du kannst dies nun ignorieren (Interupts abgeschaltet) oder die
Kartoffeln hinlegen und auf das Klingelzeichen reagieren.
Erste Schritte in der Interupt-routine 'Klingel' sind sicherlich 'zur
Tür gehen und öffnen', weitere sind situationsabhängig. (Eigentlich
gehört das hinlegen der Kartoffeln schon dazu)
Irgendwann ist die ganze Sache erledigt und Du wendest Dich wieder
Deinen Kartoffeln zu. (Inklusive dem wiederaufnehmen der Kartoffeln)
Nun kann es jederzeit wieder klingeln - auch wenn Du gerade nicht mit
den Kartoffeln beschäftigt bist. Aber Du kehrst, nachdem Du die Person
an der Tür abgefertigt hast, immer wieder an die Stelle zurück, an der
Du vorher warst.
Nun gibt es noch einen zweiten Interupt: Telefon :-)
Und sollte beides gleichzeitig passieren, muss einer der beiden warten.
Also erst mal vielen Dank, dass du dir Zeit genommen hast Jobst M.!
Den Interrupt haben wir in der Theorie schon durchgemacht, jedoch habe
ich es nicht sogut verstanden, dass ich ihn auch in der Praxis umsetzen
kann.
Das von dir geschriebene Programm hilft mir leider nicht weiter, da ich
es nicht ganz verstehe. Vor allem das mit dem
.org 0x000B
LJMP timer0_service
ist mir noch unklar.
Den Timer denke ich habe ich verstanden und auch richtig initialisiert.
Die Aktivierung des Interrupts ist auch kein Problem.
Jetzt zum prinzipiellen Programmablauf eines Interrupt(aus meinen
Unterlagen):
1. Interrupt wird während eines laufenden Befehls aktiv.
2. Interrupt wird gespeichert bis zum Befehlsende.
3. Interrupt - Typ wird identifiziert
4. Programmcounter+1 (PC,Adresszähler) wird im Stack
gespeichert(=Adresse des nächsten Befehls). Vektor des auslösenden IRQs
wird als nächste Adresse(=ausführender Befehl) in den Adresszähler
geladen(=Übergabe der Kontroller an ISR).
5. Andere IRQs werden je nach Priorität gesperrt oder zugelassen.
6. Interrupt (Service) Routine wird abgearbeitet.
7. Konfliktgefahr: alle Register bzw. Speicherplätze, die vom
Hauptprogramm benutzt und in der ISR ebenfalls benötigt werden, müssen
zu Beginn der ISR gesichert werden(PUSH - Operation) und vor dem
Rücksprung ins Hauptprogramm wieder restauriert(z.B. POP - Operation)
werden (= der ursprüngliche Zustand wiederhergestellt)
8. Am Ende der ISR wird der Programm - Counter restauriert, d.h. das
Programm setzt an der unterbrochenen Stelle fort.
9. Signalisierung an die Interrupt - Logik das der IRQ abgearbeitet
wurde(z.B. Rücksetzen von Flags)(der gleiche IRQ kann nicht gleichzeitig
zweimal bearbeitet werden)
Kann mir bitte jemand sagen wie ich die einzelnen Punkte im Programm
realisiere? Vorerst möchte ich das nur mal mit einem Interrupt
verstehen.
Wenn jemand ein einfaches fertiges Interruptprogramm hat: bitte posten,
damit ich das auch verstehe.
Gruß
tom
Frank Meier schrieb:> Tom B. schrieb:>> 3. Wie lange ist die maximale Zeit, die mit einem 8051er mit einem Timer>> bei 12MHz erreicht werden kann?>> Praktisch unendlich.
Das hilft mir leider genau nix weiter.
Gruß
tom
Tom B. schrieb:> .org 0x000B> LJMP timer0_service> ist mir noch unklar.
Das ist die Adresse, zu der der Prozessor springt, wenn der dazugehörige
Interupt auftritt ...
> 6. Interrupt (Service) Routine wird abgearbeitet.
Dies beginnt dort eben.
Schau mal, ob Du in Deinem Datenblatt etwas über Interupt Vectoren
findest. (Du solltest - ich habe es gefunden)
Peter Dannegger schrieb:>> 3. Wie lange ist die maximale Zeit, die mit einem 8051er mit einem Timer>> bei 12MHz erreicht werden kann?>> Datenblatt und Taschenrechner sind Dein Freund.
So ähnlich sehe ich das allerdings auch.
Bei einem standard 12-cycle 8051 wird TL0 mit 1MHz hochgezählt, bis zu
einem Überlauf. Dann wird der in TH0 gespeicherte Wert in TL0 kopiert
und wieder gezählt.
Wenn TH0 = 0 ist, müssen 256us vergehen, bis ein Interupt eintritt. Also
3906.25 /s
Wenn TH0 = 128 ist, benötigt er nur noch die halbe Zeit.
Du hast allerdings einen 1-cycler und kannst den Takt wohl auch noch
zwischen geteilt und ungeteilt umschalten. Wie dies zu konfigurieren
ist, steht im Datenblatt.
Was passiert denn an den Ausgängen, wenn Du mein Programm einspielst?
Gruß
Jobst
Mit solchen Antworten kann ich was anfangen! Danke Jobst M.!
>Tom B. schrieb:> .org 0x000B> LJMP timer0_service> ist mir noch unklar.>Das ist die Adresse, zu der der Prozessor springt, wenn der dazugehörige>Interupt auftritt ...
So habe ich das mit den Interrupts interpretiert:
Sobald das Überlauf - Bit beim Timer gesetzt ist, wird der Interrupt
ausgelöst.(Interrupt(Service) Request)
Also wenn jetzt das Überlauf Bit gesetzt wird, und ich bei der
Initialisierung des Programmes >.org 000Bh
und darunter >ljmp _t0
stehen habe, so springt das Programm beim Timerüberlauf in meine
work.int datei und die Interrupt Service Routine arbeitet dann
automatisch mein Interruptprogramm ab? Weiters ist mir klar, dass ich
den Wert im Akku erst sichern muss. Wenn ich das jetzt richtig
verstanden habe, sollte das so aussehen:
1. Überlaufbit wird gesetzt
2. Sprung in die work.int datei zu ORG 0000bh
3. _t0:
PUSH ACC ;Akku sichern
PUSH PSW ;Stack - Position sichern
Hier kommt jetzt mein Interruptprogramm
.......................................
POP PSW ;Rückspeichern Prozessor Status Wort
POP ACC ;Rückspeichern Akku
reti ;zurück von der interruptroutine
ljmp JT0 ;
ljmp IntError
ljmp _Reset ;Sprung zurueck zum Beginn des Programm
Das Problem ist, dass ich nicht verstehe, warum der dann wieder zurück
zum Start in die asm Datei springt.
Bitte das nochmal ausführlich erklären.
Dein Programm habe ich nicht ausprobiert. Ich könnte zwar die kleinen
Frequenzen auch mit dem Multimeter messen, aber möchte das Programm
selbst schreiben. Ich bitte um Verständnis.
laut deinem Programm brauche ich in der work.int datei nichts schreiben.
Ich denke ich habe es bald geschnallt mit dem Interrupts!
Gruß
Tom
Hi
>meinInterrupt:> push acc ;inhalt vom akku sichern> push psw ;prozessor status word sichern> setb upperled> pop psw ;inhalt von PSW ruckspeichern> pop acc ;inhalt vom akku rueckspeichern> ljmp Main
Ein Interrupt wird auch beim 8051 mit 'reti' beendet.
MfG Spess
Das habe ich nun ausgebessert, jedoch macht das Programm einfach nicht
das was ich will ...
nun leuchten beide LEDs, obwohl die untere LED nicht aktiv sein sollte.
Ich habe leider auch kein Oszilloskop um an den Ports die Frequenz zu
messen-_-
Es wäre echt super, wenn jemand den Fehler finden würde!
Gruß
Tom
Hi
>Es wäre echt super, wenn jemand den Fehler finden würde!
Mach mal ein Programm, in dem nur der wirklich benutzte Code ist. Wer
soll sich denn da durchwühlen. Vielleicht wird dir dann auch einiges
klarer.
MfG Spess
Alles was in der work.asm unter ljmp main steht ist nur zur
Initialisierung der Pins, Subroutinen, etc. also nichts relevantes für
den Programmablauf.
Also kann man sich alles unter ljmp main wegdenken.
Gruß
Tom
Tom B. schrieb:> 1. Überlaufbit wird gesetzt> 2. Sprung in die work.int datei zu ORG 0000bh> 3. _t0:> PUSH ACC ;Akku sichern> PUSH PSW ;Stack - Position sichern> Hier kommt jetzt mein Interruptprogramm> .......................................> POP PSW ;Rückspeichern Prozessor Status Wort> POP ACC ;Rückspeichern Akku> reti ;zurück von der interruptroutine> ljmp JT0 ;> ljmp IntError> ljmp _Reset ;Sprung zurueck zum Beginn des Programm
Komisch. Im Quelltext steht etwas anderes ...
> Dein Programm habe ich nicht ausprobiert. Ich könnte zwar die kleinen> Frequenzen auch mit dem Multimeter messen, aber möchte das Programm> selbst schreiben. Ich bitte um Verständnis.
Abgelehnt. Denn das Programm soll mir zeigen, ob Du mehr
Konfigurationsaufwand auf Deinem Superprozessor benötigst oder ob alles
so läuft.
Und: Nichts ist anschaulicher als ein Beispiel.
Benutze das Programm, spiel damit herum, verändere Werte und schau, was
passiert. DANN kannst Du immernoch Dein eigenes Programm schreiben.
Gruß
Jobst
Ich habe das Programm von Dir nun gestestet, jedoch ohne Erfolg.
Konnte keine Pegeländerung an den von dir angegebenen PINs finden.
Ist ein Interrupt durch einen Tastendruck einfacher zu realisieren? Ich
finde den Fehler nicht
Gruß
Tom
Die Silabs sind etwas tricky, weil man erst die IO-Pins konfigurieren
muß und die Crossbar.
Ohne das geht garnichts.
Du mußt also erstmal versuchen, die Pins mit den LEDs überhaupt als
Ausgang zu konfigurieren, d.h. die LEDs leuchten zu lassen.
Wenn das geht, konfiguriere die Tasteneingänge, d.h. die LEDs mit ner
Taste ein-/ausschalten.
Dann erst kannst Du Interrupts machen.
Besser davor noch Blinken mit Delayloop und dann Blinken mit
Timer-Polling machen.
Also immer einen Schritt nach dem anderen.
Peter
Danke für Deine schnelle Antwort!
Die Ports sind schon alle richtig initialisiert und funktionieren auch.
Die LEDs kann ich auch mit einer Zeitschleife blinken lassen.
Aber der Timer Interrupt funktioniert einfach nicht. Ich habe nochmal
die Dateien im Anhang. Schön langsam macht es mir nämlich keinen Spaß
mehr mit dem Timer - Interrupt ...
Was mache ich falsch?
Gruß
Tom
Hi
>Das ich den aktuellen Programmcounter+1 im Stack speichern muss und dann>wieder restaurieren muss.
Das musst du überhaupt nicht. Das geht automatisch.
> ljmp Main
Noch mal zum Mitschreiben: Eine Interruptroutinen wird mit RETI
beendet.
Vom restlichen Müll nicht zu reden.
MfG Spess
Tom B. schrieb:> isr_timer:>> push acc> push psw> clr upperled> lcall SP_InWait ;endlos auf Eingabe warten
Was soll das denn, im Timerinterrupt "endlos warten".
Da ist der Murx ja schon System.
Du solltest Dich erstmal hinsetzen, den PC aussschalten und mit Papier
und Stift einen Programmablaufplan erstellen (in Worten).
Erst danach kann man Instruktionen so hinschreiben, daß auch was
sinnvolles dabei herauskommt.
Peter
Na Tom - aller Anfang ist schwer!
Da die anderen ihr Pulver verschossen haben versuche ich es nochmal mit
Geduld und simplen Beispiel:
(Eigentlich ist alles schon gesagt worden... Jobst, Peter)
Reset - Vektor:
0000h: ljmp count_loop;
;Andere Vektoren
0002h:
0004h:
;...........
Interrupt - Vektor:
; der Prozessor führt den code aus der an diesen beiden Bytes 000bh
; und 000ch steht. Einfacherweise ist es ein ljump zu deiner ISR...
000bh:
ljmp T0Int
; Main Program - tue nichts (besonderes)
cont_loop:
mov A,#2
sjmp cont_loop;
T0Int:
; Aha ein Interrupt !
; Das Hauotprogramm wurde (irgendwo) unterbrochen...
; Der Rücksprung liegt (wie die Return - Adresse bei einem lcall)
; bereits auf dem Stack
mov A,#1
reti;
; Was hast du gemacht ? Du hast dem Hauptprogram den Accumulator
; "verbogen" - ist hier nicht weiter schlimm - das Hauptprogramm
; braucht den nicht wirklich! Um den Interrupt so auszuführen als
; wäre nie was gewesen musst du den Accu sichern:
push ACC
mov A,#1 ; jetzt kann der Accu "verbogen" werden
; Hier darfst Du jetzt auch einen LED - Pin
; toggle einfügen (mehr aber nicht!!!!)
pop ACC ; restaurieren des Accu
reti ; und jetzt kehre zurück an die Stelle
; wo die Unterbrechung war
Nach dem Reti wird im Hauptprogramm weitergemacht
- als wäre nie was gewesen.
Aber so ein Interrupt ist eine Ausnahme
- Man darf hier nur die notwendigesten Dinge tun. Auf keinen Fall auf
Input warten oder Aufrufe machen in Supbroutinen, die für
das Hauptprogramm gedacht sind oder so was.
Deine Interrupt Service Routine muss daher in der Lage sein vor dem
nächsten Interrupt das Reti zu erreichen.
Und nicht nur das.
Wenn das reti nur gerade so erreicht wird (weil du zuviel in der ISR
machst, bleibt dem Hauptprogramm praktisch keine Zeit mehr mal einen
Befehl ganz normal abzuarbeiten.
Im Fall des T0 Betriebsart 2 ist der Interrupt gedacht als Zeitnormal!
Du kannst dich darauf verlassen, dass dieser Interrupt alle x
mikrosekunden wieder kommt. Wenn Du also den Intrrupt auf 200
mikrosekunden
stellst und dir einen Zähler baust der 5000 mal zählt bevor er
auf null runter ist hast du dir ein Quarzgenaues - Sekundennormal
gebaut. Mit dem Sekundenzähler könntest du so weitermachen und eine
komplette Uhr bauen.
Alles klar,
viel Freude,
THaala
Tom B. schrieb:> Hat jemand ein fertiges Timer - Interrupt Programm, welches auch> funktioniert?
Das von mir geschickte funktioniert - ich habe es sogar ausprobiert -
nur eben auf einem normalen 8051 (AT89S52 mit 18.432MHz)
Peter Dannegger schrieb:> Die Silabs sind etwas tricky, weil man erst die IO-Pins konfigurieren> muß und die Crossbar.> Ohne das geht garnichts.
Das hatte ich schon befürchtet ...
Ich würde ja behaupten, daß der Prozessor zu komplex ist, um darauf
Grundlagen zu lernen. Da muss man nämlich (mindestens) 3 Sachen auf
einmal lernen, bevor sich ein Erfolg zeigt. Nur das Du nicht weißt,
welche der 3 Sachen nicht läuft.
Ist wie ein Kombinationsschloß. Sieh es sportlich :-)
Ach ja: Dein Angebot ist nichts für mich.
Gruß
Jobst
Tom B. schrieb:>Das ich den aktuellen Programmcounter+1 im Stack speichern muss>und dann wieder restaurieren muss.
Was machst du denn da für einen Scheiß?
In einer Timer-ISR darf man niemals noch ein Warteprogramm aufrufen, und
auf eine Eingabe warten, oder sonst langwierige Funktionen ausführen,
was den Sinn des Timer-Interrupts total zerstört ...
Nein, der Prozessor ist nicht zu komplex, wenn man nur einen Timer im
Interrupt haben möchte. Der Core ist 8051-kompatibel. Lediglich, um eine
LED blinken zu lassen, da muß man sich in der Tat mit den anderen
Peripherieelementen auch beschäftigen, z.B. der Pin-Konfiguration.
Gibt es vom Hersteller eigentlich keine Demo-Beispiele? Ich meine, das
wäre schon seit fast 10 Jahren so üblich.
Wilhelm Ferkes schrieb:> In einer Timer-ISR darf man niemals noch ein Warteprogramm aufrufen, und> auf eine Eingabe warten, oder sonst langwierige Funktionen ausführen,> was den Sinn des Timer-Interrupts total zerstört ...
Kann und darf man schon - allerdings muss man genau wissen, was man tut
und es muss erwünscht sein. Dann sollte man Interupts allerdings auch
schon verinnerlicht haben.
> Nein, der Prozessor ist nicht zu komplex, [...]
Für Dich nicht und für mich auch nicht. Aber für einen Anfänger ist er
zu komplex.
Wenn ein Anfänger die Möglichkeit hat in eine Falle zu tappen, dann
tappt er da auch rein. 100%.
Stell drei Fallen auf, er kommt nie an. Denn spätestens, wenn er die 2.
Falle entdeckt, tappt er wieder in die erste.
Problem speziell bei Prozessoren: Er sagt Dir nicht, in welche Falle Du
gerade getappt bist.
Dazu noch so Kunstwerke, wie mit einem 'JMP main' aus einer ISR heraus
zu hüpfen und das Chaos ist perfekt ...
> Gibt es vom Hersteller eigentlich keine Demo-Beispiele? Ich meine, das> wäre schon seit fast 10 Jahren so üblich.
Er möchte keine Beispiele ... - Ohne Worte ...
Gruß
Jobst
So, seit gestern funktioniert nun endlich alles wie ich es mir
voerstelle:)
Das Beste daran ist, dass man wenn man einen Interrupt kann auch alle
anderen Interrupts kann. Da ich ja noch Anfänger bin und auch schon mit
einem älteren 8051er gearbeitet habe, kann ich dieses Kit
weiterempfehlen. Man sollte sich jedoch im klaren sein, dass die Pin
Konfiguration nicht ganz einfach ist(Daher hat das auch mein Lehrer
gemacht, damit man möglichst schnell damit arbeiten kann)
Also vielen Dank an euch!
Gruß
Tom
> So, seit gestern funktioniert nun endlich alles wie ich es mir voerstelle:)
Mag sein, aber poste deinen Code hier. Funktioniert != fehlerfrei.
Einem Anfänger bringt man Fehler leichter ausgetrieben bzw. vermeidet,
dass er sie sich angewöhnt.
Ralf