Forum: Mikrocontroller und Digitale Elektronik Atmega 328p Referenzspannung und Kanal wählen


von Torsten W. (toto1975)


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

von Thomas E. (thomase)


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.

von Torsten W. (toto1975)


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

: Bearbeitet durch User
von Thomas E. (thomase)


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.

von Karl M. (Gast)


Lesenswert?

Hallo,

im meinen Augen ist es sinnfrei den ADC immer wieder von neuem 
einzuschalten.
1
ADCSRA |= (1 << ADEN);

Überlege bitte was Setup ist und was man für eine Wandlung machen muss.

von Stefan F. (Gast)


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.

von Manfred (Gast)


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.

von Stefan F. (Gast)


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.

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.