Forum: Mikrocontroller und Digitale Elektronik Timer1 16 Bit Modus ohne Autoreload; Programmfunktion Uhr


von Ertan M. (drbrain)


Lesenswert?

Hallo zusammen ich habe ein riesen Problem und einige Fragen zu meinem 
Assembler Programm. Programmfunktion Uhr mit Überlauferkennung

1)Frage

worin liegt der Unterschied zwischen den Befehelen mov a,xx und mov 
a,#xx
was bewirkt dieses Raute Zeichen bei der Zuweisung ?
diese Frage stelle ich nicht umsonst weil ich im Unterprogramm 
LCD_Zeitausgabe (s.u) keine LCD Ausgabe bekomme wenn die den Akkumulator 
mit mov a,#xx fülle folgendes wird dann auf dem Display gezeigt 
[124:125:126] und ohne dieses Rautezeichen bekomme ich das ewünschte 
Ergebnis.


2)Frage
wenn ich meine Zeitvariablen mit anderen Werten initialisiere z.B.
mov Minuten,#10
mov Stunden,#5
mov Sekunden,#1

startet die Uhr immer noch bei 00:00:00 wieso ?
was muss ich machen um die mit den vorinitialisierten Werten die Uhr 
starten zu lassen ?


3)Frage
wenn ich meinen Controllerboard resete dauert es ungefähr 5 Sek bis die 
Uhr anfängt loszulaufen wieso ?
jedoch wenn ich nach dem init:
[main: sjmp main] reinmache läuft die Uhr bei reset sofort los !


4) Überlauferkennung funktioniert jetzt auch nicht mehr :-(



include c51ed2.inc

Extern Code 
initLCD,loeschen,loeschzeile1,loeschzeile2,textzeile1,textzeile2,cursorp 
os,cursoran,cursoraus
Extern Code 
textaus,zifferaus,hexaus,dezaus,dualaus,dualaus1,dualaus2,charaus
Extern Code 
definierezeichen,loeschzeile3,loeschzeile4,textzeile3,textzeile4


Stunden  equ 07ch  ; Variablen im Internen RAM anglegen direkt unter dem 
SFR Register
Minuten  equ 07dh  ; Speicherbereich geht von 00h 007FH
Sekunden equ 07Eh
Zaehler  equ 07Fh

; Konstanten definieren
Takt equ 12000000 ; Systemtakt 12 Mhz. s.Datenblatt
Perioden equ 12   ; 12 Perioden auf 6 Zyklen verteilt
TMR_SEC equ Takt/Perioden ; benötigte Zeit um ein Befehl ausführen zu 
können Maschinenzyklus
Nachladewert equ 15536 ; Timer Nachladewert Autoreload

org 000h


lcall initLCD              ; LCD wird initialisiert
lcall loeschen             ; LCD Display wird gelöscht

ljmp init

org 001bh                  ; Einsprugsadresse für ISR Timer1 Überlauf
push acc                   ; Akkumulator wird im Stack gesichert
push psw                   ; Programm Status Word wird im Stack 
gesichert
CLR TR1                    ; Timer1 wird (TCON Register) abgeschalten um 
nachladen zu können s.u
mov TH1,#High Nachladewert ; High Byte von Timer1 wird geladen
mov TL1,#Low  Nachladewert ; Low  Byte von Timer1 wird geladen
Setb TR1                   ; Timer1 wird wieder gestartet da der Low und 
High Register nachgeladen wurde

DJNZ Zaehler,Exit          ; Springt zu Exit wenn der Zaehler ungleich 0 
ist
mov Zaehler,#20            ; Zaehler wird wieder nachgeladen da 1 
Sekunden erreicht wurde Rechnung: 50000 Zaehlung = 0.05 Sekunden *20 = 
Sekunde ist
inc Sekunden               ; erhöht den Inhalt von Sekunden um Wert 1
mov a,#Sekunden            ; kopiert den Inhalt von Sekunden in den 
Akkumulator
CJNE a,#60,Exit            ; vergleicht den Inhalt von von Akkumulator 
mit der Konstanten 60 und verzweigt bei ungleichheit
mov Sekunden,#0            ; der Inhalt von Sekunden wird auf 0 gesetzt 
da 60 Sekunden vergangen sind
inc Minuten                ; erhöht den Inhalt von Minuten um den Wert 1
mov a,#Minuten             ; kopiert den Inhalt von Minuten in den 
Akkumulator
CJNE a,#60,Exit            ; vergleicht den Inhalt von von Akkumulator 
mit der Konstanten 60 und verzweigt bei ungleichheit

mov Minuten,#0             ; der Inhalt von Minuten wird auf 0 gesetzt 
da 60 Minute vergangen sind
inc Stunden                ; erhöht den Inhalt von Stunden um den Wert 1 
da 60 Minuten vergangen sind
mov a,#Stunden             ; kopiert den Inhalt von Stunden in den 
Akkumulator
CJNE a,#24,Exit            ; vergleicht den Inhalt von Akkumulator mit 
der Konstante 24 und verzweigt bei ungleichheit
mov Stunden,#0             ; setzt den Wert von Stunden 0, da 24 Stunden 
vergangen sind.
Exit:
call LCD_Zeitausgabe       ;
pop psw                    ; Programm Status Word wird wieder vom Stak 
hergestellt
pop acc                    ; Akkumulator wird wieder vom Stack 
hergestellt
reti                       ; Interrupt Service Routine wird wieder 
verlassen


init:
mov TH1,#High Nachladewert ; High Byte von Timer1 wird geladen
mov TL1,#Low  Nachladewert ; Low  Byte von Timer1 wird geladen
mov TMOD,#00010000b        ; Timer 1 im Modus 1 {16 Bit Timer ohne Auto 
Reload wird aktiviert}
Setb TR1                   ; Timer1 wird aktiviert bzw. gestartet
mov Stunden,#0             ; Variable Stunden im internen RAM wird 
initialisiert  s.o
mov Minuten,#0             ; Variable Minuten im internen RAM wird 
initialisiert  s.o
mov Sekunden,#0            ; Variable Sekungen im internen RAM wird 
initialisiert s.o
mov Zaehler,#20            ; Variable Zaehler im internen RAM wird 
initialisiert s.o
Setb ET1                   ; Timer1 Überlauf wird aktiviert
Setb EA                    ; Globale Freigabe für die Interrupts im IEN0 
Interrupt Enable Register



;main:

;sjmp main

LCD_Zeitausgabe:
push acc
push psw
mov dptr,#text            ; Datenpointer auf doppelpunkt
mov a,#00                 ; Akkumulator wird auf 1 gesetzt
lcall cursorpos           ; Cursorposition LCD wird auf 0 gesetzt
mov a,Stunden             ; in den Akkumulator wird der Inhalt von 
Stunden geschrieben
lcall dezaus              ; Stunden wird auf dem Display angezeigt
mov a,#04                 ; Akkumulator wird auf 5 gesetzt
lcall cursorpos           ; Cursorposition wird auf 05
lcall textaus             ; Doppelpunkt wird eingefügt
mov a,Minuten             ; in den Akkumulator wird der Inhalt von 
Minute geschrieben
lcall dezaus
mov a,#9                  ; Akkumulator wird auf 10 gesetzt
lcall cursorpos
lcall textaus             ; doppelpunkt wird auf Position ausgegeben
mov a,Sekunden            ; in den Akkumulator wird der Inhalt von 
Sekunden geschrieben
lcall dezaus              ; Stunden wird auf dem Display angezeigt
text:  db ':',0
pop psw
pop acc
ret


end.

von Ulrich P. (uprinz)


Lesenswert?

Also wenn man schon so große Anfragen startet, sollte man das Klein 
Gedruckte mitschicken. Was für einen Controller verwendest Du denn?

Bei mov A,#30 kopierts Du den Inhalt von Adresse 30 in den Akku. Bei mov 
A,30 schreibst Du eine 30 in den Akku. Das wird vermutlich Dein Problem 
sein. Du verwechselst da was. Da ich aber nicht weiß, was für einen 
Controller Du verwendest, kann es ganuso gut auch umgekehrt sein. Schau 
also einfach mal in die passende Doku Deines Chips.

Warum das ganze bei Reset so langsam startet ist eigentlich klar. Du 
startest des Code irgendwo und es ist kein Reset-Vector definiert. Du 
solltest mal herausfinden, wo Dein Prozessor seinen Reset ansetzt. Dann 
definierst du mit org RESET_VECTOR ( << ersetzen durch adresse des 
vecors) und darunter ein LJMP main was der Prozessor beim Start machen 
soll.
In Deinem Fall ist es halt so, dass der Proz losrennt und vermutlich 90% 
seines Speichers voller 0xFF abgrast, bis er zufällig durch Deinen Code 
rennt. Oder er startet die LCALLs von Deiner Software vor der main, die 
vermutlich erst einmal einige Konfigurationen trifft, bevor das LCD und 
so initialisiert werden sollen.

Du hast da gedanklich einen Mix zwischen Assembler und C hingelegt. In 
den Prozessorspezifischen Libs ist diese Startup-Init und die 
bereitstellung der Vecoren für Reset und Interrupts integriert und sie 
werden als Namen bereit gestellt. Das muss man in Assembler eben alles 
von Hand machen.
Es gibt aber auch fertige Includes, die diese Vectoren für den Assembler 
bereits mit Namen versehen und die kompletten Tabellen bevorraten. Alles 
was man dann noch machen muss, ist die Vectoren mit den ziel-Tokens 
versehen.

Gruß, Ulrich

von Bernhard M. (boregard)


Lesenswert?

Loslaufen sollte es fast richtig:
1
org 000h
2
3
4
lcall initLCD              ; LCD wird initialisiert
5
lcall loeschen             ; LCD Display wird gelöscht
6
7
ljmp init
bei 8051 code (und so siehts aus...) liegt der reset Vector bei 0000h. 
Allerdings wird hier ein lcall gemacht, ohne daß der Stackpointer 
initialisiert wurde...

Dann sind in dem Programm ständig Fehler bei den Addressierarten:
1
mov a,#Stunden             ; kopiert den Inhalt von Stunden in den Akkumulator
2
CJNE a,#24,Exit            ; vergleicht den Inhalt von Akkumulator mit der Konstante 24 und verzweigt bei ungleichheit
3
mov Stunden,#0             ; setzt den Wert von Stunden 0, da 24 Stunden
schreibt die Adresse von "Stunden" (wg. #, als 07Ch) in den Akku und 
vergleicht dann den Akku mit 24....

Lesbar ist es so wie gepostet auch kaum...

von R. W. (quakeman)


Lesenswert?

Ulrich P. wrote:
> Bei mov A,#30 kopierts Du den Inhalt von Adresse 30 in den Akku. Bei mov
> A,30 schreibst Du eine 30 in den Akku. Das wird vermutlich Dein Problem
> sein. Du verwechselst da was. Da ich aber nicht weiß, was für einen
> Controller Du verwendest, kann es ganuso gut auch umgekehrt sein. Schau
> also einfach mal in die passende Doku Deines Chips.

Nach dem Beispielcode von Ertan Metin zu urteilen ist es ein 8051 
kompatibler Controller. Und bei diesen ist das mit der # genau 
umgedreht. ;)

Bei mov A,#30 wird der Wert 30 in den Akku geladen.
Bei mov A,30 wird der Ram-Inhalt von Adresse 30 in den Akku geladen.

Ciao,
     Rainer

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
Noch kein Account? Hier anmelden.