Binäruhr in Assembler

Sturmfeuerzeug2

Neues Mitglied
04. Aug. 2014
4
0
0
Sprachen
Guten Tag,

ich habe folgendes Problem:
Ich will eine Binäruhr programmieren in Assembler mit einem atmega8535.
Die Schaltung ist alles kein Problem, nur mit der Programmierung hab ich etwas Probleme.
Zur Schaltung:
Ich habe 20 LED's bei folgender Aufteilung: Bild der Uhr und eine externe 1Hz Beschaltung für den Takt.

Aktuell habe ich mein Programm soweit selbst geschrieben, weiß aber leider nicht wie weit das Stimmt.
Un nun zum eigentlichen Problem:
Wie mache ich die Ausgabe an die LED's?

Programmcode bis jetzt:

Code:
.include "m8535def.inc" 

	ldi r16, 0xFF
        out DDRA, r16     ; Alle Pins am Port A durch Ausgabe von 0xFF ins
                          ; Richtungsregister DDRB als Ausgang konfigurieren
        ldi r16, 0xFF
        out DDRC, r16     ; Alle Pins am Port C durch Ausgabe von 0x00 ins
                          ; Richtungsregister DDRD als Ausgang konfigurieren
        ldi r16, 0xFF
        out DDRD, r16     ; Alle Pins am Port D durch Ausgabe von 0x00 ins
                          ; Richtungsregister DDRD als Ausgang konfigurieren
        ldi r16, 0x00
        out DDRB, r16     ; Alle Pins am Port B durch Ausgabe von 0x00 ins
                          ; Richtungsregister DDRD als Eingang konfigurieren

	ldi r18, 0x00	  ; Sekunden nullen
	ldi r19, 0x00	  ; Minuten nullen
	ldi r20, 0x00	  ; Stunden nullen
	ldi r25, 0xFF
	ldi r26, 0x00
	ldi r27, 0x00


;*******************************************************


hauptschleife:

  sbic PINB,1
//  rjmp stellen
  mov  R26,R25       ; alten Eingangspegel merken  
  in   R25,PB0        ; neuen Eingangspegel einlesen
  sbrs R25,0         ; Eingang abfragen, wenn high: überspringen
  rjmp hauptschleife ; Eingang ist low --> nix zu tun
  sbrc R26,0         ; Merker abfragen, wenn low: überspringen
  rjmp hauptschleife ; Merker ist high --> nix zu tun
  rjmp steigende_flanke   

steigende_flanke:    ; unsere steigende Flanke pro Sekundenimpuls
  inc r18            ; addieren +1
  rjmp asekunden
  weiter:
  cpi r18, 60        ; vergleichen
  brsh minuten       ; wenn 60, springe zu minuten
  rjmp hauptschleife ; zurück zur Hauptschleife


minuten:

  clr r18	     ; sekungen löschen
  inc r19            ; addieren +1
  cpi r19, 60        ; vergleichen
  brsh minuten       ; wenn 60, springe zu stunden
  rjmp hauptschleife ; zurück zur Hauptschleife


stunden:

  clr r19	     ; minuten löschen
  inc r20            ; addieren +1
  cpi r20, 24        ; vergleichen
  brsh minuten       ; wenn 24, springe zu clear
  rjmp hauptschleife ; zurück zur Hauptschleife


clear:

  clr r20
  rjmp hauptschleife

;******************************************************* 

/*

stellen:
hauptschleifes:
  sbis PINB,1
  rjmp hauptschleifes

minutens:

  sbis PINB,2
  rjmp stellen
  

  inc r19            ; addieren +1
  cpi r19, 60        ; vergleichen
  brsh minuten       ; wenn 60, springe zu stunden
  rjmp hauptschleifes ; zurück zur Hauptschleife


stundens:

  clr r19	     ; minuten löschen
  inc r20            ; addieren +1
  cpi r20, 24        ; vergleichen
  brsh minuten       ; wenn 24, springe zu clear
  rjmp hauptschleifes ; zurück zur Hauptschleife


*/


Mit freundlichen Grüßen
 
Hallo, und willkommen hier im Forum...

Für Dich mag die Schaltung kein Problem sein, aber wir müssen jetzt aus dem Code heraus raten, was nun eigentlich wo angeschlossen ist. Insbesondere wenn Du den verwendeten Bits, Registern usw keine Namen gibst.

Du scheinst eine externe Quelle zu haben, die Dir über ein Bein den Sekundentakt gibt, außerdem einige Taster an PORTB
An den anderen PORTs hast Du dann jeweils die LEDs zu hängen? Dann gib denen doch den entsprechenden Namen.

Ich habe irgendwas mit max 20mA Strom durch ein Bein, max 100mA Strom durch einen PORT und max 300mA Strom durch den ganzen Controller in Erinnerung, genaueres findest Du im Datenblatt.

Um Taster zu lesen empfiehlt es sich, die mittels Pull-Wiederstand auf einen festen Pegel zu legen, und durch Betätigung den anderen Pegel zu erzwingen. Da die AVR intern aufschaltbare Pullups besitzen, verwendet man diese üblicherweise (um den externen R zu sparen), entsprechend wird an das Bein dann einfach der Taster gegen Gnd angeschlossen.

Die LEDs können je nach Strom (siehe oben) direkt oder über einen Treiber/Transistor/etc an das Bein, direkt mit entsprechendem Vorwiderstand. Ob das Bein jetzt 'ne Spannungsquelle (gegen Gnd) ist, oder 'ne Senke von Vcc ist inzwischen Wurst (AFAIR hatten die internen Bein-Ausgangstreiber früher asymmetrische max Ströme, inzwischen ist das aber egal - kontrolliere mal trotzdem im Datenblatt).

Den Pegel des Beines legt das Bit im PORT-Register fest (wenn es Ausgang ist), da diese direct bit accessible sind, kannst Du die einzelnen Bits mit SBI bzw CBI direkt setzen bzw löschen. Hier bietet sich aber an, das ganze Register mit einem Schlag zu beschreiben, also mit OUT ein Rechenregister (zB Deine Stunden) in den PORT zu schreiben.
Da Deine Stunden ja im Rechenregister 'ne binäre Zahl ist, stellen die Beine des Port dann dieselbe Zahl dar, Du mußt die Pegel dann nur noch mit den LEDs sichtbar machen..
 
Wegen Schaltplan tut mir leid, der folgt: Unbenannt2.png

Desweiteren sind mir die Daten und Fakten des µC alle bekannt, daran liegt es nicht.

Das was du in deinem letzten Abschnitt gesagt hast, ist wahrscheinlich das, wo mein Problem ist. Ich kann nur minimal die Grundlagen von Assembler. Ich habe also leider keine Ahnung wie ich das schreiben muss. Meist hilft mir ein reiner Code-Fetzen (nein ich will kein fertig geschriebenes Programm, würde ich auch nicht nein sagen, aber eigentlich will ich es nicht) um zu sehen wie ich das machen kann und das wende ich dann an.
 
Hallo,

auch von mir erstmal herzlich willkommen im Forum :flowers:

Wegen Schaltplan tut mir leid, der folgt: Anhang anzeigen 6435
kannst du den Plan nochmal direkt mit Eagle exportieren? (als PNG).
Graue Flächen als Pinbezeichnung und Textfelder lassen sich schlecht identifizieren. :p

Denk daran ... je mehr Infos du lieferst und umso besser sie sind, desto besser und schneller bekommst du auch Hilfe.
Man muß dann nicht wegen jedem Kleinkram nachfragen was natürlich alles Zeit kostet.

Gruß
Dino
 
Ohje...
Dir ist schon klar, daß man auf dem Plan nicht wirklich was erkennen kann, oder?
Einerseits ist das 'ne ziemliche Spaghetti-Darstellung, andererseits sind die Pinnamen nicht lesbar...
Ok, Du verwendest 'n externen 1Hz-Oszillator, der im wesentlichen aus einem Frequenzteiler aufgebaut ist. Warum eigentlich?
Du könntest ebenso den Controller selbst mit'nem externen Quarz betakten, und den 16bit-Timer im Sekundentakt 'n Interrupt erzeugen lassen.
(Datenblatt ab Seite 24). Dann wäre der Quarz mit 2 Bürdekapazitäten extern nötig.
Um mit dem Systemtakt unabhängig zu bleiben könnte man auch den asynchronen Modus von Timer2 nutzen. Mit einem 32,768kHz Uhrenquarz. der Timer ist ein 8bit Timer, läuft also dann alle 256 Timertakte über. Also mit 128Hz. Setzt man den Prescaler des Timers auf 128, hat man den Interrupt im Sekundentakt. Das einzige externe Bauteil wäre dann der Uhrenquarz, allerdings an den Beinen C6 und C7 (Siehe Datenblatt ab Seite 117 uns insbesondere ab Seite 131).
Unklar ist mir die auswahl der Beine zur Ansteuerung der LEDs. Sinnig wäre mMn für Stunden, Minuten und Sekunden je einen eigenen Port zu nehmen (zumindest die unteren benötigten Bits). Dein Mega hat ja genug vollständige Ports.
Was hast Du denn bei 17:23 Uhr? im Stunden-Rechenregister 0b00010001 und im Minuten-Rechenregister 0b00010111.
Und was sollen die LEDs da zeigen?
Die Stunden-LEDs: (keine LED) | (keine LED) | (keine LED) | AN | AUS | AUS | AUS | AN.
Und wann ist die LED an? Wenn 'ne 1 im entsprechenden PORT-Register Bit steht, Du willst also im PORT-Register 0b00010001 haben. Was stand nochmal im Stunden-Rechenregister?
(zur Veranschaulichung des Zusammenspiels der Bein-definierenden Register verweise ich jetzt einfach mal auf Figure 26 auf Seite 57. Du hattest ja gesagt, daß Dir die Controller-Fakten bekannt sind.)
Ein Blick in das Register-Summary (Seite 299) zeigt Dir, daß alle I/O-Register im 0x3F-Bereich liegen, also mit OUT ein Rechenregisterinhalt in das I/O-Register geschrieben werden kann, bzw mit IN der Wert eines I/O-Registers in ein Rechnregister geladen werden kann.
Die Bein-Kontroll-Register (PIN, PORT, DDR) liegen sogar alle im 0x1F-Bereich, sind also direct-bit-accessible - man kann also einzelne Bits direkt setzen/löschen, bzw bedingt darauf Instruktionen überspringen (was Du ja bereits machst))
Und wo wir gerade das Datenblatt vor der Nase haben: Seite 255/256 is 'ne Tabelle zu den electrical characteristics, dort sind insbesondere die Fußnoten 3 und 4 Interessant...
Falls Du es noch nicht hast, ist das Instruction Set beim Assembler-Programmieren unverzichtbar

Edit: Dino, das ist nicht Eagle, das ist irgend'ne andere Layout-Software. Hier war schonmal wer mit diesen unleserlichen Plänen unterwegs...
 
1. Ja ist es, ich kann es gerne aber auch in 3 oder 4 Einzeldateien hochladen, wen euch das lieber ist. Ich habe kein Eagle, kann das dementsprechend nicht machen. Das ist "Target 3001!" da hab ich die Funktion nicht gefunden, sonst hätte ich es gemacht.

2. Der externe Takt von 1Hz ist beabsichtigt, da ich das im Stromlaufplan so vorgegeben bekommen habe. Das ist auch so Aufgebaut und das werde ich jetzt auch nicht mehr ändern.

3. Deine Aussage zu den Stunden und Minutenregistern ist unbrauchbar. Schau dir nochmal das Bild an (Uhr von ELV) und denke darüber nach was du geschrieben hast. Du solltes schnell den Fehler finden.

4. Bringt mich deine komplette Antwort nicht weiter, da sie mir auf meine eigentliche Frage nicht antwortet, sondern du nur die ganze Zeit vom Datenblatt redest. Aber im Datenblatt steht nicht, wie ich das Programmiere. Da stehen die Befehle, ja, aber die habe ich über eine andere Seite, wo sie schön verständlich mit Beispiel erklärt werden.

5. Kompletter Plan der PINs (Lösung zu Punkt 3.)

x,3||x,10||xx,17
x,4||7,11||14,18
1,5||8,12||15,19
2,6||9,13||16,20
zehner,einer||zehner,einer||zehner,einer

1=PA1
2=PA2
3=PA6
4=PA5
5=PA4
6=PA3
7=PC7
8=PA6
9=PA7
10=PC3
11=PC4
12=PC5
13=PC6
14=PC0
15=PC1
16=PC2
17=PD4
18=PD5
19=PD6
20=PD7

Ich hoffe es war jetzt verständlich genug.
 
1. Ja ist es, ich kann es gerne aber auch in 3 oder 4 Einzeldateien hochladen, wen euch das lieber ist. Ich habe kein Eagle, kann das dementsprechend nicht machen. Das ist "Target 3001!" da hab ich die Funktion nicht gefunden, sonst hätte ich es gemacht...
Eagle könnteste Dir natürlich als Freeware-Demo (oder wie das jetzt auch immer heißt) trotzdem runterladen - andererseits sollte TArget doch auch die Möglichkeit bieten, lesbare Schaltpläne zu generieren...
2. Der externe Takt von 1Hz ist beabsichtigt, da ich das im Stromlaufplan so vorgegeben bekommen habe. Das ist auch so Aufgebaut und das werde ich jetzt auch nicht mehr ändern...
Du hattest nicht geschrieben, daß das so bereits in Hardware gegossen und vorgegeben ist. Auch nicht, was die Anbindung der LEDs betrifft.
Ich schrieb:
...Sinnig wäre mMn für Stunden, Minuten und Sekunden je einen eigenen Port zu nehmen (zumindest die unteren benötigten Bits). Dein Mega hat ja genug vollständige Ports...
Meiner Meinung nach sinnig...
...3. Deine Aussage zu den Stunden und Minutenregistern ist unbrauchbar. Schau dir nochmal das Bild an (Uhr von ELV) und denke darüber nach was du geschrieben hast. Du solltes schnell den Fehler finden...
Ich bin halt von der
ausgegangen. Seit wann sind denn
...zehner,einer||zehner,einer||zehner,einer...
bittesehr binär? für mich wären das dezimale Ziffern. Oder willst Du jetzt etwa binär dargestellte Dezimalstellen? Binary Coded Digits?
Dann hätteste das auch schreiben sollen.
Auf "Deinem" Bild sehe ich nur LEDs, je eine mehr als bei Binärdarstellung nötig wäre, aber egal. Soll ich jetzt daraus schlußfolgern, daß es eben nicht (wie von Dir angegeben) binär sondern BCD ist? Soll ich schlußfolgern, daß der Plan und das Konzept in Form einer (Haus-)Aufgabenstellung oder fertigen Schaltung bereits vorgegeben ist?
...Bringt mich deine komplette Antwort nicht weiter, da sie mir auf meine eigentliche Frage nicht antwortet, sondern du nur die ganze Zeit vom Datenblatt redest. Aber im Datenblatt steht nicht, wie ich das Programmiere. Da stehen die Befehle, ja, aber die habe ich über eine andere Seite, wo sie schön verständlich mit Beispiel erklärt werden...
In den Datenblättern und im Instruction Set findest Du alles, was Du zum Programmieren brauchst. Alles bis auf Deinen Algorithmus. Wenn Du das auch woanders im Netz findest, ok..
Deine Frage war:
...Wie mache ich die Ausgabe an die LED's?...
Indem Du das Bein zum Ausgang machst, und den nötigen Pegel drauflegst. Welche Register dazu nötig sind, verrät Dir das Datenblatt, welche Befehle das wie machen, das Instruction Set. Und natürlich findest Du entsprechende Hinweise auch überall im Netz...
...Denk daran ... je mehr Infos du lieferst und umso besser sie sind, desto besser und schneller bekommst du auch Hilfe.
Man muß dann nicht wegen jedem Kleinkram nachfragen was natürlich alles Zeit kostet.
Zur Ergänzung: es käme dann auch zu weniger Mißverständnissen/Fehlinterpretationen.
...Deine Aussage zu den Stunden und Minutenregistern ist unbrauchbar...Ich hoffe es war jetzt verständlich genug.
Nunja, derzeit hast Du ja je ein Rechenregister für Stunden (R20), Minuten(R19) und Sekunden(R18), wenn Du deren Inhalte nun in BCDs zerhackst, diese auf die jewiligen PORTs auseinanderrupfst und sortierst, und das ganze so ausgibst, hast Du doch, was Du willst. Wo ist Dein Problem?
Für das BCD-zerhacken könnte ich natürlich auch empfehlen, statt der 3 Rechenregister die das Uhrwerk bilden, für jede Digit einen eigenen Zähler zu verwenden, aber dann haust Du mir womöglich um die Ohren, daß das alles unbrauchbar wäre, da Du ein Uhrwerk mit binären Zahnrädchen vorgegeben hast:stupid:
 
Nunja, derzeit hast Du ja je ein Rechenregister für Stunden (R20), Minuten(R19) und Sekunden(R18), wenn Du deren Inhalte nun in BCDs zerhackst, diese auf die jewiligen PORTs auseinanderrupfst und sortierst, und das ganze so ausgibst, hast Du doch, was Du willst. Wo ist Dein Problem?

Genau das ist das Problem, ich weiß nicht wie das geht.

(Den Rest ignoriere ich einfach mal. Mir wurde das Teil so als Binäruhr präsentiert und nicht als irgendwas anderes. Daher kann ich leider keine weiteren Infos geben darüber.)


Ach und:
Nein, das Konzept ist nicht vorgegeben.
Es wurde lediglich von einem Kollegen mal als Digitalschaltung mit CMOS aufgebaut und er meinte ich könnte als Zeitvertreib das ganze mal Programmieren. Das einzige was ich mal programmiert habe war vor 2 Jahren eine LCD ansteuerung für einen Roboter aus einem Bastelwettbewerb, der einfach nur in dauerschleife einen Werbungstext angibt. Das war simpel.
 
...Es wurde lediglich von einem Kollegen mal als Digitalschaltung mit CMOS aufgebaut...
Dann sehr wahrscheinlich mit einem eigenen Frequenzzähler/-teiler für jedes Digit.
Und genau das hatte ich Dir ja als letztes auch (in Software) vorschlagen wollen: ein Register für jede Stelle. Dann hast Du statt der 3 Zahnräder 6. Erfordert beim zählen mehr Schritte, nimmt Dir dafür das umrechnen in BCD ab.
(Du könntest für die kleinste Stelle (Sekunden-Einer) übrigens auch einen Timer als Zähler verwenden, den bei 9->0 überlaufen lassen, und dort einen IRQ ankoppeln, in den dann die anderen Zahnräder (Register) eingreifen - aber dann müßte Dein Oszillator-IC an Tn verbunden werden, was wieder 'ne andere Verdrahtung wäre...)

Wenn Du bei den 3 Zahnrädern (Minuten, Stunden, Sekunden) bleiben willst, mußt Du jedesmal nach dem verändern eines der Register dieses in BCD umrechnen. beim zurücksetzen nach 0 wäre alles 0, trivial.
Beim Inkrementieren brauchst Du also dann 'n Algorithmus, der Dir aus dem Byte (binär) 2 Bytes (BCD) berechnet. Wie? Generell geht das so, daß man sooft die größte mögliche Zehnerpotenz abzieht (und das zählt), bis es dabei zu 'nem Überlauf kommt. Der wird dann wieder rückgängig gemacht, die gezählten Subtraktionen sind dann dieses Digit. danach gehts mit der nächstkleineren Potenz weiter. Hier wäre alles kleiner 100 (2 Digits), also kopierst Du die Binärzahl in das Register, welches hinterher die Einer-Digit sein soll.
Das Register für die Zehner Digit ist 255.
Schleifeneinsprung
Zehner inkrementieren
vom Einer 10 abziehen
wenn kein überlauf zurück nach Schleifeneinsprung
danach wieder 10 auf Einer addieren, Zehner und einer enthalten dann die Digits.

Jetzt kommt die Zuordnung der LEDs an die Prozessorbeine. Mal sind die entsprechend der binären Darstellung gewählt, mal andersrum; mal aus einem Port, mal aus mehreren...

Die Stunden-Zehner sind zB genau "falschrum" an PORTA.
Die Stunden-Einer "richtigrum", die könnte man also mit etwas schieben zusammen mit den Zehnern nach PortA schreiben. Da aber auf PORTA auch zwei der Minuten-Zähler liegen muß PORTA vorher ausgelesen und "herummaskiert" werden, also RMW...
Moment mal: irgendwas stimmt da nicht... 1=PA6=8 ??
Die Minuten-Zehner wären irgendwie vollkommen durcheinander, die Einer wieder in umgekehrter binärer Reihenfolge...
Bei den Sekunden wären die einzelnen Stellen auch jeweils in umgekehrter binärer Reihenfolge.

Diese ganze Anordnung macht es natürlich aufwändiger, das jetzt alles im Programm zurechtzudröseln, daß es auf die Ports paßt.
Dort, wo nur die Reihenfolge der Bits falschrum ist, kann man das mit Schieben und Rollen (über das Carry) umdrehen, bei den anderen müssen die Bits in den einzelnen Digits abgefragt werden, und die entsprechenden Bits für die Port-Register vorbereitet/zusammengefügt werden. Da in der Zuordnung nicht wirklich ein erkennbares System steckt, läuft das dann auf ein entsprechend ... umständliches/mühseliges Programm raus.

Die (vorgegebene) einfache Verdrahtung der LEDs (Hardware) hat Dir 'ne Suppe eingebrockt, die Du nun mit 'nem komplizierterem Programm (Software) auslöffeln mußt.:eating:
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)