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
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
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.
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
In der Check funktion ist die Carryflag Abfrage. Wie könnte man hier die Frage beantworten: Wann wird das Carryflag auf 1 gesetzt?
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
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.
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
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
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
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?
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
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 ?
http://www.keil.com/support/man/docs/a51/a51_st_rseg.htm http://www.keil.com/support/man/docs/a51/a51_st_segment.htm und weitere Seiten aus der Doku. Vor allen Dingen aber http://www.keil.com/support/man/docs/a51/a51_controls.htm
:
Bearbeitet durch User
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 ?
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
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
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
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.
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
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
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.
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?
Asasassasaasasa Ass schrieb: > Alle Zahlen die in meiner Tabelle bcd festgelegt sind Falsche Antwort
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
Weil die Buchstaben von a-f nicht angezeigt werden kann. Das erklärt mir immer noch nicht mein jc bcd :D
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!
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
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. :))
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
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
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
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.