Hallo! Zu meinem verwendeten System: Ich habe ein Mikrocontroller System mit einen 12Mhz Mikrocntroller. Die Ausgabe der Stoppuhr erfolgt auf der BCD-7-Segment Anzeige (welche an Port 1 und 2 des Mikrocontrollers angeschlossen ist). Außerdem ist eine Schalterplatine an Port 0 angeschlossen für Zusatzfunktionen. Zur besseren Veranschaulichung können diese einzelne Elemente meines Systems untern folgenden Links angeschaut werden: Mikroconroller: http://dbi-design.de/clemens/projekt/mikrocontroller.jpg BCD-7-Segment Anzeige: http://dbi-design.de/clemens/projekt/bcd_7_seg.jpg Tasterplatine: http://dbi-design.de/clemens/projekt/taster.jpg Mit diesem System will ich nun eine Stoppuhr in Assembler realisieren. Die Stoppuhr soll folgende Funktionen aufweisen: 1. Start 2. Stopp 3. Speichern einer gestoppten Zeit 4. Abrufen einer gespeicherten Zeit Diese 4 Funktionen sollten für die Schalter aufgerufen werden können. Das Stoppuhr Programm muss in Assembler geschrieben werden und muss ebenso mit Interrupts arbeiten. Dies ist vorgeschrieben daran kann ich nichts ändern. Tipps für andere Sprachen oder ohne Interrupts bringen mir deswegen relativ wenig, trotzdem danke schonmal! Nun zu meinem eigenlichen Problem. Ich habe natürlich schon angefangen mit diesem Projekt komme aber einfach nichtmehr weiter. Ich steh irgendwie total auf dem Schlauch wie man gerne zu sagen pflegt ich hoffe deswegen auf eure Hilfe. Vielen Dank schoneinmal für Tipps oder Programmänderungsvorschläge! -------------------------------------------------------------------- Nun das bisherige Programm: $include (reg52.inc) org 0000h MOV R0,#0 ; Zähler MOV R1,#0 MOV R2,#0 ; bestimmt welche der Anzeigen aktiv ist MOV R3,#0 MOV R4,#0 ; für Segment rechts Hundertstel Zehner MOV R5,#0 ; für Segment Mitte rechts Sekunden Einer MOV R6,#0 ; für Segment Mitte links Sekunden Zehner MOV R7,#0 ; für Segment links Minuten Einer loop: ; hier wird zukünftig die neue Uhrzeit berechnet call neueUhrzeit ;aufrufen Hauptprogramm neueUhrzeit call ausgabe ;aufrufen Ausgabe Programm call wait ; aufrufen Warte Programm, wartet 4 ms LJMP loop ; aufrufen loop neueUhrzeit: INC R1 ; erhoehe Register 1 CJNE R1,#250d,weiter ;Springe nach weiter wenn der Inhalt von R1 ungleich 250d ist MOV R1,#0d ;Lade Register 1 mit dem Wert 0 INC R2 ; erhoehe Register 2 CJNE R2,#10d,weiter ;Springe nach weiter wenn der Inhalt von R2 ungleich 10d ist MOV R2,#0d ;Lade Register 2 mit dem Wert 0 INC R3 ; erhoehe Register 3 CJNE R3,#10d,weiter ;Springe nach weiter wenn der Inhalt von R3 ungleich 10d ist MOV R3,#0d ;Lade Register 3 mit dem Wert 0 mSek: INC R4 ; erhoehe Register 4 CJNE R4,#10d,weiter ;Springe nach weiter wenn der Inhalt von R4 ungleich 10d ist MOV R4,#0d ;Lade Register 4 mit dem Wert 0 INC R5 ; erhoehe Register 5 CJNE R5,#10d,weiter ;Springe nach weiter wenn der Inhalt von R5 ungleich 10d ist MOV R5,#0d ;Lade Register 5 mit dem Wert 0 mMin: INC R6 ; erhoehe Register 6 CJNE R6,#6d,m2 ;Springe nach m2 wenn der Inhalt von R6 ungleich 6d ist CJNE R7,#10d,m2 ;Springe nach m2 wenn der Inhalt von R7 ungleich 0d ist MOV R6,#0 ;Lade Register 6 mit dem Wert 0 MOV R7,#0 ;Lade Register 7 mit dem Wert 0 m2: CJNE R6,#10,weiter ;Springe nach weiter wenn der Inhalt von R6 ungleich 10 ist MOV R6,#9 ;Lade Register 6 mit dem Wert 9 INC R7 ; erhoehe Register 7 LJMP weiter ;aufrufen von weiter weiter: RET ;Rücksprung aus dem Unterprogramm ;Unterprogramm wait benötigt genau 4ms bei 12MHz wait: PUSH 01 PUSH 02 MOV R1,#1 wait1: MOV R2,#164 wait2: DJNZ R2,wait2 NOP DJNZ R1,wait1 NOP NOP NOP POP 02 POP 01 RET ausgabe: INC R0 CJNE R0,#04,rechts MOV R0,#0 rechts: CJNE R0,#0,mire MOV A,R4 CALL BCD7Seg MOV P1,A MOV P2,#00001110b mire: CJNE R0,#1,mili MOV A,R5 CALL BCD7Seg MOV P1,A MOV P2,#00001101b mili: CJNE R0,#2,links MOV A,R6 CALL BCD7Seg MOV P1,A MOV P2,#00001011b links: CJNE R0,#3,m1 MOV A,R7 CALL BCD7Seg MOV P1,A MOV P2,#00000111b m1: RET ; Wandelt vom BCD-Code in den 7-Segment-Code BCD7Seg: INC A MOVC A,@A+PC RET DB 3Fh, 06h, 5Bh, 4Fh, 66h, 6Dh, 7Dh, 07h, 7Fh, 6Fh end
Wie wärs, wenn Du erstmal nen Programmablaufplan schreibst, also verbal ausdrückst, was wann und wie zu tun ist. Eine Aufgabe in Code umzusetzen ist leicht. Das Schwierige am Programmieren ist jedoch, erstmal diese Aufgaben sinnvoll zu formulieren. Peter
@Clemens, das wichtigste fehlt ja wohl..oder ???? Was ist denn mit Timer ????? Normalerweise läßt man den bei Betätigung einer Taste laufen. Incrmentiert im Interrupt eine Variable ( RAM Zelle) auf. Überträge auf die nächtse und so weiter. Ne Kette eben. Allerdings wirst Du wohl um Interruptprioritäten nicht herum kommen. Die Anzeige ist ja nicht so wichtig wie die exakte Erfassung der Zeit. Den LED Multiplex inkl. oder exkl. Decoder kann der 2. Timer machen. Wie Peter sagt, Dir fehlt das eigentliche Konzept. So denn..... ran ans Schmierblatt....
Clemens, in einer Elektor Ausgabe der letzten 2 Jahre war eine solche Stoppuhr realisiert. Hier kannst Du Dich einmal konzeptionell befruchten lassen, denn da scheinst Du etwas Nachholbedarf zu haben. Der "Schwierigkeitsgrad" einer solchen Aufgabenstellung ist nicht sehr anspruchsvoll, wenn man sich etwas einliest und vor allem einen "Plan" entwickelt. Die Zutaten sind ja schon genannt: Timer geschickt initialisieren (Quarztakt beachten, denn die Uhr soll ja nicht zum Pfandhaus gehen), Interruptserviceroutine (fehlt bei Dir völlig) für den Timer (Kurz halten, am besten mit einem "Flag" arbeiten) drumherum baust Du dann schön Dein Zählwerk auf !! In der Hauptroutine kannst Du dann prima Deine 7-Segmentanzeige (Multiplexen oder statisch) versorgen und auch die Tasten befragen. Hier mußt Du selbst bewerten ob ein paar Mikrosekunden Verzögerung bis zur Abfrage des Tastenstatus ein Problem darstellen. Du kannst die Tasten natürlich auch per Interrupt befragen, aber ein paar Befehlszyklen gehen Dir immer verloren, wahrsagen können die Controller leider nicht. Hau rein ! D.S.
Hallo Danke schoneinmal für die Tipps. Also die obige Datei habe ich bekommen und mit der soll ich Arbeiten. Ehrlich gesagt versteh ich das mit dem Interrupt allerdings selbst nicht so ganz. Kennt jemand von euch eine gute Erklärung dazu? Das würde mir auch sehr weiterhelfen. Ansonsten habe ich mittlerweile mal einen sehr allegemeinen Programmablaufplan erstellt: http://dbi-design.de/clemens/projekt/pap.jpg Ich weiß allerdings nicht wie ich das Abrufen der gespeicherten Zeit bewerkstelligen soll.
naja geht doch schon. So nun brauchst Du noch nen Timer,der Dir ne Zeitbasis macht. zB alle 100ms oder alles 10ms etc.pp Dazu nimmt man Timer 1 oder Timer 0. Deine Quarzfrequenz kennst Du ja oder wählst sie entsprechend zB 12 Mhz. Dann hast du 1uS Zykluszeit, damit läßt sich prima arbeiten, da der 8051 12 Takte für einen Zyklus ( Befehl) braucht. Der Start des Stoppuhrprogramms macht nichts anderes als einfach den Timer zu starten. Und bei Stopptaste einfach den Timer stoppen. Wie gesagt, das Schlüsselwort lautet "Timer" !! Beim Überlauf löst der Timer nen Interrupt (Programmunterbrechung) aus. Im Interrupt muß Du nur noch ne Variable oder Speicherstelle hochzählen und wieder raus. Wenns ganz genau sein soll dann setzt Du im Interrupt nur nen Flag und springst mit RETI gleich wieder raus. Der Rest siehe oben....
ähhmm! Das Programm sollte nicht gerade bei Adresse 0000h starten, weil gleich dahinter ja die Interrupt Einsprungadressen befinden. Könnte so unerwünschte effekte geben. Lieber mal so machen: org 0000h LJMP Start ... ;Ab Adresse 03h Hardware Einsprung Aderessen für Interrupt org 000Bh ;Interrupt Timer 0 LJMP ISR_Timer0 ... oder org 001bh ;Interrupt Timer 1 LJMP ISR_Timer1 ... ... von mir aus ab Adresse 100 oder höher egal org 0100h Start: ... ... mov TMOD,#00000010b ;Timer0 aktivieren mov TL0,#0 mov TH0,#0 SETB EA SETB ET0 clr TF0 SETB TR0 LJMP Start ISR_Timer0: clr TF0 ... ... RETI ;Return Interrupt oder ISR_Timer1: clr TF1 ... ... RETI ; Return Interrupt Gruß norad
der, der Ahnung davon hat und Recourcenaufteilung der MCU nicht einem Compiler überlassen will !
Sorry Stephan. Aber es bleibt dabei, heute schreibt niemand mehr in Assembler. Zu mindestens Keiner der der ernst genohmmen werden will. PS.: Bei mir in der Firma & Kunden hat es sich immer weider rausgestellt das ein Prozessor zu klein/schwach war und er gewechselt werden musste. Wie geht den das in Assembler? Also bitte nie Assembler, Ihr macht euch das leben nur unnötig schwer.
Mittlerweile habe ich das Programm ergänzt, so gut es ging. Könntet ihr das mal durchschauen? Wäre nett! $include (reg52.inc) Starttaster bit P0.1 Resettaster bit P0.2 org 0000h LJMP start ;Einsprungadresse Interrupt-Serviceroutine für Timer 0 org 000Bh LJMP isrTimer0 org 0100h Start: SETB P1.0 ;Taster an P1, um Port als Eingang zu haben abfrage: MOV a,p1 JB a.0,abfrage Hilfsflag ist 1? Wenn ja dann SETB TR0 wenn nein SETB Taster CALL neueUhrzeit CALL ausgabe CALL wait JMP abfrage initRegister: MOV R0,#0 ;bestimmt welche der Anzeigen aktiv ist MOV R1,#0 ;Zähler von o bis 249 -->4ms*250 = 1 Sec MOV R2,#0 ;Sekunden Einer MOV R3,#0 ;Sekunden Zehner MOV R4,#0 ;für Segment rechts Minuten Einer MOV R5,#0 ;für Segment Mitte rechts Minuten Zehner MOV R6,#0 ;für Segment Mitte links Stunden Einer MOV R7,#0 ;für Segment links Stunden Zehner RET initTimer0: SETB ET0 ;Freigabe Timer0. Bit im Reg IE, Reg.-Adresse SETB EA ;Globale INT Freigabe. Bit im Reg IE MOV TMOD,#00000001b ;Timer0 konfiguieren, Modus1: 16bit Zaehler MOV TL0,#060h ;Timer0 vorladen MOV TH0,#0F0h ;65536 - 4000 = 61536 = F060h (4ms) CLR TF0 SETB TR0 ;Start Timer0 LJMP start ;Interrupt-Service-Routine für Timer0 isrTimer0: CLR TF0 MOV TL0,#060h ;Timer0 erneut vorladen MOV TH0,#0F0h ;65536 - 4000 = 61536 = F060h (4ms) CALL neueUhrzeit ;neue Uhrzeit berechnen CALL ausgabe ;Ausgabe auf Anzeige RETI ;Ende der Interrupt-Service-Routine neueUhrzeit: INC R1 ; erhoehe Register 1 CJNE R1,#250d,weiter ;Springe nach weiter wenn der Inhalt von R1 ungleich 250d ist MOV R1,#0d ;Lade Register 1 mit dem Wert 0 INC R2 ; erhoehe Register 2 CJNE R2,#10d,weiter ;Springe nach weiter wenn der Inhalt von R2 ungleich 10d ist MOV R2,#0d ;Lade Register 2 mit dem Wert 0 INC R3 ; erhoehe Register 3 CJNE R3,#10d,weiter ;Springe nach weiter wenn der Inhalt von R3 ungleich 10d ist MOV R3,#0d ;Lade Register 3 mit dem Wert 0 mSek: INC R4 ; erhoehe Register 4 CJNE R4,#10d,weiter ;Springe nach weiter wenn der Inhalt von R4 ungleich 10d ist MOV R4,#0d ;Lade Register 4 mit dem Wert 0 INC R5 ; erhoehe Register 5 CJNE R5,#10d,weiter ;Springe nach weiter wenn der Inhalt von R5 ungleich 10d ist MOV R5,#0d ;Lade Register 5 mit dem Wert 0 mMin: INC R6 ; erhoehe Register 6 CJNE R6,#6d,m2 ;Springe nach m2 wenn der Inhalt von R6 ungleich 6d ist CJNE R7,#10d,m2 ;Springe nach m2 wenn der Inhalt von R7 ungleich 0d ist MOV R6,#0 ;Lade Register 6 mit dem Wert 0 MOV R7,#0 ;Lade Register 7 mit dem Wert 0 m2: CJNE R6,#10,weiter ;Springe nach weiter wenn der Inhalt von R6 ungleich 10 ist MOV R6,#9 ;Lade Register 6 mit dem Wert 9 INC R7 ; erhoehe Register 7 LJMP weiter ;aufrufen von weiter weiter: RET ;Rücksprung aus dem Unterprogramm ;Unterprogramm wait benötigt genau 4ms bei 12MHz wait: PUSH 01 PUSH 02 MOV R1,#1 wait1: MOV R2,#164 wait2: DJNZ R2,wait2 NOP DJNZ R1,wait1 NOP NOP NOP POP 02 POP 01 RET ausgabe: INC R0 CJNE R0,#04,rechts MOV R0,#0 rechts: CJNE R0,#0,mire MOV A,R4 CALL BCD7Seg MOV P1,A MOV P2,#00001110b mire: CJNE R0,#1,mili MOV A,R5 CALL BCD7Seg MOV P1,A MOV P2,#00001101b mili: CJNE R0,#2,links MOV A,R6 CALL BCD7Seg MOV P1,A MOV P2,#00001011b links: CJNE R0,#3,m1 MOV A,R7 CALL BCD7Seg MOV P1,A MOV P2,#00000111b m1: RET ; Wandelt vom BCD-Code in den 7-Segment-Code BCD7Seg: INC A MOVC A,@A+PC RET DB 3Fh, 06h, 5Bh, 4Fh, 66h, 6Dh, 7Dh, 07h, 7Fh, 6Fh end
@Clemens SETB P1.0 > ;Taster an P1, um Port als Eingang zu haben >abfrage: MOV a,p1 > JB a.0,abfrage Irgendwie unübersichtlich! Taster EQU 28h ;Bit Adressierbarer Bereich ab 25h (8 Bit) Vorschlag! MOV 25h,P1 ;Informationen von Prort 1 in 25h speichern MOV C,Taster ;Taster betätigt? JC abfrage ;Ja! ...
>>> Aber es bleibt dabei, heute schreibt niemand mehr in Assembler. Zu
mindestens Keiner der der ernst genohmmen werden will. <<<
Oh Gott, sind die Meisten mittlerweile zu Blöd für Assembler, statt
sinnvolle Hilfe zu geben, aber das kannst du ja nicht kannst ja nur C,
dann so einen Blödsinn zu verzapfen, sorry mußte mal gesagt werden.
Bei mir sinds 10% C und 90% Assembler.
Sorry das ich nichts zum Thema sage aber das mußte raus.
@ Clemens, sorry für den Mißbrauch.
Dein Spaghetticode ist zwar angewachsen, aber trotzdem sieht da keiner durch. Nochmal, es bringt nicht, planlos drauflos zu coden, da kommt immer nur Mist raus. Du brauchst erstmal einen Plan. Also was soll wie erfolgen, wenn welche Tasten gedrückt wird, was soll wie dargestellt werden usw. Was Du brauchst, ist ein Timerinterrupt, um: - eine genaue Zeitbasis zu haben - Die Anzeige zu multiplexen - Die Tasten zu entprellen Im Hauptprogramm erfolgt dann die eigentliche Ablaufsteuerung, nachdem Du Dir einen Plan gemacht hast, wie diese überhaupt aussehen soll. Code kannst Du erst schreiben, nachdem Du weißt, was gemacht werden muß. Peter
@Clemens, das soll doch ne Stoppuhr werden ?? Oder ???? Wie kannst Du es Dir dann leisten in der ISR ne komplette Ausgabe zu machen ?? SO NICHT !!!!! In der ISR: Timer neu laden INC Variable oder Flag setzen und raus !!!! Das wars ... mehr gehört da nicht rein falls Du Zehntel un Hunderstel messen willst. Die Wait Schleife würde ich in den 2 Timer packen. Allerdings muß die Priorität von Timer 1 höher sein !!! Oder Du mmußt dafür sorgen das Timer 2 den Timer 1 nicht unterbricht. Dann bringe alles mal etwas in Form. Habe jetzt nicht viel Zeit, bin auf Arbeit. Hast Du schon simuliert ??? @Oliver "PS.: Bei mir in der Firma & Kunden hat es sich immer weider rausgestellt das ein Prozessor zu klein/schwach war und er gewechselt werden musste. Wie geht den das in Assembler? " Da fragt man sich doch wer die Planung gemacht hat ...... Mitten im Projekt wird die MCU zu klein ?? Und kein Ersatz aus der gleichen Familie ??? AU MAN !!!!!...
"Da fragt man sich doch wer die Planung gemacht hat ......" Warscheinlich gar keiner. Manchmal wird die Planung notgedrungen erst dann gemacht, wenn der Spaghetticode zu groß und zu undurchschaubar geworden ist. Und oh Wunder, plötzlich paßt das Programm sogar in nen kleineren MC. Peter
OK, also alle reden in diesem Thema davon aber ich selbst habe keine Ahnung: Was ist ein Timer Interrupt? Könnte mir jemand mal ein Beispiel geben? Ich selbst habe wenig Ahnung von Interrupts und verstehe ehrlich gesagt die Interrupt Programmierung in meinem Programm nichteinmal (was u.a. auch dazu führt das bis jetzt noch kein gutes Programm dabei rauskam). Der Ablauf des Programms habe ich ja schoneinmal festgelegt, in einem Pap ( http://dbi-design.de/clemens/projekt/pap.jpg ). Ich weiß ja also was ich programmieren will, nur fehlt mir irgendwie das Verständnis dazu. Das Problem ist eben auch das ich ja mit Interrupts arbeiten muss (wurde mir so vorgegeben). Ich sollte wohl am besten mich ersteinmal in Interrupts einlesen. Kennt jemand von euch eine gute Beschreibung, Homepage, o.ä zum Thema Interrupts? Danke im Voraus!
au Backe Clemens,,, sag mal verlangen die Lehrer heute unmögliches oder ist das "Lernen" zur Unsitte erklärt worden und deshalb unschicklich ??? Bist Du der einzige von Euch der nix versteht oder alle ?? Schau mal hier, da steht alles über Interrupts für 8051. http://www.goblack.de/desy/mc8051chip/datenblatt/interupt/index.html
@Peter, und was soll ich sagen, meistens haben solche Leute auch noch Jobs von denen wir nur träumen können :-( armes Deutschland...wo können wir nur noch ein par Terraflops herbekommen ???
Na der Plan sieht ja gar nicht so schlecht aus, daran kann man weiterarbeiten: 1. Im allgemeinen möchte man eine Aktion beim Drücken, wie es scheint startest Du den Zähler aber erst beim Loslassen (Start = 1). 2. Was passiert beim Speichern ? Wird der alte Wert überschrieben ? 3. Nirgends wird der gespeicherte Wert angezeigt. 4. Was wird überhaupt angezeigt, Du hast ja nur 4 Stellen. Hier wird ein Interrupt angesprungen: ;Einsprungadresse Interrupt-Serviceroutine für Timer 0 org 000Bh LJMP isrTimer0 Ist also wohl nicht von Dir, wenn Du das nicht erkannt hast. Unterprogramme im Interrupt sind: naja. Aber die selben Unterprogramme im Interrupt und im Main sind oberpfui ! Du unterbrichst ein Programm mit sich selbst. Aufm PC gibts dafür knallhart nen Blue-Screen. Peter
Ich denke, dein Hauptproblem ist, dass du dich zu sehr verzettels indem du an 5 Baustellen gleichzeitig arbeitest. Weiters glaub ich, dass du das was dir vorgegeben wurde (den Code, nicht die Aufgabenstellung) zu sehr als Gesstzbuch ansiehst, dass unveränderbar ist. Meiner Ansicht nach solltest du den Code so wie er war studieren, rausfinden wie die einzelnen Teile funktioniert haben (zb der ganze Bereich der die eigentliche Uhr in 7 Registern realiert hat: Wie wird diese 'Uhr' um eine Einheit hochgezählt, wie funktioniert die Ausgabe auf die Anzeige), ev. mal ein bischen damit spielen und ihn verändern, und dann: fang neu an. Als allererstes solltest du mal im Originalcode die ganzen Kommentare, ala: INC R1 ; erhoehe Register 1 CJNE R1,#250d,weiter ; Springe nach weiter wenn der ; Inhalt von R1 ungleich 250d ist MOV R1,#0d ;Lade Register 1 mit dem Wert 0 rauwerfen. Diese Kommentare sind naemlich ein Musterbeispiel dafuer, wie man nicht kommentiert: Der Kommentar erzaehlt dir nichts, er wiederholt nur dass was ohnehin in der Anweisung auch steht. Aber was ist R1? R1 enthaelt offensichtlich einen Sub-Sekunden Zaehler. Durch den Interrupt Mechanismus wird die Funktion eine bestimmte Anzahl mal in der Sekunde angesprungen. An einer anderen Stelle im Programm findet sich der Kommentar ;Unterprogramm wait benötigt genau 4ms bei 12MHz das deckt sich genau mit den 250 die da oben vorkommen. Wenn ein Durchlauf 4 ms dauert, dann ist nach genau 250 durchläufen exakt 1 Sekunde vergangen. Das sollte man dokumentieren, zb so: INC R1 ; erhoehe den 4ms Zaehler CJNE R1,#250d,weiter ; Wenn die Routine noch nicht 250 ; mal aufgerufen wurde, dann gibt ; es nichts zu tun: -> weiter MOV R1,#0d ; den 4ms Zaehler wieder auf 0 setzen INC R2 ; und zur Sekunden-Einerstelle ; 1 dazzuzaehlen CJNE R2,#10d,weiter ; Gibt das einen Überlauf 9->10? ; Wenn nein, alles getan: -> weiter MOV R2,#0d ; Es gab einen Überlauf. d.h. die ; Einerstelle der Sekunden fängt wieder ; bei 0 an zu zählen ... INC R3 ; ... und bei den Zehnern der Sekunden ; gehst um 1 hoch CJNE R3,#6d,weiter ; Wenn hier noch nicht 6 (also 6*10 ; Sekunden) zusammengekommen sind: ; nichts weiter zu tun: -> weiter .... ; wieder bei 0 Sekunden anfangen ; und bei dem Minuten Einer um ; 1 hochzählen ; Übertrag 9->10 bei den Einern? ; Zehner um 1 hochzählen, ; usw ; usw Siehst du den Unterschied in der Qualitaet der Kommentare. Jetzt erzählt mir der Kommentar, was an dieser Stelle warum geschieht. Und zwar in meinen Worten. Das ein Sprung nach weiter erfolgt, wenn R2 den Wert 10 erreicht hat, das sehe ich auch im Quelltext. Die Frage ist nur: Warum macht man diesen Sprung, bzw. warum macht man ihn manchmal nicht? Was ist die Idee hinter diesem Sprung? Das sind Dinge die ein Kommentar beantworten muss, nicht die Klartext-Wiedergabe des Assembler-Befehls. Und solange du diese Transformation der Kommentare nicht machst, wirst du auch nie verstehen, was in deinem Programm zur Zeit eigentlich vor sich geht und vor allen Dingen: was die Idee hinter diesem urspruenglichen Program war. Erst wenn du das komplett verstanden hast, weil du es studiert hast und von jeder Anweisung sagen kannst welchen Zweck sie hat (wiederum: Zweck im Sinne von: was passiert auf höherer Ebene. Ein INC R4 hat natuerlich den 'Zweck' R4 hochzuzaehlen. Das meine ich nicht. Der Zweck ist die 'Einer der Minuten' hochzuzählen, weil eben 1 Minute vergangen ist) erst dann wirst du in der Lage sein, einen neuen Programmplan für deine Stoppuhr zu erstellen. Ein Plan der auch realistisch ist und umgesetzt werden kann.
So, ich habe das ganze Programm nun (nach meinen Vorstellungen) mal sinnvoll überarbeitet. Ich denke das die Grundfunktion (die laufende Zeit) nun funktionieren sollte. Da ich das Programm dank der Hilfe von vielen hier mittlerweile nun endlich verstehe möchte ich nun die eigentlich wichtigen Funktionen einbauen. So soll das Programm ja auf Tastendruck gestartet, gestoppt, die aktuelle Zeit gespeichert und die Zeit resettet werden. Die Taster dazu liegen an Port 3 (wegen Interrupt). Diese abzufragen stellt auch kein Problem dar, das Problem besteht nur darin das ich nicht weiß was ich wie unterbrechen kann (z.B. für Start/Stopp). Es wäre natürlich gut den Interrupt Timer zu unterbrechen mit Stopp oder zu Starten mit Start aber wie könnte ich sowas bewerkstelligen. Starten wäre wohl das kleinere Problem, aber so zu Stoppen das die aktuelle Zeit auch stehenbleibt und weiter angezeigt wird. Ich hab mir überlegt ob ich die Start und Stopp Funktion über ein Externes Interrupt laufen lassen soll (EX0 und EX1). Aber ich weiß nicht wie ich das dann mit dem unterbrechen und dem einspringen machen kann bzw. ob ich überhaupt mehrere Interrupts in einem Programm verwenden kann. Ich bräuchte da deswegen Ideen wie ich so etwas bewerkstelligen kann. Das Resetten wäre wohl das einfachste, in dem ich einfach die Register alle 0 setze. Danke im Voraus mal wieder für eure sehr hilfreiche Hilfe! ----------------------------------------------------------- Hier noch das aktuelle Programm: $include (reg52.inc) Starttaster bit P3.2 Stopptaster bit P3.3 Resettaster bit P3.4 Merkertaster bit P3.5 org 0000h LJMP start ;Einsprungadresse Interrupt-Serviceroutine für Timer 0 org 000Bh LJMP isrTimer0 org 0100h start: CALL initRegister ;Register initialisieren CALL initTimer0 ;Interrupt Timer initialisieren loop: LJMP loop ;Endlosschleife initRegister: MOV R0,#0 ;bestimmt welche der Anzeigen aktiv ist MOV R1,#0 ;Zähler von o bis 249 -->4ms*250 = 1 Sec MOV R2,#0 ;für Segment rechts Sekunden Einer MOV R3,#0 ;für Segment Mitte rechts Sekunden Zehner MOV R4,#0 ;für Segment Mitte links Minuten Einer MOV R5,#0 ;für Segment links Minuten Zehner RET initTimer0: SETB ET0 ;Freigabe Timer0. Bit im Reg IE, Reg.-Adresse SETB EA ;Globale INT Freigabe. Bit im Reg IE MOV TMOD,#00000001b ;Timer0 konfiguieren, Modus1: 16bit Zaehler MOV TL0,#060h ;Timer0 vorladen MOV TH0,#0F0h ;65536 - 4000 = 61536 = F060h (4ms) SETB TR0 ;Start Timer0 RET ;Interrupt-Service-Routine für Timer0 isrTimer0: MOV TL0,#060h ;Timer0 erneut vorladen MOV TH0,#0F0h ;65536 - 4000 = 61536 = F060h (4ms) CALL neueUhrzeit ;neue Uhrzeit berechnen CALL ausgabe ;berechnete Uhrzeit ausgeben RETI ;Ende der Interrupt-Service-Routine neueUhrzeit: INC R1 ;erhöht den Zaehler CJNE R1,#250d,weiter ;Wenn die Routine noch nicht 250 mal aufgerufen wurden ;dann springe nach weiter, da nichts geschieht MOV R1,#0d ;den Zaehler wieder auf Null zurücksetzen INC R2 ;Sekunden Einerstelle um Eins erhöhen CJNE R2,#10d,weiter ;Entsteht dadurch kein Überlauf (9->10) springe ;nach weiter MOV R2,#0d ;Es gab einen Überlauf, dadurch muss die Einerstelle ;zurückgesetzt werden INC R3 ;Die Zehnerstelle der Sekunden muss um Eins erhöht werden CJNE R3,#6d,weiter ;Wenn die Zehnerstelle noch nicht 6 anzeigt springe ;nach weiter MOV R3,#0d ;Es gab einen Überlauf, dadurch muss die Zehnerstelle ;zurückgesetzt werden INC R4 ;Die Minuten Einerstelle um Eins erhöhen CJNE R4,#10d,weiter ;Entsteht dadurch kein Überlauf (9->10) springe ;nach weiter MOV R4,#0d ;Es gab einen Überlauf, dadurch muss die Einerstelle ;zurückgesetzt werden INC R5 ;Die Minuten Zehnerstelle um Eins erhöhen CJNE R5,#6d,weiter ;Entsteht dadurch kein Überlauf (5->6) springe ;nach weiter MOV R2,#0d ;Es gab einen Überlauf, dadurch muessen Register 2 bis 5 MOV R3,#0d ;zurückgesetzt werden. Da die Uhr nicht mehr MOV R4,#0d ;anzeigen kann MOV R5,#0d ausgabe: INC R0 ;erhöht die Anzeigennummer CJNE R0,#04,rechts ;Ist der Wert ungleich 4 springe nach rechts MOV R0,#0 ;Setzt den Wert der Anzeigennummer zurück rechts: CJNE R0,#0,mire ;Ist die Anzeigennummer ungleich 0 springe nach mire MOV A,R2 ;Schreibe den berechneten Uhrzeitwert in den Akku CALL BCD7Seg ;Ruft Werte für BCD7Seg Anzeige auf MOV P1,A ;Gibt den im Akku gespeicherten Wert auf P1 aus MOV P2,#00001110b ;gibt die Anzeigenposition auf P2 aus mire: CJNE R0,#1,mili ;Ist die Anzeigennummer ungleich 1 springe nach mili MOV A,R3 ;Schreibe den berechneten Uhrzeitwert in den Akku CALL BCD7Seg ;Ruft Werte für BCD7Seg Anzeige auf MOV P1,A ;Gibt den im Akku gespeicherten Wert auf P1 aus MOV P2,#00001101b ;gibt die Anzeigenposition auf P2 aus mili: CJNE R0,#2,links ;Ist die Anzeigennummer ungleich 2 springe nach links MOV A,R4 ;Schreibe den berechneten Uhrzeitwert in den Akku CALL BCD7Seg ;Ruft Werte für BCD7Seg Anzeige auf MOV P1,A ;Gibt den im Akku gespeicherten Wert auf P1 aus MOV P2,#00001011b ;gibt die Anzeigenposition auf P2 aus links: CJNE R0,#3,m1 ;Ist die Anzeigennummer ungleich 3 springe nach m1 MOV A,R5 ;Schreibe den berechneten Uhrzeitwert in den Akku CALL BCD7Seg ;Ruft Werte für BCD7Seg Anzeige auf MOV P1,A ;Gibt den im Akku gespeicherten Wert auf P1 aus MOV P2,#00000111b ;gibt die Anzeigenposition auf P2 aus m1: RET ;Rücksprung aus dem Unterprogramm ; Wandelt vom BCD-Code in den 7-Segment-Code BCD7Seg: INC A MOVC A,@A+PC RET DB 3Fh, 06h, 5Bh, 4Fh, 66h, 6Dh, 7Dh, 07h, 7Fh, 6Fh END
> So soll das Programm ja auf Tastendruck gestartet, gestoppt, die > aktuelle Zeit gespeichert und die Zeit resettet werden. Das ist schon mal falsch. Dein Programm läuft die ganze Zeit. Du kannst es nicht starten, stoppen oder was auch immer. Das Programm läuft bereits. Was du willst ist den Zeitgeber starten und stoppen! Der Zeitgeber ist in deinem Programm der Timer. Soblad der Timer nicht mehr läuft steht auch deine Uhr. Sobald du den Timer wieder laufen lasst, läuft auch deine Uhr. Das ist ein bischen so wie bei den altmodischen (schönen) Pendeluhren. Die werden gestoppt indem man das Pendel stoppt. In deinem Programm ist der Timer mit dem Pendel gleichzusetzen. Nur gibt es in deinem Programm eine klitzekleine Eigenheit: Mit dem Zeitgeber gekoppelt ist auch das Anzeigen der Uhrzeit. Das muesste man entkoppeln, da ja die Anzeige auch weiterhin gemacht werden soll, auch wenn der Zeitgeber selbst nicht läuft. Das ist aber kein Problem, denn letztendlich läuft ja dein Hauptprogramm irgendwann hier auf: loop: LJMP loop ;Endlosschleife und bleibt hier hängen. Alles was jetzt noch passiert ist, dass in regelmässigen Zeitabstaenden die Timer-Interrupt Funktion aufgerufen wird, die das 'Uhrwerk' weiterschaltet und die Anzeige bedient. Und natürlich läuft das Hauptprogramm wie wild in dieser Schleife weiter. Das eigentliche Hochzählen der Uhr erfolgt, wie bereits gesagt ja in einem Interrupt. Es spricht aber nichts dagegen, das Anzeigen der Uhrzeit genau in diese Schleife zu verlagern ... loop: call ausgabe LJMP loop und dafür die Ausgabe aus dem Interrupt wegzulassen: ;Interrupt-Service-Routine für Timer0 isrTimer0: MOV TL0,#060h ;Timer0 erneut vorladen MOV TH0,#0F0h ;65536 - 4000 = 61536 = F060h (4ms) CALL neueUhrzeit ;neue Uhrzeit berechnen RETI ;Ende der Interrupt-Service-Routine Siehst du. Jetzt zeigt dein Programm ständig die Uhrzeit an, und durch starten bzw. stoppen des Timers, läuft die Uhr oder sie läuft eben nicht. (Ich muss jetzt ein bischen raten, da ich den 8051 nicht kenne) dh. das hier SETB ET0 ;Freigabe Timer0. Bit im Reg IE, lässt die Uhr laufen. Während das hier CLRB ET0 die Uhr wieder anhält. Alles was du jetzt noch tun musst ist, die Schalter abfragen und je nachdem welcher Schalter gedrückt wurde, entweder das eine oder das andere ausführen.
danke für die schnelle und gute Antwort ich werde es gleich testen! Sollte das einwandfrei funktionieren muss ich mir nur noch was für den "Merker" überlegen.
> Alles was du jetzt noch tun musst ist, die Schalter abfragen
Ich vergass:
Das Abfragen der Schalter kannst du natuerlich auch in
der Hauptschleife machen. Wenn du 2 verschiedene Schalter
für starten und stoppen nimmst, brauchst du das dann auch
nicht entprellen. Sobald der 'Start'-Schalter gedrückt wurde,
gibst du den Timer frei, sobald der 'Stop'-Schalter gedrückt
wurde, stoppst du den Timer wieder:
loop: call ausgabe ; damit wir auch was sehen
hole Zustand vom Schalter 'Start'
ist er gedrückt?
wenn ja: SETB ET0
hole Zustand vom Schalter 'Stop'
ist er gedrückt?
wenn ja: CLRB ET0
jmp loop
Die Details wie man an die Schalter rankommt, bzw. woran man
erkennt ob einer gedrückt ist, weis ich nicht. Das musst
du wissen. Aber vom Prinzip her müsste das schon so funktionieren.
In diese Schleife baust du dann auch noch eine 3.te Schalterabfrage
ein, die das Uhrwerk wieder auf 0 zurücksetzt. Da du mitlerweile
ja verstehst wie die Uhr funktioniert, sollte das kein grosses
Problem mehr sein: Einfach alle Register die das Uhrwerk bilden
auf 0 setzen.
In der schnelle mal Programmiert: -------------------- org 0100h start: JB Starttaster,SETB ET0 ;Startaster abfragen LJMP start ;Endlosschleife CALL initRegister ;Register initialisieren CALL initTimer0 ;Interrupt Timer initialisieren loop: CALL Ausgabe ;berechnete Uhrzeit immer ausgeben JB Stopptaster,CLRB ET0 ;Stopptaster abfragen JB Resettaster,springer :Resettaster abfragen LJMP loop ;Endlosschleife springer: CALL initRegister ;Register zurücksetzen ------------------------------ Kann mir jemand bestätigen ob sowas funktionstüchtig wäre? Ich hatte schoneinmal Probleme mit dem springen (also JB Befehl).
start: JB Starttaster,SETB ET0 ;Startaster abfragen das kann ich mir nicht vorstellen. Wie alle Srungbefehle, wird JB eine Ziel haben wollen zu dem es springt. SETB ET0 ist aber kein Ziel. SETB ET0 ist eine Anweisung! Aber du kannst die Logik ja auch umdrehen. Springen wenn der Taster nicht gedrückt ist: loop: call ausgabe JNB Starttaster, Weiter_bei_Stop SETB ET0 Weiter_bei_Stop: JNB Stopptaster, Weiter_bei_Reset CLRB ET0 Weiter_bei_Reset: JNB Resettaster, Weiter_bei_ CALL initRegister Weiter_bei_: jmp loop
> -------------------- > org 0100h > start: JB Starttaster,SETB ET0 ;Startaster abfragen > LJMP start ;Endlosschleife Warum willst du unbedingt, dass deine Stoppuhr nur ein einziges mal zu gebrauchen ist, wenn du mit demselben Aufwand auch eine Stoppuhr bauen kannst, die man starten, stoppen, starten, stoppen, resetten, starten, stoppen etc. kann? Und zwar in dieser oder jeder anderen beliebigen Reihenfolge. Ausserdem ist es keine sehr gute Idee einen Timer freizugeben noch bevor man ihn initialisiert hat :-)
Du musst noch sehr viel genauer werden. Durch einen Cut&Paste Fehler hast du dir dein Pgm zerstört. Wenn ich mir den Pgm-Teil 'ausgabe' anschaue, denn sehe ich dort im wesentlichen 4 mal den gleichen Abschnitt: rechts: CJNE R0,#0,mire ;Ist die Anzeigennummer ungleich 0 ;springe nach mire MOV A,R2 ;Schreibe den berechneten Uhrzeitwert in den Akku CALL BCD7Seg ;Ruft Werte für BCD7Seg Anzeige auf MOV P1,A ;Gibt den im Akku gespeicherten Wert auf P1 aus MOV P2,#00001110b ;gibt die Anzeigenposition auf P2 aus lediglich das Register im MOV A,R2 und das Label als Sprungziel, wo es weiter geht variiert. Das ist aber seltsam, eigentlich würde ich erwarten, daß es einen Unterschied in der Ausgabe gibt, je nachdem auf welche Stelle du ausgibst. Da ist aber keiner. Jett scrolle ich mal hoch, ganz an den Anfang: Und siehe da. In jedem der 4 Abschnitte wird ein anderer Wert an P2 ausgegeben. Ganz so wie man es erwarten würde. Denn irgendwo muss es ja einen Unterschied geben, sonst landen ja alle Ausgaben immer an der LED-Anzeige.
> sonst landen ja alle Ausgaben immer an der LED-Anzeige. da fehlt ein sinnentstellendes Wort: sonst landen ja alle Ausgaben immer an derselben LED-Anzeige und verteilen sich nicht auf die 4 vorhandenen.
das verstehe ich nicht ganz: MOV P2,#00001110b hier wird doch bestimmt auf welche der 4 Anzeigen der Wert angezeigt werden soll? Oder verstehe ich da irgendetwas falsch?
@Karl Heinz, woher Du Deine Ruhe nimmst und die Zeit..... Hut ab !!!! Mir gefällt Deine Art die Sachen zu erklären, die für uns so selbstvertsändlich sind..... Habe ich mal beim "44780 zeigt nur Kästchen" Tread versucht.. 100 Einträge nur für den Init des LCD !!! gab nur böse Haue von "Abgehobenen ".. als ich versucht habe es auf die Art " MCU an Display...habe Daten" zu erklären Mach weiter so.... stephan Henning
> das verstehe ich nicht ganz: > > MOV P2,#00001110b > > hier wird doch bestimmt auf welche der 4 Anzeigen der Wert angezeigt > werden soll? Autsch. Kommanmdo retour. Ich hab mich verlesen. War ein langer Tag, und heiss war's auch und ... Tschuldigung. Mein Fehler
Macht ja nix, Fehler sind Menschlich... Ich konnte das Programm leider noch nicht testen, da die Übertragungssoftware (Pony Prog) irgendwelche Fehler anzeigt (bezüglich I/O Schnittstelle oder sowas in die Richtung). Were das ganze jetzt aber mal bei mir zuhause ausprobieren... Vorerst gehe ich aber mal davon aus, dass das Programm so funktioniert. Was aber noch fehlt ist eben dieser Merker, welcher sich eine gestoppte Uhrzeit merken soll. Ich habe schon verschiedene Überlegungen angestellt, z.B. - Wert in akku schreiben (ist aber wohl zu groß, oder?) - Wert einem der beiden freistehenden Register (R6 und R7) zuweisen, aber da bekomm ich ja auch nicht die 4 Zahlen rein - Wert einfach an eine bestimmte Adresse schreiben, z.B. 060h Alles ist aber nach meinen Erkenntnissen nicht möglich, deswegen erbitte ich nun wiedereinmal eure Hilfe. Nur eine Idee würde mich eventuell schon weiter bringen! Danke im Voraus!
Na ja. Zuerst mal musst du überlegen, dass du sowas wie 'die Zeit' als eine Einheit ja gar nicht hast. 'Die Zeit' ist verteilt auf (Moment, muss zaehlen gehen) die Register R1 bis R5 R1 der 4ms Zaehler R2 Einerstelle der Sekunden R3 Zehnerstelle der Sekunden R4 Einerstelle der Minuten R5 Zehnerstelle der Minuten Wenn du also 'die Zeit' irgendwo zwischenspeichern möchtest, dann wirst du halt die Inhalte dieser 5 Register irgendwo sichern muessen. Wieso soll das nicht möglich sein, die Inhalte dieser 5 Register im Speicher in 5 Bytes abzulegen?
warum ist das nicht möglich ??? 4 dezimale Zahlen passen doch in 2 Bytes rein. 2 Register oder 2 Speicherstellen. 1 Byte besteht aus 2 Nibbles und mit einem Nibble kann man Zahlen von 0-15 darstellen richtig ?? da wir aber dezimal nur bis 10 zählen nimmst Du ein Nibble und dividierst es durch 15 (0Ah) und hast den dez. Wert. Dann das 2. Nibble usw.
@stephan Machs nicht unnötig kompliziert. Clemens schwimmt doch sowieso schon hinten und vorne. Wenn du ihn jetzt auch noch in Nibble-verarbeitung reinjagst ... (Ich weiss das das alles in Wirklichkeit nicht kompliziert ist. Nur: Wie erklärst du das jemanden der noch nicht mal 5 Bytes irgendwo im Speicher ablegen und wieder laden kann)
moin moin, @Stephan >> da wir aber dezimal nur bis 10 zählen nimmst Du ein Nibble und >> dividierst es durch 15 (0Ah) und hast den dez. Wert. 2Zeile = 2Fehler, bitte nochmal. @Clemens Merker? Machs wie mit einem Spickzettel in der Schule, da kommt doch auch das rauf was Du Dir nicht merken kannst/willst. Nimm also Speicherzellen z.B. ab 60H und lege da die Werte ab, welche Du später noch gebrauchen tust. Vergleiche das mit dem, so wie Du es manuell tun würdest. Mit Gruß Pieter
natürlich zählen wir nur von 0 bis 9, kommt davon wenn man auf Arbeit....
So, mittlerweile bin ich fertig mit diesem Projekt und möchte mich bei euch für eure Hilfe bedanken. Weiter unten findet ihr den funktionierenden, getesteten Code. Da ich immernoch einen Drang habe eine bessere Note zu erreichen, frage ich mich ob es nicht möglich wäre statt den Minuten und den Sekunden, die Sekunden und die Hundertstel auszugeben. Wie wäre das mit meinem Programm realisierbar? Habt ihr irgendwelche gute Vorschläge? Für Antworten wie immer dankbar! Gruß Clemens ----------------------------------------------- Aktuelles Programm (getestet!): $include (reg52.inc) Starttaster bit P0.0 Stopptaster bit P0.1 Resettaster bit P0.2 Merkertaster bit P0.3 Abruftaster bit P0.4 org 0000h LJMP start ;Einsprungadresse Interrupt-Serviceroutine für Timer 0 org 000Bh LJMP isrTimer0 org 0100h start: CALL initRegister ;Register initialisieren CALL initTimer0 ;Interrupt Timer initialisieren loop: CALL ausgabe ;berechnete Werte ausgeben JB Starttaster, Weiter_bei_Stop ;Abfrage des Starttasters SETB ET0 ;Freigabe Timer 0 Weiter_bei_Stop: JB Stopptaster, Weiter_bei_Merker ;Abfrage des Stopptasters CLR ET0 ;Zuruecksetzen des Timers Weiter_bei_Merker: JB Merkertaster, Weiter_bei_Abruf ;Abfrage des Merkertasters MOV 061h,R0 ;Schreibe die gestoppten Werte MOV 062h,R1 ;an Stellen im Speicher MOV 063h,R2 MOV 064h,R3 MOV 065h,R4 MOV 066h,R5 Weiter_bei_Abruf: JB Abruftaster,Weiter_bei_Reset ;Abfrage Abfragetaster MOV R0,061h ;gespeicherte Werte den MOV R1,062h ;Registern zuweisen MOV R2,063h MOV R3,064h MOV R4,065h MOV R5,066h CALL ausgabe ;gespeicherte Werte ausgeben Weiter_bei_Reset: JB Resettaster, Weiter_bei_nichts ;Abfrage Resettaster CALL initRegister ;Register zuruecksetzen Weiter_bei_nichts: LJMP loop ;Endlosschleife initRegister: MOV R0,#0 ;bestimmt welche der Anzeigen aktiv ist MOV R1,#0 ;Zähler von o bis 249 -->4ms*250 = 1 Sec MOV R2,#0 ;für Segment rechts Sekunden Einer MOV R3,#0 ;für Segment Mitte rechts Sekunden Zehner MOV R4,#0 ;für Segment Mitte links Minuten Einer MOV R5,#0 ;für Segment links Minuten Zehner RET initTimer0: SETB EA ;Globale INT Freigabe. Bit im Reg IE MOV TMOD,#00000001b ;Timer0 konfiguieren, Modus1: 16bit Zaehler MOV TL0,#060h ;Timer0 vorladen MOV TH0,#0F0h ;65536 - 4000 = 61536 = F060h (4ms) SETB TR0 ;Start Timer0 RET ;Ruecksprung aus dem Unterprogramm ;Interrupt-Service-Routine für Timer0 isrTimer0: MOV TL0,#060h ;Timer0 erneut vorladen MOV TH0,#0F0h ;65536 - 4000 = 61536 = F060h (4ms) CALL neueUhrzeit ;neue Uhrzeit berechnen RETI ;Ende der Interrupt-Service-Routine neueUhrzeit: INC R1 ;erhöht den Zaehler CJNE R1,#250d,weiter ;Wenn die Routine noch nicht 250 mal aufgerufen wurden ;dann springe nach weiter, da nichts geschieht MOV R1,#0d ;den Zaehler wieder auf Null zurücksetzen INC R2 ;Sekunden Einerstelle um Eins erhöhen CJNE R2,#10d,weiter ;Entsteht dadurch kein Überlauf (9->10) springe ;nach weiter MOV R2,#0d ;Es gab einen Überlauf, dadurch muss die Einerstelle ;zurückgesetzt werden INC R3 ;Die Zehnerstelle der Sekunden muss um Eins erhöht werden CJNE R3,#6d,weiter ;Wenn die Zehnerstelle noch nicht 6 anzeigt springe ;nach weiter MOV R3,#0d ;Es gab einen Überlauf, dadurch muss die Zehnerstelle ;zurückgesetzt werden INC R4 ;Die Minuten Einerstelle um Eins erhöhen CJNE R4,#10d,weiter ;Entsteht dadurch kein Überlauf (9->10) springe ;nach weiter MOV R4,#0d ;Es gab einen Überlauf, dadurch muss die Einerstelle ;zurückgesetzt werden INC R5 ;Die Minuten Zehnerstelle um Eins erhöhen CJNE R5,#6d,weiter ;Entsteht dadurch kein Überlauf (5->6) springe ;nach weiter MOV R2,#0d ;Es gab einen Überlauf, dadurch muessen Register 2 bis 5 MOV R3,#0d ;zurückgesetzt werden. Da die Uhr nicht mehr MOV R4,#0d ;anzeigen kann MOV R5,#0d weiter: RET ;Ruecksprung aus dem Unterpogramm ausgabe: INC R0 ;erhöht die Anzeigennummer CJNE R0,#04,rechts ;Ist der Wert ungleich 4 springe nach rechts MOV R0,#0 ;Setzt den Wert der Anzeigennummer zurück rechts: CJNE R0,#0,mire ;Ist die Anzeigennummer ungleich 0 springe nach mire MOV A,R2 ;Schreibe den berechneten Uhrzeitwert in den Akku CALL BCD7Seg ;Ruft Werte für BCD7Seg Anzeige auf MOV P1,A ;Gibt den im Akku gespeicherten Wert auf P1 aus MOV P2,#00001110b ;gibt die Anzeigenposition auf P2 aus mire: CJNE R0,#1,mili ;Ist die Anzeigennummer ungleich 1 springe nach mili MOV A,R3 ;Schreibe den berechneten Uhrzeitwert in den Akku CALL BCD7Seg ;Ruft Werte für BCD7Seg Anzeige auf MOV P1,A ;Gibt den im Akku gespeicherten Wert auf P1 aus MOV P2,#00001101b ;gibt die Anzeigenposition auf P2 aus mili: CJNE R0,#2,links ;Ist die Anzeigennummer ungleich 2 springe nach links MOV A,R4 ;Schreibe den berechneten Uhrzeitwert in den Akku CALL BCD7Seg ;Ruft Werte für BCD7Seg Anzeige auf MOV P1,A ;Gibt den im Akku gespeicherten Wert auf P1 aus MOV P2,#00001011b ;gibt die Anzeigenposition auf P2 aus links: CJNE R0,#3,m1 ;Ist die Anzeigennummer ungleich 3 springe nach m1 MOV A,R5 ;Schreibe den berechneten Uhrzeitwert in den Akku CALL BCD7Seg ;Ruft Werte für BCD7Seg Anzeige auf MOV P1,A ;Gibt den im Akku gespeicherten Wert auf P1 aus MOV P2,#00000111b ;gibt die Anzeigenposition auf P2 aus m1: RET ;Rücksprung aus dem Unterprogramm ; Wandelt vom BCD-Code in den 7-Segment-Code BCD7Seg: INC A MOVC A,@A+PC RET DB 3Fh, 06h, 5Bh, 4Fh, 66h, 6Dh, 7Dh, 07h, 7Fh, 6Fh END
> Da ich immernoch einen Drang habe eine bessere Note zu erreichen, > frage ich mich ob es nicht möglich wäre statt den Minuten und den > Sekunden, die Sekunden und die Hundertstel auszugeben. > Wie wäre das mit meinem Programm realisierbar? Natürlich. Es ist aber an der Zeit, dass du selbst anfängst nachzudenken. Die Änderungen sind trivial sobald du verstanden hast was bei einer Uhr die Hunderstel/Sekunden anzeigt anders ist als bei einer die Minuten/Sekunden anzeigt. Hinweise: Wenn 59 Sekunden vergangen sind, was passiert dann? Muss dasselbe auch passieren wenn 59 Hunderstel Sekunden vergangen sind?
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.