Forum: Mikrocontroller und Digitale Elektronik Unsigned long deklarieren?


von Tscheburaschka (Gast)


Lesenswert?

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?

von holger (Gast)


Lesenswert?

>läuft bis 32767 und springt in den negativen Bereich also -32767.
>Woran liegt das?

Zeig mal die Ausgaberoutine. Vermutlich liegt der Fehler dort.

von Mi M. (mike123)


Lesenswert?

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.

von H.j.Seifert (Gast)


Lesenswert?

liegt garantiert an der Ausgabe.
Compiler?

von Mi M. (mike123)


Lesenswert?

ich tippe auch auf die Ausgabe, aber wir sind hier ja net beim Lotto...

von Tscheburaschka (Gast)


Lesenswert?

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.

von eProfi (Gast)


Lesenswert?

probiers mal mit
 test=adcval*1000UL;

von Tscheburaschka (Gast)


Lesenswert?

@eProfi

ja sieh mal einer an, SUPER es geht, herzlichen Dank für die schnelle 
Hilfe.

Was heißt dieses UL?

von eProfi (Gast)


Lesenswert?

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]);

von eProfi (Gast)


Lesenswert?

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;

von Tscheburaschka (Gast)


Lesenswert?

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.

von eProfi (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.