Hallo, Ich habe da n kleines Zahlenproblem. Ich bekomme vom meinem LM75 die Temperatur im Binären Format geliefert. Sowohl TWI wie auch Display laufen schon. Nun will ich die Temperatur in Dezimal auf einem LCD ausgeben. Wer kann mir dabei helfen wie ich die Binäre Zahl so umwandeln kann damit ich Sie an das Display schicken kann ?? ICH HABE DIE FAQ gelesen und nichts gefunden was mir geholfen hat, NEIN ich will keinen Fertigen Code auf dem Silbertablett serviert bekommen und NEIN, die Suche durch das Forum hat keinen für mich verständlichen Erfolg gebracht. Ich brauche eine Lösung die in Assembler umgesetzt werden kann. In C Hilft mir das leider alles nichts. Danke im Voraus für die Hilfe :-) Mfg Tim
entweder schaust du dir itoa mal etwas genauer an, oder die nachfolgende Funktion:
1 | /**
|
2 | * Wandelt übergebene Vor- und Nachkommastellen durch Festkommaarithmetik in eine Zeichenkette um.
|
3 | * @param vork Angabe der Vorkommastelle
|
4 | * @param nachk Angabe der Nachkommastelle
|
5 | * @param tstring Pointer der Zeichenkette, in welche Ergebnis gespeichert werden soll (muss mind 10Bytes beinhalten, z.B. '-125.1250'+'Stringende')
|
6 | */
|
7 | void temptoa(int8_t vork, int8_t nachk, char* tstring) |
8 | {
|
9 | uint8_t i; |
10 | int16_t tmp; |
11 | |
12 | tstring[9]='\0'; //Stringende-Zeichen |
13 | tmp=nachk>>4; //laut Datenblatt nur ersten 4 Bit für Nachkomma |
14 | if( vork < 0 ) { //Vorzeichen hinzufügen |
15 | tstring[0] = '-'; |
16 | vork = -vork; |
17 | //1 auffüllen geaschieht automatisch wenn msb=1
|
18 | //tmp|=0xFFF0; //wenn negativ, dann durch >>4 entstandenen 0 mit 1 ersetzen, damit noch negative Zahl
|
19 | tmp=-tmp; |
20 | }
|
21 | else { |
22 | tstring[0] = ' '; |
23 | tmp&=~(0xFFF0); //falls pos Temp, aber nachk=0b10000000 --> durch msb=1 und >>4 wird nach vorne automatisch mit 1 aufgefüllt, da µC denkt dass neg. Zahl |
24 | }
|
25 | |
26 | for(i=3; i>=1; i--) { |
27 | tstring[i]=(vork % 10) +'0'; //Schleife rückwärts wegen modulo, '0' Addieren um ASCII-Wert für Zahl zu erhalten |
28 | vork /= 10; //nächste Stelle (kein Komma, da variable 'vork' kein float) |
29 | }
|
30 | |
31 | tstring[4]=','; |
32 | |
33 | tmp=tmp*625; //eigentlich *0,0625, aber *625 um float zu vermeiden |
34 | for(i=4; i>=1; i--) { |
35 | tstring[4+i]=(tmp % 10) +'0'; //Schleife rückwärts wegen modulo, '0' Addieren um ASCII-Wert für Zahl zu erhalten |
36 | tmp /= 10; //nächste Stelle (kein Komma, da vork kein float) |
37 | }
|
38 | }
|
Ich muss dazu sagen, dass die Funktion bei meinem DS7505 genutzt wird. Der hat ein paar mehr Nachkommastellen (12Bit Auflösung). Deswegen hatte ich mich für eine programmierung der Festkommaarithmetik entschieden um dem Problem aus dem Weg zu gehen ständig mit 0,0625 zu multiplizieren.
Danke für die schnelle Antwort, kann man den Code auch in Assembler portieren?? Die Funktion in C sieht schon sehr komfortabel aus aber ich MUSS das Problem vorerst in Assembler lösen ;-)) Grüße Tim
Hallo, schau ins Tutorial unter ADC, ziemlich am Ende gibt es auch eine Int_to_ASCII in ASM. http://www.mikrocontroller.net/articles/AVR-Tutorial:_ADC#Ausgabe_als_Spannungswert Gruß aus Berlin Michael
Ich bin in Assambler nicht so fit, aber ein paar Schleifen, If bedingungen, Shifts etc. solltest du doch hinkriegen. Im Endeffekt wird ja nichts gemacht, als die "binäre" Zahl modulo 10 zu dividieren um die einzelnen Stellen zu erhalten und dann mit ASCII '0' zu addieren. Sonderfall ist hier nur, dass bei den Nachkommastellen diese im vordersten Nibble stehen und ich da um 4 shiften muss. Deswegen musste ich auch aufpassen, dass ich mir dadurch nicht eine "negative" Zahl erstelle (also noch einmal Maskieren)
Danke für den Tip, lerne gerade erst mit den uC´s umzugehen und am Anfang ist alles immer ziemlich verwirrend. Warum muss man mit ASCII '0' addieren ?? mfg Tim
>Warum muss man mit ASCII '0' addieren ??
Weil '0' 0x30 ist. Und 0x30 + 0 ist '0'
Weil '1' 0x31 ist. Und 0x30 + 1 ist '1'
...
Und wenn man sich mal die Mühe macht nach
ASCII Code zu suchen, dann findet man das in 0.3s.
Aber manche sind einfach nur zu faul.
Hallo Holger, danke für deine Hilfe. Es tut mir leid dich enttäuschen zu müssen. ETWAS NICHT ZU VERSTEHEN heißt nicht FAUL zu sein. Mich nervt es echt immer wieder in Foren auf KLUGSCHEI?ER zu stoßen die anscheinend auf nichts anderes warten als ihren Frust an Leuten auszulassen die FREUNDLICH nach Hilfe Fragen. Wenn ich zu FAUL gewesen WÄRE dann hätte ich geschrieben das ich keinen BOCK habe selber nach einer Lösung zu suchen und jemanden brauche der MEIN Problem löst. Wie du aber sicherlich lesen kannst habe ich darum geben mich auf den Richtigen Weg zu bringen weil ich selber nicht auf die Lösung komme. Es hat halt nich jeder der mit dem Thema uC anfängt schon profundes Wissen aus der Weltraumforschung parat. Und ich habe nunmal gelernt, das wenn ich etwas nicht weiss nunmal Fragen muss damit es einem jemand erkährt !! Wenn doofe Kommentare ernten wollte dann hätte ich den Thread wohl eher :"Haltet mir für doof und Faul" bennen sollen. Nichts gegen dich persönlich aber ich hab die Nase voll in Foren immer wieder nur zu lesen :"DU DEPP MUSST DIE SUCHE BENUTZEN", dann bräuchte man nämlich kein Forum mehr sondern nur noch ein WIKI.... Und wie bereits geschrieben nutzt einem die beste Hilfe nichts, wenn man Sie nicht versteht oder eindfach nur ne Denkblockade hat... mfg Tim
Da stimme ich Tim völlig überein!!! Manchmal ist es echt graußig geworden hier, viele denken sie seien Gott und man müsste ihnen die Füsse lecken. Sehr schade eigentlich :/ Aber es gibt hier zum Glück genauso viele, die sehr hilfreich zur Seite stehen, auch blutigen Anfängern - denen gillt auch hier mein Dank! Und WARUM man zu 0x30 nochmal ne 0 addieren muß hast du noch nicht mal beantworten können holger.
weil 30 Hex eine 0 Dezimal ist. Laut ASCII Tabelle.
in Assembler ganz grob so, ( einfache Methode) Zähler (B) mit 30h vorladen (wegen ASCII) dann Ausgangswert (A) von LM 75 in Hex minus 64h (100dez) und den Zähler (B) plus eins Wenn kein Überlauf dann wieder minus 64h und Zähler plus eins. das ganze so lange bis überlauf ist ( als Schleife ) Wenn Überlauf dann Zähler (B) minus eins und Ausgangswert (A) plus 64h jetzt das ganze mit 0Ah (10 dez) (als schleife) und dann noch mit 1 (als Schleife ) gilt allerdings erstmal für 8 Bit Zahlen. Bei 16 Bit entsprechend größer. zB. mal für 16 Bit...8051 geht aber auch anders... ************************************************************ ; 16 bit Binär zu Dez /ASCI 16 Bit wert in R2 high, R3 Low ;************************************************************ asci1 equ 30h asci2 equ 31h asci3 equ 32h asci4 equ 33h asci5 equ 34h mov asci1,#30h ; 00 für Dez / 30h für ASCII mov asci2,#30h mov asci3,#30h mov r2,#0h mov r3,#09h clr c ;mov b,#10000 div10000: mov a,r3 ; Zehntausender subb a,#10h mov r3,a mov a,r2 subb a,#27h mov r2,a jc end_zt inc asci1 jmp div10000 end_zt: mov a,r3 add A,#10h mov r3,a mov a,r2 addc a,#27h mov r2,a div1000: clr c mov a,r3 ; Tausender subb a,#0E8h mov r3,a mov a,r2 subb a,#03h mov r2,a jc end_t inc asci2 jmp div1000 end_t: mov a,r3 add a,#0E8h mov r3,a mov a,r2 ; Hunderter addc a,#03h mov r2,a div100: clr c mov a,r3 subb a,#64h mov r3,a mov a,r2 subb a,#0 mov r2,a jc end_h inc asci3 jmp div100 end_h: mov a,r3 ; Zehner und Einer add a,#64h mov b,#0Ah div ab add a,#30h mov asci4,a mov a,b add a,#30h mov asci5,a mov a,asci1 ; Vornullunterdrückung cjne a,#30h,null4 mov asci1,#20h null1: mov a,asci2 cjne a,#30h,null4 mov asci2,#20h null2: mov a,asci3 cjne a,#30h,null4 mov asci3,#20h null3: mov a,asci4 cjne a,#30h,null4 mov asci4,#20h null4: end
Also muss ich das Register (z.B. R16)= 00011111 durch Modulo 10 Teilen, mag jetzt wieder ne Anfänger Frage sein, aber der Befehlssatz sieht keine Modulo Operation vor...... Werde aber sicherheitshalber (bevor ich wieder angeraunzt werde) das AVR Arithmetic Tutorial durchforsten ob ich da was finde. Aber davon mal abgesehen. Ich Teile die Zahl durch 10 und der "Modulo" Rest gibt dann die erste Dezimalstelle an, die nächste Modulo 10 Operation gibt dann den "Rest" also die 2.te Dezimalstelle aus usw. Würde es funktionieren das ich diese Schleife unterbrechen kann wenn ich das Register auf "o" überprüfe ?? Also tst R16 oder ist das zu einfach gedacht?? mfg Tim
ich denke Du willst Assembler ?? Module gibts da nicht.
Oh, da war Stephan ein kleines bisschen schneller als ich mit meinen Fingern. Werde mir das Listing mal genauer anschauen. Ich Danke dir schonmal dafür. Wenn ich Dazu Fragen habe, wende ich mich vertrauensvoll an dich ;-)) Gruß Tim
Ich meinte ja auch die MODULO Operation. Tschuldigung wenn ich da was falsch geschrieben habe. Ich bezog mich mit der MODULO Operation auf Remote1 mfg Tim
@stephan Das ist 8051-Assembler. Ich fürchte der TO hat einen AVR (zumindest ist "tst R16" ein AVR-Befehl).
war nen Schreibfehler von mir. Aber die MODULO gibts in ASM nicht. Auf nem 8051 kannst Du DIV AB machen und mit nem AVR halt die Schleifenmethode mit Subtraktion (Urmethode). Der AVR kann nicht dividieren (in Hardware). (Außer zu Schieben damit die Profis nicht raunen)
Mit dem Überlauf ist das CARRY Flag gemeint?? geht das auch auf "1" wenn eine Rechenoperation negativ geworden ist?? Ich ging bis jetzt davon aus, das ein Carry nur kommt wenn ich einen positiven Überlauf habe.. mfg Tim
@georg, jep richtig erkannt. MODULO ist aber auch kein ASM :-) Mal schauen was er aus dem DIV AB beim Zehner macht !
Hallo Tim, der LM75 ist doch über I2C angeschlossen ? da solltest du aber 2 Byte in denen die benötigten 9Bit sind) bekommen ... das 1. Byte Bit(7) Polarität Bit 6-0 und vom 2. Byte Bit(7) für Komma (5) Wert. ------ 1.Byte 2.Byte 00000001 0xxxxxxx = 1,0 00000000 1xxxxxxx = 0,5 00000000 0xxxxxxx = 0,0 Grad 11111111 1xxxxxxx = - 0,5 11111110 0xxxxxxx = - 1,0 usw. Gruss Ralf
Zu schade, daß der AVR keinen DA (decimal adjust) Befehl hat, dann wärs ganz einfach (alles andere könnte man übersetzen). 16 Bit binär nach packedBCD für 8051: BIN to BCD: For R2=#16d ;Bit-Anzahl mov R0, #Integer ;LSB clr C for R3=#2 ;Byte-Anzahl=2 mov A, @R0 rlc A mov @R0, A inc R0 next mov R0, #BCD_Wert for R3=#2 ;Byte-Anzahl=2 mov A, @R0 addc A, @R0 da A mov @R0, A inc R0 next Next ret
@old school Jepp da haste Recht. Ist in 2 Byte untergebracht. Ich habe mir folgenden Ansatz ausgedacht (wenn ich auch noch nicht weiss wie das Umsetzen kann): Ich Maskiere mit einer Bitmaske das erste Byte aus ob ich eine führende 1 habe (>> neg Zahl). Wenn "ja" dann das 2.er Komplement bilden und schonmal ein "-" ans Display, wenn "nein" kein 2.er Komplement bilden und "+" ans Display senden. Im nächsten Schritt würde ich im ersten Byte die Umwandlung von Bin in Ascii durchführen um den Temp Wert "Betrag" zu haben. Zuletzt würde ich im 2.ten Byte das MSB auf 0 oder 1 überprüfen um zu wissen ob ich ,5 oder nicht ,5 Anzeigen muss. Zu guter letzt würde ich (von hinten nach Vorne) die Zahlen ans Display ausgeben. Alternativ könnte man doch auch nach jeder "Umwandlung" die entsprechende Zahl an das Display senden, da ich ja mit "-100" anfange also die 100.er Stelle auslote ??? Mfg Tim
Also, habe gerade mal einen Test gemacht und in AVR Studio Simuliert. Zum guten Schluss muss ich noch temp1-temp3 mit "30h" addieren um das entsprechende ASCII Zeichen für die Zahl zu erhalten. Anschließen muss ich "nur noch" temp1-3 an das Display übergeben und hätte schon mal in Dezimal die Temperatur dort stehen. Negative Temperaturen und Nachkommastellen sind noch nicht berücksichtigt !!! Es geht dabei lediglich um die Umwandlung in ASCII. Ist das so Richtig wie ich das gemacht habe ?? Mfg Tim
>Es geht dabei lediglich um die Umwandlung in ASCII. >Ist das so Richtig wie ich das gemacht habe ?? Schon mal selber ausprobiert?
>Zum guten Schluss muss ich noch temp1-temp3 mit "30h" addieren um das >entsprechende ASCII Zeichen für die Zahl zu erhalten. und genau deswegen wurde der Zähler bei mir mit 30h vorher geladen. tricky !!
Stephan Henning schrieb: > und genau deswegen wurde der Zähler bei mir mit 30h vorher geladen. > tricky !! Da haste recht, warum einfach wenn´s auch schwer geht grins. Werde mal nach der Arbeit versuchen das ganze einzubinden. Ich danke euch für die Tips. Ihr habt mir wirklich weitergeholfen. Jetzt habe ich es verstanden was da passieren muss damit es klappt. mfg Tim
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.