Hallo ich habe den obigen Beitrag gelesen und will mich auch daran
halten. Aber mein Prozessor wohl nicht.
Ich habe eine Schaltung mit einem Mega 16 aufgebaut. Die geht auch.
Am Port PA0 will ich eine Spannung messen (Zwischen 0 und 5 Volt)
Da die 5V aus 1024 Stücken bestehen, muss ich den ADC Wert *5 /1024
nehmen.
Ich habe am Mega 16 auch eine JTAG Schnittstelle, so dass ich die
Operationen verfolgen kann
adc16 ist das Korrekte Ergebnis vom AD Programm (uint16_t)
Der Wert soll * 5000 genommen werden und dann durch 1024 Dividiert
werden
Dann hat man das Ergebnis im mV
adc16 = (adcval=ADC_Read_Avg(0,10)); Das geht bei fast 4V =
987
adc64 = (adc16 * 5000); adc64 uint64_t
adc32 = (adc16 * 5000); adc32 uint32_t
adcul = (adc16 * 5000); adcul unsigned long
Nach dem schrittweisen Ausführen steht bei Wert (Watch Ansicht)
bei allen 3 Variablen 19800 anstatt 4935000 ???
Kann mir jemand helfen was ist falsch? Ich brauche nur eine Zeile, die
aber richtig rechnet.
... unabhängig davon, dass ich den Sinn dieser Rechnerei nicht
verstehe.... ein uint64_t gibts zwar beim avr-gcc... imho ist dieser
allerdings dennoch bloß 32 Bit groß.
Sinn...........
ich möchte einfach nur aus dem Wert z.B.985 die Spannung in mV
ausrechnen und wenn bei einer Teiloperation (* 5000) schon Quatsch
rauskommt, brauche ich mit dem Ergebnis nicht weiter rechnen.
@Frank G. (frankg)
>Sinn...........>ich möchte einfach nur aus dem Wert z.B.985 die Spannung in mV>ausrechnen
Dann solltest du den Artikel Festkommaarithmetik noch einmal in Ruhe
lesen, dort steht nämlich alles drin. 64 Bit Operationen braucht man
dazu mal sicher NICHT, 32 Bit reichen.
Expertentip . . .
"Wichtig ist dabei, daß "
etc. pp.
Viele Wege führen nach Rom:
1024 und 5000 kann man maximal um 8 kürzen, am besten durch 4, es
bleiben
256 und 1250
d.h. statt der Division durch 256 lässt man das unterste Byte weg.
Aber es gibt noch eine elegantere Lösung, wenn man sich die Bits und
deren Wertigkeit ansieht:
1
Bit Wert mV
2
9 512 2500
3
8 256 1250
4
7 128 625
5
6 64 312,5
6
5 32 156,25
7
4 16 78,125
8
3 8 39,0625
9
2 4 19,53125
10
1 2 9,765625
11
0 1 4,8828125
1
uint16_tmask=512,add=2500,mV=0;
2
do{
3
if(adc&mask)mV+=add;
4
add>>=1;
5
}while((mask>>=1)!=0);
6
//Dann ist die maximale Summe: 2500+1250+625+312+156+78+39+19+9+4= 4992
7
8
//Genauer ist wegen Runden:
9
uint16_tmask=512,add=2500,mV=0;
10
do{if(adc&mask)mV+=add;add>>=1;}while((mask>>=1)>4);add=20;// mask ist jetzt 4
Ralph S. schrieb:> ein uint64_t gibts zwar beim avr-gcc... imho ist dieser> allerdings dennoch bloß 32 Bit groß.
Das ist falsch. Wo ein int64 draufsteht, ist auch ein int64 drin.
Aber: "double" und "float" sind auf dem AVR gleich.
@eProfi (Gast)
>Alles aus dem Stegreif und ungetestet.
Und auch völlig daneben. Der Op wollte nicht mehr als einen ADC-Wert in
ein eine Meßgröße umrechnen und nicht irgendwelche Exkurse in die Welt
der Micro- und Nonsensoptimierung unternehmen. Das Ziel erreicht man mit
einer einfachen, übersichlichtlichen Zeile C-Code, die zu 99% auch
vollkommen ausreicht.
Es geht noch schneller, wenn man die Reihenfolge umdreht und die ersten
Additionen (solange die Summe in 8 Bit passt), mit 8 Bit ausführt:
1
typedefunion{
2
uint16_tW;/Word
3
struct{
4
uint8_tL;//Lo-Byte (Reihenfolge je nach Endianess)
5
uint8_tH;//Hi-Byte (Reihenfolge je nach Endian-ness)
6
};
7
}un_i16;
8
9
un_i16mV;
10
mV.W=0;
11
if(adcl&1)mV.L+=5;//8-Bit-Addition
12
if(adcl&2)mV.L+=10;
13
if(adcl&4)mV.L+=20;
14
if(adcl&8)mV.L+=40;
15
if(adcl&16)mV.L+=79;
16
if(adcl&32)mV.W+=157;//16-Bit-Addition
17
if(adcl&64)mV.W+=313;
18
if(adcl&128)mV.W+=626;
19
if(adch&1)mV.W+=1250;
20
if(adch&2)mV.W+=2500;
21
22
//bei 3300 geht noch eine Zeile mehr mit .L:
23
mV.W=0;
24
if(adcl&1)mV.L+=3;//8-Bit-Addition
25
if(adcl&2)mV.L+=6;
26
if(adcl&4)mV.L+=13;
27
if(adcl&8)mV.L+=26;
28
if(adcl&16)mV.L+=52;
29
if(adcl&32)mV.L+=104;
30
if(adcl&64)mV.W+=207;//16-Bit-Addition
31
if(adcl&128)mV.W+=413;
32
if(adch&1)mV.W+=826;
33
if(adch&2)mV.W+=1650;
Um den vollen 16-bit-Wertebereich zu nutzen, kann man die addierten
Werte mit 8 (nur 4 shifts), 10 (human readable), 13 (65535/5000=13,107),
16 (nur 4 shifts) oder 19 (65535/3300=19,859) multiplizieren (dadurch
werden sie genauer) und nach den Additionen wieder dividieren, bringt
aber fast nichts.
Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.
Wichtige Regeln - erst lesen, dann posten!
Groß- und Kleinschreibung verwenden
Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang