Forum: Mikrocontroller und Digitale Elektronik Anfängerproblem Assembler 8052


von Pohl (Gast)


Angehängte Dateien:

Lesenswert?

Hallo alle Zusammen,

erstmal vorweg, ich bin absoluter Anfänger was Assembler-Programmierung 
angeht und dies ist mein 1. "Projekt" an dem ich Arbeite.

Ich habe hier einen auf dem 8052 basierenden Mirkocontroller (genauer 
gesagt, dieses Teil: 
[[http://eitidaten.fh-pforzheim.de/daten/labore/mclt/pdf/TeachDongle.pdf]])

Jedenfalls habe ich vor, dafür einen Countdown/Timer mit folgenden 
Funktionen zu schreiben:
- Anzeige auf Display im HH:MM:SS format.
- Mit Taste1 soll die "zu bearbeitende" Cursor Position ausgewählt 
werden können.
- Mit Taste2 soll der Wert festgelegt(um 1 erhöht) werden können 
(Countdown-Zeit)
- Taste3 ist zum Starten/Stoppen gedacht.
- Wenn die Zeit bei 0 angelangt sollte am besten noch irgendein 
Signal(Visuell) ausgegeben werden

Lange Rede kurzer Sinn, hier mal kurz das relevante aus meinem aktuellen 
Code für meine unten folgende Frage:
1
;Hier steht meine Timer-Fkt, die im Sekundentakt die Sekunden bzw. ggf. ;Minuten/Stunden erhöht.
2
;Das meine Timer-Fkt momentan noch hochwärts zählt ist erstmal nicht ;relevant
3
4
_Main:
5
6
MOV TH1,#HIGH RESET_VALUE ;Initialize timer high-byte
7
MOV TL1,#LOW RESET_VALUE  ;Initialize timer low-byte
8
MOV TMOD,#10h             ;Set timer 1 to 16-bit mode
9
SETB TR1                  ;Start timer 1 running
10
MOV HOURS,#00             ;Initialize to 0 hours
11
MOV MINUTES,#00           ;Initialize to 0 minutes
12
MOV SECONDS,#00           ;Initialize to 0 seconds
13
MOV TICKS,#20             ;Initialize countdown tick counter to 20
14
SETB EA                   ;Initialize interrupts
15
SETB ET1                  ;Initialize Timer 1 interrupt
16
17
18
;"Ausgabe"                 ;====================
19
20
lcall _LCD_INI
21
lcall _CLEAR_LCD
22
mov a, #HOURS
23
mov a, #':'                ; HIERZU MEINE FRAGE
24
call _LCD_OUT
25
mov a, #MINUTES
26
mov a,#':'
27
call _LCD_OUT
28
mov a,#SECONDS
29
                           ;====================
30
31
;====== LCD-Ausgabe ===================================
32
; Sorgt für die Ausgabe & das die Courser Position 1. nach rechts springt
33
_LCD_OUT:
34
push Acc
35
mov DPTR,#pDispS
36
MOV A,#06h        
37
movx @dptr,A
38
CALL _Delay_K       ; 4.1 ms
39
pop Acc
40
mov DPTR,#pDispD        
41
movx @dptr,A
42
CALL _Delay_L                   ; 10 ms
43
ret
44
;Hier kommt noch Code der lediglich für die Initialisierung des Displays ist.
/dies ist nur ein Code-Ausschnitt, der Komplette Code befindet sich im 
Anhang./

Meine eigentlich Frage bezieht sich auf die Ausgabe. Und zwar soll ja 
die Zeit wie oben genannt in diesem(HH:MM:SS) Format angezeigt werden.
Was aber bei aktuellen Code angezeigt wird ist lediglich "::". Ich habe 
keine Idee, wie ich es hinbekomme meine Variablen (HOURS, MINUTES, 
SECONDS) angezeigt zu bekommen.

Ich hoffe hier kann mir jemand weiterhelfen.


mfg
Pohl

:
von Spess53 (Gast)


Lesenswert?

Hi

>mov a, #HOURS
>mov a, #':'                ; HIERZU MEINE FRAGE
>call _LCD_OUT

Was meinst du, welchen Wert der Akkumulator beim Aufruf vom _LCD_OUT 
hat?

MfG Spess

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Spess53 schrieb:
> Was meinst du, welchen Wert der Akkumulator beim Aufruf vom _LCD_OUT
> hat?
Aber auch das Einfügen des Funktionsaufrufs wird nicht weiterhelfen:
1
:
2
mov a, #HOURS
3
call _LCD_OUT   ; Stunden ausgeben
4
mov a, #':'  
5
call _LCD_OUT
6
:
Denn LCD_OUT gibt genau 1 Zeichen aus. Die Stunden, Minuten und Sekunden 
haben aber je 2 Zeichen...  :-o

Pohl schrieb:
> wie ich es hinbekomme meine Variablen (HOURS, MINUTES,
> SECONDS) angezeigt zu bekommen.
Es ist sehr ungünstig, hier die Stunden, Minuten und Sekunden  von 
0..23/59 zu zählen, denn anschliessend musst du diese zweistelligen 
Dezimalzahlen in zwei einzelne Stellen für die Ausgabe umrechnen.

Überaus Einfach wird es, wenn du diese Variablen hast:
StdZehner
StdEiner
MinZehner
MinEiner
SekZehner
SekEiner

Dann sieht dein Code nämlich so aus:
1
:
2
mov a, #StdZehner
3
call _LCD_OUT   
4
mov a, #StdEiner
5
call _LCD_OUT   
6
mov a, #':'  
7
call _LCD_OUT
8
:

Und: das ist eigentlich ein sehr einfacher Fehler. Da könnte man mit ein 
wenig Nachdenken (Frage: wie kommt ein Zeichen aufs Display?) 
tatsächlich selber draufkommen...

von Spess53 (Gast)


Lesenswert?

HI

>Dann sieht dein Code nämlich so aus:

>:
>mov a, #StdZehner
>call _LCD_OUT
>mov a, #StdEiner
>call _LCD_OUT
>mov a, #':'
>call _LCD_OUT
>:

Funktioniert auch nur, wenn in ASCII gezählt wird. Oder vor der Ausgabe 
noch mal 0x30 zu a addieren.

Es gib noch andere Fehler:

...
call _LCD_OUT
mov a,#SECONDS
;====== LCD-Ausgabe ===================================
; Sorgt für die Ausgabe & das die Courser Position 1. nach rechts 
springt
_LCD_OUT:
push Acc
....
CALL _Delay_L                   ; 10 ms
ret

Das wird unweigerlich zum Absturz führen.

MfG Spess

von Wilhelm F. (Gast)


Lesenswert?

Lothar Miller schrieb:

> Es ist sehr ungünstig, hier die Stunden, Minuten und Sekunden  von
> 0..23/59 zu zählen, denn anschliessend musst du diese zweistelligen
> Dezimalzahlen in zwei einzelne Stellen für die Ausgabe umrechnen.
>
> Überaus Einfach wird es, wenn du diese Variablen hast:
> StdZehner
> StdEiner
> MinZehner
> MinEiner
> SekZehner
> SekEiner

OK, das ist für einen Beginner erst mal übersichtlicher. Ansonsten 
spricht doch nichts dagegen, eine zweistellige BCD-Zahl in einem Byte zu 
lassen, denn es spart Speicher.

Dafür gibt es dann z.B. die Befehle PUSH ACC und SWAP ACC, ANL A, #0Fh, 
um das Byte leicht in Halbbytes zu zerlegen. So jedenfalls mache ich es 
meistens.

Wenn man sehr viele Zahlen in einem Programm hat, dann lohnt es sich 
auch, eine Funktion BIN_TO_BCD einmalig im Code zu installieren, und 
grundsätzlich nur mit Binärzahlen zu rechnen. Das ist dann noch 
platzsparender.

Aber, Assembler bringt auf jeden Fall Spaß mit Dingen, die man in der 
Hochsprache nicht mehr hat.

von Pohl (Gast)


Lesenswert?

Erstmal herzlichen Dank für die Antworten.

>Denn LCD_OUT gibt genau 1 Zeichen aus. Die Stunden, Minuten und Sekunden
>haben aber je 2 Zeichen...

Das klingt natürlich überaus logisch. Hab es gleichmal umgeschrieben.

Jetzt sieht das Ganze tatsächlich so aus:
1
:
2
mov a, #HZehner
3
call _LCD_OUT
4
mov a, #HEiner
5
call _LCD_OUT
6
mov a, #':'
7
call _LCD_OUT
8
mov a, #MZehner
9
call _LCD_OUT
10
:

Und meine Ausgabe so:
"|x:)x:<-x"    (x ist hierbei leer/nichts)

Da ist ja offensichtlich immernoch der Wurm drin.
Ich als laie würden den Fehler in meinem Code für den Timer vermuten.
Allerdings sollte ja hierduch:
1
:
2
MOV HZehner,#0            ;Initialize to 0 HZehner
3
MOV HEiner,#0             ;Initialize to 0 HEiner
4
MOV MZehner,#0            ;Initialize to 0 MZehner
5
MOV MEiner,#0             ;Initialize to 0 MEiner
6
MOV SZehner,#0            ;Initialize to 0 SZehner
7
MOV SEiner,#0
8
:
wenigstens ganz zu beginn die Anzeige auf "00:00:00" stehen?!

Nun habe ich vermutet, dass diese Initialisierung fehlerhaft ist.
Wenn ich allerdings
1
:
2
MOV HEiner,#'0'
3
:
schreibe, hätte ich schätzungsweise die richtige Ausgabe, aber meinen 
Wert ja nicht initializiert.
Wenn ich
1
:
2
MOV HEiner,#30h  ; Meines Wissens nach ASCII 0
3
:
schreibe, verändert sich aber bei der Ausgabe auch nichts:
"|x:)x:<-x"    (x ist hierbei leer/nichts)

von Wilhelm F. (Gast)


Lesenswert?

@Pohl:

Du könntest es, wie von mir schon angedeutet, folgendermaßen machen, 
wenn du zwei Ziffern in einem Byte hast, bspw. Minuten:

1
LCD_CHAR:                       ; ASCII ACC --> LCD-RAM-AREA
2
        MOV     @R0,A           ; Adresse in R0
3
        INC     R0              ; Auto-Inkrement RAM-Zeiger
4
        RET
5
6
LCD_BLANK:
7
        MOV     A,#' '          ; Sende ein Leerzeichen
8
        SJMP    LCD_CHAR
9
10
LCD_BYTE:
11
        PUSH    ACC             ; sende BYTE hexadezimal,
12
        SWAP    A               ; ACC wird zerstoert
13
        ACALL   LCD_NIBBLE
14
        POP     ACC
15
LCD_NIBBLE:                     ; LCD-Ausgabe 1 Zeichen 0..F
16
        ANL     A,#0x0F
17
        ADD     A,#246
18
        JC      LCD_HEXOUT
19
        ADD     A,#58
20
        SJMP    LCD_CHAR
21
LCD_HEXOUT:
22
        ADD     A,#65
23
        SJMP    LCD_CHAR


Die Funktion LCD_BYTE verarbeitet beide Halbbytes in einem Byte 
nacheinander.

Die Funktion LCD_CHAR ist bei mir die Ausgabe ans Display, aber sie 
schreibt erst mal nur in ein Spiegel-RAM. Woanders wird dann das gesamte 
Display in einem Zug komplett geschrieben. Das hat den Hintergrund, daß 
ich schlechte Erfahrungen damit habe, hier und da am Display mal ein 
Zeichen zu schreiben. Seitlich betrachtet traten am Display 
Flimmereffekte auf. Die verschwinden, wenn man immer nur das gesamte 
Display in einem Rutsch beschreibt.

Das fand ich in einem Buch zu einem µC-Projekt von 1987 mal. Schon ein 
Viertel Jahrhundert alt.

von Pohl (Gast)


Lesenswert?

@Ferkes

vielen Dank für deine Mühe. Ich versteh zwar, was du mir sagen willst 
und den Sinn dahinter..aber nicht sehr viel von dem Code und noch 
weniger davon, wie ich das bei mir einbauen soll.
Nimm mir das bitte nicht übel, ist wie gesagt, mein 1. Projekt.
Ich wäre schonmal ziemlich froh, wenn ich nur meine einfach Varianten 
zum funktionieren bekommen würde.

von Wilhelm F. (Gast)


Lesenswert?

Pohl schrieb:

> @Ferkes
>
> vielen Dank für deine Mühe. Ich versteh zwar, was du mir sagen willst
> und den Sinn dahinter..aber nicht sehr viel von dem Code und noch
> weniger davon, wie ich das bei mir einbauen soll.

Der ist doch nun wirklich total simpel, übersichtlicher gehts kaum noch.

Notfalls nimm dir ein Blatt Papier, ein Stapel Druckerpapier kostet ja 
heute nix, und simuliere einen Programmteil schrittweise auf Papier. So 
lernte ich das in EDV im Studium, Objekt war der olle 8085.

Man trägt oben in Spalten die betreffenden Register ein, deren Werte und 
Änderungen man haben möchte, und trägt nach jeder Befehlszeile die neuen 
Werte der Register in der darunter liegenden Zeile ein. Handsimulation, 
wenn man keinen echten Simulator auf dem PC hat. Es ist ein wenig 
Schreibarbeit, aber das ist zum Erfolg schon nötig.

Kürzlich simulierte ich einen selbst entworfenen Bubble-Sort-Algorithmus 
noch so, da waren 5 Blatt Papier weg. Als ich ihn dann ins Programm 
einbaute, lief er prompt, wie erwünscht.

Man kommt dann leicht auch so Dingen auf die Spur, die ich oben sah. 
Z.B. als der Akkumulator überschrieben wurde. Da bekommt man aber auf 
Dauer einen Blick für.

> Nimm mir das bitte nicht übel, ist wie gesagt, mein 1. Projekt.

Nein, tue ich nicht. Ich nehme nur selten was übel, da muß man schon 
richtige Beleidigungen versuchen. So weit wie du jetzt war ich etwa 
1992, also vor 20 Jahren.

> Ich wäre schonmal ziemlich froh, wenn ich nur meine einfach Varianten
> zum funktionieren bekommen würde.

Das kommt noch, mit der Zeit und der Übung ergibt sich alles.

Bist du etwas weiter gekommen?

Aber wenn du Fragen hast, wir sind hier auf alle Fälle da.

von Peter D. (peda)


Lesenswert?

Du mußt die Zahl in Digits zerlegen.
Dafür hat der 8051 den "DIV AB" Befehl (B = 10). Das Ergebnis ist der 
Zener, der Rest der Einer.
Und dann #'0' dazu addieren, damit ASCII draus wird.

Du brauchst auch nicht extra die Zeichen weiter zu zählen, das kann das 
LCD selber. Einfach im LCD-Init den Mode so setzen.
Du bist der erste, der diesen Mode nicht nutzt.


Peter

von Wilhelm F. (Gast)


Lesenswert?

Peter Dannegger schrieb:

> Du mußt die Zahl in Digits zerlegen.
> Dafür hat der 8051 den "DIV AB" Befehl (B = 10). Das Ergebnis ist der
> Zener, der Rest der Einer.
> Und dann #'0' dazu addieren, damit ASCII draus wird.

Peter, das macht meine oben genannte Funktion LCD_BYTE. Sie macht aus 
zwei Nibbles in einem Byte den ASCII-Wert.

Da sind zwar komische Zahlen drin, aber schau mal, was da wirklich 
gemacht wird.

von Peter D. (peda)


Lesenswert?

Wilhelm Ferkes schrieb:
> Peter, das macht meine oben genannte Funktion LCD_BYTE. Sie macht aus
> zwei Nibbles in einem Byte den ASCII-Wert.

Nö, die gibt Hex aus.
Aus 59 wird dann "3B".
Als Mensch möchte man es doch lieber dezimal, also "59".


Peter

von Wilhelm F. (Gast)


Lesenswert?

Peter Dannegger schrieb:

> Wilhelm Ferkes schrieb:
>> Peter, das macht meine oben genannte Funktion LCD_BYTE. Sie macht aus
>> zwei Nibbles in einem Byte den ASCII-Wert.
>
> Nö, die gibt Hex aus.
> Aus 59 wird dann "3B".
> Als Mensch möchte man es doch lieber dezimal, also "59".
>
>
> Peter

Nein. Meine Funktion befindet sich augenblicklich in Programmen, und 
arbeitet völlig richtig. Bei Hex-Zahlen gibt sie Hex A bis F aus, und 
bei Dezimalzahlen 0 bis 9. Das ist doch nicht so schwer, oder?

von Bernd N. (Gast)


Lesenswert?

1
MOV HEiner,#30h  ; Meines Wissens nach ASCII 0
2
call _LCD_OUT

Das ist korrekt und sollte dir eine 0 (Null) auf das Display zaubern. 
Wenn das nicht funktioniert dann schau dir deine _LCD_OUT an.

von Peter D. (peda)


Lesenswert?

Wilhelm Ferkes schrieb:
> Meine Funktion befindet sich augenblicklich in Programmen, und
> arbeitet völlig richtig. Bei Hex-Zahlen gibt sie Hex A bis F aus, und
> bei Dezimalzahlen 0 bis 9.

Die Funktion kann nicht wissen, ob die Zahl hex oder dezimal ist, sie 
gibt immer hex aus.
Dein Trick wird daher sein, Du zählst anders.
Also nicht mit "INC Zahl", sondern mit:
1
  mov a, zahl
2
  add a, #1
3
  da  a          ; convert to packed-BCD addition
4
  mov zahl, a

In der Praxis ist es effektiver, die CPU immer binär rechnen zu lassen 
(ihr Lieblingsformat) und erst zur Ausgabe nach dezimal zu wandeln.
Mit "DIV AB" ist das auch einfacher und weniger Code.


Peter

von Wilhelm F. (Gast)


Lesenswert?

Peter, nochmal:

Im Byte wird ein Nibble ausgeblendet, und der Rest in 4 Bits kann immer 
nur eine Dezimalziffer oder Hexadezimalziffer sein.

Das kannst du jetzt mit mir rauf und runter diskutieren, da ergibt sich 
nichts anderes.

Meine Software läuft damit zur höchsten Zufriedenheit.

Probier mein Codebeispiel aus. Auf Papier, oder Simulator.

von Pohl (Gast)


Lesenswert?

Ich komm gerade nicht richtig weiter. Arbeite irgendwie an zwei 
Baustellen gleichzeitig und an keiner richtig.
Einmal die "einfache" Variante mit HZehner, HEiner, MZehner(...).
und dann noch die "bessere" Variante mit nur jeweils einer Variablen.

Mir persönlich ist die "einfache" Variante lieber, da ich bei ihr 
wenigstens mit gutem Gewissen behaupten kann, dass ich einigermaßen 
weiß, was ich tue ;)

Mehr hilfe bekomme ich hier aber für die "bessere" Version.

Jetzt nochmal kurz, damit ich weiß, dass nicht beide Baustellen an der 
falschen Stelle sind:
1
:
2
;====== Interrupt-Adressbereich ==========================================
3
org     1Bh
4
push    ACC
5
clr     TR1                ;Timer1 anhalten
6
mov     TH1, #HIGH ClkCnt  ;High-Teil Counter1
7
mov     TL1, #LOW  ClkCnt  ;Low -Teil Counter1
8
setb    TR1                ;Timer1 wieder starten
9
djnz    TICKS,EXIT_RTC     ;Decrement TICKS, if not yet zero we ;exit immediately
10
MOV     TICKS,#30          ;Reset the ticks variable
11
INC     SECONDS            ;Increment the second varaiable
12
MOV     A,SECONDS          ;Move the seconds variable into the ;accumulator
13
CJNE    A,#60,EXIT_RTC     ;If we haven't counted 60 seconds, we're done.
14
MOV     SECONDS,#0         ;Reset the seconds varaible
15
INC     MINUTES            ;Increment the number of minutes
16
MOV     A,MINUTES          ;Move the minutes variable into the ;accumulator
17
CJNE    A,#60,EXIT_RTC     ;If we haven't counted 60 minutes, we're done
18
MOV     MINUTES,#0         ;Reset the minutes variable
19
INC     HOURS              ;Increment the hour variable
20
EXIT_RTC:
21
POP     PSW                ;Restore the PSW register
22
POP     ACC                ;Restore the accumulator
23
RETI                       ;Exit the interrupt routine                               
24
:
25
_Main:
26
mov     TH1, #HIGH ClkCnt  ;High-Teil Counter1
27
mov     TL1, #LOW  ClkCnt  ;Low -Teil Counter1
28
mov     TMOD,#10h          ;Konfiguration Timer1 als 16bit Counter
29
setb    TR1                ;Starte Timer 1
30
MOV     HOURS,#00          ;Initialize to 0 hours
31
MOV     MINUTES,#00        ;Initialize to 0 minutes
32
MOV     SECONDS,#00        ;Initialize to 0 seconds
33
MOV     TICKS,#30          ;Initialize countdown tick counter to 30
34
setb    ET1                ;Erlaube Timer 1 Interrupt
35
setb    EA                 ;Erlaube global Interrupts
36
:
Dieser Teil sollte ja ordnungsgemäß funktionieren und meine 
Sekunden/Minuten/Stunden entsprechen erhöhen. Oder hab ich hier schon 
einen Fehler eingebaut?!

von Spess53 (Gast)


Lesenswert?

Hi

>Oder hab ich hier schon einen Fehler eingebaut?!

8052 kenne ich eigentlich nicht wirklich. Aber was mir bei dem Code 
auffällt:

push    ACC    <<
clr     TR1
.....
EXIT_RTC:
POP     PSW    <<
POP     ACC    <<
RETI

So etwas bereitet im allgemeinen Probleme.

MfG Spess

von Peter D. (peda)


Lesenswert?

Wilhelm Ferkes schrieb:
> Probier mein Codebeispiel aus. Auf Papier, oder Simulator.

Auch der Simulator bleibt dabei.
Mit dem Aufruf:
1
        mov     r0, #40h
2
        mov     a,  #59
3
        call    lcd_byte
steht an 40h: 3 und 41h: B


Peter

von Wilhelm F. (Gast)


Lesenswert?

Dann hast du im Akku 59 binär drin stehen. Also 0x3B. Sowas doofes aber 
auch! Wenn schon, dann 059H, oder 0x59.

Meinetwegen auch 0xAF. Wenn ich AF auf dem Display ausgeben möchte.

von Peter D. (peda)


Lesenswert?

Wilhelm Ferkes schrieb im Beitrag #2818950:
> Du kannst den Assembler nicht!

Nö, mache ich ja auch erst seit 1991.

Hier nochmal das komplette Testprogramm mit Deiner Routine:
1
        mov     r0, #40h
2
        mov     a,  #59
3
        call    lcd_byte
4
        jmp     $
5
LCD_CHAR:                       ; ASCII ACC --> LCD-RAM-AREA
6
        MOV     @R0,A           ; Adresse in R0
7
        INC     R0              ; Auto-Inkrement RAM-Zeiger
8
        RET
9
LCD_BYTE:
10
        PUSH    ACC             ; sende BYTE hexadezimal,
11
        SWAP    A               ; ACC wird zerstoert
12
        ACALL   LCD_NIBBLE
13
        POP     ACC
14
LCD_NIBBLE:                     ; LCD-Ausgabe 1 Zeichen 0..F
15
        ANL     A,#0Fh
16
        ADD     A,#246
17
        JC      LCD_HEXOUT
18
        ADD     A,#58
19
        SJMP    LCD_CHAR
20
LCD_HEXOUT:
21
        ADD     A,#65
22
        SJMP    LCD_CHAR
23
end
Ergebnis: 40h: '3', 41h: 'B'
Und nun sage nicht, der Simulator lügt.

Hier dagegen ein funktionierendes Programm:
1
        mov     r0, #40h
2
        mov     a,  #59
3
        call    lcd_val
4
        jmp     $
5
lcd_val:
6
        mov     b, #10
7
        div     ab              ; a: tens, b: ones
8
        call    lcd_digit
9
        mov     a, b
10
lcd_digit:
11
        add     a,  #'0'        ; number to ASCII
12
LCD_CHAR:                       ; ASCII ACC --> LCD-RAM-AREA
13
        MOV     @R0,A           ; Adresse in R0
14
        INC     R0              ; Auto-Inkrement RAM-Zeiger
15
        RET
16
end
Ergebnis: 40h: '5', 41h: '9'


Peter

von Wilhelm F. (Gast)


Lesenswert?

Peter, probier meine Beispiele, die lange funktionieren.

Ich bin hier für Bullshit nicht bereit.

von Peter D. (peda)


Lesenswert?

Wilhelm Ferkes schrieb:
> Dann hast du im Akku 59 binär drin stehen. Also 0x3B. Sowas doofes aber
> auch!

Ja was denn sonst?
"INC Sekunde" zählt nunmal von 0 bis 59 dezimal, also von 0x00 .. 0x3B 
hex.
Das ist nicht doof, sondern ganz normales Zählen einer CPU.

Wilhelm Ferkes schrieb:
> Wenn schon, dann 059H, oder 0x59.

Das ist wirklich doof.
Wenn Du anders zählst, dann sag es doch auch.
Dazu brauchst Du aber spezielle Zählroutinen, die ein anderes Format 
benutzen. "INC" geht da nicht mehr.

von Pohl (Gast)


Lesenswert?

.
Nächste Frage: Hoffe die kann mir einer vielleicht beantworten.
1
:
2
MOV HZehner,#30h        ;2      
3
MOV HEiner,#0             
4
MOV MZehner,#0            
5
MOV MEiner,#0             
6
MOV SZehner,#0            
7
MOV SEiner,#0
8
MOV TICKS,#20           
9
SETB EA                   
10
SETB ET1                 
11
12
lcall _LCD_INI
13
lcall _CLEAR_LCD
14
mov a, #HZehner        ;1
15
call _LCD_OUT          ;3
16
:
17
_LCD_OUT:
18
push Acc
19
mov DPTR,#pDispS
20
MOV A,#06h        
21
movx @dptr,A
22
CALL _Delay_K       
23
pop Acc
24
mov DPTR,#pDispD        
25
movx @dptr,A
26
CALL _Delay_L         
27
ret 
28
:


Wenn ich das ganze mit dem Debugger durchgehe habe ich bei Markierung 1 
in a 0x01 stehen, anstatt 0x30. Wie kann das sein?
Das gleiche Ergebnis auchnoch, wenn ich bei Markierung 2 verschieden 
Versionen ausprobiere (mov HZehner, #0x30  ...)
und bei Markierung 3 dann in a sogar 0x6c, was im übrigen auch dem "l" 
entsrpicht, welches ich dann am Display angezeigt bekomme.
Ich verstehe einfach nicht, was da falsch läuft

von Wilhelm F. (Gast)


Lesenswert?

Peter Dannegger schrieb:
> "INC Sekunde" zählt nunmal von 0 bis 59 dezimal, also von 0x00 .. 0x3B
>
> hex.

Nein. Man muß bei einer Addition um 1 immer den Befehl "DA A" benutzen, 
damit die Zahl BCD bleibt. Damit wird eine 9 zur Null, und Carry oder 
Halfcarry sind gesetzt, machen dann einen BCD-gerechten Übertrag.

von Wilhelm F. (Gast)


Lesenswert?

Peter, du kannst mit mir diskutieren bis zum Erbrechen. Mein Programm 
mit Zahlenausgaben Ziffernausgaben dezimal oder hexadezimal läuft. 
Einwandfrei. Wenn dir was nicht passt, mußt du es nach simulieren, aber 
ich befürchte da nichts, weil meine Anwendung ja funktioniert.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Das Herumgebastle mit den BCD Zahlen wäre mir zu aufwendig. Ich würde 
die 6 Stellen einfach ASCII '0' bis ASCII '9' zählen, dann erübrigt sich 
jegliche Korrektur, weil schon die einzelnen Stellen den richtigen Wert 
haben...

von Wilhelm F. (Gast)


Lesenswert?

Lothar Miller schrieb:

> Das Herumgebastle mit den BCD Zahlen wäre mir zu aufwendig. Ich würde
> die 6 Stellen einfach ASCII '0' bis ASCII '9' zählen, dann erübrigt sich
> jegliche Korrektur, weil schon die einzelnen Stellen den richtigen Wert
> haben...

In größeren Assemlerprogrammen hat man eine Funktion installiert, die 
skalierbar beliebige Bytelängen von BIN nach BCD wandelt, und umgekehrt. 
Wo ist da das wirkliche Problem?

C rechnet intern auch nur binär, und der printf() wandelt BIN nach BCD. 
Der printf() ist an Laufzeit auch nicht zu unterschätzen.

von Pohl (Gast)


Lesenswert?

Lothar Miller schrieb:
> Das Herumgebastle mit den BCD Zahlen wäre mir zu aufwendig.

Danke, so nämlich auch meine Sicht.
Allerdings nochmal zu meiner letzten Frage:
1
:
2
MOV HZehner,#30h
3
:
4
mov a, #HZehner
5
:

Jetzt sollte doch in "a" 0x30 stehen?!
Stadessen steht da aber 0x01.

Ich würde mich sehr freuen, wenn mir jemand hierauf eine einfache 
Antwort geben könnte.

von Peter D. (peda)


Lesenswert?

Wilhelm Ferkes schrieb:
> Man muß bei einer Addition um 1 immer den Befehl "DA A" benutzen,
> damit die Zahl BCD bleibt.

Hatte ich ja oben schon vermutet:

Beitrag "Re: Anfängerproblem Assembler 8052"
"Dein Trick wird daher sein, Du zählst anders."

Du bist darauf aber in keinster Weise eingegangen.
Im Gegenteil, Du hast felsenfest behauptet, Deine Routine mache genau 
das gleiche, wie "DIV AB":

Beitrag "Re: Anfängerproblem Assembler 8052"
"Peter, das macht meine oben genannte Funktion LCD_BYTE."

Und das macht sie eben nicht.


Wilhelm Ferkes schrieb:
> In größeren Assemlerprogrammen hat man eine Funktion installiert, die
> skalierbar beliebige Bytelängen von BIN nach BCD wandelt

Macht aber auch schon in kleinen Programmen Sinn, statt extra 
Zählroutinen zu entwickeln.
Insbesondere, da es für 8Bit-Werte besonders einfach geht.


Peter

von Wilhelm F. (Gast)


Lesenswert?

Peter Dannegger schrieb:

> "Peter, das macht meine oben genannte Funktion LCD_BYTE."

> Und das macht sie eben nicht.

Mach es. Diese Funktion funktioniert bei mir seit Jahren. Du kannst sie 
nicht weg diskutieren.

von Pohl (Gast)


Lesenswert?

Seit mir nicht böse, aber könntet ihr eure ewige Diskussion vielleicht 
privat weiterführen, ich habe jedesmal die Hoffnung, jemand Antwortet 
auf meine Frage und dann sowas.

von Wilhelm F. (Gast)


Lesenswert?

Pohl schrieb:
> Seit mir nicht böse, aber könntet ihr eure ewige Diskussion vielleicht
> privat weiterführen, ich habe jedesmal die Hoffnung, jemand Antwortet
> auf meine Frage und dann sowas.

Sorry, Pohl, wenn mich jemand angreift, der keine Ahnung hat.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Pohl schrieb:
>
1
:
2
 MOV HZehner,#30h
3
 :
4
 mov a, #HZehner
>
> Jetzt sollte doch in "a" 0x30 stehen?!
> Stadessen steht da aber 0x01.
>
> Ich würde mich sehr freuen, wenn mir jemand hierauf eine einfache
> Antwort geben könnte.
Der Schlüssel liegt im #: das zweite Mal darf kein # da stehen...
Aber es wäre auch besser, HZehner nicht an Adresse 0x01 zu definieren...

von Peter D. (peda)


Lesenswert?

Pohl schrieb:
> Ich würde mich sehr freuen, wenn mir jemand hierauf eine einfache
> Antwort geben könnte.

Der #-Operator sagt dem Assembler, es ist eine Zahl.
Ohne # ist es eine Adresse.


Aber warum probierst Du ständig was anderes?
Es bringt nichts, wenn man planlos rumprobiert.

Dein erster Code war doch schon ganz gut.
Jetzt nur noch "DIV AB" benutzen, um die Zahl in 2 Ziffern zu zerlegen 
und fertig.
Siehe 2. Codebeispiel:
Beitrag "Re: Anfängerproblem Assembler 8052"

Und wenns läuft, dann noch das Auto-Increment des LCD einschalten und 
das manuelle Increment streichen.

Nochn Tip:
Wenn Du was änderst, dann poste den neuen gesamten Code als Anhang.
Es kostet Dich nichts und wir können alle Änderungen sehen.
Immer nur ein Schnipselchen zu sehen, ist ziemlich blöde. Das macht 
keinen Spaß.


Peter

von Pohl (Gast)


Angehängte Dateien:

Lesenswert?

Vielen Dank, ganz ganz langsam komm ich voran.
Habe mich inzwischen für die Variante mit Zehner/Einer entschieden.
1
:
2
mov   a, MZehner
3
call   _LCD_OUT
4
mov   a, MEiner
5
call  _LCD_OUT
6
mov   a,#':'
7
call   _LCD_OUT
8
mov   a,SZehner
9
call   _LCD_OUT
10
mov   a, SEiner
11
call   _LCD_OUT
12
;====== LCD-Ausgabe ;=========================================================
13
_LCD_OUT:
14
push   Acc
15
mov   DPTR,#pDispS
16
MOV   A,#06h        
17
movx   @dptr,A
18
CALL   _Delay_K       ; 4.1 ms
19
pop   Acc
20
mov   DPTR,#pDispD        
21
movx   @dptr,A
22
CALL   _Delay_L             ; 10 ms
23
ret 
24
:
In diesem abschnitt ist auch schon mein nächstes Problem
Die Ausgabe erfolgt jetzt fast richtig:
"00:00:0III" Warum er das aber bei letzten Stelle nicht richtig macht, 
ist mir ein Rätsel...
Hat das was damit zu tun, dass er die Sekunden ja direkt hochzählt?(Die 
Anzeige verändert sich aber auch nach mehreren Minuten nicht)

@Peter, diesmal hab ich auch den gesamten Code angehängt :-)


PS: langsam komm ich mir richtig blöd vor, weil ich hier ja so garnichts 
auf die Reihe bekomme.
Hab kurz mal versucht, das ganze in C zu machen, allerdings gestalltet 
sich da die Display-Initialisierung äusserst schwierig, da ich nur 
lcd-Steuer & Datenregisteradresse und keinerlei Port angaben für die 
Initialisierung des Displays habe(Warte da noch auf eine Mail) aber 
egal, ich will das jetzt in Assembler durchziehen.

von Peter D. (peda)


Lesenswert?

Sei doch nicht so schusselig.

Code läuft immer der Reihe nach ab.
Wenn Du was einfügst, wird es genau dort auch ausgeführt.
Unterfunktionen fügt man also nicht ein, sondern hängt sie an.
1
_Main:
2
; ...
3
call   _LCD_OUT      ; and after this call ???
4
;====== LCD-Ausgabe =========================================================
5
_LCD_OUT:
6
; ...
7
ret                  ; stack underflow
8
9
jmp _Ende            ; dead code (never reached)


Peter

von Peter D. (peda)


Lesenswert?

Pohl schrieb:
> Hab kurz mal versucht, das ganze in C zu machen, allerdings gestalltet
> sich da die Display-Initialisierung äusserst schwierig

Warum?

Du mußt die Adresse doch nur nach xdata casten, damit ein MOVX gemacht 
wird:
1
#define pDispS  0xF100        // Adresse LCD-Steueregister
2
#define pDispD  0xF101        // Adresse LCD-Datenregister
3
4
void lcd_control( char c )
5
{
6
  *(char xdata *)pDispS = c;
7
}
8
9
void lcd_data( char c )
10
{
11
  *(char xdata *)pDispD = c;
12
}


Peter

von Peter D. (peda)


Lesenswert?

Wilhelm Ferkes schrieb:
> Mach es. Diese Funktion funktioniert bei mir seit Jahren. Du kannst sie
> nicht weg diskutieren.

Du zählst ja auch im packed-BCD Format.

Wenn aber offensichtlich ist, daß der TO binär zählt, dann kannst Du ihm 
doch keine Ausgaberoutine andrehen, die nur packed-BCD kann.
Und dann noch behaupten "Passt scho".

Wie wenn jemand ein Wort aus dem Englischen übersetzten will und Du 
gibst im aber ein chinesisch Wörterbuch.
Er kann damit auch rein garnichts anfangen, um sein Problem zu lösen.
Da kannst Du noch so störrisch das Gegenteil behaupten.


Peter

von Pohl (Gast)


Lesenswert?

@Peter
/call   _LCD_OUT      ; and after this call ???/

Hat das einen Sinn, eine LCD_REFRESH Funktion zu schreiben und hier 
aufzurufen?
Muss ich so eine Funktion nicht sowieso früher oder später schreiben, 
damit sich auf dem display überhaupt was tut, oder ändert sich das 
automatisch, wenn die Variablen geändert werden?

von Peter D. (peda)


Lesenswert?

Pohl schrieb:
> @Peter
> /call   _LCD_OUT      ; and after this call ???/

Damit ist gemeint, Du rufst sie erst auf und läufst danach in sie 
hinein.

Das kann in Ausnahmefällen gewollt sein, aber definitiv nicht im Main.
Im Main gibt ein RET einen Stackunderflow, d.h. Du springst sonstwo hin.

Das Main darf nirgends nicht in ein RET hinein laufen!


Pohl schrieb:
> oder ändert sich das
> automatisch, wenn die Variablen geändert werden?

Nö, Magie gibt es beim Programmieren nicht.
Wenn Du in der Schule was ausgerechnet hast, dann erscheint das nicht 
magisch auf der Tafel.
Du mußt aufstehen, hingehen und es ran schreiben.

Die Ausgabefunktion muß also jedesmal aufgerufen werden, wenn was neues 
angezeigt werden soll.


Peter

von Pohl (Gast)


Angehängte Dateien:

Lesenswert?

Also ich komm mit dieser mircoController/Assembler Programmierung nicht 
auf einen grünen Zweig. Es hat einfach noch immer nicht CLICK in meinem 
Kopf gemacht.

Hab jetzt nochmal ein bisschen was verändert.
Was jetzt passiert.. die Anzeige kommt ordnungsgemäß im HH:MM:SS format 
und startet direkt mit dem Hochzählen. Hierbei aber noch ein paar 
Probleme.
Problem 1:
nach 00:00:09 folgt 00:00:11  // nach 00:00:19 folg 00:00:21  usw.
Problem 2:
Das ganze läuft etwas zu schnell, sprich nicht im Sekunden-Takt.
Schade, denn der Code-Teil, welcher für dies zuständig ist, ist der 
Teil, bei dem ich mir am Sichersten war, dass er korrekt funktioniert.
Problem 3:
Das ganze läuft Unkonstant, dh. manchmal wird am ende noch eine 
zusätzliche Ziffer angezeigt, manchmal startet es einfach von neu.
EDIT: Inzwischen läuft es konstant, schon bei 00:09:30 ohne Fehler 
yipieeh :-)
Problemchen 4:
So wie es jetzt ist, sieht das ganze sehr unschön aus, da nach jeder 
Sekunde die komplette Anzeige "neu aufgebaut" wird.

von Peter D. (peda)


Lesenswert?

Ja, wo soll man da anfangen.

Ausgabe im Interrupt ganz böses Foul. Ausgaben immer im Main. Sonst hast 
Du bei größeren Programmen mehrere LCD-Instanzen, d.h. ein 
Textdurcheinander.

Am besten machst Du die Zeitzählung auch im Main. Der Interrupt setzt 
nur ein Flag, daß eine Sekunde rum ist.
Ansonsten mußt Du alle Zeitbytes unter Interruptsperre zwischenspeichern 
(atomar), damit sie konsistent sind und dann diese Kopie ausgeben.

Und was soll die Ausgabe nach Sekundeneiner zählen?
Da kriegst Du natürlich Mist angezeigt.
Entweder vor oder nach der Zeitberechnung, aber nicht mittendrin.

Und LCD-Datenblatt lesen, Ausgaben dauern nicht 10ms, sondern etwa 50µs. 
Man muß die CPU doch nicht absichtlich ausbremsen.
Und schmeiß endlich das manuelle Increment raus. Du bist wirklich der 
einzigste, der es benutzt.

Das Flackern kommt vom LCD-Clear, daher benutzt das in der Praxis 
keiner. Man überschreibt einfach den alten Text mit dem neuen.
Das LCD-Init macht man natürlich auch nur einmal.


Peter

von Peter D. (peda)


Lesenswert?

Guck mal auf Seite 65 des ADuC832-Datenblattes.

Der MC hat doch schon einen fix und fertigen TIME INTERVAL COUNTER 
(TIC).
Das Ding enablen und die Register auslesen.
Einfacher gehts nun wirklich nicht.


Peter

von Pohl (Gast)


Lesenswert?

Wenn du wüsstest, wie viele Stunden ich schon hier reingesteckt habe und 
das dann mit meinem aktuellen code bzw können vergleichst, würdest du 
mich zweifellos für völlig zurückgeblieben halten.

Das mit dem TIC habe ich bereits ziemlich zu beginn gesehen gehabt, 
wusste damit aber nichts anzufangen.
Ich habe sogar ein beispiel-Programm für die TIC's des ADuC832, 
allerdings weiß weder ich noch mein Compiler (keilµVision3) was damit 
anzufangen.

von Bernd N. (Gast)


Lesenswert?

Was dir nicht gelingt ist dem Ganzen eine Struktur zu geben. Eigentlich 
brauchst du in "main" ja nur die Uhrzeit auszugeben. Vor der "main" 
machst du die Initialisierung etc. und in der ISR wird die Uhrzeit in 
deine Hilfsregister geschrieben.

Beispiel:
1
... Display Initialisieren
2
... Timer setzen
3
... etc etc.
4
5
_AUSGABE:  [Cursor an die Ausgabe Position des Displays]
6
    mov   a, HZehner
7
    call   _LCD_OUT
8
    mov   a, HEiner
9
    call   _LCD_OUT
10
    mov   a, #':'
11
    call   _LCD_OUT
12
    mov   a, MZehner
13
    call   _LCD_OUT
14
    mov   a, MEiner
15
    call  _LCD_OUT
16
    mov   a,#':'
17
    call   _LCD_OUT
18
    mov   a,SZehner
19
    call   _LCD_OUT
20
    mov   a, SEiner
21
    call   _LCD_OUT
22
    ljmp    _AUSGABE      ;endless loop

Ich hoffe du kommst dahinter. In Assembler geht alles der Reihe nach, 
eigentlich ganz einfach.

von Pohl (Gast)


Angehängte Dateien:

Lesenswert?

@Bernd vielen Dank, das hilft mir zumindest vom Verständnis schonmal 
sehr weiter und ich hab das auch direkt versucht im Code umzusetzen.

@Peter Hab meinen Code umgeschrieben und verwende jetzt den internen 
TIC.

Jetzt stimmt auch das Zählen im SekundenTakt.
So, wie ging das jetzt nochmal mit dem, dass wenn ich z.B. MIN als 
2-stellige Zahl hab diese dann ausgeben kann?
..wenn ich da nochmal nach oben in die alten Kommentar schaue..
werd ich wohl (z.B) MIN irgendwie mittels
1
div ab
in die Zehner und Einer aufspalten müssen.
Und/Oder eine neue LCD_OUT schreiben?!


Werd jetzt noch ein bisschen daran tüfteln, der Tag ist ja noch jung :-)

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Pohl schrieb:
> werd ich wohl (z.B) MIN irgendwie mittels   div ab
> in die Zehner und Einer aufspalten müssen.
Ja.
> Und/Oder eine neue LCD_OUT schreiben?!
Ja, und/oder diese Aufteilung dann dort reinpacken...

Oder (wie schon erwähnt) gleich im BCD-Format zählen. Dann musst du nur 
noch die beiden Nibbles mittels swap und Bitoperationen (Ausmaskieren) 
in die beiden Stellen (Zehner/Einer) zerlegen...

von Peter D. (peda)


Lesenswert?

Lothar Miller schrieb:
> Oder (wie schon erwähnt) gleich im BCD-Format zählen.

Ist beim TIC keine Option, das zählt binär.
Man kann nur auswählen, ob die Stunden bis 23 zählen oder bis 255.

Einfach mal im Befehlssatz die Beschreibung von "DIV AB" durchlesen, 
dann fällt einem die Lösung wie Schuppen von den Augen.


Peter

von Pohl (Gast)


Angehängte Dateien:

Lesenswert?

Hier mal meine div ab - Funktion, die könnte so funktionieren?!
1
LCD_Hour:
2
mov r0, 40h
3
mov a, Hour
4
call DIV_AB
5
ljmp Ausgabe
6
DIV_AB:
7
mov b,#10
8
div ab
9
call LCD_ASCII
10
mov a,b
11
LCD_ASCII:
12
add    a, #'0'
13
LCD_CHAR:
14
mov    @r0,a
15
inc    r0
16
ret
Frage 1: Die Funktion ist wie sie ist, doch eine Endlosschleife? sie 
soll aber doch nur 2mal ausgeführt werden, oder täusche ich mich?!
Frage 2: Wie baue ich das ganze in mein LCD_OUT ein?
1
_LCD_OUT:
2
push   Acc
3
mov   DPTR,#pDispS
4
MOV   A,#06h        
5
movx   @dptr,A
6
CALL   _Delay_K       ; 4.1 ms
7
pop   Acc
8
mov   DPTR,#pDispD        
9
movx   @dptr,A
10
CALL   _Delay_K             ; 10 ms
11
ret

von Pohl (Gast)


Angehängte Dateien:

Lesenswert?

EDIT:
Habs hinbekommen. Funktioniert jetzt.

So, jetzt brauch ich noch die ganze Button-belegung,
1button: cursorposition
2button: aktuelle cursorposition um 1 erhöhen (Zeit einstellen)
3button: start/stop.


Für jegliche Tipps, bin ich sehr dankbar.


Achja, das ganze sollte dann natürlich noch rückwärts laufen...

von Pohl (Gast)


Angehängte Dateien:

Lesenswert?

Code ist jetzt wesentlich kürzer und besser kommentiert, hoffe damit 
fällt das helfen vielleicht leichter.

Für meine Buttons hab ich folgendes geschrieben:
1
:
2
Ausgabe:
3
jb button1, next1     ; springe zu next1, wenn button1 nicht gedrückt
4
;noch keine funktion
5
next1:
6
jb button2, next2     ; springe zu next2, wenn button2 nicht gedrückt
7
mov a, hour         ; schiebe hour in a
8
inc a           ; erhöhe a um 1 (und damit auch hour?!)
9
;sollte sich später der cursorposition anpassen
10
next2:
11
jb button3, next3      ; springe zu next3, wenn button3 nicht gedrückt
12
ANL     TIMECON, #0FDh    ; Clear TIEN bit to stop the counter
13
ANL     TIMECON, #0FEh    ; Clear the TCEN bits to clear the registers(hour,min,sec)
14
mov hour, #0        ; hour auf 0 setzen
15
mov min,#0          ; min auf 0 setzen
16
mov sec,#0          ; sec auf 0 setzen
17
18
next3:
19
lcall _CP           ;Cursor an die Ausgabe Position des Displays
20
mov a,Hour           ; Ausgabe Stunden
21
:

Allerdings passiert garnichts, die uhr läuft immer einfach fröhlich 
weiter.
(Sie ist nach einem reset am mircroController auch nicht resetet, 
sondern läuft beim alten wert weiter)
Ich hoffe ihr könnt mir sagen, was ich falsch mache.

von Karl H. (kbuchegg)


Lesenswert?

Pohl schrieb:

> next1:
> jb button2, next2     ; springe zu next2, wenn button2 nicht gedrückt
> mov a, hour         ; schiebe hour in a
> inc a           ; erhöhe a um 1 (und damit auch hour?!)
> ;sollte sich später der cursorposition anpassen


Wenn du die Stunde an A um 1 erhöht hast, solltest du das dann aber auch 
wieder zurück nach 'hour' verschieben. Ansonsten kannst du in A erhöhen 
bis du schwarz wirst. 'hour' interessiert das nicht was du in A machst 
und nur 'hour' ist letztendlich der Wert mit dem deine Uhr tatsächlich 
operiert.

> > inc a           ; erhöhe a um 1 (und damit auch hour?!)

Um auf den Kommentar einzugehen.
Warum soll das gemacht werden. Der Befehl lautet 'Increment A' und genau 
das wird gemacht. A hat mit 'Hour' nichts zu tun. Das sind 2 
verschiedene Dinge. Steht in hour der Zahlenwert 17, dann steht nach 
einem
  mav a, hour
ebenfalls der Zahlenwert 17. D.h. da ist einfach ein Wert von einem 
Speicher in einen anderen Speicher umkopiert worden. Kopie! Nur 
deswegen, weil du den Wert umkopiert hast, gibt es keine irgendwie 
magische Verbindung zwischen A und Hour.

Du interpretierst immer noch zuviel in die Dinge hinein! Der µC macht 
genau, und zwar 100% genau, das was der Befehl aussagt. Nicht mehr und 
nicht weniger. In einem µC passiert nichts irgendwie 'magisch'.

von Pohl (Gast)


Lesenswert?

Ah, oke.
1
jb button2, next2   ; springe zu next2, wenn button2 nicht gedrückt
2
mov a, hour         ; schiebe hour in a
3
inc a               ; erhöhe a um 1
4
mov hour, a         ; schiebe a in hour
So sollte das dann also klappen?
Und zu den Interrupts, wie kann ich die denn für diese Zeit 
deaktivieren?
STI / CLI  lösen bei mir einen SYNTAX ERROR aus, gibt es sowas auch für 
den 8051(bzw. 8052)?

von Peter D. (peda)


Lesenswert?

Ich meine mich zu erinnern, daß man den TIC anhalten muß, um schreiben 
zu dürfen.

Man muß auch nicht nach A laden und zurück, INC geht auch auf Adressen.


Peter

von Pohl (Gast)


Angehängte Dateien:

Lesenswert?

Peter Dannegger schrieb:
> Ich meine mich zu erinnern, daß man den TIC anhalten muß, um schreiben
> zu dürfen.
Gut, denn im fertigen Programm soll das schreiben ja auch nur im 
"angehaltenen" Modus funktionieren.

Mal ne konkrete Frage:
1
Ausgabe:
2
jb button1, next1     ; springe zu next1, wenn button1 nicht gedrückt
3
lcall restart       ; startet counter
Wenn ich das ganze so im Programm hab steht meine Anzeige Ordnungsgemäß 
bei 00:00:00. Sie sollte dann aber anfangen zu laufen, wenn ich button1 
drücke.
Da passiert aber nichts(auch nicht bei gedrückt halten).

Komischerweise Startet die Anzeige aber sofort wenn ich ich statt "jb" 
"jnb" verwende:
1
Ausgabe:
2
jnb button1, next1     ; springe zu next1, wenn button1 nicht gedrückt
3
lcall restart       ; startet counter
Mir ist klar, warum, dass so ist, aber mich interessiert, warum es dann 
bei "jb" + Knopfdruck nicht funktioniert.

(Kompletter Quellcode im Anhang)

von Pohl (Gast)


Angehängte Dateien:

Lesenswert?

Das Ganze hat sich mit einem vorausgestellten
1
clr buttonX
beheben lassen, komisch, denn clr buttonX stand ganz am Anfang im Code.

Jetzt versuche ich erstmal Button3 so zu belegen, dass beim
1x drücken, gestoppt wird, beim 2x drücken, angehalten.
Und am besten noch bei längeren drücken auf 0 gesetzt.

Für Tipps aller Art, wie ich das machen könnte, wäre ich sehr dankbar.


Achja, gibt es eine Möglichkeit, dass man einen Befehl nur ausführen 
lässt, wenn man 2 Knöpfe gleichzeitig drückt?
Sowas in der Art wie:
1
jb button1, button3, next1    ; springe zu next 1, wenn button 1 und 3 nicht gedrückt sind


Wie gesagt, für Hilfe aller Art, die mir ewige Rumtüftelei ersparen, bin 
ich sehr dankbar.

von Peter D. (peda)


Lesenswert?

Es gibt schon gute Tastenlösungen, die sind allerdings in C geschrieben:

Beitrag "Universelle Tastenabfrage"


Ich sehe gerade im ersten Post, Du willst ja runter zählen, das kann der 
TIC nicht.
Ist aber kein Problem, Du zieht vor dem Anzeigen die Zeit einfach von 
23:59:59 ab.


Peter

von Pohl (Gast)


Angehängte Dateien:

Lesenswert?

Peter Dannegger schrieb:
> Es gibt schon gute Tastenlösungen, die sind allerdings in C geschrieben:
>
> Beitrag "Universelle Tastenabfrage"

Vielen dank, allerdings ist das schon sehr komplex und ergibt für mich 
gerade wenig Sinn. Werd morgen mal versuchen mich da reinzudenken.
Wenn jemand aber was vergleichbares in assembler hat, wäre das eine 
riesen Hilfe für mich.

Hab meine Anforderungen jetzt (vorerst) etwas runtergeschraubt:
button1 erhöht die Stunden
button2 die Minuten
und button3 die Sekunden.
Jetzt muss ich nur noch durch langes oder doppeltes drücken von tasten 
die Start-Funktion einbauen.

Peter Dannegger schrieb:
> Ist aber kein Problem, Du zieht vor dem Anzeigen die Zeit einfach von
> 23:59:59 ab.
Wie stelle ich das am besten an? denn,
1
:
2
Ausgabe:
3
lcall _CP           ;Cursor an die Ausgabe Position des Displays
4
mov a,255
5
subb a,Hour           ; Ausgabe Stunden
6
call LCD_HOUR
7
mov a,#':'           ; ...
8
call _LCD_OUT
9
mov a, 59
10
subb a, MIN
11
call LCD_MIN
12
:
so funktioniert das ganze schonmal nicht, wenn nach einstellen einer 
Zeit gestartet wird, resetet die Uhr auf 00:00:00 und beginnt dann wie 
gewohnt hochzuzählen.

Ach und eine Sache noch:
Bei dem eingebauten TIC kann man ja laut datenblatt zwischen 255h und 
24h umstellen. Wie genau aber stell ich denn auf 24h?
Alles was ich habe, ist das

  MOV    TIMECON, #03h  ; initialise timecon to count in 1/128s
                              ; -set TCEN to enable the time clock
                              ; -set TIEN to enable the TIC
                              ; -clear STI to allow automatic relaod
                              ;  of interval timeout
            ; -clear TFH to disable 24 hr counting

was aber genau das Gegenteil macht, sprich statt auf 24 auf 255 stellt.

Und das aus dem Datenblatt: 
[[http://www.analog.com/static/imported-files/data_sheets/ADUC832.pdf]]
(tabelle S65)

BIT | Name  | DISCRIPTION
[6] |  TFH  | Twenty-four hour select bit. Set by the user to enable the 
h             our counter to count from 0 to 23. Cleared by the user to
              enable the hour counter to count from 0 to 255.

Womit ich aber leider auch nichts anfangen kann, da ich keine Ahnung 
habe, wie ich das Bit setzte


An dieser Stelle möchte ich mich auch mal recht Herzlich bei euch allen 
bedanken!
Ihr wart mir eine sehr große Hilfe! Ohne euch, wäre ich nie soweit 
gekommen. Vielen Dank.
(Ein paar Fragen werd ich wohl noch Stelle, dann habt ihr aber bald ruhe 
vor mir smile )

von Pohl (Gast)


Lesenswert?

Gibt es einen Befehl, ähnlich cjne (Compare and Jump if not equal)
nur das verglichen wird, ob ein Operande größer bzw kleiner vom anderen 
ist?

oder wäre es möglich den cjne befehl irgendwie so zu verwenden?

von Peter D. (peda)


Lesenswert?

Pohl schrieb:
> oder wäre es möglich den cjne befehl irgendwie so zu verwenden?

Ja, siehe Befehlsmanual. Er setzt das Carry-Flag.


Peter

von Pohl (Gast)


Lesenswert?

Tut mir leid, ich weiß nicht wie das gehen soll.

Wenn ich google benutze finde ich nur die jg, jl(...) Befehle, die es 
beim 8051 aber wohl nicht gibt.

von Peter D. (peda)


Lesenswert?

Pohl schrieb:
> Tut mir leid, ich weiß nicht wie das gehen soll.

Welchen Teil der CJNE-Beschreibung im Befehlsmanual verstehst Du denn 
nicht?
1
        dseg    at 30h
2
wert0:  ds      1
3
wert1:  ds      1
4
5
        cseg
6
compare:
7
        mov     a, wert0
8
        cjne    a, wert1, _not_equal ; C = (a < wert1)
9
_equal:                         ; wert0 = wert1
10
; ...
11
        ret
12
_not_equal:
13
        jnc     _greater
14
_lesser:                        ; wert0 < wert1
15
; ...
16
        ret
17
_greater:                       ; wert0 > wert1
18
; ...
19
        ret
20
21
end

http://www.self8051.de/CJNE_A,direct,rel,13463.html


Peter

von Pohl (Gast)


Lesenswert?

Danke, ich glaube ich hab es jetzt so einigermaßen verstanden.
Aber habe die Befürchtung, das sich das auf mein Problem nicht anwenden 
lässt:
1
;geplant ist, das bei kurzen Tastendruck (<2sec) Hour um 1 erhöht wird
2
; bei langen Tastendruck (>2sec) soll gestartet werden
3
jb button1, next1            ;springe zu next1, wenn button1 nicht gedrückt
4
lcall stop                   ;stoppt TIC (falls er läuft)
5
lcall clear                  ;setzte TIC auf 0
6
lcall restart                ;starte Tic neu
7
jnb button1, $               ;warte hier bis button1 losgelassen wird
8
lcall stop                   ;stoppe Tic
9
loop:  
10
  mov a, sec           
11
  cjne a, #2, ungleich   ;vergleich abgelaufene sec mit 2
12
  sjmp A_ist_KlGl        
13
ungleich:
14
  jc  A_ist_KlGl       
15
  lcall restart        ; starte Tic neu (sec >2)
16
  ret
17
A_ist_KlGl:            ; wenn sec < 2
18
  inc Hour             ; erhöhe hour um 1
19
  ret

von Pohl (Gast)


Lesenswert?

Frage:
ist es "einfacher", wie ich es bisher versuche, einen Knopf mit 2 
Funktionen zu belegen(also langes und kurzes drücken zu unterscheiden)
oder
eine Funktion  zu schreiben, die bei Knopfdruck weiterspringt (Hier von 
Stunden zu Minuten zu Sekunden) und den aktuell ausgewählten wert, dann 
mit einem 2. Knopf zu verändern?


Bitte helft mir weiter, mit Ideen, wie ich das machen könnte, oder am 
besten beispielcode.
Ich zerbrech mir schon seit stunden den Kopf, hab beides ausprobiert, 
bin aber zu keinem zufriedenstellenden Ergebnis gekommen.

von Pohl (Gast)


Lesenswert?

Ich hab das ganze jetzt auf eine völlig andere Art gelöst.
Das ist aber ja auch egal.
Eine (hoffentlich) letzte Frage habe ich noch immer:

Pohl schrieb:
> Bei dem eingebauten TIC kann man ja laut Datenblatt zwischen 255h und
> 24h umstellen. Wie genau aber stell ich denn auf 24h?
> Alles was ich habe, ist das
>
1
>   MOV    TIMECON, #03h        ; initialise timecon to count in 1/128s
2
>                               ; -set TCEN to enable the time clock
3
>                               ; -set TIEN to enable the TIC
4
>                               ; -clear STI to allow automatic relaod
5
>                               ;  of interval timeout
6
>                               ; -clear TFH to disable 24 hr counting
7
>
> was aber genau das Gegenteil macht, sprich statt auf 24 auf 255 stellt.

Und die Informationen aus dem Datenblatt (Seite 65)
http://www.analog.com/static/imported-files/data_sheets/ADUC832.pdf

Der Befehl muss ja quasi dieser sein
MOV    TIMECON, #XXX
nur mit den richtigen XXX.

Ich hoffe, das sich ein "Wissender" (smile) kurz die Mühe machen 
könnte und mir die Richtigen XXX nennen kann. Oder zumindest kurz 
erklärt, wie ich sie herausfinden kann.

von Peter D. (peda)


Lesenswert?

Pohl schrieb:
>>                               ; -clear TFH to disable 24 hr counting
>> > was aber genau das Gegenteil macht, sprich statt auf 24 auf 255 stellt.

Nein.
Es macht ganz genau das, was im Kommentar steht.
Du machst den Eindruck, als ob Du sehr zerstreut bist.

Du gehst sehr planlos vor und das fällt Dir ständig auf die Füße.
Hast Du schonmal was anderes programmiert, außer 8051 Assembler?

Der Trick beim Programmieren ist, man schreibt kleine Module 
(Funktionen) und wenn eins fertig ist, dann fast man es auch nicht mehr 
an, sondern ruft es nur auf.

In Assembler muß man zu jedem Modul einen Header als Kommentar 
schreiben. Also was geht in welchen Registern hinein, was macht sie und 
was geht in welchen Registern hinaus, welche Register werden zerstört.

Module mitten im Programm und drumherum springen fördert in keinster 
Weise den Durchblick. Am besten ganz nach hinten damit, hinter die 
Mainloop.


Pohl schrieb:
>> clr button1
>> jb button1, next1     ; springe zu next1, wenn button1 nicht gedrückt

Das ist schonmal ganz großer Mist.
Der Pin ist damit Ausgang low, da kann nichts mehr eingelesen werden 
bzw. nur bei sehr hohem Kurzschlußstrom.
Lies Dir mal die Portbeschreibung durch.
Tasten müssen immer gegen GND schalten, dann fließt nur der Pullup-Strom 
(50µA).


Peter

von Pohl (Gast)


Lesenswert?

Was macht es denn dann?
Für mich steht da relativ eindeutig, dass das TFH-Bit auf 0 gesetzt wird 
und somit der TIC auf 255h. Das gegenteil (TFH auf 1) würde den TIC doch 
auf 24h setzten.
Was ist dann mein Denkfehler?

C, C++, ein bisschen LISP(das ist aber eine andere Geschichte)
Das Problem ist nicht, dass ich Planlos vorgehe, das mag vielleicht den 
eindruck erwecken, da ich hier ständig meine Taktik ändere. Das liegt 
aber daran, dass mein Plan A oft für mich einfach nicht zu realisieren 
war, mangels (Grund)verständnis von Assembler.
Das durcheinander sehe ich ein, muss mich aber auch hier rechtfertigen, 
dass das an dem vielen herumprobieren von mir liegt(wo wir wieder beim 
Grundverständnis wären) Da der Code mit ~200Zeilen da relativ kurz ist, 
habe ich als Programmierer keineswegs den überblick verloren.

Peter Dannegger schrieb:
>>> clr button1
>>> jb button1, next1     ; springe zu next1, wenn button1 nicht gedrückt
>
> Das ist schonmal ganz großer Mist.
So großer Mist ist das garnicht, bei diesem MicroController wird mit
clr button1     button1 auf Input gesetzt. Da bin ich mir sicher.
Ohne das clr spricht der button nicht mal an.


So jetzt wurde viel geredet, meine Frage steht allerdings noch immer im 
Raum.
Ich will doch nur wissen mit welchen Befehl (/wie ich darauf komme in 
einfachen Worten) ich das "TFH" Bit auf High setzten kann und somit die 
24h aktiviere.

von Ralf (Gast)


Lesenswert?

>> Das ist schonmal ganz großer Mist.
> So großer Mist ist das garnicht, bei diesem MicroController wird mit
> clr button1     button1 auf Input gesetzt. Da bin ich mir sicher.
Der Port 1 des AduC832 hat keine Ausgangstreiber, und laut Datenblatt 
ist der Port für digitalen Input zu löschen, deine Aussage ist somit 
korrekt.

Aber du darfst eins nicht vergessen: Peter kennt den 8052-Core zwar sehr 
gut, aber er kann nicht unbedingt wissen, dass sich der AduC832 in 
dieser Hinsicht anders verhält! Bei einem 100% 8052 kompatiblen Core 
würde der von ihm beschriebene Effekt auftreten und das Ausgangslatch 
auf low gehen.
Diese Abweichungen erschweren es zusätzlich, da Peter (wie ich anfangs 
auch) von einem 100%-Core ausgeht.

Ralf

von Pohl (Gast)


Lesenswert?

Ok.

Pohl schrieb:
> Ich will doch nur wissen mit welchen Befehl (/wie ich darauf komme in
> einfachen Worten) ich das "TFH" Bit auf High setzten kann und somit die
> 24h aktiviere.

Woran liegt es, dass mir hier keiner eine Antwort geben kann?
Sind zu wenig Informationen gegeben? (ich hab aber auch nicht mehr)
Könnt das selbst ihr nicht beantworten?
Wollt ihr es nicht beantworten, weil das zu Zeitaufwändig wäre?
              - dann würde ich mich freuen, wenn mir jemand in einfachen 
Worten sagt, wie ich es selbst herausfinden kann?

von Peter D. (peda)


Lesenswert?

Pohl schrieb:
> Woran liegt es, dass mir hier keiner eine Antwort geben kann?

Wohl daran, daß keiner weiß, was Deine Schwierigkeit ist.
Ich vermute mal, die Zuordnung der Bitstelle zu einem Wert.

TFH ist Bit 6, also Wert 040h
1
ORL TIMECON, #040h
und schon ist es gesetzt.
Man kann auch schreiben:
1
ORL TIMECON, #1 shl 6
In C würde man schreiben:
1
  TIMECON |= 1<<6;


Die Kenntnis der Bitmanipulationen wird eigenlich bei jedem 
Programmierer vorausgesetzt, daher sieht niemand ein Problem darin.


Peter

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.