mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Assembler-Programm für Binäruhr


Autor: sirpreis (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Servus,

ich will mit n paar Kollegen ne Binäruhr bauen, (zum an die Wand
hängen), ähnlich wie diese hier:
www.thinkgeek.com/cubegoodies/lights/59e0/

Jetzt hab ich aber gar keine ahnung von Assembler, habe da mal bissel
was zusammenkopiert und selbst was versucht, aber das klappt irgendwie
nicht, wie ich will :P kann mir da mal jemand n bissel hilfestellung
geben?


INCLUDE 89C2051.mc

LJMP Initialisierung 'Überspringe Interruptroutine nach einem Reset
(000Bh): 'Einsprungadresse Interrupt Timer 0

'Realisierung der 50mS Zeitbasis:
MOV A,TL0 'Speicher TL0 im Akku (Zeit seit Überlauf)
ADD A,#B3h 'A = A + (Grundeinstellung B0 + 3)
MOV TL0,A 'Setze den errechneten Wert wieder in den TL0

'Routine zum "Hochzählen" der Uhrzeit:
INC R7 'Register 7 speichert die Zahl der Interrupts

CJNE R7,#20,Zurück 'Wenn bereits 20 Interrupts, dann:
MOV R7,#00 'Interruptzähler auf 0
INC R0 'Sekunden = Sekunden + 1


'Der Teil ist von mir, nicht drüber lachen :P

CJNE R0,#1,Zurück 'Überprüft ob Sekunden = 1
SETB P1.0
SETB P1.1
SETB P1.2
SETB P1.3 'Alle LEDs wieder aus (schwachsinn?!?)
CPL P1.0 '1 Sekunde >= erste LED an

CJNE R0,#2,Zurück
SETB P1.0
SETB P1.1
SETB P1.2
SETB P1.3 'Alle LEDs wieder aus (schwachsinn?!?)
CPL P1.1 '2 Sekunden >= zweite LED an


CJNE R0,#3,Zurück
SETB P1.0
SETB P1.1
SETB P1.2
SETB P1.3 'Alle LEDs wieder aus (schwachsinn?!?)
CPL P1.0
CPL P1.1 '3 Sekunden >= erste + zweite LED an


'Ja und so weiter, aber das muss ja viiiiiiiiiiiel einfacher gehen,
aber da ich keine ahnung habe...




CJNE R0,#60,Zurück 'Wenn Sekunden = 60, dann
MOV R0,#0 'Sekunden = 0
INC R1 'Minuten = Minuten + 1

CJNE R1,#60,Zurück'Wenn Minuten = 60, dann
MOV R1,#0 'Minuten = 0
INC R2 'Stunden = Stunden + 1

CJNE R2,#24,Zurück 'Wenn Stunden = 24, dann
MOV R2,#0 'Stunden = 0

Zurück:
RETI 'Zurück aus der Interruptbehandlung ins Programm

'************************************************

INITIALISIERUNG:
MOV R0,#0 'Sekunden auf 0
MOV R1,#0 'Minuten auf 0
MOV R2,#0 'Stunden auf 0
MOV R7,#0 'Interruptzähler auf 0

'Grundeinstellung des Timer 0 und der dazugehörigen Interrupts:
MOV TMOD,#01h 'Timer 0 Modus = 1
MOV TH0,#3Ch 'High Byte vom Timer 0 setzen
MOV TL0,#B0h 'Low Byte vom Timer 0 setzen
SETB EA 'Interruptbehandlung aktivieren
SETB ET0 'Interrupt für Timer 0 aktivieren
SETB TR0 'Timer 0 Start

Start:
LJMP Start



Vielleicht kurz zur Erklärung, die LEDs sind halt an den Ports am
Mikrocontroller angeschlossen (muss mich wohl auch nochmal
schlaumachen, wo und wie die drangepackt werden).. naja, die Uhr ist ja
selbsterklärend, und je nach Sekunden, Minuten, Stunden sollen dann die
jeweiligen LEDs angesprochen werden

Wäre jeder Hilfe dankbar..

sirpreis

Autor: Thomas Schattat (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
geht auch eingacher:
Anstelle immer die Bytes mit einem Wert zu vergleichen und ggf zu
springen kann man folgendes tun, Beispiel fuer R0:

MOV A, R0
ADD A, #01h
DAA
MOV R0, A

Damit ist ein BCD Zaehler realisiert. DAA bedeutet "Decimal Adjust
Accu", wenn beim Addieren ein Nibble groesser als 9 vorkommt wird es
richtiggestellt.
Beispiel:

A ist 19h (0001 1001 b)
eins dazu:
A ist nun 1Ah (0001 1010 b)
nun DAA:
A ist nun 20h (0010 0000 b), das ist was gewuenscht war.

Machste mit allen Zaehlregistern und gibst das so auf die Ports aus,
dann kommt genau das Ergebnis das gewuenscht wurde heraus.

EASY??

Gruss
Thomas

Autor: sirpreis (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
also die möglichkeit für
CJNE R0,#60,Zurück 'Wenn Sekunden = 60, dann
etc. eintauschen? und was genau bringts mir?
wenn R0 00011001 ist, also 25 sekunden,
was bringt mir dann dieser bcd zähler?
kommt doch später
00100000, 32_10 raus... :)

aber danke schonmal.

Autor: sirpreis (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ach ich glaub ich muss nur etwas drüber nachdenken, dann verstehe ich
das schon :P

Autor: sirpreis (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich habs so mehr oder weniger verstanden,

nun, dann kann ich
ja das ganze immer auf den Port
geben,
MOV P1, A... dann stimmen die Einer
der Sekunden ja schonmal..
wie kann ich das jetzt machen, dass,
wenn das Highnibble (z.b. bei den Sekunden)
0101 (5) überschreitet (5, da ja nach 59
Sekunden wieder 0 kommt)
automatisch z.b. dem Lownibble in R1 eins
zuaddiert? :/
Ebenso dann bei den Stunden..

Autor: Thomas Schattat (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
Beispiel:
R3 hat die Sekunden BCD mässig
;Sekunden wie beschrieben hochzählen, dann:

MOV A, R3   ;Sekunden in Akku laden
ADD A, #A6h  ;A6h dazuaddieren
JNC weiter   ;Wenn es kein Carry gab war es noch nicht 60 oder größer
MOV R3, #0   ;Wenn doch Sekunden auf Null und minuten genau so
weiterzählen.

Minuten weiterzählen wie die Sekunden...

weiter:   ; hier geht es bei weniger  als 59 (59h+Ahh = FFh)
; Ausgabe sollte folgen...

Autor: sirpreis (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
magst mir noch kurz erklären, wieso A6h dazuaddieren?
166? :)

dank dir..
sirpreis

Autor: sirpreis (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ach ja, wie kann ich n byte "invertieren"? XOR R0,#255 ?

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
CJNE R0,#60,Zurück 'Wenn Sekunden = 60, dann
MOV R0,#0 'Sekunden = 0
INC R1 'Minuten = Minuten + 1

CJNE R1,#60,Zurück'Wenn Minuten = 60, dann
MOV R1,#0 'Minuten = 0
INC R2 'Stunden = Stunden + 1

CJNE R2,#24,Zurück 'Wenn Stunden = 24, dann
MOV R2,#0 'Stunden = 0



Das ist doch vollkommen o.k., wo ist jetzt das Problem ?

Die Zehner und Einer kriegst Du ja bequem mit "DIV AB" raus.

Und dann ab auf die LEDs (7-Segment dekodieren willst Du ja nicht).


Aber ein 2051 hat nur 15 Pins, das reicht nicht für 20 LEDs, es sein
denn, Du multiplext.



Peter

Autor: sirpreis (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
wenn du mir kurz erklärst, wie ich DIV AB nutze? wo stehen dann die
Zehner und die Einer? dann müsste ich sie ja nur noch "invertieren"
(oder wie das auch immer heißen mag, und auf den port geben.

Autor: sirpreis (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ach ja..

INCLUDE 89C51.mc

:)

Autor: Thomas Schattat (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
59h + A6h ist genau FFh, also gerade noch kein Carry. Ab 60h gibt es ein
Carry und der Sprungbefehl feuert, alles klar?
ich wuerde folgendermasse programmieren:

;Sekunden R0
;Minuten  R1
;Stunden  R2

INC R7 'Register 7 speichert die Zahl der Interrupts

CJNE R7,#20,Zurück 'Wenn bereits 20 Interrupts, dann:
MOV R7,#00 'Interruptzähler auf 0

;ab hier von mir:

MOV A, R0
ADD A, #01h
DA A
MOV R0, A   ;bis hier ist R0 eins weiter
ADD A, #A6h
JNC weiter  ;wenn Carry dann wars 60, sonst weiter
MOV R0, #0  ;Sekunden auf 0
MOV A, R1   ;dasselbe mit den Minuten...
ADD A, #01h
DA A
MOV R1, A
ADD A, #A6h
JNC weiter  ;wenn Carry dann wars 60, sonst weiter
MOV R1, #0  ;und den Stunden...
MOV A, R2
ADD A, #01h
DA A
MOV R2, A
ADD A, #DCh ;denn: 24h+DCh=100h, also Carry bei >23
JNC weiter
MOV R2, #0  ;war 24, also auf 0
weiter:
;ab hier Multiplexausgabe der Zeiten an LEDs

Autor: crazy horse (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
und noch was ganz anderes: den Zeitzähler als reinen Binärzähler, der
jede Sekunde incrementiert wird, Zähler geht bis 60(s)*60(min)*24(h),
wird also bei 86400 wieder auf 0 gesetzt. Der eigentliche Zähler wird
damit einfacher, dafür musst du dann bei der Ausgabe etwas mehr
rechnen, mehrere Divisionen. Gibt fertige Routinen, die sowohl den
Ganzteil- als auch den Rest der Division liefern.

Zähler/60: Rest=Sekunden
Ergebnis/60: Rest=Minuten
Ergebnis: Stunden

Dann nochmal s,min und Stunden in Einer und 10er teilen, ausgeben,
fertig. Sieht erstmal komplizierter aus, als es ist.
Das ist keine Wertung, was besser ist, viele Wege führen nach Rom. Mir
persönlich gefällt diese Lösung besser.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"wenn du mir kurz erklärst, wie ich DIV AB nutze?"

Z.B.:

59 / 10 = 5 Rest 9

Wenn man Assembler programmiert, sollte man sich doch mal den
Befehlssatz ansehen.


Peter

Autor: sirpreis (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@crazy horse
hört sich ganz nett an, gefällt mir besser als die andere lösung.
naja, hab leider noch nie was wirklich mit assebler programmiert (und
auch sonst recht wenig)... wie siehtn das mit solch einem "großen"
binärzähler aus.. wie kann ich denn bis 86400 zählen? son byte geht
doch nur bis 255 oder wie? :)

@peter dannegger
haste nen link zum Befehlssatz? deine rechnung war mir schon klar, nur
die praktische anwendung von DIV AB nicht :)

danke, sirpreis

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"haste nen link zum Befehlssatz?"

Z.B:

http://www.atmel.com/dyn/resources/prod_documents/...


Peter

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.