hallo ich habe ein problem, wie kann ich mit den 8051 in 32 bit rechnen. das problem besteht darin, dass ich eine 32 bit dualzahl, an den 4 ports anliegen hab, diese in eine dezimalzahl umrechnen will und dann seriell ausgeben will. das zweite stellt nicht so das problem dar, jedoch das erste. ich hatte mir das ganze bisher so gedacht: zuerst kontrollier ich das höchste bit auf 0 oder 1, um zu wissen ob das ne pos. oder negative dualzahl ist. dann würde ich port 0 auslesen und bit bit für kontrollieren ob da ne 0 oder 1 drinsteht und jeweils z.b. 2^0, 2^1 etc. dann immer dazuaddieren. das ganze geht ja auch bei port0 (8bit) ganz gut, aber wie gehts nun weiter :/ es bringt mir ersten ja nix mit port 1 das gleiche zu machen, da ich ja irgendwann über meine 8 bit bzw. 16 bit drüber hinaus bin, spätestens bei port 3. andererseits muss ich das ergebnis ja auch irgenwie abspeichern können und dann so drauf zugreifen, dass ich das die dann ziffernweise (also für jede zahl 4 bit) am seriellen port ausgeben kann.
so ich meld mich nochmal, ich komm leider mit dem angegebenen code für die 32 bit arithmetik überhaupt nicht klar. wie man 32 bit addiert ist mit mittlerweile klar geworden (immer 1 byte mit dem gleichwertigen anderen, bei übertrag beim nächsten byte halt noch mit dazu), aber ehrlich gesagt hab ich net mal die ahnung ob ich arithmetik überhaupt brauch. wie gesagt ich soll eine 32 bit dualzahl (die im 2er komplement vorliegt) in eine dezimalzahl (+vorzeichen) unwandeln und am ser.port ausgeben. das prob was sich mir nun stellt ist, ich muss ja an die einzelnen dezimalziffern drankommen, da nutzt mir ja rechnen eigentlich nix. gute wäre es zum beispiel, wenn ich die dezimalzahl zuerst abcheck ob bit 32 0 oder 1 ist, wenns 0 ist alles ok, wenns 1 ist bild ich das komplement und addier noch ne 1 dazu. das bekomm ich selbst noch hin. nun wäre es aber geil wenn ich z.b. die dezimalzahl direkt in bcd wandeln könnte, weil da wären ja genau 4 bit eine dezimalziffer und ich bräuchte immer nur 4 bits nehmen, das in dezimal umwandeln und dann entweder nochmal pro bcd-tetrade in einer speicherstelle zwischenspeichern und wenn alles fertig ist halt über die schnittstelle rausschicken. nur wie kann ich ne dualzahl in bcd umwandeln? jedenfalls so ne 32 bit dualzahl? mit 8 bit wäre das ganze ja leicht und 16 bit, könnte ich bestimmt auch noch irgendwie im acc und b register unterbringen aber 32 bit geht halt nicht. ich hab auch schon probiert mit rotation, aber das bringt mich auch nicht wirklich weiter. hoffe einer kann mir bissi auf die sprünge helfen, wichtige wäre mir, dass mir einer die mathematik oder das grundlegende zeigt, wie das geht, wenn ichs verstanden hab kann ich auch den assembler code selbst entwerfen, aber ich hab halt net mal ne ahnung wie ich das anstellen soll. PS: PW vergessen und nicht an meinem rechner und pw zuschicken lassen ging net, also hab ich mich flux mal neu angemeldet :)
Du hast Dir meinen Link nicht angesehen oder ist mein Englisch zu schlecht ? Schau Dir mal die Funktion ADIVR10 an. Die teilt durch 10 und liefert den Rest im ACC. Du mußt nur noch '0' (ASCII) addieren und dann ab in die Serielle. Zusätzlich zeigt F0, ob das Ergebnis Null ist und man die Wandlung abbrechen kann oder weiter teilen muß. Welchen 8051 benutzt Du ? Standardmäßig hat der doch nur 4 Ports. Es ist ungewöhnlich, 32Bit parallel einzulesen. Meistens kann man die 4 Byte hintereinander einlesen und spart damit massig Potpins. Peter
welcher 8051 kann ich net sagen, das ganze wird reine theorie :) wird wohl nur mit nem terminalprogramm getestet, wir warn auch noch gar net an nem echten µcontroller dran, bzw. bisher nur bissi fpga und so zeug programmiert. also deinem tipp konnte ich entnehmen, dass die dualzahl durch 10 geteilt wird und der rest im acc steht, das ist auch logisch. das mit '0' ist mir scho mal untergekommen :) nur ich versteh immer noch net, wie der 8bit µcontroller die 32 bit zahl durch 10 teilt, der kann doch eigentlich nur mit 8 bit bzw. 16 bit bei multi/div umgehen. den code hab ich mir schon durchgelesen. das #precision soll z.b. die anzahl der bits meiner darstellen (also muss ich dort #32 schreiben, das # gibt ja an, dass das ne konstante sein soll oder?). und wieso beginnen die sprungmarken mit einem ?. hat das einen bestimmten grund? und so ganz versteh ich auch net was das programm eigentlich macht, also zuerst wird #precision ins register 2 übertragen, dann wird der accu gelöscht, nun gehts schon los, was ist aptr? wahrscheinlich ne symbolische adresse oder? also adpr wird ins register 0 übertragen, nun wird register 0 um 1 decrementiert, dann wird durch indirekte adressiernng (adresse steht in register 0) der accuinahlt mit diesem speicherplatz getauscht und dann wie 4 niederwertigsten bits nochmal, also im endeffekt nur die 4 höherwertigen bits, swap a heißt doch glaube dass die 4 unteren bits des accus mit den 4 oberen bits getauscht/rotiert werden oder?... also die befehle kenn ich soweit alle nur, ich versteh die logik dahinter nocht so 100 %, also was der code eigentlich macht. ich werd mich diese nacht nochmal drüber machen den code zu verstehen :) aber wie gesagt, hab bisher kaum programmiererfahrungen mit assembler. danke schon mal für die hilfe, ich bewunder echt die leute, die da durchblicken :)
Der 8051 ist ein 8-Bitter, d.h. 32 Bit sind 4 Byte, also precision = 4. Das ? habe ich genommen für Sprungmarken, die funktionslokal sind. APTR ist der Beginn eines Speicherbereiches, der fürs Rechnen benutzt wird (je Operand 4 Byte für 32 Bit). Peter
hätte noch paar kleine fragen :) in aptr steht auf deutsch also immer die zahl mit der ich rechnen will und zwar hab ich das so verstanden immer nur 8 bit, da du in deinem beispielpogramm ja atpr: ds 1 schreibst und das ja bedeutet es wird 1 byte speicherplatz reserviert im astack stehen die adressen der speicherstellen wo ich meine werten von den ports hingelegt hab, bzw. da muss ich die werte der ports hintransferieren. astack ds 4 * precision (ich muss precision=4 wählen da ja 4 byte) reserviert für den astack nun 4 byte speicher. jetzt kommt schon die erste frage: wie kann ich dem astack jetzt adressen vorgeben also wo der seine werte her holen soll, weil bisher beginnt der ja an adresse 30h (jedenfalls im beispielprogramm, da steht ja dseg at 30h), bedeutet das von 30h bis 38h liegt nun der speicherbereich vom atpr und von 38h bis 58h liegt dann mein astack?
hmmm leider geht das ganze net zu editieren oben :) mir ist aufgefallen bei astack definierst du: astack ds 4*precision, wähle ich also precision 4, reserviert der 16 byte für astack(4*4=16), wieso das?
hmm das mit den adressen kann auch net stimmmen hab nen kurzes programm geschrieben und das haut net hin precision equ 4 dseg at 30h aptr: ds 1 cseg at 0h MOV 30h,P0 MOV R0,APTR MOV P1,@R0 normal sollte der doch Port0 auf Adresse 30h tansferieren, dann nimmt der das was in APTR steht (sollte doch 30h sein oder, wenn ich das pben mit dseg at 30h initialisier?) und tranferiert das ins R0, von dort wird indirekt adressiert und zwar adresse 30h (was dort als inhalt drin steht) sollte in den Port1 aber irgendwie schiebt der mir 0h in Port1, also steht da auch 0h drin, wieso steht in adresse 30h net das was ich port0 vorgeb?
ps: mit cseg haben wir gearbeitet aber dseg ist mir leider noch nie untergekommen, vielleicht versteh ich da was falsch, aber dseg steht doch für datensegment oder? ab dieser adresse legt der seine daten ab, also z.b. APTR?
hmm dsa hat sich erledigt, geht doch, bin grad leicht durcheinander gekommen, in aptr stimmt scho alles, muss ja 0 raus kommen, steht ja gar nix drin, sorry wenn ich soviel hier im forum schreib, aber blick echt kaum durch und muss mich mühsam einarbeiten in die materie
ist schon ewig her, seit ich das entwickelt habe. Also APTR ist nur der Merker für den Zeiger und ASTACK ist dann der eigentliche Speicherbereich. Wie tief ASTACK ist, hängt davon ab, wie viele Variablen man gleichzeitig ablegen will. Will man z.B. 2 Werte addieren, muß da auch Platz für 2 Werte sein, also 2 * 4 = 8 Byte. Peter
so nochmal nachgefragt :) um wirklich sicher zu gehen: ich poste auch mal den code ^^ ;********************** Division / 10 for decimal output **************** ;Attention: Input must be positive ! ;Output: X = X / 10, ACC = X % 10 ; F0 = (F0 and 0) if X != 0; adivr10: mov r2, #precision clr a mov r0, aptr ?ad101: dec r0 xch a, @r0 xchd a, @r0 swap a mov b, #10 div ab ;H-Digit /10 swap a xch a, @r0 swap a add a, b swap a mov b, #10 div ab ;L-Digit /10 xchd a, @r0 mov a, @r0 jz ?ad102 clr f0 ?ad102: mov a, b djnz r2, ?ad101 ret also ich versuch jetzt mal in meinen worten zu erklären, wie das ganze funktionieren soll in precision wird in r2 kopiert, d.h. dort steht dann die anzahl meiner bytes drin, die meine zahl die ich von dual in dezimal umwandeln will hat. in zusammenhang mit der letzten zeile djnz r2,.... bedeutet das ganze ist ne schleife und bei 32 bit (4byte) dualzahlen, wird das ganze von programm von marke ?ad101 bis zu dem djnz... genau 4 mal durchlaufen, also immer für 8 bit nehm ich mal an, ist ja auch logisch irgenwie clr a ist wohl klar mov r0, aptr aptr ist sozusagen ne art stack, also wie der normale stack nur halt extra programmiert, in diesem stehen eigentlich adressen drin, wo die daten (dualzahl) hinterlegt ist und die zeile heißt, in r0 wird die adresse der ersten 8 bits meiner dualzahl von aptr transferiert und dann wird r0 mit dec r0 um eins dekrementiert (wieso das gemacht wird verstehe ich noch nicht). nun wird mit a,@r0 der speicherinhalt in den akku geladen und zwar der unter der adresse im register r0 steht nun werden die 4 untersten bites wieder zurückgetauscht mit swap a werden nun die 4 untersten mit den 4 obersten bits im accu getauscht im hilfsregister b wird nun dezimal 10 geladen und div ab teilt nun a mit b wieder swap a dann wird nocmal der inhalt der von r0 indirekt addressierten speicherzelle mit a getauscht und nochmal swap a nun wird a und b addiert wieder swap a und a nun wieder durch 10 geteilt a wird nun wieder mit der speicherstelle (R0 indirekt adressiert) getauscht, bzw. nur die 4 unteren bits und dann wird wieder alles untereinander getauscht durch mov a,@R0 ist der akku 0 wird auf ?ad102 gesprungen und der rest der letzten division (B) in den akku geladen bitte korrigieren falls ich da was falsch verstanden hab, ich versuch nämlich grad mal auf dieser grundlagen durchzusteigen, was dieser code eigentlich macht bzw. wie er es macht. was ich auch noch nicht verstanden haben (dafür ist wohl apdec: (increment arithemtic pointer) da, wie er dann die nächsten 8 bit von der dualzahl holt. kann ja nur so gemacht werden, dass aptr decrementiert wird und somit die nächsten 8 bit meiner dualzahl adressiert oder? also atpr adressiert mir immer indirekt die speicherstelle von astack, wo gerade ein ergebnis drin steht? da der astack bei 4 byte 16 byte groß ist, kann es ja nur sein, dass auch zwischenergebnisse in diesem drin stehen. aptr adressiert mir doch aber immer nur 1 byte vom astack und decrementiert wird der astack immer gleich um die precision also um 4 byte, wie komm ich also an die 3 anderne byte ran?
ja das hab ich mitlerweile auch verstanden :) mit zeiger meinst du bestimmt zeiger auf den speicherbereich von astack nur ich komm mit der ganzen adressierungsgeschichte noch nicht so klar was ich jetzt gemacht hätte ist, dass ich meine dualzahlen direkt im speicherbereich vom astack (kann man ja ausrechnen wenn man ein cseg vorgibt) abgespeichert hätte. dann müsste ich nur noch gucken, dass aptr mir immer darauf zeigt, was ich gerade brauch. und genau das ist mir noch unklar wie ich das hinbekomme und zwar, weil mir noch nicht klar ist, wie die eigentliche division durchgeführt wird, also wieso die mathematik dahinter ist, wenn ich das verstanden hätte, könnte ich mich ja auch um atpr kümmern, damit der das richtig macht, aber ich versteh es immer noch net :/. bisher haben wir immer nur lauflichter programmiert, einfache 8 bit addition ,sinuston am port generieren. das schwierigste bisher war mal nen kleines programm mit interrupts, aber das brauch ich hier ja gar nicht :) "ist schon ewig her, seit ich das entwickelt habe. Also APTR ist nur der Merker für den Zeiger und ASTACK ist dann der eigentliche Speicherbereich. Wie tief ASTACK ist, hängt davon ab, wie viele Variablen man gleichzeitig ablegen will. Will man z.B. 2 Werte addieren, muß da auch Platz für 2 Werte sein, also 2 * 4 = 8 Byte. Peter"
noch ne kleine frage, wo wird eigentlich das ergebnis hingespeichert? ne 32 bit zahl kann doch max. rund 4 mrd. dezimal werden bzw. im zweierkomplement rund 2 mrd. d.h. ich muss mit 10 dezimalziffern rechnen, die ich ja auch irgendwo speichern muss? wie gesagt ich blick den code noch nicht so ganz durch und auch net wo mein ergebnis eigentlich hingelegt wird, eigentlich bleibt ja nur der astack übrig, aber wie wird das gemacht?
hmmm ich geh hier wohl vielen auf den keks weil sich keiner mehr zu wort meldet ich hab das ganze nochmal durchprobiert und bin zu folgenden gekommen: nehmen wir an ich hab ne 16 bit dualzahl 01000100 00101000 (17448) die stehen an speicherstelle 32h und 31h nun nehm ich mir zuerst 32h vor der code macht nun nix anders als die 8 bit durch 10 dezimal zu teilen und damit den rest zu berechnen der rest wird gespeichert im akku nun wird mit den anderen 8 bit das gleiche gemacht und wieder durch 10 geteilt und der rest ermittelt. der rest von der ersten teilaktion und der rest von der zweiten teilaktion sind nun addiert (falls beides kleiner gleich 10, ansonsten muss ich wohl nochmal 10 abziehen) meine niederwertigste dezimalziffer. in adresse 32 h und 33 h steht jeweil der ganze teil der durch/10 division, mit dem ich nun das ganze spiel wieder mach, so dass ich dezimalziffer 2, 3,... bekomm da 16 bis max. 5dezimalziffern entspricht muss ich das also 5 mal wiederholen also ingesamt 10 mal die division durch 10 und restermittlung? nun stellt sich mir nur die frage: wie bekomm ich das jeweilige restergebnis aus dem akku raus? der läuft an in ner schleife, muss ich das irgendwo in dem code noch einfügen, also in der schleife oder wie kann ich den akku mit dem divisionsrest sichern?
und noch ne frage: wie kann ich das mit dem programmcode am geschicktesten machen, dass der mir bei 32 bit immer z.b. zuerst den teil der in z.b. in 34h, dann in 33h, dann in 32h, dann 31h gespeichert ist berechnet, dazu muss ich doch aptr immer dekrementieren oder aber das fehlt im dem code total, wie das gemacht wird versteh ich noch net so ganz
"nun nehm ich mir zuerst 32h vor" Du kannst nicht einzelne Bytes getrennt behandeln, da kommt nur Mist raus. Die Routine ADIVR10 arbeitet immer über die komplette 32Bit-Zahl. Anbei mal ein Testprogramm, welches hex 499602D2 nach dezimal wandelt. Die 32Bit Operanden werden in ASTACK abgelegt (niederwertiges Byte zuerst) und APTR zeigt dann auf den nächsten freien Speicher hinter dem letzten Operanden. Die Ziffern in A kannst Du entweder direkt auf ne Anzeige ausgeben oder woanders abspeichern, z.B. mittels R1 als Zeiger. Peter
ich hab nun 5 stunden rumgebastelt und das programm ist fast fertig :) hab vieles nun manuell aufgebaut, bzw. für 32 bit umgebastelt :) hab sogar vorher die prüfung des msb auf 0 oder 1 hinbekommen und dann die 2er komplementbildung :)^^ nun fehlt nur noch die schnittstelle, da les ich mich grad etwas ein wie das geht, aber danke scho mal für die hilfe, wenn ich mit der schnittstelle net zurecht komm, meld ich mich nochmal
"und dann die 2er komplementbildung" Hoffentlich hast Du nicht vergessen, auch den Übertrag abzuziehen (siehe Funktion AABS). Peter
ne das passt scho, nu hab ich nur nen anders prob^^ mit der seriellen schnittstelle, ich hab ja wie gesagt kein µcontroller hier, das ganze soll rein theoretisch gemacht werden und wird wohl später überprüft. aber genau um die überprüfung gehts wie kann ich das mit der seriellen schnittstelle testen? hab gelesen das ginge mit nem terminal programm, aber wie muss ich die software einstellen oder muss ich da was spezielles programmieren? benutze keil µvision 2
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.