Hallo, ich stehe gerade gewaltig auf dem Schlauch, benutze einen Atmega 32 mit C. Ich möchte eine Variable deklarieren wo eine Zahl > 1000000 abgelegt wird, jetzt habe ich probiert so eine long Variable zu deklarieren: uint32_t test; oder auch so unsigned long test; Wenn ich die berechnung laufen lasse und das Ergebnis auf einem LCD ausgebe sehe ich, dass der Compiler diese Variable als Int angelegt hat den die Zahl läuft bis 32767 und springt in den negativen Bereich also -32767. Woran liegt das? Die Berechnung ist sehr simpel, ich lese einen ADC Wert also max 1024 und multipliziere diesen mit 1000. Ich weiß ist eine blöde Frage, aber könte mir einer auf die Sprünge helfen?
>läuft bis 32767 und springt in den negativen Bereich also -32767. >Woran liegt das? Zeig mal die Ausgaberoutine. Vermutlich liegt der Fehler dort.
Hi, poste mal deinen Code. Evtl. müsstest du einen Cast machen!? Kenne ja deinen code nicht! also z.B. so: unsigned long test; test = 1000 * (unsigned long) ((ADC_High << 8)| ADC_Low); Du musst dem Compiler schon bekannt machen, dass du das ganze in einem unsigned long speichern willst.
ich tippe auch auf die Ausgabe, aber wir sind hier ja net beim Lotto...
So Nachwuchs ist versorgt, da bin ich wieder. Das ist meine Routine: >#include <avr/interrupt.h> >#include <avr/io.h> >#include "usart.h" >#include "lcd.h" >#include <util/delay.h> >#include <stdint.h> >volatile int speed = 10001; >uint16_t ReadChannel(uint8_t mux); >int main (void) >{ > //Initialisierung des LCD Displays 4 Bit Mode > LCD_Init(); > //Löschen des Displays > LCD_Clear(); > //Globale Interrupts freischalten > sei(); >> unsigned long test; > int vor,hinter,ergebnis; > uint16_t adcval; > uint16_t wert1; > uint16_t wert2; > uint16_t wert3; > uint8_t wert10; > do > { > adcval = ReadChannel(1); /* MUX-Bits auf 0b0000 -> Channel 0 */ > test=adcval*1000; > ergebnis=test/1024; > vor=ergebnis/10; > hinter=ergebnis%10; > //Ausgabe eines Textes auf dem LCD Display > LCD_Print(0,0,"Temperatur %i.%i2C ",vor,hinter); >> LCD_Print(1,0,"ADC-Wert %i ",test); > LCD_Print(2,0," "); > LCD_Print(3,0," "); > } > while(1); >} Ich hoffe ihr könnt mir helfen.
@eProfi ja sieh mal einer an, SUPER es geht, herzlichen Dank für die schnelle Hilfe. Was heißt dieses UL?
das ist ein häufig gemachter Trugschluß. Der Compiler sieht, adcval ist 16-bit, 1000 ist auch 16-bit, also multipliziert er 16x16->16-bit und erweitert dann das Ergebnis auf 32 Bit. Aber nebenbei, aus der Ferne erscheinen mir die nächsten Zeilen auch noch verbesserungswürdig: > ergebnis=test/1024; > vor=ergebnis/10; > hinter=ergebnis%10; Du meinst wohl vorkomma und nachkomma, aber das geht anders. Am statt *1000/1024 kannst Du gleich *64000 nehmen. Das folgende /65536 sparst Du Dir, indem Du einfach auf das high-Word des Ergebnisses zugreifst (am besten mit einer Union): #define lo 0 //je nach Endianess des Prozessors evtl. umgekehrt #define hi 1 union{unsigned long L;unsigned int I[2];} bigadc; bigadc.L=64000*adcval+32768; //erweitern und aufrunden LCD_out(bigadc.I[hi]);
Was heißt dieses UL? das heißt, er soll das 1000 als unsigned long interpretieren. ginge genauso: test=adcval*(unsigned long)1000; test=(unsigned long)adcval*1000; test=(unsigned long)adcval*(unsigned long)1000; aber mit dem UL (eigentlich reicht auch ein L) geht's am kürzesten. Hast Du das mit dem vor - nach schon herausgebracht? Ich würde auf Folgendes tippen: > vor=ergebnis/100; > hinter=ergebnis-100*vor;
Also es ist vielleicht nicht die schönste Lösung aber es funktioniert so wie ich das gemacht habe. Mit dem ADC lese ich einen Wert von 0 bis 5V ein, das ist mein Temperaturbereich von 0 bis 100 C°. Mit der Rechnung wollte ich folgendes erreichen: adcval * 1000 <--(steht für 100 C°mit einer nachkomma Stelle) Temperaturwert=------------- 1024 <--(Auflösung AD Wandler) So jetzt habe ich den Temperaturwert mit einer Nachkommastelle als eine ganze Zahl vorliegen. Und dann trenne ich halt die Vor und die Nachkomastelle. Was meinst du mit herausgebracht? Deine andere Lösung verstehe ich nicht ganz.
gut, dann erkläre ich es etwas ausführlicher: #define LO 0 //je nach Endianess des Prozessors evtl. umgekehrt #define HI 1 union{unsigned long L;unsigned int I[2];} bigadc; bigadc.L=64000*adcval+32768; //erweitern und aufrunden LCD_out(bigadc.I[HI]); anstatt *1000/1024 kannnst Du auch *64000/65536 rechnen. Das /65536 erledigst Du, indem Du die unteren 16 Bits abschneidest - mit anderen Worten, du verwendest nur die oberen 16 Bits des 32bit-Ergebnisses. Dazu verwende ich gerne die o.g. Union, damit kann man wahlweise auf die 32Bit (.L) oder auf das high- (.I[HI]) oder low-Word (.I[LO]) zugreifen. Vermutlich musst Du *64000L schreiben, sonst ist das Ergebnis wieder nur 16Bit. Das +32768 zum Runden entspricht einem +0,5 und anschließendes Abschneiden der Nachkommastellen. >Also es ist vielleicht nicht die schönste Lösung aber es funktioniert >so wie ich das gemacht habe. Poste doch mal bitte deine Version. Viel Erfolg
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.