Forum: Mikrocontroller und Digitale Elektronik Gleitkommazahlen


von Peter (Gast)


Lesenswert?

Hallo,

ich will mit dem internen AD-Wandler eines Atmega eine Spannungswert 
auslesen, in eine Gleitkommazahl umrechnen und auf einem LCD-Display 
anzeigen lassen.

Zum Beispiel: 1 Bit im ergebnissregister des ADW entspricht 54,244mV.
Ich will jetzt in V umrechnen auf eine Stelle hinterm Komma und auf 
einen LCD Display anzeigen lassen.

Könnte mir jemand helfen?

mfg peter

von Floh (Gast)


Lesenswert?

Ungeschickt.
Gleitkomma ist bäh.
Rechne es als Ganzzahl in mV aus, bei der Ausgabe verschiebst du dann 
das Komma um 3 Stellen und lässt die letzten 2 Stellen weg.
:-)

von Andreas K. (derandi)


Lesenswert?

Haste denn wenigstens schon mit was angefangen?

von Peter (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

@Floh
die idee ist eigentlich gar nicht schlecht.

Hier ist mal mein gesammter Programmcode, aber intressant ist nur der 
Teil mit der Umrechnung. Ich habe ihn mit Anzeige Gleitkommazahl 
makiert.

mfg peter

von Falk B. (falk)


Lesenswert?


von Floh (Gast)


Lesenswert?

Peter schrieb:
> Hier ist mal mein gesammter Programmcode

Du kommst aus der Assemblerecke. ;-)
Was du da im Programm versuchst, ist rjmp mit goto nachzubauen.
Ist eigentlich nicht zu empfehlen, da C selbst "bessere/gebräuchlichere" 
Strukturen mitbringt, als unbedingte Sprünge irgendwohin.
Stichwort Funktionen.

Oder z.B. so was:
>  Spannungswert = ADCH, ADCL;

da solltest du dich mal über den Kommaoperator schlau machen :-)

von eProfi (Gast)


Lesenswert?

Mit Multiplikation:
Beitrag "Re: Float-Berechnung auf 8051 mit SDCC"


Ganz anderer Ansatz:
Nimm die Routinen zur Ausgabe von Zahlen von Peter Danegger, nur dass Du 
nicht dezimale Werte subtrahierst / addierst, sondern die Aquivalente zu 
1V, 0,1V etc.
Somit geht die Umwandlung ganz ohne Division und Multiplikation.
1
#include<stdio.h>
2
#include<conio.h>
3
4
char c;
5
unsigned int i=0x0123<<6;//linksbündig  entspricht 1,4208V ergibt 1,421
6
//wenn das ADLAR-Bit in ADMUX gesetzt ist, entfällt das Schieben um 6
7
8
void main(void){
9
  putch(' ');
10
11
  i=(   1<<6);  //ergibt 0,004
12
  i=(   1<<6)+2;//ergibt 0,005
13
//i=(1023<<6)+2;//ergibt 4,995
14
15
  c='0';
16
  while(i>=65536/   5){c++;i-=65536/   5;} //13107
17
  putch(c);putch(',');
18
19
  c='0';
20
  while(i>=65536/  50){c++;i-=65536/  50;} //1310
21
  putch(c);
22
23
  c='0';
24
  while(i>=65536/ 500){c++;i-=65536/ 500;} //131
25
  putch(c);
26
27
  c='0';
28
  while(i>=65536/5000){c++;i-=65536/5000;} //13
29
  putch(c);
30
31
  putch(' ');
32
33
  i=(1023<<6)+2;//ergibt 5,000
34
35
  c='0';
36
  while(i>=65472/   5){c++;i-=65472/   5;} //13094
37
  putch(c);putch(',');
38
39
  c='0';
40
  while(i>=65472/  50){c++;i-=65472/  50;} //1309
41
  putch(c);
42
43
  c='0';
44
  while(i>=65472/ 500){c++;i-=65472/ 500;} //130
45
  putch(c);
46
47
  c='0';
48
  while(i>=65472/5000){c++;i-=65472/5000;} //13
49
  putch(c);
50
  }

von eProfi (Gast)


Lesenswert?

Der vorige Ansatz war nur als Ideenspender gedacht, er funktioniert bei 
manchen Werten nicht korrekt (z.B. wird statt 0,210  0,20: ausgegeben).
Deshalb hier eine neue Version:

von den 1024 Werten weichen 26 um 0,001 vom korrekt gerundeten Wert ab, 
damit kann man leben.
1
  register unsigned int i;
2
  register char c;
3
  i=(   x<<6)+6;//Schieben entfällt bei ADLAR=1, +6: runden
4
//i=(1023<<6)+6;//Test: ergibt 4,995
5
  c='0';
6
  while(i>=13107){c++;i-=13107;} //13107.2
7
  putch(c);putch(',');
8
9
  c='0';i+=i*4;i-=2; //das selbe wie i=i*5-2; (-2: Korrektur, da vorher Nachkommastellen abgeschnitten wurden)
10
  while(i>= 6553){c++;i-= 6553;} //6553.6
11
  putch(c);
12
13
  c='0';i+=i*4;i*=2;i-=2; //das selbe wie i=10*i-2; aber kürzerer Code
14
  while(i>= 6553){c++;i-= 6553;}
15
  putch(c);
16
17
  c='0';i+=i*4;i*=2;i-=2;
18
  while(i>= 6553){c++;i-= 6553;}
19
  putch(c);
Das alternativ Subtrahieren / Addieren habe ich absichtlich nicht 
gemacht, da das Vorzeichen-Bit ein Bit Genauigkeit kostet.

von df1as (Gast)


Lesenswert?

Darf man kein printf() nehmen? Ansonsten:

unsigned long dV;

dV = ((unsigned long) ADC-Wert * 568789L) >> 20;
printf ("Spannung = %lu,%lu V", dV / 10, dV % 10);

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.