Atmega 328p Referenzspannung und Kanal wählen

#4992816
Lesenswert?

Hallo in die Runde,

ich bin mir nicht sicher ob ich das richtig verstanden habe was ich bis 
jetzt über den ADC gelesen/gelernt habe. Ich möchte gerne bei dem Atmega 
328p die Spannung an einem Akku messen. Als Referenz möchte ich die 
interne 1,1 Volt nehmen ADC Eingang ist ADC3 (siehe Datenblatt Seite 
317. Nun habe ich dazu folgenden Code geschrieben:
1
#define ADC_MUX_MASK ((1<<MUX3)|(1<<MUX2)|(1<<MUX1)|(1<<MUX0))
2

3
void setup() {
4
ADMUX = (1 << REFS1) | (1 << REFS0);    //Interne 1.1 Volt
5
ADCSRA |= (1 << ADPS2) | (1 << ADPS1);          // Frequenzvorteiler
6
}
7

8
void loop() {
9
adcval = ADC_Read(3);
10
//mach was mit adcval
11
}
12

13
int ADC_Read(int kanal) {
14
  int a;
15
  ADMUX = (ADMUX & ~ADC_MUX_MASK) | (kanal & ADC_MUX_MASK);
16
  ADCSRA |= (1 << ADEN);      //ADC starten
17
  delay(250);
18
  ADCSRA |= (1 << ADSC);      //DUMMY erste Messung 
19
  while (bitRead(ADCSRA, ADSC));  //warten bis Messung beendet ist
20
  a = ADC;            //ADC auslesen
21
  a = 0;
22

23
  for (int i = 0; i < 5; i++) {             //Mehrfachmessung starten
24
    ADCSRA |= (1 << ADSC);      //Erste Messungen
25
    while (bitRead(ADCSRA, ADSC));  //warten bis Messung beendet ist
26
    a += ADC;
27
  }
28
  a = a / 5;
29

30
  return a;
31
}

Ich bin mir ein wenig unsicher ob der Code stimmt, da Anfänger und das 
Ergebnis sobald ich eine LED an PB5 mit HIGH einschalte der ADC Wert um 
20 sinkt (475 ohne LED 455 mit eingeschalteter LED). Am AREF sitzt wie 
unter 
https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Analoge_Ein-_und_Ausgabe 
beschrieben ein Kondensator.

Ich bin für jeden Tipp Dankbar

Viele Grüße
Torsten
#4992845
Lesenswert?

Der Prescaler für den ADC-Takt muß noch eingestellt werden.

Die durchgehende Verwendung von int als Variablentyp ist nicht gut. Nimm 
unsigned char und erst wenn der Wertebereich 255 überschreitet int, 
besser noch unsigned int.

Dividieren durch 5 ist eine schlechte Idee. Da muß der Controller 
richtig rechnen. Nimm 4 oder 8 Werte. Dann wird die Division mit einer 
einfachen Schiebeoperation erledigt.

Wenn der Akku die Versorgungsspannungsquelle des Controllers ist, kann 
man die Spannung auch intern und ohne externe Beschaltung mit Bandgap 
gegen Vcc messen.
#4992870
Lesenswert?

Thomas E. schrieb:
> Der Prescaler für den ADC-Takt muß noch eingestellt werden.

Ich dachte das hätte ich mit
1
ADCSRA |= (1 << ADPS2) | (1 << ADPS1);          // Frequenzvorteiler
erledigt oder habe ich da was falsch verstanden?

Thomas E. schrieb:
> Die durchgehende Verwendung von int als Variablentyp ist nicht gut. Nimm
> unsigned char und erst wenn der Wertebereich 255 überschreitet int,
> besser noch unsigned int.

Werde ich umsetzen

Thomas E. schrieb:
> Dividieren durch 5 ist eine schlechte Idee. Da muß der Controller
> richtig rechnen. Nimm 4 oder 8 Werte. Dann wird die Division mit einer
> einfachen Schiebeoperation erledigt.

Das ist eine gute Idee.

Viele Grüße
Torsten
#4992888
Lesenswert?

Torsten W. schrieb:
> Ich dachte das hätte ich mitADCSRA |= (1 << ADPS2) | (1 << ADPS1);
> // Frequenzvorteiler
> erledigt oder habe ich da was falsch verstanden?

Ne, das hab ich übersehen.

Das
>  ADCSRA |= (1 << ADEN);      //ADC starten

kannst du auch damit kombinieren

Also:

ADCSRA |= (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1);

und startest auch gleich:
1
void Setup(void)
2
{
3
  ADCSRA |= (1 << ADEN) | (1 << ADSC)| (1 << ADPS2) | (1 << ADPS1);
4
  ADMUX = (1 << REFS1) | (1 << REFS0);
5
  while (bitRead(ADCSRA, ADSC));
6
  (void)ADCH;   //Dummy Read
7
}

Den Dummy Read kann man nach dem Enable des ADC machen, muß aber nicht 
sein. Nach einer Kanalumschaltung ist es vollkommen unnötig.
Gast #4993021
Lesenswert?

Mit dem Dummy Read hat es folgendes auf sich: Man kann den ADC ja 
automatisch fortlaufend messen lassen. Wenn du dann den Kanal 
(zwangsläufig während der Messung) umschaltest, bekommst du danach ein 
Ergebnis, bei dem unklar ist, zu welchem Kanal es gehört. Denn je nach 
Zeitpunkt des Befehls findet die tatsächliche Kanal-Umschaltung 
verzögert statt. Diese unklare Messung wird dann gerne als Dummy 
verworfen.

In deinem Fall finden aber Einzel-Messungen statt, da ist das nicht 
nötig.
Gast #4993662
Lesenswert?

Stefan U. schrieb:
> Mit dem Dummy Read hat es folgendes auf sich: Man kann den ADC ja
> automatisch fortlaufend messen lassen. Wenn du dann den Kanal
> (zwangsläufig während der Messung) umschaltest, bekommst du danach ein
> Ergebnis, bei dem unklar ist, zu welchem Kanal es gehört.
Ich betreibe den AT328 als Arduino. Da hat es sich ergeben, dass ich den 
Meßwert hole, wegwerfe und einen Zweiten hole.

Meist stimmt schon der erste Wert, aber oft genug leider nicht.
Gast #4993830
Lesenswert?

> Meist stimmt schon der erste Wert, aber oft genug leider nicht.

Möglicherweise hat deine Signalquelle einen (zu) hohen 
Ausgangswiderstand, so dass sie den S&H Kondensator im ADC nicht schnell 
genug umladen kann. Dann muss man halt ein bisschen warten, ich auch 
kein Problem.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren