Hallo, ich bräuchte mal eure Hilfe, ich bekomme zuhause meine Keil-Software mit Windows7 nicht zum Laufen. Ich muss eine Ampelsteuerung in Assembler mit einem 80C552 realisieren. Ich habe da auch etwas geschrieben (s. Anhang) aber da ich es nicht ausprobieren kann, möchte ich euch bitten mal drüber zu schauen ob es klappen kann. Da ich nur 8 Ausgänge zur Verfügung habe, gibt es eine Ampel für die Hauptstraße, eine für die Nebenstraße und eine Fußgängerampel. Die Aufteilung des Ports seht Ihr in der Datei. Folgendes habe ich mir Überlegt, ich möchte die Fußgängerampel mit einem Timer-Interrupt auf grün schalten. Dafür starte ich direkt am Anfang einen 60s Timer (die Werte für die Timer sind erst mal fiktiv) In dem Unterprogramm ISRT1 sage ich dann, solange Register 1 nicht null ist, springe nicht zu M10. M10 ist dann der Punkt, an dem die Grünphase für die Fußgänger beginnt. Bin mal gespannt ob ich völlig auf dem Holzweg bin Danke schon mal im Voraus für die Hilfe
hmmm, das ist quatsch was ich da geschrieben habe. Die Fußgängerampel muss doch in ein Unterprogramm oder? Und mit dem Timer-Interrupt löse ich das Unterprogramm aus?!?!??
Hallo! 1.Tip: Du darfst die Timer-Initialisierungen natürlich nicht einfach "überspringen".
Hi Ich kenne weder den Controller noch das benutze Programmiergerät / Tool. Aber trotzdem denke ich dir helfen zu können. Wenn du ein Programm über eine Ampelsteuerung schreiben willst, dann überlege, wieviele Schritte du benötigst. Für eine einfache Fußgängerampel sind es sechs. Bei einer Kreuzung ein paar mehr. Schreibe dir im Klartext einmal auf, wie diese Schritte aussehen Grundstellung= Schritt 1 Schritt 1: Hauptstraße hat grün. Fußgänger hat rot Schritt 2: Hauptstraße hat gelb. Fußgänger hat rot Schritt 3: Hauptstraße hat Rot. Fußgänger hat rot Schritt 4: Hauptstraße hat Rot. Fußgänger hat grün Schritt 5: Hauptstraße hat Rot. Fußgänger hat rot Schritt 6: Hauptstraße hat Rot und gelb. Fußgänger hat rot Schritt 7 = Schritt 1 nun brauchst du einen Timer, sagen wir mal, der alle Sekunden ein UP aufruft In diesem UP reduzierst du einen vorbesetzte Wartezeit (Zähler) und wenn diese 0 ist setzt du deinen Schrittzähler weiter, definierst die neue Wartezeit, z. B. wenn du die Fußgängerampel in Schritt 4 für 10 sek. auf Grün schaltest dann setze die Wartezeit auf 10. Dadurch kannst du die Zeiten unterschiedlich lang parametrieren. Anschließend rufst du eine Auswerte-Routine auf, die erfragt, welcher Schritt aktuell ist und entsprechend die Ausgänge setzt. Nun, diese Steuerung würde auch ohne Fußgänger die Ampelsequenz ständig durchlaufen, also brauchst du etwas, welches diese Sequenz freigibt und in Schritt 6 zurückgenommen wird. Da du alles in kleine Unterprogramme packen kannst, ist es relativ einfach nachvollziehbar. Dein Hauptprogramm besteht nun nur noch aus Start: Lies Eingabe ist Start_Ampelzyklus dann zu Schrittkette Ist Taster dann setze Flag Start_Ampelzyklus Setze Wartezeit Schrittkette: Ist_Schrittwechsel dann Auswertung ( und Ausgabe) Springe zu Start Auswertung: Ist_Schrittwechsel zurücksetzen Inc Schrittzähler Ist Schrittzähler =7 dann Schrittzähler =1 ist Schrittzähler = 1 dann Schritt 1 Ist Schrittzähler = 2 dann Schritt 2 usw Ret Schritt 1: StartAmpelzyklus zurücksetzen Ausgabemuster der Lampen ausgeben Ret Schritt 2: nächste Wartezeit eintragen Ausgabemuster der Lampen ausgeben Ret etc. Timer : ( aufruf im Sekundentakt) Start_AmpelZyklus dann zur Wartezeit Reti Wartezeit: ( wenn Taster dann Aufruf im Sekundentakt) Dec Wartezeit Wartezeit=0 dann Setze Ist_Schrittwechsel Ret Dadurch erhälst du übersichtliche UP's und dein Programm ist auch noch für andere Aufgaben gewappnet, da der Timer nicht das Programm aufhält. Gruß oldmax
Kay --- schrieb: > Ich habe da auch etwas geschrieben (s. Anhang) aber da ich es nicht > ausprobieren kann, möchte ich euch bitten mal drüber zu schauen ob es > klappen kann. Nimm einen Simulator und probier es aus. http://www.dontronics.com/zip/sim51.zip Wenn Die Autofahrer aber rauskriegen, daß Du es bist, der sie 60s warten läßt, wirst Du regelmäßig zerstochene Reifen haben. Eine ISR mit RET ist ganz schlecht. Und eine ISR mit LJMP zum Main ist ganz ganz schlecht. Peter
Hmm, ich glaube das ich mir das alles noch mal durch den Kopf gehen lassen muss am Kopf kratz Aber Danke erst mal für die Anregungen.
Kay --- schrieb: > In dem Unterprogramm ISRT1 sage ich dann, solange Register 1 nicht null > ist, springe nicht zu M10. M10 ist dann der Punkt, an dem die Grünphase > für die Fußgänger beginnt. Ich verstehe nicht den Sinn, wozu soll das Springen gut sein? Auch die StVO verbietet springen. Die Ampelphasen haben immmer in einer bestimmten Reihenfolge zu erfolgen! Wie schon gesagt, ausm Interrupt gibt es nur einen Ausgang und der heißt RETI. Alles andere (DJNZ, LJMP, RET) ist verboten! Hier mal ein Beispiel, wie ich das machen würde. Ich würde die Delays und LED-Muster in eine Tabelle packen, dann kann man sie leicht ändern.
1 | ; Beschreibung |
2 | ; Port1 |
3 | ; |
4 | ; HS Fuß NS |
5 | ; | | | |
6 | ; |-------| |---| |-------| |
7 | ; 7 6 5 4 3 2 1 0 |
8 | ; rt ge gr gr rt gr ge rt |
9 | ; |
10 | CSEG at 8000h |
11 | Start: |
12 | mov dptr, #ampel_tab ; start of table |
13 | main: |
14 | clr a |
15 | movc a, @a+dptr ; get delay time [sec] |
16 | jz start ; delay = 0: end of table |
17 | call delay_sec |
18 | inc dptr |
19 | clr a |
20 | movc a, @a+dptr ; get lights after delay |
21 | mov p1, a |
22 | inc dptr |
23 | jmp main |
24 | ;------------------------------------------- |
25 | ampel_tab: |
26 | db 2, 10001100b ; Hauptstraße (HS) rot, Fußgänger (Fuß) rot, Nebenstraße (NS) grün |
27 | db 10, 11001010b ; HS rot/geld, Fuß rot, NS gelb |
28 | db 2, 00101001b ; HS grün, Fuß rot, NS rot |
29 | db 10, 01001011b ; HS gelb, Fuß rot, NS rot/gelb |
30 | db 2, 10001100b ; HS rot, Fuß rot, NS grün |
31 | db 10, 10001010b ; HS rot, Fuß rot, NS gelb |
32 | db 2, 10010001b ; HS rot, Fuß grün, NS rot |
33 | db 10, 10001011b ; HS rot, fuß rot, NS rot/gelb |
34 | db 0 ; 0 = end of table |
35 | ;-------------------------------------------- |
36 | delay_val equ 50000 ; 50.000 cycle = 50ms at 12MHz |
37 | |
38 | ;input: A = delay [1..255sec] |
39 | delay_sec: |
40 | mov r5, #20 ; 20 * 50ms = 1s |
41 | _dse1: |
42 | mov r6, #high(delay_val/2+253) |
43 | mov r7, #low(delay_val/2-2) |
44 | _dse2: |
45 | djnz r7, _dse2 |
46 | djnz r6, _dse2 |
47 | djnz r5, _dse1 |
48 | djnz acc, delay_sec |
49 | ret |
50 | |
51 | |
52 | end |
Peter
Hallo Peter, vielen Dank für deinen Vorschlag, dass mit den Tabellen hatte ein Schulkollege auch in der letzten Stunde auf dem Tisch. Da war unser Pauker nicht von begeistert, da.....zu fortgeschritten.... nennen wir es mal so. Meine erste Idee ist wirklich quatsch, denn ich kann nicht einfach mitten drin den Interrupt auslösen, die Ampelschaltung muss erstmal "ablaufen" Ich denke das man die Fußgängeranforderung speichern muss, und dann an geeigneter Stelle das Unterprogramm "Fußgänger" starten sollte. Ich habe das mal mit [code] ISR: ; Unterprogramm für die Interrupt-Service-Routine anl P3.2 ; abfragen des Port 3.2 setb 20h.0 ; setzen des Speicherbits 20h.0 reti ; Rücksprung aus der Interupt-Service-Routine [/code} Und an anderer Stelle frage ich dann ab jnz 20h.0, Fussgaenger ; springe wenn 20h.0 nicht =0 ist zu "Fußgänger" aber da meckert er dann beim Build. Ob das mit dem 20h.0 richtig ist, wage ich allerdings zu bezweifeln, dass hat mir ein Schulkollege gesagt. Gruß Kay
Kay --- schrieb: > Hallo Peter, > > vielen Dank für deinen Vorschlag, dass mit den Tabellen hatte ein > Schulkollege auch in der letzten Stunde auf dem Tisch. Da war unser > Pauker nicht von begeistert, da.....zu fortgeschritten.... nennen wir es > mal so. Dann bleibt immer noch die Möglichkeit die Tabelle zu 'unrollen' Schreib dir eine Subroutine, die die Länge der Phase in einem Register erhält, das für die Lampen auszugebende Bitmuster in einem anderen Register. Die Subroutine gibt das Muster aus und wartet die angegebene Zeit Dein Hauptprogramm macht dann nichts anderes als nacheinander für jede Phase die beiden Werte in die entsprechenden Register zu laden und die Subroutine aufzurufen. Also im Grunde wie die Tabellenlösung, nur ohne Tabelle :-)
1 | mainloop: |
2 | mov r5, #2 |
3 | mov r6, 10001100b ; Hauptstraße (HS) rot, Fußgänger (Fuß) rot, Nebenstraße (NS) grün |
4 | call phase |
5 | |
6 | mov r5, 10 |
7 | mov r6, 11001010b ; HS rot/geld, Fuß rot, NS gelb |
8 | call phase |
9 | |
10 | mov r5, 2 |
11 | mov r6, 00101001b ; HS grün, Fuß rot, NS rot |
12 | call phase |
13 | |
14 | mov r5, 10 |
15 | mov r6, 01001011b ; HS gelb, Fuß rot, NS rot/gelb |
16 | call phase |
17 | |
18 | mov r5, 2 |
19 | mov r6, 10001100b ; HS rot, Fuß rot, NS grün |
20 | call phase |
21 | |
22 | mov r5, 10 |
23 | mov r6, 10001010b ; HS rot, Fuß rot, NS gelb |
24 | call phase |
25 | |
26 | mov r5, 2 |
27 | mov r6, 10010001b ; HS rot, Fuß grün, NS rot |
28 | call phase |
29 | |
30 | mov r5, 10 |
31 | mov r6, 10001011b ; HS rot, fuß rot, NS rot/gelb |
32 | |
33 | jmp mainloop |
Wenn du schon weißt, wie man Makros anlegt, kann man sich auch ein Makro machen und so den Schreibaufwand reduzieren
Kay --- schrieb: > Ich denke das man die Fußgängeranforderung speichern muss, und dann an > geeigneter Stelle das Unterprogramm "Fußgänger" starten sollte. Da Du einen Interrupteingang nimmst, macht der das Speichern schon selber, Du mußt ihn nur auf Flanke setzen. Und dann im Code:
1 | ; ... code |
2 | jnb IE0, kein_fussgaenger |
3 | clr IE0 ; Interrupt Bit loeschen |
4 | ; ... code fuer Fussgaenger Gruen |
5 | kein_fussgaenger: |
6 | ; ... code |
Ein Interrupthandler ist dafür nicht nötig. Peter
Hi
1 | mov r5, 10 |
2 | mov r6, 01001011b ; HS gelb, Fuß rot, NS rot/gelb |
3 | call phase |
@K.H. ich hoffe, du sitzt nicht irgendwo an Ampelsteuerungen.. wenn ich HS als Hauptstrasse und NS als Nebenstrasse definiere sehe ich auf beiden Seiten Gelb... und da darf man schon oder noch fahren. ( kann man hier irgendwo Smilies zum Einfügen finden ? ) Ich weiß nicht, warum ihr soviel Codeschnipsel vorlegt, ich denke ich habe die Vorgehensweise allgemein gültig beschrieben. Oder hab ich's unverständlich rübergebracht ? Wär ja möglich, denn meine Frau versteht mich auch nicht immer.... In euren Vorschlägen sehe ich eigentlich immer, das der Controller in der "Wartezeit" der einzelnen Phasen nix anderes machen kann. Der Taster braucht keinen Interrupt, es genügt, wenn das Tasterereignis einfach nur erfasst wird. Dazu braucht es noch nicht einmal eine Entprellung, da das Tastersignal erst nach Ablauf der Ampelphase zurückgesetzt wird. Dagegen ist ein Timerinterrupt sinnvoll, da er für viele Zwecke genutzt werden kann. Ob im ms-Bereich oder s- Bereich. Er ruft ein kleines UP auf, welches dem Ereignis entsprechend reagiert. Wie bereits beschrieben: z.B. dec. eines Wertes in einer Variablen / Register kontrollieren ob null und dementsprechend entweder nix tun oder Ereignis bearbeiten. Das kann so schwer doch nicht sein. Gruß oldmax
oldmax schrieb: > ich hoffe, du sitzt nicht irgendwo an Ampelsteuerungen.. wenn ich HS als > Hauptstrasse und NS als Nebenstrasse definiere sehe ich auf beiden > Seiten Gelb... und da darf man schon oder noch fahren. Ob die Phasen und Kommentare stimmen, muß der OP schon selber prüfen. Die Beispiele sollen nur das Prinzip zeigen. > In euren Vorschlägen sehe ich eigentlich immer, das der Controller in > der "Wartezeit" der einzelnen Phasen nix anderes machen kann. Könnte man leicht ändern. Aber man muß ja auf den Pauker Rücksicht nehmen. > Dazu braucht es noch nicht einmal eine Entprellung Stimmt. Für mich selber würde ich trotzdem die Entprellung aus der Schublade ziehen. Die dient dann eben nur der Störunterdrückung. Peter
Hey, ich habe mit einem Schulkollegen gestern noch etwas gebastelt. Danke für die vielen Ideen, aber die meisten waren/sind etwas zu hoch gegriffen, so lange machen wir das noch nicht mit dem Assembler. Ich habe nochmal eine andere Version von der 'Steuerung angehangen, vieleicht kann da ja mal jemand rüber schauen. Muss mir unbedingt mal einen USB/serial-Adapter zulegen. Beim Build mekert Keil bei drei zeilen, Text1.a52(68): error A38: NUMBER OF OPERANDS DOES NOT MATCH INSTRUCTION Text1.a52(101): error A38: NUMBER OF OPERANDS DOES NOT MATCH INSTRUCTION Text1.a52(144): error A38: NUMBER OF OPERANDS DOES NOT MATCH INSTRUCTION aber wieso?? Gruß
Wenn du noch nett bist, dann suchst du die Zeile 68 raus und postest die
extra
> so lange machen wir das noch nicht mit dem Assembler
Dann solltet ihr gleich mal eine der wichtigsten Lektionen lernen:
Komentiere nicht das, was sowieso schon im Code steht!
Solche Kommentare
1 | mov R0, #200 ; lade das Register 0 mit 200 vor |
2 | call Timer ; Aufruf des Unterprogramm "Timer" |
sind für die Tonne! Die kannst du dir sparen. Der Kommentar sagt nichts aus, was nicht auch schon im Quelltext steht. Im Quelltext steht, dass R0 mit 200 geladen wird, im Kommentar steht, dass R0 mit 200 geladen wird. Wozu dann der Kommentar, wenn dort sowieso nichts steht, was mich weiterbringt. Im besten Fall bringt mich so ein Kommentar nicht weiter. Im schlimmsten Fall ist er einfach nur falsch, weil zb der Code geändert wird und auf den Kommentar vergessen wurde. Was mich interessieren würde: Was hat es mit diesen 200 auf sich? Warum 200? Warum nicht 199 oder 201? Haben die 200 eine Bedeutung? Welche? genauso bei der anderen Zeile Das hier das UP Timer aufgerufen wird, sehe ich auch im Code, das brauchst du im Kommentar nicht hinschreiben. Generell: Kommentiere das Warum? und nicht das Wie? Bei einem Kommentar will ich wissen: Warum wird etwas gemacht? Was ist die Idee an dieser Stelle im Code? Welche Algorithmen werden unter Umstaänden verwendet? Wie funktionieren die? Welche Bewandtnis hat es mit irgendwwelchen Zahlenwerten? Das gehört in den Kommentar Wie etwas dann implementiert wird, sehe ich im Code.
jnz 20h.0, Fussgaenger ; springe wenn 20h.0 nicht =0 ist zu "Fußgänger" Äh nein. So funktioniert das nicht. Was soll das sein "wenn 20h.0 nicht 0 ist" Ich kenn zwar deinen µC überhaupt nicht, aber das würde mich schwer wundern, wenn man sich bei einem jnz auf ein Bit eines Ports beziehen könnte Ein jnz wertet üblicherweise die Statusflags aus, die ein vorhergehender Befehl wie gewünscht eingestellt hat
@K.H. Ich schreibe mir immer die Finger wund weil mein Pauker das so möchte...... leider. Aber durch dein "Einwand" gegenüber den Komentaren, ist meine Meinung gegenüber dem Pauker gefestigt, er hat keine Ahnung von dem was er erzählt. Das merkt man im Unterricht sehr. Der kann keinem einen roten Fahden in die Hand geben und mal ein Programm durcharbeiten. Aber das mit dem roten Fahden habe ich auch in noch keinem Buch gefunden. Ich suche wirklich ein Buch, das wie bei allen anderen Themen mit dem "berühmten" "Hello World" anfängt. Ich denke ich gebe das Programm so ab und gut ist.
Kay --- schrieb: > Ich denke ich gebe das Programm so ab und gut ist. Als Pauker würde ich darauf bestehen, auch das Hex-File zu kriegen. Dann kannnst Du schonmal nichts abgeben, was einen Fehler ausgibt. Und simulieren ist wirklich nicht schwer. Peter
Hallo! Beim 8051 ist 20h im internen RAM bit-adressierbar. Es dient also als Flag. Je nach Assembler kann man das aber nicht so schreiben. Es ist nämlich an der Bitadresse Null. Der Assemblerbefehl lautet also JNB 0h, marke (JumpNoBit adresse, label)
Peter Dannegger schrieb: > Kay --- schrieb: >> Ich denke ich gebe das Programm so ab und gut ist. > > Als Pauker würde ich darauf bestehen, auch das Hex-File zu kriegen. Dann > kannnst Du schonmal nichts abgeben, was einen Fehler ausgibt. > > Und simulieren ist wirklich nicht schwer. > > > Peter Du ich wolte den Fehler nicht verheimlichen, das Programm wird eh auf Funktion geprüft. Wenn du die Hex-Datei meinst an die ich gerade denke, ist diese eh auf einem Eprom. Gruß
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.