Hallo,
habe mich hier angemeldet weil ich ein Problem bei der Programmierung
eines 8051 Mikrokontrollers habe.
Ich soll eine Ampelschaltung mit 1 Kfz Ampel und 1 Fußgängerampel
machen.
Für die Fußgänger gibt es eine Ruftaste.
Das Problem ist der Interrupt den ich für den Notbetrieb eingebaut habe.
Wird der Interrupt ausgelöst blinkt die KFZ Ampel gelb.
Ich poste hier einmal den kompletten ASM Code:
1
INCLUDEREG_51.pdf
2
3
codeat0
4
5
SJMPinit
6
ORG0013h
7
8
isr:LCALLblink
9
RETI
10
11
12
init:SETBEA
13
SETBEX1
14
SETBIT1
15
16
start:SETBP2.0
17
CLRP2.1
18
CLRP2.2
19
CLRP2.3
20
SETBP2.4
21
22
CLRP2.6
23
CLRP2.7
24
25
m1:MOVA,P2
26
CJNEA,#31h,m1
27
SETBP2.6
28
CLRP2.6
29
LCALLzeit1
30
CLRP2.0
31
SETBP2.1
32
LCALLzeit1
33
CLRP2.1
34
SETBP2.2
35
LCALLzeit1
36
SETBP2.3
37
CLRP2.4
38
LCALLzeit2
39
CLRP2.3
40
SETBP2.4
41
LCALLzeit1
42
SETBP2.1
43
LCALLzeit1
44
SETBP2.0
45
CLRP2.1
46
CLRP2.2
47
JMPstart
48
49
zeit1:;Übergangsphase1s
50
MOVR0,#00Fh
51
m2:DJNZR0,m2
52
RET
53
54
zeit2:;Auto-Rotphase4s
55
MOVR0,#0FFh
56
m3:DJNZR0,m3
57
RET
58
59
60
blink:MOVR1,#30d
61
m4:MOVP2,#00h
62
LCALLzeit1
63
MOVP2,#02h
64
LCALLzeit1
65
DJNZR1,m4
66
RET
67
68
END.
Das Problem ist, wenn das Programm gerade am Ablauf ist und ich dann den
Interrupt auslöse. Dann nämlich speichert er sich ja die
Rücksprungadresse. Wenn er nun im UP Blink das mit dem Interrupt
ausgeführt wird, die KFZ Ampel gelb blinkt, sind die Bits alle anders
gesetzt.
Nun springt er nach einer gewissen Zeit aus dem Notbetrieb wieder heraus
und zurück an die Stelle mitten im Programm. Dann funktioniert nichts
mehr.
Ich wollte es irgendwie so lösen, dass wenn der Interrupt zuende ist,
dass das Programm wieder von vorne anfängt. Also bei start. Wie könnte
ich das machen?
Ich musste immer mit SETB und CLRB Arbeiten weil sonst das Programm
8051win mit dem wir nachher das vorführen sollen nichts macht. Also
einfach mit MOV bla bla geht nicht.
Habt ihr eine Idee?
Grüße
Du musst doch einfach nur die Rücksprungadresse, die beim Auslösen des
Interrupts gespeichert wird mit der Adresse von "Start" überschreiben.
Ich weiß jetzt nicht wie das Register beim 8051 heißt, aber da gibts
bestimmt eins.
Warum machst du nicht einfach eine ordentliche Schrittkette mit
geeigneten Transitionen für alle Ampelzustände, auch für den Zustand
"Ampel_gestört_blinkt".
Interrupts werden dazu nicht benötigt.
@Matthias Lipinsky
>Warum machst du nicht einfach eine ordentliche Schrittkette mit>geeigneten Transitionen für alle Ampelzustände, auch für den Zustand>"Ampel_gestört_blinkt".>Interrupts werden dazu nicht benötigt.
Da es sich um eine Aufgabe handelt, würde ich mal fast behaupten dass es
mit Interrupts gemacht werden soll. Solche aufgaben werden gerne zu
Übungszwecken verwendet.
Aus meine ASM-Laiensicht:
Ich würde in der ISR nicht zur Blinkroutine springen, sondern nur ein
Flag ändern, dass regelmäßig in deiner Schaltung abgerufen wird (z.B.
vor jeder Schaltung und während des Wartens).
So kommst du mit deiner Finite-State-Machine nicht durcheinander...
Timmo H. wrote:
> Du musst doch einfach nur die Rücksprungadresse, die beim Auslösen des> Interrupts gespeichert wird mit der Adresse von "Start" überschreiben.> Ich weiß jetzt nicht wie das Register beim 8051 heißt, aber da gibts> bestimmt eins.
mhh wenn ich das wüsste wäre das natürlich die Lösung!
>Interrupts werden dazu nicht benötigt.
Ist aber leider in der Aufgabe verlangt.
>Dein Problem liegt hier:
Danke stimmt hast du Recht, das mit $ hatten wir noch nicht gelernt.
Ändert aber leider nichts an meinem Problem.
>Ich würde in der ISR nicht zur Blinkroutine springen, sondern nur ein>Flag ändern, dass regelmäßig in deiner Schaltung abgerufen wird (z.B.>vor jeder Schaltung und während des Wartens).>>So kommst du mit deiner Finite-State-Machine nicht durcheinander...
Sry versteh ich nicht ganz.
>Siehe Interrupt
Mh joa hat mir jetzt nicht weitergeholfen, wenn du auf was spezielles
Hinweisen willst, gib mir bitte noch ein Stichwort ;)
Danke auf jeden Fall für die vielen Antworten in kürzester Zeit! Ich bin
sicher wir finden eine Lösung!
Greetz
Skua S. wrote:
> Im Init> mov R7,#0>> in ISR> mov R7,#1>> vor jedem lcall zeitx> mov A,R7> CJNE A,#1,blinken>> am ende von blinken> mov R7,#0> ljmp start
Das ist ja genial! Glaube mein INF Lehrer wird das nicht raffen :D
Hab kurz gebraucht es nachzuvollziehen, aber macht echt sinn und ist
genialst!
Vielen Dank!!!
NOch ne Frage benutzt hier jemand 8051win? Ist das Problem bekannt das
ich beschrieben habe? Also das ich die Ampelschaltung mit SETB und CLRB
machen muss und nicht einfach MOV p2, wert?
Karl Suleyman wrote:
> NOch ne Frage benutzt hier jemand 8051win? Ist das Problem bekannt das> ich beschrieben habe? Also das ich die Ampelschaltung mit SETB und CLRB> machen muss und nicht einfach MOV p2, wert?
Welches Problem?
Du benutzt es ja:
1
blink:MOVR1,#30d
2
m4:MOVP2,#00h;<-hier
3
LCALLzeit1
4
MOVP2,#02h;<-undhier
5
LCALLzeit1
6
DJNZR1,m4
7
RET
Also funktioniert es doch.
Wäre auch schlimm, wenn ein 8051-Assembler kein MOV könnte.
Peter
>Ich würde in der ISR nicht zur Blinkroutine springen, sondern nur ein>Flag ändern, dass regelmäßig in deiner Schaltung abgerufen wird (z.B.>vor jeder Schaltung und während des Wartens).
Und was macht das denn für einen SInn?
Da kann ja gleich statt des Flags, das EIngangspin abgefragt werden!
(So wie es sinnvoller ist)
>>Interrupts werden dazu nicht benötigt.>Ist aber leider in der Aufgabe verlangt.Beitrag "Re: Berechnung einer Pause"
Die Bitbefehle sind doch das tolle an den Dingern.
Der Assembler hat bestimmt auch einen EQU Befehl.
Damit kannst du am anfabg des Programmes die Pins und Register benennen.
Dann geht sowas wie
CLRB RotFussgaenger
SETB GruenFussgaenger
oder
MOV Anforderung,#1
@lippy: Ja was will man tun! Das ganze ist sogar ein Projekt und wird
mir wenn ichs gut mach 12pkt (Abi Note) bringen O.o ....
Stimmt mit EQU könnt ich das ganze eigentlich ein wenig Durchschaubarer
machen ;)
Was mir noch eingefallen ist, wenn ich vor jedes LCall die Abfrage
mache, ob der Interrupt ausgelöst wurde, dauert das ja auch noch eine
gewisse Zeit bis dann Blink wirklich aufgerufen wird. Das ist ja gerade
der Sinn am Interrupt das es keine Verzögerung geben soll.
Kann ich denn irgendwie die Rücksprungadresse vom Interrupt verändern?
Die wird doch im Stack gespeichert oder?
Das Problem mit dem MOV Befehl war, dass wenn ein Bit gelöscht wurde,
konnte man es nicht mehr neusetzen. Ich werde aber das noch einmal
überprüfen.
Was wäre denn die saubere Lösung die man bevozugen sollte? Mit SETB CLRB
oder MOV?
>Das ganze ist sogar ein Projekt und wird>mir wenn ichs gut mach 12pkt (Abi Note) bringen O.o ....
Ich würde das dann ohne Interrupt programmieren. Eine ordentliche
Schrittkette mit geeigneten Transistionen und fertig.
Bei Punktabzug würde ich mit den Lehrern rumdiskutieren.
(Hab ich immer so gemacht-geschadet hats mir gewöhnlich nicht)
mh ok kannst du mir noch kurz sagen was "geeignete Transistionen" sind?
Habe ich so noch nie gehört und google hat mir jetzt auch nichts
erklärendes geliefert.
Meinst du damit die Abfragen?
>Meinst du damit die Abfragen?
Ja. Das sind die Übergänge von einem Schritt in einen anderen.
>mit 1 Kfz Ampel und 1 Fußgängerampel
Man könnte das etwa so aufschlüsseln:
Nr. ZustandsName Kfz-Ampel(R+Ge+Gn) Fussgängerampel(R+Gn)
=======================================================================
0 Ampel aus blinkt gelb alles aus
1 Stopp rot rot
2 Anfahren rot+gelb rot
3 Fahren grün rot
4 Bremsen gelb rot
5 Laufen rot grün
Das sind die Zustände. Jetzt musst du dir für jeden Zustand separat
Gedanken machen, unter welchen Bedingungen du in welchen (neuen) Zustand
übergehst.
Beispiel:
Zustand 3:Fahren
Dieser Schritt wird beendet, wenn (zB):
- eine Zeit x abgelaufen ist, dann zu Zustand 4.
- Notbetrieb aktiviert, dann zu Zustand 0
Das war beispielhaft (und muss nicht stimmen). Mache das für jeden
Zustand.
Das kannst du dann ganz easy programmieren:
Beitrag "Re: Programm bzw. Ablaeufe steuern"
Matthias Lipinsky wrote:
>>Ich würde in der ISR nicht zur Blinkroutine springen, sondern nur ein>>Flag ändern, dass regelmäßig in deiner Schaltung abgerufen wird (z.B.>>vor jeder Schaltung und während des Wartens).>> Und was macht das denn für einen SInn?> Da kann ja gleich statt des Flags, das EIngangspin abgefragt werden!> (So wie es sinnvoller ist)>
1) Weils gefordert ist.
Und rational: 2) Eine Störung ist eine Störung, und die muss in einer
Ampelanlage sicher gefangen werden und in einen definierten Zustand
führen.
Wenn das Signal 'Störung' nur sehr kurz anliegt, kann es sonst sein,
dass es von der Anlage nicht bemerkt wird....
>Wenn das Signal 'Störung' nur sehr kurz anliegt,
Eine Ampelanlage ist kein schnelles (Mikro..Nanosekunden) System!
Also was soll da hier kurz sein..?
>Weils gefordert ist.
Das ist kein Argument. Oder gilt bei Entwicklungen auch:
"Junger Freund, wir machen das schon immer so!"
Wenn das so wäre, würden wir heute noch in Höhlen hausen!
Aber wenns dir gefällt, bau in der ISR ein Flag ein, welches du dann
zyklisch abfragst. Das ist zwar sinnlos aufwändig, aber du hast deine
ISR..
Karl Suleyman wrote:
> Skua S. wrote:>> Im Init>> mov R7,#0>>>> in ISR>> mov R7,#1>>>> vor jedem lcall zeitx>> mov A,R7>> CJNE A,#1,blinken>>>> am ende von blinken>> mov R7,#0>> ljmp start>>> Das ist ja genial! Glaube mein INF Lehrer wird das nicht raffen :D
Wenn er es rafft, wirds aber ne 6 geben.
Aus einem Interrupt ins Main zu springen ist ein ganz böses Foul, weil
das bald einen Stacküberlauf gibt.
Solche "genialen" Stolperfallen sind typisch für Anfänger.
Man muß erstmal den Unterschied zwischen einem Jump und einem Call
lernen.
Es klang ja schon an, daß Interrupt Unterbrechung mit nachfolgender
Wiederaufnahme bedeutet und daher nicht gut geeignet ist, um etwas
abzubrechen.
Auf MCs setzt daher der Interrupt nur ein Flag, womit dann in der
Mainloop verzweigt wird.
In Betriebssystemen kann ein Interrupt auch etwas abbrechen, indem er
Funktionen aufruft, um eine laufende Task zu killen. Das ist aber doch
sehr kompliziert, da dabei der Stack und der RAM aufgeräumt werden muß
und diverse andere Sachen.
Peter
@ peda:
der springt aber nicht von isr ins main. er setzt ja nur ein Register.
blinken ist ja ein UP und wird von dem Vergleich aufgerufen. Nicht
direkt von der ISR.
So dürfte es kein Stack überlauf geben.
Berichtige mich wenn ich doch falsch liege ;)
Wollte ich kurz anmerken, die anderen Beiträge habe ich noch nicht
verarbeitet ;)
@Lippy: Ich glaube das würde unseren Umfang sprengen. Klar sieht
wahrscheinlich so sauberes Programmieren aus, mit case und if,
allerdings fällt dem Lehrer das sofort auf, dass es nicht von mir sein
kann, denn das haben wir selbst so noch nicht gemacht.
Deshalb fordert er das auch so nicht.
>allerdings fällt dem Lehrer das sofort auf, dass es nicht von mir sein>kann, denn das haben wir selbst so noch nicht gemacht.
Das ist gewöhnlich aber kein Problem. Wenns eine Hausaufgabe ist, kannst
du dir jederzeit Hilfe holen.
Wichtig ist jedoch immer, das du die Lösung erklären kannst.
Also wenn du mein Vorschlag selbst durchziehst, dann kannst du dem
lehrer auch alles im Detail erklären. Somit kann er das nicht negativ
bewerten.
Wenn er will, das du das allein machst, dann muss es eine Klausur sein.
>Ich glaube das würde unseren Umfang sprengen.
Das ist ein Trugschluss. Ich würde sagen, das dauert mit Programmierung
einen Samstagnachmittag (vielleicht den Abend noch, als Anfänger).
Sicherlich dauert das Austellen der Zustände und deren Übergänge
(Transitionen) länger als das danach zu programmieren, aber so ist das
gewöhnlich bei "professioneller Programmierung". Und: Gewöhnlich
funktioniert das dann auf Anhieb.
Eine Fehlersuche, aufgrund von Spaghetticode dauert Größenordungen
länger..
PS: 70% des Codes schreibt man in 30% der Zeit.
Karl Suleyman wrote:
> der springt aber nicht von isr ins main. er setzt ja nur ein Register.> blinken ist ja ein UP und wird von dem Vergleich aufgerufen. Nicht> direkt von der ISR.
Stimmt, er setzt wohl nur ein Flag.
Ist eben schwer, Code zu verstehen, wenn er nicht richtig da steht.
Statt ein ganze Byte zu nehmen "MOV R7,#1", reicht aber ein Bit völlig
aus "SETB F0".
Peter
na toll jetzt wollte ich den quellcode ändern und mir in 8051win
anschauen, nun funktioniert dieses Programm nicht mehr. Ich könnte
verrückt werden...
Klick ich auf Run oder Step passiert einfach nichts mehr.
Matthias Lipinsky wrote:
>>Wenn das Signal 'Störung' nur sehr kurz anliegt,>> Eine Ampelanlage ist kein schnelles (Mikro..Nanosekunden) System!> Also was soll da hier kurz sein..?>
Darum geht es ja nicht. Ab dem Moment, wo du nicht mehr garantieren
kannst, dass wirklich alle Störungen abgefangen werden, ist das doch
eher mies.
Leute, die behaupten, man müsse diverse Eingaben nicht prüfen, weil
String nie länger als xx Zeichen wären, sind auch alle hingefallen.
Bei sicherheitstechnischen Anlagen geht es am Ende wirklich nur darum
beweisen zu können, dass alle Störungen in einen sicheren Zustand
überführt werden.
Danke auf jeden Fall für eure Antworten!
Gibt es noch weiter Vorschläge? Konnte leider bisher noch nichts Testen
da ich hier keinen Lizenzschlüssel habe. Nur in der Schule :(