Forum: Mikrocontroller und Digitale Elektronik ADC gibt keien realistischne wert (atmega8)


von Ralph F. (feu)


Lesenswert?

Hallo,
ich möchte mit einem atmega8 am PC2 Spannung messen. die Referenz ist 
die interne Sp.quelle. Nur gibt das die Schaltung nur misst aus, egal ob 
ich den Aingang auf Masse lege oder gegen Uref. Ich lege den code mit 
bei. Veilleicht hat jemand eine Idee woran es liegen könnte.
Vielen Dank im Voraus

Ralph
1
float ADC_measure (uint8_t ADC_pin, uint8_t U_ref)
2
//ADC_pin =2; Uref=2720
3
{
4
 int16_t value;
5
 uint8_t i;
6
 ADMUX = ADC_pin;  
7
 ADMUX   |= (1<<REFS1) | (1<<REFS0);
8
 ADCSRA   = (1<<ADEN) | (1<<ADPS0) | (1<<ADPS1);
9
 ADCSRA |= (1<<ADSC);
10
 while (ADCSRA & (1<<ADSC)) {}
11
 value = ADCW;
12
 value = 0;
13
 for (i=0;i<4;i++)
14
 {
15
   ADCSRA |= (1<<ADSC);
16
   while (ADCSRA & (1<<ADSC)) {}
17
   value += ADCW;
18
 }
19
 ADCSRA &= ~(1<<ADSC);
20
 value /= 4;
21
 value = value * U_ref /1024;
22
 return value;
23
}

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

>  value = value * U_ref /1024;


value ist ein INteger, U_ref ist ein Integer, 1024 ist ein INteger.
Damit ist diese ganze Berechnung komplett in Integer durchzuführen.
Dein Rückgabewert von 'float' für die Funktion ändert daran nichts mehr.

FAQ
Der Punkt "Datentypen in Operationen"

"gibt Mist aus"
Wie sieht der Mist aus? Wie und wo gibst du aus?
Wenn auf der Anzeige Mist auftaucht, liegt das oft auch daran, dass die 
Ausgabefunktion Mist ist.

von Karl H. (kbuchegg)


Lesenswert?

> ... value * U_ref ....

des weiteren ist zu klären, in welchem Zahlenbereich sich dieses 
Zwischenergebnis bewegen wird. Ist hier mit Overflows zu rechnen?

von Ralph F. (feu)


Lesenswert?

Ich würde 0x000 bei ADC2 auf Masse und 0x3FF bei Vin = Uref erwarten.

Eigentlich kann es nicht zum overflow kommen da 4 * 10bit gut in 16bit 
passen und Uin immer < Uref ist.

Ich rufe die routine in einer Schleife immer wieder auf. Wenn ich nun 
über ein Poti Vin verändere müsste eigentlich auch der wert aus dem 
Wandler signifiante Aenderungen anzeigen.

von Ralph F. (feu)


Lesenswert?

klar jetzt weiss ich was du meinst. werde es ausprobieren

Danke!

von Lutz (Gast)


Lesenswert?

Ralph Feuchter schrieb:
> ADCSRA &= ~(1<<ADSC);

Das ist nach Ende der for-Schleife nicht erforderlich, da dies ja im 
while der for-Schleife schon als Loopbedingung Voraussetzung für das 
Ende ist.
Doof ausgedrückt; ich hoffe du weißt, was ich meine...

von Ralph F. (feucom)


Lesenswert?

Vielen Dank für Eure tips,
ich meld mich wieder, irgend etwas klappt mit den interrupts nicht. muss 
es erstmal rausfinden

ralph

von Ralph F. (feucom)


Lesenswert?

Karl Heinz hat natürlich Recht mit dem überlauf,

habe  jetzt einen typ

uint32_t value1;


eingeführt.
trotzdem funktioniert es nicht

value1 = 1023 * 2720;

müsste eigentlich in 32 bit passen,es kommt aber neben der Warnung 
integer overflow in expression tatsächlich zum überlauf.

kann mir noch jemand sage warum

vielen dank

Ralph

von Karl H. (kbuchegg)


Lesenswert?

Ralph Feuchter schrieb:

> trotzdem funktioniert es nicht
>
> value1 = 1023 * 2720;
>
> müsste eigentlich in 32 bit passen,es kommt aber neben der Warnung
> integer overflow in expression tatsächlich zum überlauf.
>
> kann mir noch jemand sage warum

weil 1023 ein int ist (16 Bit)
und 2720 ein int ist (16 Bit)

damit wird die Multiplikation als 16 Bit Multiplikation ausgeführt.

das du das Ergebnis davon in 32 Bit speichern willst, ist zwar schön, 
ändert aber nichts daran, dass es dem Compiler völlig egal ist, wenn es 
darum geht auszuwählen, wie eine bestimmte Operation zu implementieren 
ist Da zählen einzig und alleine die Operanden der Operation.

von Ralph F. (feu)


Lesenswert?

nachdem was du schreibst müssen die Faktoren dann auch in 32 bit sein, 
wenn ich es richtig verstanden habe.
Im richtigen?? code steht bei mir dann:

uint32_t x;
.......
x = x* 2720;
wobei x vor der operation nicht grösser ist als 1023.
2720 bleibt als fester wert aber integer 16bit.

Ich werde es jedenfalls mal so ausprobieren.

Vielen Dank

Ralph

von Stefan (Gast)


Lesenswert?

> int16_t value;
> ...
> value /= 4;
> value = value * U_ref /1024;

So macht man das:

int16_t value;
...
value=(int32_t) value*U_ref/4096;

von Ralph F. (feucom)


Lesenswert?

vielen Dank für eure Hilfe, wäre schön, wenn es nun gehen würde, macht 
es aber nicht. ich habe jetzt ein Poti am pin 25 (ADC2). Da  die Messung 
in einer Schleife steckt müsste sich eigentlich der Wert ändern. aber 
egal ob ich 0V oder Uref (ist jetzt AVcc) anliegt es kommt immer der 
gleiche Misst raus, gerade als wenn es der falsche pin wäre.
Hat jemand eine Idee?


uint16_t value;
uint8_t i;
ADMUX =0;
ADCSRA=0;
ADMUX   |= (1<<MUX1)|(1<<REFS0);
ADCSRA  |= (1<<ADEN) | (1<<ADPS0) |(1<<ADPS2);

while(1)
{
   ADCSRA |= (1<<ADSC);
   while (ADCSRA & (1<<ADSC)) {}
   value = ADCW;
   value = 0;

   for (i=0;i<4;i++)
   {
     ADCSRA |= (1<<ADSC);
     while (ADCSRA & (1<<ADSC)) {}
     value += ADCW;
     //value += 1234;
   }
   value /= 4;
   value = (uint32_t) value  * 2720 / 1024;

  int_2_BCD ( value,& anzeige_ziffern);
};

Die Funktion int_2_BCD() ist für die Anzeige. Sie legt den Messwert als 
BCD in einer globalen Variablen ab, die dann über ISR(TIMER0_OVF_vect) 
auf eine 7 Segment Anzeige angezeigt wird. Diese Funktion geht 
eigentlich, da ein fester Wert (//value += 1234;) richtig angezeigt 
wird.

Vielen Dank!

ralph

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.