Forum: Mikrocontroller und Digitale Elektronik ADC des ATmega128


von Jens K. (mister232)


Lesenswert?

Hallo Leute,

könnt ihr mal über folgenden Code schauen:
1
// Function to initialize the microcontroller's internal ADC
2
void init_ADC(void)
3
{
4
  ADMUX = (1<<REFS0) | (1<<ADLAR); // Select AVCC as reference, Left adjust ADC result to allow easy 8 bit reading
5
  ADCSRA = (1<<ADPS1) | (1<<ADPS0) | (ADPS2); // Prescaler = 128 -> 62.5kHz at 8MHz clock
6
  ADCSRA |= (1<<ADEN); // Enable ADC
7
  
8
  ADCSRA |= (1<<ADSC); // Dummy conversion, required in datasheet
9
  while (ADCSRA & (1<<ADSC)){} // Wait for conversion to be done
10
  (void) ADCW; // Read conversion result and throw away
11
}
12
13
// Function which does one ADC conversion at the selected ADC channel
14
uint16_t internal_ADC(uint8_t channel)
15
{
16
  ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F); // Select channel for AmpSig1
17
  ADCSRA |= (1<<ADSC); // Convert signal
18
  while (ADCSRA & (1<<ADSC)){} // Wait for conversion to be done
19
  
20
  return ADCW;
21
}

Iregendwie will der ADC nicht. Er gibt mir immer nur Werte zwischen 15V 
und 16V aus, obwohl der Eingang auf GND liegt.

An AVCC liegen 5V aus einer Referenzspannungsquelle und die im 
Datenblatt angegebene LC-Schaltung

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Jens K. schrieb:
> ADCSRA = (1<<ADPS1) | (1<<ADPS0) | (ADPS2); // Prescaler = 128 ->
> 62.5kHz at 8MHz clock

kleiner Tippfehler

von M. K. (sylaina)


Lesenswert?

Jens K. schrieb:
> Iregendwie will der ADC nicht. Er gibt mir immer nur Werte zwischen 15V
> und 16V aus, obwohl der Eingang auf GND liegt.

Also für 15 und 16V bräuchte man etwas mehr infos, was aber auffällt: Du 
hast ADLAR gesetzt und liest das komplette ADC-Register aus. Das ist 
bestimmt nicht so gewollt. Bei ADLAR benutzt man eigentlich nur das 
ADCH-Byte, das ADCL-Byte interessiert dabei eigentlich nicht.

: Bearbeitet durch User
von Jens K. (mister232)


Lesenswert?

Vielen Dank, jetzt klapts!

von Jens K. (mister232)


Lesenswert?

Zu früh gefreut :-(

Jetzt kommt nur noch 0V raus, auch wenn am Eingang 5V liegen

von Jens K. (mister232)


Lesenswert?

Der Aufruf der Funktion sieht momentan so aus:
1
// *********** Amperometric sensor 1 **********************************
2
    AmpSig1 = (internal_ADC(0) * 5) / 1024; // Convert ADC value to volt value
3
    
4
    // *********** Amperometric sensor 2 **********************************
5
    AmpSig2 = (internal_ADC(1) * 5) / 1024; // Convert ADC value to volt value
6
    
7
    dtostrf(AmpSig1, 6, 2, value_as_string);
8
    sprintf(output,"%s V\n\r", value_as_string);
9
    debug_message(output);
10
    dtostrf(AmpSig2, 6, 2, value_as_string);
11
    sprintf(output,"%s V\n\n\r", value_as_string);
12
    debug_message(output);

von M. K. (sylaina)


Lesenswert?

Aufbau auch OK?
Ah, und mach mal Float-Zahlen in deiner Berechnung. Nicht dass du in INT 
rechnest.

also *5.0 und /1024.0

: Bearbeitet durch User
von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Du hast leider die Definition für deine AmpSig1 und 2 Variablen nicht 
gepostet, und auch den Buffer 'value_as_string' nicht. dstrtof() will da 
double sehen und der Buffer muss gross genug sein.

Zum Testen ist es hilfreich, dir ADCW einfach mal mit itoa auf den 
Output zu werfen.

von Jens K. (mister232)


Lesenswert?

Also das mit dem 5.0 und 1024.0 bringt zumindest schonmal andere Werte 
als 0V auf den Schirm. Am Anfang wird für die erste Variabel 0.31V and 
für die zweite 0.32V ausgegeben. Der erste Wert geht dann auf 0.33V hoch 
und bleibt da, egal welche Spannung ich am Eingang anlege.

AmpSig1 und AmpSig2 sind float Variablen, der Buffer für dstrof() ist 
groß genug.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Jens K. schrieb:
> AmpSig1 und AmpSig2 sind float Variablen,

Warum verwendest du dann dtostrf()? Float ist float und double is 
double.
Float Variablen gibst du ohne Umschnurzel-Trara direkt mit sprintf aus:
1
sprintf(value_as_string,"%f V\n\r", AmpSig1);

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Jens K. schrieb:
> Also das mit dem 5.0 und 1024.0 bringt zumindest schonmal andere Werte
> als 0V auf den Schirm. Am Anfang wird für die erste Variabel 0.31V and
> für die zweite 0.32V ausgegeben. Der erste Wert geht dann auf 0.33V hoch
> und bleibt da, egal welche Spannung ich am Eingang anlege.
>
> AmpSig1 und AmpSig2 sind float Variablen, der Buffer für dstrof() ist
> groß genug.

Hast du schon versucht dir mal stumpf den ADC-Wert ausgeben zu lassen, 
also  statt deinen Code mal
1
uint16_t AmpSig1;
2
uint16_t AmpSig2;
3
AmpSig1 = internal_ADC(0);
4
AmpSig2 = internal_ADC(1);
5
6
itoa(AmpSig1, value_as_string, 10);
7
sprintf(output,"%s V\n\r", value_as_string);
8
debug_message(output);
9
itoa(AmpSig2, value_as_string, 10);
10
sprintf(output,"%s V\n\n\r", value_as_string);
11
debug_message(output);
zu probieren? Und bist du dir sicher, dass die Spannung, die du angelegt 
hast, auch am Pin anliegt? (direkt mal auf dem Pin messen)

Die Änderungen von oben hast du schon umgesetzt (u.a. das "Problem" mit 
ADLAR und ADSP2)?

Matthias S. schrieb:
> Float Variablen gibst du ohne Umschnurzel-Trara direkt mit sprintf aus:

Und dann bekommt er, je nach Compiler-Version (wie das Makefile 
aufgebaut ist usw.), ein ? raus. Ich nehme dabei auch immer dtostrf();

: Bearbeitet durch User
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.