Forum: Mikrocontroller und Digitale Elektronik 8051 carryflag


von Achim S. (ahmooo)


Lesenswert?

Hallo,

ich hätte mal eine Frage zum carryflag.
Ich habe ein Programm, was ich gerade analysiere. Das Programm kann nur 
Zahlen auf einer 7 Segment Anzeige anzeigen, die in Bcd Format sind.

Es wird gecheckt, ob die eingegeben Zahl in bcd Format kleiner als 10 
ist.
Und man kann ja dann am carryflag erkennen, wenn es gesetzt ist, ob die 
Zahl in bcd Format ist oder in hexa.

Nehmen wir an die eingegeben zahl ist die 11 in hexa . Wird dann 10-11 
gerechnet und man hat ein buffer underflow ? Ich bin mir nicht sicher .

MfG

von Peter R. (pnu)


Lesenswert?

So kann mans machen, aber:
Üblicherweise prüft man durch Addition: Nibble + 6, bei Überlauf (in 
Carry oder Halfcarry) dann entsprechende Korrektur: Im betroffenen 
Nibble Subtraktion von 9 und im nächsthöheren Nibble Addition von 1

übrigens:
8051 kennt aber den Befehl "adjust decimal" . Dabei werden beide 
Nibbles, das untere per halfcarry und das obere per carry geprüft und 
entsprechend korrigiert. Das vereinfacht die Geschichte. (Ist übrigens 
ein Befehl, den ich beim Übergang zum AVR sehr vermisst habe).

Bei Addition zweier BCD-Zahlen also:

ADD a,r0  ;Addition von Akku und r0, unmittelbar folgt:
DAA    ;adjust decimal accumulator, als Korrektur beim Auftauchen von 
A...F

von Peter D. (peda)


Lesenswert?

Asasassasaasasa Ass schrieb:
> Wird dann 10-11
> gerechnet und man hat ein buffer underflow ?

Mit Sicherheit nicht. Ein Bufferunderflow ist, wenn Du auf ein Array 
unterhalb des ersten Elements zugreifst.

Asasassasaasasa Ass schrieb:
> Ich bin mir nicht sicher .

Da wir Deinen Code nicht kennen und auch nicht wissen, was Du machen 
willst, können wir die Frage auch nicht beantworten.

von Achim S. (ahmooo)


Lesenswert?

1
;*****************************
2
; Segmentierung von Speicher *
3
;*****************************
4
5
stack_seg SEGMENT IDATA      ;Deklaration Stack segment  indirekt adressierbarer, internes RAM zb Stack
6
code_seg  SEGMENT CODE         ;Deklaration Code Segment, Programmspeicher ROM
7
8
;*****************************
9
;* Stack-Initialisierung *****
10
;*****************************
11
12
RSEG stack_seg             ; RAM-Speicher wird ausgewählt unser Stack
13
14
init:      DS 10           ; 10 Byte Stack wird reserviert, damit Daten gesichert werden nach LIFO
15
      
16
      CSEG AT 0         ; assembliert den nachfolgenden Block an die Adresse 0. , Absolutes Codesegment startet immer bei 0
17
      JMP main      
18
19
      org 0Bh           ; Adresse für die ISR von Timer0 festlegen der nachfolgende Code wird ab Adresse 0B im Programmspeicher abgelegt
20
      JMP timer_0        ; Läuft Timer 0 ab, verzweigt der Controller zur Adresse 0Bh zur Interruptbehandlungsroutine
21
22
      org 50h           ; Anfangsadresse/Einsprungstelle für die BCD-Tabelle wird festgelegt
23
      JMP bcd        ; Tabelle an Adresse 50h
24
25
;*****************************
26
; Tabelle fur BCD-Anzeige ****
27
;*****************************
28
29
bcd:        ; Kodierung der BCD-Ausgabe
30
      DB 3Fh   ;Zahl auf der 7seg Anzeige: 0
31
      DB 06h  ;Zahl auf der 7seg Anzeige: 1
32
      DB 5Bh  ;Zahl auf der 7seg Anzeige: 2
33
      DB 4Fh  ;Zahl auf der 7seg Anzeige: 3
34
      DB 66h  ;Zahl auf der 7seg Anzeige: 4
35
      DB 6Dh  ;Zahl auf der 7seg Anzeige: 5
36
      DB 7Dh  ;Zahl auf der 7seg Anzeige: 6
37
      DB 07h   ;Zahl auf der 7seg Anzeige: 7
38
      DB 7Fh  ;Zahl auf der 7seg Anzeige: 8
39
      DB 6Fh   ;Zahl auf der 7seg Anzeige: 9
40
41
42
;*****************************
43
; Konstantendefinition *******
44
;*****************************
45
46
timer_low    EQU    78h
47
timer_high    EQU    0ECh
48
49
;*****************************
50
; Hauptprogramm **************
51
;*****************************
52
53
RSEG code_seg          ; ROM-Speicher wird ausgewählt
54
55
main:
56
      MOV SP, #init    ; Stackpointer wird aufgeladen mit allem was in Label  init steht
57
58
      MOV TMOD, #01h    ; Timer-Mode 16-Bit wird gewählt
59
      MOV TH0, #timer_high; -- Bei 16-Bit 65536 Maschinenzyklen. Wir brauchen 5ms Pause = 5000 Maschinenzyklen
60
      MOV TL0, #timer_low  ; 65536-5000= 60536 = EC78h  
61
                ; damit muss der timer vorgeladen werden damit nach 5ms überläuft => flimmerfrei Anzeige
62
      SETB EA        ; Interruptfreigabe
63
      SETB ET0      ; Freigabe Timer 0 Register mit dem kann ein interrupt freigegeben werden
64
      SETB PT0      ; Timer 0 high priority
65
66
      MOV P0, #00h    ; Ports auf 0 setzen
67
      MOV P1, #00h
68
      MOV P2, #00h
69
      MOV R4, #01h    ; Und-Maske zum Auslesen von High-Bits
70
71
;*****************************
72
; Werte von Port 2 auslesen **
73
;*****************************
74
75
read:
76
      MOV R0, P2      ; Werte von Port 2 werden in Register gespeichert
77
      MOV R6, #1      ; Wait Startwert = 1 ,1x 5ms dieser wird im timer 0 dekrementiert
78
79
      CLR C        ; Carryflag wird gelöscht im Register PSW
80
81
      MOV A, R0      ; Werte von Port 2 werden in Akku geladen
82
      ANL A, #0Fh      ; ---- FFFF : höherwertige bits von port 2 werden ausgeschaltet
83
      CALL check      ; Unterfunktion check aufrufen
84
      SETB P1.0         ; Cathode 0 geht an
85
      SETB TR0      ; Timer 0 wird gestartet
86
      CALL wait      ; Wartezeit
87
      CLR P1.0      ; Cathode 0 geht aus
88
89
      MOV A, R0      ; Werte von Port 2 werden in A geladen
90
      SWAP A        ; Bits werden umgedreht
91
      ANL A, #0Fh      ; FFFF ---- : Hinteren werte von Port 2 werden gelöscht
92
      CALL check      ; Unterfunktion check aufrufen
93
      SETB P1.1      ; Cathode 1 geht an
94
      SETB TR0      ; Timer 0 wird gestartet
95
      CALL wait      ; Unterfunktion wait aufrufen
96
      CLR P1.1      ; Cahtode 1 geht aus
97
98
      JMP read
99
100
;*****************************
101
; Wartezeit ******************
102
;*****************************
103
104
wait:
105
      CALL output      ; Unterfunktion output aufrufen
106
      MOV A, R6      ; Startwert wird in Akku geladen
107
      JNZ wait      ; Bei A!=0 zu wait springen
108
      MOV R6, #1      ; Wait Startwert = 1 ,1x 5ms
109
      CLR TR0        ; Timer stoppen
110
      RET          ; Sprung zu main
111
112
;*****************************
113
; Check **********************
114
;*****************************
115
116
check:
117
      CJNE A, #0Ah, not_10; Compare&Jump if not equal Vergleicht die niederwertigen Bits im Akku mit 10 
118
      JMP error      ; wenn =10 error
119
      
120
not_10:    
121
      JC bcd_out      ; jump if carry is set Wenn Carry = 1 springe zu bcd_out
122
      JMP error 
123
124
;*****************************
125
; Fehlerabarbeitung **********
126
;*****************************
127
128
error:
129
      MOV R2, #7Fh    ; 8 wird in Akku geladen
130
      MOV R7, #5      ; 5 für Dauer der Sequenz 5s 
131
132
timer:              
133
      SETB TR0      ; Timer 0 starten
134
      MOV R6,#100      ; 100 Durchläufe für Timer  
135
      SETB P1.0      ; Cathode 0 geht an
136
137
timer_on:
138
      MOV A, R6      ; Wert von R6 in A laden
139
      CALL output
140
      JNZ timer_on    ; Bei A != 0 springe zu timer_on
141
      CLR P1.0      ; Cathode 0 ausschalten
142
      MOV R6, #100    ; 100 Durchläufe für Timer
143
; 5ms x100=0,5sek=> 5x(0,5 an 0,5s aus) => 5sek Sequenz
144
timer_off:
145
      MOV A, R6      ; Wert von R6 in A laden
146
      JNZ timer_off    ; Bei A != 0 springe zu timer_off
147
      DJNZ R7, timer    ; Verringere R7 um 1 und falls R7 != 0 springe zu timer
148
      JMP read
149
150
;*****************************
151
; BCD-Umwandlung ************* wert in akku wird in bcd format umgewandelt für die ausgabe auf 7 segment anzeige
152
;*****************************
153
154
bcd_out:
155
      MOV dptr, #bcd    ; DPTR Data Pointer 2-Byte-Register wird mit der BCD-Tabelle geladen
156
      MOVC A, @a+DPTR    ; Akku wird mit dem Wert an der Adresse A + DPTR geladen
157
      MOV R2, A      ; wert von akku wird auf r2 gespeichert
158
      RET          ; Rücksprung zum Hauptprogramm
159
160
;*****************************
161
; Anzeigezyklus **************
162
;*****************************
163
164
output:            
165
      MOV A, R2        ; Anzeigewert in Akku laden
166
      ANL A, R4      ; Akku mit Undmaske 0000 0001 maskieren
167
      MOV P0, A      ; Wert im Akku wird an Port 0 ausgegeben
168
      MOV A, R4      ; Undmaske in Akku laden
169
      RL A        ; Rotate Left Undmaske nach links verschieben 0000 0010
170
      MOV R4, A      ; Undmaske zwischenspeichern
171
      CJNE A, #80h, output; Compare and Jump if not equals Undm mit 1000 0000 vergleichen, wenn Wert erreicht abbrechen
172
      MOV P0, #00h    ; P0 wird gelöscht
173
      MOV R4, #01h    ; Undmaske wird auf Startwert gesetzt
174
      MOV A, R6
175
      RET          ; Rücksprung zu wait
176
177
;*****************************
178
; Interruptroutine ***********
179
;*****************************
180
181
timer_0:            ; alle veränderten Register retten
182
      PUSH PSW      ; PSW (Flag) Register auf den Stack legen, damit das Programm nach Beendigung des Interrupts ungestört weiter arbeiten kann
183
      PUSH ACC      ; Akku auf den Stack legen  und sichern
184
      DEC R6        ; Zählregister wird dekrementiert
185
      MOV TH0, #timer_high; Timer 0 Register neu laden
186
      MOV TL0, #timer_low  ; --------------//------------
187
      POP ACC        ; Akku aus dem Stack rausnehmen, wird wiederhergestellt
188
      POP PSW        ; PSW aus dem Stack rausnehmen, wird wiederhergestellt
189
      RETI        ; Interruptserviceroutine beenden ,Rücksprung zum Interrupt auf dem Stack liegenden letzten Ausführungsposition
190
191
END

: Bearbeitet durch User
von Achim S. (ahmooo)


Lesenswert?

In der Check funktion ist die Carryflag Abfrage. Wie könnte man hier die 
Frage beantworten: Wann wird das Carryflag auf 1 gesetzt?

von Peter D. (peda)


Lesenswert?

CJNE A, #0Ah, not_10;
bedeutet A - #0Ah.
D.h. C wird gesetzt, wenn A < #0Ah

von Achim S. (ahmooo)


Lesenswert?

ok danke und was wird bei JC bcd out gemacht

von Peter D. (peda)


Lesenswert?

Du hast übrigends auch einen Bufferoverflow, nämlich einen 
Stackoverflow:
1
read:
2
...
3
CALL check 
4
...
5
check:
6
...
7
JMP read

: Bearbeitet durch User
von Achim S. (ahmooo)


Lesenswert?

Was heißt das jetzt :-) ?

von Georg G. (df2au)


Lesenswert?

Asasassasaasasa Ass schrieb:
> BCD-Tabelle wird festgelegt
>       JMP bcd        ; Tabelle an Adresse 50h

Was soll dieser Sprung bewirken? Die Tabelle enthält keinen ausführbaren 
Code.

von Peter D. (peda)


Lesenswert?

Eine mit CALL aufgerufene Funktion darf immer nur mit RET beendet 
werden.

von Georg G. (df2au)


Lesenswert?

Asasassasaasasa Ass schrieb:
> ANL A, #0Fh      ; ---- FFFF : höherwertige bits von port 2 werden
> ausgeschaltet
Der Kommentar ist unglücklich geschrieben. "---- 1111" wäre richtiger.


>       SWAP A        ; Bits werden umgedreht
Kommentar ist falsch. Die Bits werden nicht umgedreht sondern es wird 
das obere mit dem unteren Nibble getauscht.


>       ANL A, #0Fh      ; FFFF ---- : Hinteren werte von Port 2 werden
> gelöscht
Auch, wenn du das richtige machst, löscht der Befehl die oberen Bits.

Ganz allgemein: Deine Art der Kommentierung ist wenig hilfreich.
1
      MOV P0, #00h    ; P0 wird gelöscht
2
      MOV R4, #01h    ; Undmaske wird auf Startwert gesetzt
Besser wäre:
1
      MOV P0, #00h    ; alle Kathoden aus
2
      MOV R4, #01h    ; mit Kathode 1 geht es weiter
1
timer:
2
      SETB TR0      ; Timer 0 starten
3
      MOV R6,#100      ; 100 Durchläufe für Timer
wird meist funktionieren. Da R6 vom Timer dekrementiert wird, wäre es 
defensiver so:
1
timer:
2
      MOV R6,#100      ; 100 Durchläufe für Timer
3
      SETB TR0      ; Timer 0 starten

: Bearbeitet durch User
von Achim S. (ahmooo)


Lesenswert?

Das Programm habe ich leider nicht selbst geschrieben. Ich weiß nur das 
das carryflag gesetzt wird weil wir ein bufferunderflow haben weil eine 
größere Zahl von einer kleineren abziehen aber welche Zahl von welcher 
abgezogen wird weiß ich nicht

von Achim S. (ahmooo)


Lesenswert?

kann mir einer vielleicht diesen Teil des Programms erklären, was da 
genau gemacht wird stack seg Segment IDATA oder CSEG AT0 usw also 
eigentlich alles von oben nach unten. Danke im Vorraus
1
;*****************************
2
; Segmentierung von Speicher *
3
;*****************************
4
5
stack_seg SEGMENT IDATA      ;Deklaration Stack segment  indirekt adressierbarer, internes RAM zb Stack
6
code_seg  SEGMENT CODE         ;Deklaration Code Segment, Programmspeicher ROM
7
8
;*****************************
9
;* Stack-Initialisierung *****
10
;*****************************
11
12
RSEG stack_seg             ; RAM-Speicher wird ausgewählt unser Stack
13
14
init:      DS 10           ; 10 Byte Stack wird reserviert, damit Daten gesichert werden nach LIFO
15
16
      CSEG AT 0         ; assembliert den nachfolgenden Block an die Adresse 0. , Absolutes Codesegment startet immer bei 0
17
      JMP main
18
19
      org 0Bh           ; Adresse für die ISR von Timer0 festlegen der nachfolgende Code wird ab Adresse 0B im Programmspeicher abgelegt
20
      JMP timer_0        ; Läuft Timer 0 ab, verzweigt der Controller zur Adresse 0Bh zur Interruptbehandlungsroutine
21
22
      org 50h           ; Anfangsadresse/Einsprungstelle für die BCD-Tabelle wird festgelegt
23
      JMP bcd        ; Tabelle an Adresse 50h

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Asasassasaasasa Ass schrieb:
> kann mir einer vielleicht diesen Teil des Programms erklären

Ist doch schon alles kommentiert.
Was ist Dir an den Kommentaren unklar?

von Achim S. (ahmooo)


Lesenswert?

Warum ist cseg at 0?warum wir es gemacht ? Was bring das org 0bh und das 
org 50h

von Karl H. (kbuchegg)


Lesenswert?

Weil der Assembler 2 Modi hat, auf das sich Anweisungen beziehen können. 
Der eine Modus sorgt dafür, dass Dinge im RAM-Speicher angelegt werden, 
der andere Modus sorgt dafür, das alles weitere in den Flash-Speicher 
kommt.

Mittels den Anweisungen RSEG bzw. CSEG wird der Modus umgeschaltet. 
Nachfolgende zb DS beziehen sich dann entweder auf das RAM oder auf den 
Flash.

Jetzt willst du aber zb nicht haben, dass dein Programm einfach irgendwo 
im Speicher steht. Denn nach dem Starten beginnt der Prozessor an der 
Stelle 0 die Befehle abzuarbeiten. D.h. es wäre auch vernünftig, wenn 
das Programm im Flash an der Adresse 0 beginnen würde.

Und dann gibt es noch Fälle, in denen man bestimmte Codeteile an 
bestimmte Stellen im Flash platzieren muss. Beispielsweise bei 
Interrupts ist das oft so gelöst, dass der Prozessor eine bestimmte 
Adresse als Reaktion auf einen auftretenden Interrupt anspringt. Will 
man also haben, dass bei auftreten eines Interrupts bestimmter Code 
ausgeführt wird, dann hat man sich nach dem µC zu richten. Springt der 
eine bestimmte Adresse an, dann muss man seinen Befehl(e) eben an diese 
Adresse im Speicher bugsieren. Und genau das macht ORG. Es sagt aus. 
Alles nachfolgende kommt ab genau dieser Adresse im Speicher.

Aber: Hast du denn keine Doku? Ohne nachzulesen, was bestimmte 
Assembler-Direktiven genau machen, wirst du nicht weit kommen! Speziell 
wenn es darum geht, anderen Code zu analysieren. Bei jedem Assembler 
gibt es auch eine Doku, was die Assembler-Direktiven genau machen. Die 
muss man halt auch mal lesen und darüber nachdenken, was das Gelesene im 
Zusammenhang mit dem vorliegenden Code wohl bewirken wird und warum der 
Autor das wohl gemacht hat. Genau dieses, das darüber nachdenken was man 
da gelesen hat und welche Bedeutung das hat, genau das IST nämlich 
"Analysieren".

: Bearbeitet durch User
von Achim S. (ahmooo)


Lesenswert?

Die 0bh ist doch ein vordefinierten Wert für den interrupt Vektor und 
die 50 bh ist doch der erste freie Speicher wo etwas gespeichert werden 
kann oder ?

von Karl H. (kbuchegg)


Lesenswert?


: Bearbeitet durch User
von Achim S. (ahmooo)


Lesenswert?

Ok danke. Jetzt nochmal zurück zum carryflag. In meinen Programm haben 
wir ja ein buffer underflow also ein borrow. Wenn dann carryflag 
gesetzwidrig weiß das Programm dass die eingelesene Zahl in bcd Format 
ist aber wie wird sie berechnet? Ich weiß dass eine größere Zahl von 
einer kleineren abgezogen wird aber welche Zahlen ?

von Karl H. (kbuchegg)


Lesenswert?

Asasassasaasasa Ass schrieb:
> Ok danke. Jetzt nochmal zurück zum carryflag. In meinen Programm haben
> wir ja ein buffer underflow


bitte, bitte, bitte, bitte

Lass den 'buffer' weg!

Du siehst unheimlich dämlich aus, wenn du das als einen buffer underflow 
bezeichnest. Da ist weit und breit kein Buffer im Spiel. Ein 'buffer 
underflow' oder 'buffer overflow' ist etwas völlig anderes und hat nicht 
das geringste mit der Thematik hier zu tun. Komplett andere Baustelle.

Ok?

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Asasassasaasasa Ass schrieb:

> gesetzwidrig weiß das Programm dass die eingelesene Zahl in bcd Format
> ist aber wie wird sie berechnet?

was willst du da berechnen?

Entweder die eingestellte Zahl ist kleiner als 10 und sie kann mit der 
7-Seg ausgegeben werden, oder sie ist es nicht - dann kann sie auch 
nicht ausgegeben werden.

berechnet wird da gar nichts. Ein Bitmuster (das du als Zahl ansiehst) 
wird vom Port eingelesen und abhängig von diesem Bitmuster wird ein 
anderes Bitmuster an den Port mit der 7-Segment Anzeige ausgegeben.

> Ich weiß dass eine größere Zahl von
> einer kleineren abgezogen wird aber welche Zahlen ?

Beim Compare
1
     CJNE A, #0Ah
ist das offensichtlich die Zahl #0Ah, oder eben in dezimaler 
Schreibweise eine 10.
UNd die andere Zahl, von der angezogen wird, wird welche sein? das ist 
die im Akku. Steht ja in der Anweisung auch dort "Compare Akku mit 10 
(und springe wenn nicht gleich". Wo kommt die Zahl im Akku her? Na, dann 
schau halt mal von wo Check aufgerufen wird! Wie kommt der Akku dort zu 
seinem Wert? Wo kommt der her? Da muss man dann eben auch mal den Code 
rückwärts verfolgen. Wie ist man an diese Stelle im Code gekommen? Was 
ist davor passiert? Welche Werte sind woher in welche Register gekommen? 
Wo sind die wieder hergekommen? etc.


Du analysierst den Code. Analyse bedeutet nicht, dass man da einmal 
drüber liest, sich zurück lehnt und sagt 'Schön wars'. Analyse bedeutet, 
dass sich während der Analyse neue Fragen auftun, die man beantwortet, 
indem man den Code nochmal durchgeht und spezielles Augenmerk darauf 
legt, was zur Lösung dieser Frage im Code zu sehen ist. Daraus ergeben 
sich dann wieder neue Fragen etc. etc. Bis dann irgendwann die Phase 
beginnt, in der man die Antworten auf die Fragen im Code findet, oft 
auch unter Zuhilfenahem von angenommenen Werten in Register (wenn 
Benutzerinteraktion im Spiel ist) und Durchspielen des Codes und sich 
ansehen, wie der Code darauf reagiert. Damit kann man dann immer mehr 
Fragen beantworten bis dann irgendwann auch die letzte Frage beantwortet 
ist ... man ist mit der Anylase durch und versteht den Code in allen 
Einzelheiten. Aber das ist nichts, was man nach 1 mal durchlesen und 
'Super' sagen erreichen kann.

Und - das ganze ist wie radfahren. Mann kann es nur lernen, indem man es 
tut. Noch etwas haben die beiden gemeinsam: bei den ersten Versuchen 
wird es einen ein paar mal ordentlich auf die Schnauze hauen. Wer dann 
drann bleibt, nicht aufgibt und weitermacht, der wird es auch irgendwann 
lernen. Das gilt genauso für radfahren wie es auch für Code analysieren 
gilt.

: Bearbeitet durch User
von Achim S. (ahmooo)


Lesenswert?

Ich bin das Programm zisch mal durchgegangen meine Frage bezog sich auf 
das jc bcd.
Oder hat es was mit dem cjne zu tun.
Bei cjne vergleicht er die Zahl im Akku also die von mir eingegebene 
Zahl ob sie ungleich 10 ist jetzt könnte die Zahl kleine 11 sein da weiß 
man ja noch nicht ob sie im bcd Format ist erst im nächsten Schritt wird 
es ja bekannt. Da weiß ich halt leider nicht was man macht bzw welche 
Zahlen von einander subtrahiert.
Ist es aber richtig wenn ich jetzt die 11 in hexa habe undminus 10 
rechne wird ja sozusagen eine Minus Zahl rauskommen also haben wir ein 
underflow Unterschreitung des Wertebereichs des Registers? Und deswegen 
wird das cf gesetzt

von Wilhelm F. (Gast)


Lesenswert?

Asasassasaasasa Ass schrieb:

> Warum ist cseg at 0?warum wir es gemacht ? Was bring das org 0bh
> und das org 50h

CSEG at 0 heißt im Klartext Codesegment auf Adresse Null. Dort startet 
das Programm nach Reset. Bei 0bh liegt der Interruptvektor für den 
Timerinterrupt, und bei 50h liegt der Programmstart. ORG setzt den 
Location Counter auf einen neuen Wert.

RSEG heißen redefinierte Segmente, die vorher schon mal z.B. mit CSEG 
oder DSEG definiert waren.

Zu alle dem sollte man das Assembler-Manual mal lesen, dort stehts.

von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz schrieb:

> berechnet wird da gar nichts. Ein Bitmuster (das du als Zahl ansiehst)
> wird vom Port eingelesen und abhängig von diesem Bitmuster wird ein
> anderes Bitmuster an den Port mit der 7-Segment Anzeige ausgegeben.

d.h. genau genommen sind es 2 Stück.
Es werden 8 Bit vom Port gelesen (also eine '2 stellige BCD Zahl'). Für 
die erste Anzeige sind aber nur die unteren 4 Bit des gelesenen 
relevant. Für die zweite Anzeige sind die oberen 4 Bit relevant. Und das 
ist auch schon alles.
Wenn am Port die Hex-Zahl #23h eingestellt ist, dann tauchen auf den 
beiden Anzeigen die '2' und die '3' auf. Eben weil die Hex-Zahl #23h 
war. Denn dazu muss man nichts rechnen. Dazu muss man einfach nur die 
#23h in 2 Teile aufteilen. Den Teil #03h und den Teil #02h. Beide kann 
man fast gleich behandeln, indem man sie in das jeweils zugehörige 
Muster für die 7-Segment Anzeige umwandelt. Man muss nur dafür sorgen, 
dass der richtige Teil dann auch an der richtigen der beiden 7-Seg 
Anzeigen auftaucht. Aber 'Rechnen' im Sinne von 'Fetsstellen welche Zahl 
da eingestellt war', muss man gar nichts. Genau deswegen benutzt man ja 
das BCD System.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Asasassasaasasa Ass schrieb:
> Ich bin das Programm zisch mal durchgegangen meine Frage bezog sich auf
> das jc bcd.
> Oder hat es was mit dem cjne zu tun.
> Bei cjne vergleicht er die Zahl im Akku also die von mir eingegebene
> Zahl ob sie ungleich 10 ist jetzt könnte die Zahl kleine 11 sein da weiß
> man ja noch nicht ob sie im bcd Format ist

vergiss bitte an dieser Stelle den Begriff 'BCD'. Er ist hier sowas von 
uninteressant.

Es geht einfach nur um die Fragestellung:
Ist die Zahl im Register (die aus den unteren 4 Bits gebildet wird) 
größer oder kleiner/gleich als 10. IM ersten Fall hat man kein Muster, 
welches man auf die 7-Seg ausgeben könnte, im zweiten Fall hat man 
eines.

Um mehr geht es an dieser Stelle nicht.
Das ist einfach nur die Fragestellung: wenn ich an einer 7-Seg die 
Ziffern '0' bis '9' anzeigen kann, kann ich dann damit die 4-Bit Zahl im 
Akku anzeigen ja oder nein.

Erst von einer höheren Warte aus, ist diese Fragestellung gleichwertig 
mit "Liegt eine BCD Zahl vor". Aber das interessiert den Code nicht 
sonderlich. Der weiß nichts von einem Konzept 'BCD'.

Im übrigen: wenn du Code analysierst, dann solltest du schon wissen, was 
die einzelnen Befehle GENAU machen. Wenn du es nicht weißt, dann schau 
in die Doku. Wir sind hier kein Vorlesverein.

: Bearbeitet durch User
von Achim S. (ahmooo)


Lesenswert?

Jedes Segment wir Einzel angesteuert aber die Aufgabe ist es doch zu 
erkennen ob die Zahlen in bcd Format ist,falls nicht blinkt das Segment 
. Und meine frage ist es wie erkennt man es.

von Karl H. (kbuchegg)


Lesenswert?

Asasassasaasasa Ass schrieb:
> Jedes Segment wir Einzel angesteuert aber die Aufgabe ist es doch zu
> erkennen ob die Zahlen in bcd Format ist,falls nicht blinkt das Segment
> . Und meine frage ist es wie erkennt man es.

Wann ist denn ein Bitmuster KEINE BCD-Zahl?

Oder anders ausgedrückt: Was muss denn für ein beliebiges Bitmuster in 
einem Register gelten, damit es eine BCD Zahl sein kann?

Ist #20h  eine BCD Zahl?
Was ist mit #8Fh? #A5h, #EEh, #47h

Welches davon sind BCD Zahlen und warum?

von Achim S. (ahmooo)


Lesenswert?

Alle Zahlen die in meiner Tabelle bcd festgelegt sind

von Karl H. (kbuchegg)


Lesenswert?

Asasassasaasasa Ass schrieb:
> Alle Zahlen die in meiner Tabelle bcd festgelegt sind

Falsche Antwort

von Achim S. (ahmooo)


Lesenswert?

Die 47

von Karl H. (kbuchegg)


Lesenswert?

Asasassasaasasa Ass schrieb:
> Die 47

die #47h

wichtig: Hex-Schreibweise! ALs Dezimalzahl wäre das ja 71. Auf der 
Anzeige soll aber nicht 71 stehen, sondern da sollen die Ziffern 4 und 7 
aufleuchten.

Gut. Und warum ist das so. Warum ist #47h gültig, #4Dh aber nicht? Und 
warum ist #B7h keine gültige BCD-Zahl?

: Bearbeitet durch User
von Achim S. (ahmooo)


Lesenswert?

Weil die Buchstaben von a-f nicht angezeigt werden kann.
Das erklärt mir immer noch nicht mein jc bcd :D

von Route_66 (Gast)


Lesenswert?

Hallo!
Du solltest erst mal ein Buch zur Hand nehmen und studieren, welche 
Befehle was machen, welche überhaupt Flags beeinflussen und wie. Ein 
Forum kann Dir diese Grundlagen überhaupt nicht vermitteln. Außerdem hat 
Keiner Lust, seine wertvolle Zeit damit zu verplempern, Dir jedes Komma 
und Semikolon zu erklären. Ich jedenfalls nicht!

von Achim S. (ahmooo)


Lesenswert?

Jetzt hast du aber deine "wertvolle" zeit geopfert.

von Karl H. (kbuchegg)


Lesenswert?

Asasassasaasasa Ass schrieb:
> Weil die Buchstaben von a-f nicht angezeigt werden kann.
> Das erklärt mir immer noch nicht mein jc bcd :D


Laangsam. Dazu kommen wir noch.
Erst mal muss ich wissen, dass du eine Vorstellung davon hast, was 
eigentlich passieren muss bzw. soll.
Eine BCD-Zahl liegt also genau dann vor, wenn jede der beiden 
Hex-Ziffern der Zahl im Bereich 0 bis 9 liegt. Sobald eine der beiden 
Ziffern (oder beide) im Bereich A bis F liegen, ist das keine gültige 
BCD-Zahl mehr.

D.h. wenn vom Port das Bitmuster für #47h eingelesen wird, dann muss 
dieses BItmuster in die beiden Teile #07h und #04h zerlegt werden. Denn 
die einzelnen Ziffern können ja auch einzeln geprüft werden.
Das muss nicht in einem Rutsch passieren, sondern das kann auch 
nacheinander passieren. Genau das macht der Teil hier
1
read:
2
      MOV R0, P2      ; Werte von Port 2 werden in Register gespeichert
3
4
      ...
5
6
      MOV A, R0      ; Werte von Port 2 werden in Akku geladen
7
      ANL A, #0Fh      ; ---- FFFF : höherwertige bits von port 2 werden ausgeschaltet
8
      CALL check      ; Unterfunktion check aufrufen

wenn check aufgerufen wird, steht vom Portinhalt #47h erst mal die #07h 
im Akku. Denn durch den ANL wurden die obersten 4 Bit, das ist genau der 
#4xh Anteil, definiert auf 0 gesetzt.

Soweit so gut. Wie gehts bei check weiter?
1
check:
2
      CJNE A, #0Ah, not_10; Compare&Jump if not equal Vergleicht die niederwertigen Bits im Akku mit 10

A, also die #07h werden mit #0Ah verglichen, indem intern eine 
Subtraktion #07h minus #0Ah gemacht wird und die Flags entsprechend 
gesetzt werden. Welche Flags werden denn wie gesetzt?
Das Ergebnis der Subtraktion ist definitiv nicht 0, daher wird das Zero 
Flag nicht gesetzt. Es findet aber ein Unterlauf statt, also wird das 
Carry Flag gesetzt.

Damit kommen wir zum 2.ten Teil der Anweisung ...JNE... Jump not Equal. 
Das Zero Flag ist nicht gesetzt (was soviel bedeutet wie: bei der 
Subtraktion kam nicht 0 raus, was soviel bedeutet wie sie waren nicht 
gleich). 'Not Equal' ist also der Fall, also wird ge-jumped. Weiter 
gehts bei not_10, der Jump nach error wird also übersprungen.

Weiter gehts mit
1
      JC bcd_out      ; jump if carry is set Wenn Carry = 1 springe zu

Ist das Carry gesetzt?
Ja ist es. Das vom Compare gesetzte Carry ist immer noch gesetzt. 
Dazwischen lag ja kein Befehl, der es gelöscht hätte.
Warum war das Carry noch mal gesetzt? Weil bei der internen Subtraktion 
ein Unterlauf entstand. Von irgendetwas wurde #0Ah (also dezimal 10) 
abgezogen. Wenn das unterläuft, dann bedeutet das, dass dieses irgendwas 
kleiner als #0Ah (also dezimal 10) gewesen sein muss, denn sonst wäre es 
ja nicht untergelaufen. Unser irgendwas war #07h, damit ist ja check 
aufgerufen worden. Und in der Tat. Das stimmt auffallend. #07h ist 
tatsächlich kleiner als #0Ah.

Schlussfolgerung: die Ziffer im Akku, die beim Aufruf von check vorlag 
ist eine Ziffer, die ausgegeben werden kann. Und auch das stimmt wieder 
mit den Erwartungen überein: die Ziffer war im Beispiel #07h und das ist 
eine, für die es eine Darstellung auf der 7-Seg gibt.

Der JC wird also genommen (weil das Carry Flag ja gesetzt ist) und 
weiter gehts bei bcd_out, wo dann die Ziffer ausgegeben wird.

Irgendwann ist check fertig und es geht zurück zum Aufrufer. Also zurück 
an diese Stelle
1
read:
2
      MOV R0, P2      ; Werte von Port 2 werden in Register gespeichert
3
4
      ...
5
6
      MOV A, R0      ; Werte von Port 2 werden in Akku geladen
7
      ANL A, #0Fh      ; ---- FFFF : höherwertige bits von port 2 werden ausgeschaltet
8
      CALL check      ; Unterfunktion check aufrufen
9
10
<------------------------------------
11
...

Da findet dann ein bischen Geplänkel mit der 7-seg statt, so dass auch 
die richgie Stelle aufleuchtet. Aber dann wirds wieder interessant
1
      ....
2
3
      MOV A, R0      ; Werte von Port 2 werden in A geladen
4
      SWAP A        ; Bits werden umgedreht
5
      ANL A, #0Fh      ; FFFF ---- : Hinteren werte von Port 2 werden gelöscht
6
      CALL check      ; Unterfunktion check aufrufen
7
...

Aha!
Wieder wird der Wert aus R0 geholt, welcher ja der Wert vom Port war. 
Also die #47h
Wieder finden Manipulationen statt.
Zuerst der Swap, der aus #47h die #74h macht.
Dann der ANL, welcher die oberen 4 Bit ausmaskiert, und aus den #74h 
eine #04h macht.
Und dann wird check aufgerufen. Und was die damit macht, wissen wir ja 
bereits. check überprüft, ob der WErt im Akku (also die #04h) kleiner 
als 10 sind (sind sie) und wenn ja geht es bei bcd_out weiter.

Deine Aufgabe:
Angenommen am Port ist #4Bh eingestellt.
Wie ist dann der Ablauf im Programm?

: Bearbeitet durch User
von Achim S. (ahmooo)


Lesenswert?

4Bh
Also am Anfang wird der Wert 4Bh in den Akku geladen. Anschließend 
werden die High Nibble ausgeschaltet mit dem ANL und wir betrachten die 
xBh.
Jetzt wird xBh-0Ah berechnet und das Ergebnis ist ungleich 0 aber 
diesmal die +1. Jetzt dürfte kein Carryflag gesetzt werden, da wir kein 
Unterlauf haben und wir springen in die Error Funktion.
Hier wird die 8 in den Akku geladen, damit alle Segmente blinken.
Nachdem alles durch ist wird die 4Bh wieder in den Akku aus dem Register 
geladen. Swap, die High Nibble und Low Nibble werden vertauscht. ANL und 
wir betrachten nur noch die x4h.
Check 4-10= -6 Unterlauf Carryflag wird gesetzt die Zahl ist in BCD 
Format.

Ich danke dir. Deine Antwort war sehr hilfreich. :))

von Karl H. (kbuchegg)


Lesenswert?

Und eines sollte auch schon klar geworden sein.
Dein Frage aus dem Eröffnungsposting

> Nehmen wir an die eingegeben zahl ist die 11 in hexa .
> Wird dann 10-11 gerechnet

ist unsinnig.
Denn der Schlüssel zum ganzen besteht darin, dass nicht die eingegebene 
Zahl 11 (in hexa) untersucht wird, sondern die eingegebene Zahl in die 
'Einer' und die 'Zehner' zerlegt wird und die beiden Ziffern getrennt 
untersucht werden.

Das hättest du aber aus dem Code herauslesen können, bzw. du hättest es 
erahnen können, wenn dir klar gewesen wäre (und du das auch angewendet 
hättest), wann denn eigentlich eine eingegebene Hex-Zahl tatsächlich 
eine BCD-Zahl ist. Es hilft nämlich ungemein in der Analyse, wenn man 
erst mal eine gewisse Vorstellung davon hat, was denn höchst 
wahrscheinlich im Code passieren wird, weil man weiß welche Bedingungen 
eigentlich einzuhalten sind.

Die Prüfung auf gültige BCD Zahl lässt sich nicht an einer einzigen 
Anweisung festmachen. Es ist die komplette Sequenz über mehrere 
Anweisungen, die das erledigt. Das scheinst du nicht behirnt zu haben.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Asasassasaasasa Ass schrieb:
> 4Bh
> Also am Anfang wird der Wert 4Bh in den Akku geladen. Anschließend
> werden die High Nibble ausgeschaltet mit dem ANL und wir betrachten die
> xBh.
> Jetzt wird xBh-0Ah berechnet und das Ergebnis ist ungleich 0 aber
> diesmal die +1. Jetzt dürfte kein Carryflag gesetzt werden, da wir kein
> Unterlauf haben und wir springen in die Error Funktion.
> Hier wird die 8 in den Akku geladen, damit alle Segmente blinken.
> Nachdem alles durch ist wird die 4Bh wieder in den Akku aus dem Register
> geladen. Swap, die High Nibble ...


Ho, ho, ho.
Immer langsam mit den jungen Pferden. Das ist nicht das was im Programm 
steht. Wenn der jump nach error erfolgt, geht es wie weiter?

1
error:
2
....
3
4
      JMP read

Es geht nicht zurück zum Aufrufer. Es erfolgt ein Sprung nach read. Da 
ist nix mehr mit 'untersuchung der Zehnerstelle', die nächste Zahl wird 
vom Port eingelesen.

Und das ist auch (grundsätzlich) gut so, auch wenn es technisch falsch 
realisiert ist. Denn bei #4Bh ist ja nach der Betrachtung des #0Bh klar, 
dass es keine BCD Zahl mehr sein kann, unabhängig davon ob die 
'Zehner'-Stelle korrekt wäre oder nicht.

: Bearbeitet durch User
von Achim S. (ahmooo)


Lesenswert?

ich meinte eigentlich mit der 11 nicht 11h sondern 0Bh.
War das ws ich jetzt aber geschrieben habe soweit richtig? Bis auf die 
Error funktion? Wenn die Zahl bei der Subtraktion im plus bereich liegt 
wird kein Carryflag gesetzt

von Karl H. (kbuchegg)


Lesenswert?

Asasassasaasasa Ass schrieb:

> Error funktion? Wenn die Zahl bei der Subtraktion im plus bereich liegt
> wird kein Carryflag gesetzt


Wie oft soll es jetzt noch wiederholt werden?
Wenn bei einer Subtraktion ein Unterlauf entsteht, in a - b das a als 
kleiner als b ist, dann wird das Carry Flag gesetzt, ansonsten wird es 
gelöscht.

Konzeptionell kann man als Mensch schon sagen 'positives Ergebnis' bzw. 
'negatives Ergebnis'. Deinem µC ist das egal, für den gibt es kein 
positiv oder negativ. Für den gibt es nur Überlauf und Unterlauf (oder 
eben wenn du so willst: Borgen von der Stelle links)

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Asasassasaasasa Ass schrieb:
> ich meinte eigentlich mit der 11 nicht 11h sondern 0Bh.

Dann schreibs auch so hin, wenn du das so meinst.
Dann gibts keine Missverständnisse

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.