mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Ampelsteuerung mit 80C552 und µvision3 in Assembler


Autor: Kay --- (kingganja)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Kay --- (kingganja)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?!?!??

Autor: Route_66 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

1.Tip:
Du darfst die Timer-Initialisierungen natürlich nicht einfach 
"überspringen".

Autor: oldmax (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: KingGanja (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.
;            Beschreibung      
;               Port1
;          
;    HS     Fuß    NS
;    |      |      |
;  |-------|  |---|  |-------|
;  7  6  5  4  3  2  1  0
;  rt  ge  gr  gr  rt  gr  ge  rt
;
CSEG at 8000h
Start:
  mov  dptr, #ampel_tab  ; start of table
main:
  clr  a
  movc  a, @a+dptr       ; get delay time [sec]
  jz  start              ; delay = 0: end of table
  call  delay_sec
  inc  dptr
  clr  a
  movc  a, @a+dptr       ; get lights after delay
  mov  p1, a
  inc  dptr
  jmp  main
;-------------------------------------------
ampel_tab:
  db  2,  10001100b      ; Hauptstraße (HS) rot, Fußgänger (Fuß) rot, Nebenstraße (NS) grün
  db  10, 11001010b      ; HS rot/geld, Fuß rot, NS gelb
  db  2,  00101001b      ; HS grün, Fuß rot, NS rot
  db  10, 01001011b      ; HS gelb, Fuß rot, NS rot/gelb
  db  2,  10001100b      ; HS rot, Fuß rot, NS grün
  db  10, 10001010b      ; HS rot, Fuß rot, NS gelb
  db  2,  10010001b      ; HS rot, Fuß grün, NS rot
  db  10, 10001011b      ; HS rot, fuß rot, NS rot/gelb
  db  0                  ; 0 = end of table
;--------------------------------------------
delay_val  equ  50000    ; 50.000 cycle = 50ms at 12MHz

;input: A = delay [1..255sec]
delay_sec:
  mov  r5, #20           ; 20 * 50ms = 1s
_dse1:
  mov  r6, #high(delay_val/2+253)
  mov  r7, #low(delay_val/2-2)
_dse2:
  djnz  r7, _dse2
  djnz  r6, _dse2
  djnz  r5, _dse1
  djnz  acc, delay_sec
  ret


end


Peter

Autor: Kay --- (kingganja)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 :-)
mainloop:
  mov  r5, #2
  mov  r6, 10001100b      ; Hauptstraße (HS) rot, Fußgänger (Fuß) rot, Nebenstraße (NS) grün
  call phase

  mov  r5, 10
  mov  r6, 11001010b      ; HS rot/geld, Fuß rot, NS gelb
  call phase

  mov  r5, 2
  mov  r6, 00101001b      ; HS grün, Fuß rot, NS rot
  call phase

  mov  r5, 10
  mov  r6, 01001011b      ; HS gelb, Fuß rot, NS rot/gelb
  call phase

  mov  r5, 2
  mov  r6, 10001100b      ; HS rot, Fuß rot, NS grün
  call phase

  mov  r5, 10
  mov  r6, 10001010b      ; HS rot, Fuß rot, NS gelb
  call phase

  mov  r5, 2
  mov  r6, 10010001b      ; HS rot, Fuß grün, NS rot
  call phase

  mov  r5, 10
  mov  r6, 10001011b      ; HS rot, fuß rot, NS rot/gelb

  jmp  mainloop

Wenn du schon weißt, wie man Makros anlegt, kann man sich auch ein Makro 
machen und so den Schreibaufwand reduzieren

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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:

; ... code
        jnb     IE0, kein_fussgaenger
        clr     IE0                    ; Interrupt Bit loeschen
; ... code fuer Fussgaenger Gruen
kein_fussgaenger:
; ... code

Ein Interrupthandler ist dafür nicht nötig.


Peter

Autor: oldmax (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi
  mov  r5, 10
  mov  r6, 01001011b      ; HS gelb, Fuß rot, NS rot/gelb
  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

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Kay --- (kingganja)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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ß

Autor: Kay --- (kingganja)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
hier noch die Datei

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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
    mov R0, #200        ; lade das Register 0 mit 200 vor
    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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Kay --- (kingganja)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@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.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Route_66 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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)

Autor: Kay --- (kingganja)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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ß

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.