89C2051 Anfänger

Hallo NG,
bin völliger Newbie in der MicroProzessor Programmierung. Die Jump-Befehle habe ich einigermassen drauf. Aber kann mir jemand sagen, wie ich Schleifen programmieren muss, die nach einer bestimmten Zeit wieder verlassen werden? Ich brauche eine Verzögerung von 500 ms, 1000 ms, 3000 ms und 30000 ms (30 Sekunden). Solange sollen bestimmte Vorgänge ablaufen, bevor wieder zur Hauptroutine zurückgesprungen wird. Auf der Platine taktet ein 16 MHz Quarz. Hab schon 3 Artikel im Net zur Programmierung durchforstet und mir schwirrt schon der Kopf. Aber ich weiss noch immer nicht, wie man das macht. Danke für eine Antwort.
Gruß Norbert

Hallo,

bin völliger Newbie in der MicroProzessor Programmierung.

Die Microcontroller-Seite
http://www.erikbuchmann.de/
http://wwwiti.cs.uni-magdeburg.de/~buchmann/privat/m…

Die Jump-Befehle habe ich einigermassen drauf. Aber kann mir
jemand sagen, wie ich Schleifen programmieren muss, die nach
einer bestimmten Zeit wieder verlassen werden? Ich brauche
eine Verzögerung von 500 ms, 1000 ms, 3000 ms und 30000 ms (30
Sekunden). Solange sollen bestimmte Vorgänge ablaufen, bevor
wieder zur Hauptroutine zurückgesprungen wird. Auf der Platine
taktet ein 16 MHz Quarz. Hab schon 3 Artikel im Net zur
Programmierung durchforstet und mir schwirrt schon der Kopf.
Aber ich weiss noch immer nicht, wie man das macht. Danke für
eine Antwort.
Gruß Norbert

http://www.elektronik-kompendium.de/public/buchmann/…
http://www.kneissl.org/8051/
ISBN: 3895761419 Buch anschauen
http://www.buch24.de/1001-0/3-437882-1.html

mfg
W.

Hallo,

als Grundsatz: so gut wie jeder Controller enthält mindestens einen Timer, der einen ->Interrupt auslösen kann - d.h. wenn er abgelaufen ist, startet er einen ->Interrupt-Service, das ist ein (von dir zu schreibendes!) Programmstück, was der Controller eben machen soll, wenn seine Zeiteinheit abgelaufen ist. Die ->Timer sind weitgehend programmierbar, ich würde also einen der Timer so programmieren, dass er alle 10 msec seine Serviceroutine auslöst.

Für deine Anforderung „500 msec“ richtest du dir dann einen Zähler ein, der von 50 auf 0 herunterzählt und bei 0 das tut, was er eben tun soll, und dabei auch den Zähler wieder auf 50 setzt. Ebenso für die anderen Zeiträume. Was ich beschrieben habe, läuft unabhängig vom Hauptprogramm!

Was ich mit -> gekennzeichnet habe, sind Begriffe, in die du dich einlesen solltest, besonders mit den zum Controller-Baustein gelieferten Unterlagen.

Gruss Reinhard

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Vielen Dank, ihr beiden. Gibt’s irgendwo ein Codebeispiel? Sonst geht der ganze Sonntag wieder mit Literatur drauf und abends ist das Prog dann immer noch nicht fertig. Welche Befehle nehme ich zum Laden des Registers und wie zähle ich runter? Schon gut - ich fange gleich an und suche die angegebenen Literaturstellen durch. Aber vielleicht kommt einer von euch mit einem Codeschnipsel dazwischen? Da reicht’s evt. noch heute nachmittag für einen Spaziergnag mit der Familie :wink:
Gruß Norbert

Hab eine Schleife fertig:
ST1:
MOV R1,#FFh
ST2:
DJNZ R1,ST2
DJNZ R0,ST1

Damit werden 131 332 Zyklen durchlaufen. Aber wieviel Millisekunden sind das nun bei einem 16 MHz Quartz? Bestimmt nicht viele. Und wenn ich ca. 30 Sekunden brauche, wieviele Register muss ich dann benutzen?
Gruß Norbert

Hallo Norbert,

vielleicht so:

MOV R0,#0
ST1:
MOV R1,#0
ST2:
DJNZ R1,ST2
DJNZ R0,ST1

Bei einem Quarz mit 16 MHz hast Du ca. 1333333 Befehlszyklen pro Sekunde (1 Befehlszyklus = 12 Quarzzyklen)

Also würde Deine Verzögerungsschleife ca. 100 msec dauern. Wenn Du das noch einmal verschachtelst (mit einem Register R2), kommst Du schon auf ca. 25 Sekunden.

Mit dem Timer-Interrupt geht es natürlich auch, für den Anfang reicht Deine Methode vielleicht aber.

Grüße,

I.

Danke Idomeneo,
ich sehe schon, dass Deine Schleife besser ist. Bleibst Du noch ein bisschen da? Nun brauche ich ja 4 unterschiedliche Verzögerungen (0.5, 1, 3 und 30 Sekunden - kommt nicht auf die Millisekunde an). Baue ich da für jede eine extra Schleife? Oder wie geht das mit dem Timer? Hab gelesen „Interrupt bei Überlauf“ ???
Gruß Norbert

Hallo Norbert,

eine Möglichkeit ist natürlich, Du baust für jede Verzögerung eine eigene Schleife, und warum nicht? - Der 89C2051 hat 2 kByte Flash, wenn das ausreicht, und man sieht es dem Gerät nachher nicht an, auf welche Weise das Mikrocontroller-Programm realisiert ist. Hauptsache, es funktioniert.

Etwas eleganter wäre es, wenn Du eine Verzögerungsfunktion hast, der Du die Zeit mittels eines Parameters übergeben könntest.

Z. B. so:

Delay:
st1:
MOV r1,#0
st2:
MOV r2,#0
st3:
DJNZ r2,st3
DJNZ r1,st2
DJNZ r0,st1
ret

Die beiden inneren Schleifen dauern ungefähr 100 msec, mit r0 übergibst Du einen Parameter, der bestimmt, wie lange die Verzögerung in 100 msec-Einheiten dauert. Also wenn Du z. B. vor dem Aufruf r0 = 5 setzt, werden es ca. 0.5 sec:

MOV r0,#5
RCALL Delay

Und entsprechend für 1 sec r0 = 10 usw.
Allerdings geht das nur bis rund 25 sec.

Dann kannst Du aber folgendes machen:

MOV r0,#0
RCALL Delay ; ungefähr 25.6 sec
MOV r0,#44
RCALL Delay ; die restlichen 4.4 sec, zusammen 30 sec.

Diese Schleifen haben den Nachteil, daß sie nur warten, bis die Zeit verstrichen ist, sonst passiert nichts.

Noch eleganter ist es, diese Verzögerungen mit dem Timer-Interrupt zu realisieren, allerdings für Anfänger auch schwieriger. Dazu muß nämlich der Timer und sein Interrupt erst einmal nach dem Programmstart initialisiert werden. Der Vorteil ist aber, der Mikrocontroller kann irgendetwas anderes machen, und gleichsam im Hintergrund läuft der Timer, und nach Ablauf der gewünschten Zeit kann eine andere Aktion gestartet werden.

Drei Dinge brauchst Du in diesem Fall:

  1. Die bereits genannte Initialisierung (z. B. Timer 0, Modus 1 = 16-Bit-Timer):

MOV tmod,#00000001b ; Modus 1 für Timer 0
MOV tl0,#0 ; Voreinstellung für low- und high-Byte
MOV th0,#ffh ; des 16-Bit-Zählregisters wählen
setb et0 ; Timer-Interrupt freigeben
setb ea ; generelle Interruptfreigabe
setb tr0 ; Timer 0 starten

(Der Assembler sollte all diese Symbole tmod, et0, ea, tr0 usw. verstehen)

Der Timer 0 zählt nun das Zählregister th0/tl0 vom Anfangswert (hier ff00) aufwärts, beim Überlauf (0 erreicht) wird der Interrupt ausgelöst, d. h. hier nach 256 Zyklen = 0.19 msec. Für z. B. 10 msec müßte die Voreinstellung lauten:, weil der Timer dann 13333 Zyklen bis zum Überlauf zählt.
(MOV th0,#cbh und MOV tl0,#23h)

  1. Die Timer-Interrupt-Routine

timer0:
PUSH acc ; Akkumulator und Programmstatuswort
PUSH psw ; auf dem Stack zwischenspeichern
MOV a,tl0 ; Zähl-Register wieder mit Anfangswert laden
ADD a,#3 ; (Zur Korrektur 3 hinzuzählen, weil für den
MOV tl0,a ; Interrupt-Aufruf drei Befehlszyklen verbraucht
MOV th,#ffh ; wurden.
MOV a,r0 ; r0 wird bei jedem Interrupt-Aufruf dekrementiert
JZ br1 ; bis es 0 ist
DEC r0
br1:
POP psw
POP acc
RETI

  1. Das Hauptprogramm besteht, nach der Initialisierung, im wesentlichen aus einer Schleife mit Abfragen, die dann Aktionen ausführt, je nach Ergebnis der Abfragen.

Das Intervall starten:

MOV r0,#50d z. B. dann hat r0 nach 0.5 sec wieder den Wert 0.

Die Abfrage:

MOV a,r0
JZ --> verzweigt zu einer Aktion, wenn r0 0 erreicht hat.

Literatur z. B. Das Mikrocontroller-Kochbuch von Andreas Roth

Grüße,

I.

Brrrr. Wie lernt man denn sowas? Da werden sich meine Miezen aber freuen, wenn ihre Katzenklappe durch so ein feines Programm gesteuert wird. Ich mach mich mal drüber, Deinen Code zu verstehen. Ob ich es bis Mitternacht geschafft habe, glaube ich kaum. Hab recht vielen Dank für Deine Mühe. Gruß Norbert

P.S. Hier mal meine ersten Gehversuche. Vielleicht magst Du ja Katzen und hilfst noch a bisserl. Wenn ja, dann evt. per Mail (meine Adresse ist eh in allen Spamlisten, daher schreib ich sie hier: [email protected]), da kann man’s übersichtlicher schreiben. Die Platine ist schon fertig. Nur noch das Programm fehlt :wink:

’ Programm für Katzenklappe
.
INCLUDE 89C2051.mc
.
Taste1…EQU…P3.2…'schaltet Motor ein, wenn länger als 0.5 Sekunden geschlossen
Taste2…EQU…P3.3…'schaltet Motor aus, wenn länger als 0.5 Sekunden geschlossen
Taste3…EQU…P3.4…'Annäherungsschalter über Optokoppler, schaltet Motor aus
Quit_Open…EQU…P3.5…'Quittierung Klappe offen (Rückmeldung 1 = High)
Quit_Close…EQU…P3.7…'Quittierung Klappe zu (Rückmeldung 2 = High)
.
Motor…EQU…P1.7…'Ausgang für Motor (High = Ein)
Sender…EQU…P1.6…'Ausgang für Sender-Rückmeldung (High = Ein)
Gong…EQU…P1.5…'wird ausgelöst, wenn Annäherung
.
Begin:
…MOV…P1,#00h…'Grundeinstellung: Alle Pins von Port1 auf Low
…MOV…P3,#00h…'Grundeinstellung: Alle Pins von Port3 auf Low
.
Basis:
…JB…Taste1,Motor_Start
…JB…Taste2,Motor_Stop
…JB…Taste3,Motor_Stop
…JMP…Basis
.
Motor_Start:
…MOV…R0,#0
…MOV…R1,#0
…MOV…R2,#5
…CALL…Time
…JNB…Taste1,Basis
…SETB…Motor
…JMP…Basis
.
Motor_Stop:
…MOV…R0,#0
…CALL…Time
…JNB…Taste2,Basis
…CLR…Motor
…JMP…BASIS
.
Time1:
…DJNZ…R2,Time2
…MOV…R1,#0
.
Time:
…DJNZ…R1,Time
…DJNZ…R0,Time1
…RET