Forum: Mikrocontroller und Digitale Elektronik ADC-Kanäle sukzessive abfragen


von StefanK (stefanka)


Lesenswert?

Hallo,

ich will drei ADC-Kanäle (0 bis 2) so schnell wie möglich hinter 
einander abfragen, die Werte der Kanäle separat aufsummieren und nach 
z.B. vier Wiederholungen die Mittelwerte bilden und die Messungen 
beenden. Die Wandlungen sollen im Hintergrund laufen und den Prozessor 
nicht warten lassen.

Wie macht man das am elegantesten? Hat jemand ein Beispiel?

von Gunnar F. (gufi36)


Lesenswert?

StefanK schrieb:
> Wie macht man das am elegantesten? Hat jemand ein Beispiel?

int h=adc(0);
int i=adc(1);
int j=adc(2);

von Peter D. (peda)


Lesenswert?

StefanK schrieb:
> so schnell wie möglich

1k schnell oder 1M schnell?

StefanK schrieb:
> Wie macht man das am elegantesten?

Und elegant soll es auch noch sein.
Mir reicht es schon, wenn es funktioniert.

von Mi N. (msx)


Lesenswert?

StefanK schrieb:
> Wie macht man das am elegantesten?

Summierer mit anschließendem Integrator.
Das läuft voll im Hintergrund.

von Florian (flori_n)


Lesenswert?

Die Frage ist so unspezifisch. Mit den gegebenen Angaben:

Akkumulatorregister auf 0 setzen.
Nacheinander Kanal auswählen, Wandlung starten, Ergebnis abwarten, 
Ergebnis auf das jeweilige Akkumulatorregister addieren.
Das ganze viermal, dann den Inhalt der Akkumulatorregister durch vier 
teilen.

Oder worauf bezieht sich die Frage genau?

von StefanK (stefanka)


Lesenswert?

Dann will ich mal mehr spezifizieren. Das ganze soll auf einem Arduino 
entwickelt/getestet werden und später auf einem ATtiny laufen. Ich will 
die Fähigkeit Des AD-Wandlers laufend zu messen geschickt nutzen, so 
dass das Hauptprogramm nicht warten muss.

von Florian (flori_n)


Lesenswert?

Dann geht es genauso, wie beschrieben.
Den ADC auf maximal 200 kHz konfigurieren (so kenne ich es von den AVR), 
ADC-Interrupt aktivieren, Kanal auswählen und Wandlung starten.
Am Ende der Wandlung das Ergebnis auslesen, den nächsten Kanal auswählen 
und die nächste Wandlung starten.

von Mi N. (msx)


Lesenswert?

StefanK schrieb:
> Dann will ich mal mehr spezifizieren.

Erwähne am besten nicht, was das werden soll, und warte, bis es 
Sonnabend geworden ist.
ATTiny und möglichst schnell geht eher in Richtung schwarzer Schimmel.

von StefanK (stefanka)


Lesenswert?

Florian schrieb:
> Dann geht es genauso, wie beschrieben.
> Den ADC auf maximal 200 kHz konfigurieren (so kenne ich es von den AVR),
> ADC-Interrupt aktivieren, Kanal auswählen und Wandlung starten.
> Am Ende der Wandlung das Ergebnis auslesen, den nächsten Kanal auswählen
> und die nächste Wandlung starten.

Danke Florian. Kann man in der Interruptroutine bereits auf den nächsten 
Kanal umschalten und die nächste Wandlung für diesen anstossen?

Gibt es Beispiele für Implementierungen? Das ist doch vermutlich ein 
Standardfall, dass man mehrere Kanäle direkt hintereinander auslesen 
will.

von Rainer W. (rawi)


Lesenswert?

StefanK schrieb:
> Wie macht man das am elegantesten?

Indem man ersteinmal die Randbedingungen klar legt.

Welche ADCs kommen in Frage, wie hoch muss die Auflösung mindestens 
sein, welche µCs kommen in Frage, was ist der Mindestwert für "so 
schnell wie möglich", was darf es kosten?

von StefanK (stefanka)


Lesenswert?

Das hier kommt dem am nächsten, was ich suche:
https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Analoge_Ein-_und_Ausgabe#Der_interne_ADC_im_AVR

/* ADC Einzelmessung */
uint16_t ADC_Read( uint8_t channel )
{
  // Kanal waehlen, ohne andere Bits zu beeinflußen
  ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
  ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
  while (ADCSRA & (1<<ADSC) ) {   // auf Abschluss der Konvertierung 
warten
  }
  return ADCW;                    // ADC auslesen und zurückgeben
}

...und genau das "warten" will ich vermeiden:
while (ADCSRA & (1<<ADSC) ) {   // auf Abschluss der Konvertierung 
warten
  }

von S. L. (sldt)


Lesenswert?

> Kann man in der Interruptroutine bereits auf den nächsten
> Kanal umschalten und die nächste Wandlung für diesen anstossen?

Warum nicht?
  Woher sollte der ADC wissen, ob er im Hauptprogramm oder in der ISR 
gestartet wird?

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

StefanK schrieb:
> Wie macht man das am elegantesten? Hat jemand ein Beispiel?

Nacheinander auslesen!
Beispiel?
Nicht 100%. Einfach umzubauen.


StefanK schrieb:
> Dann will ich mal mehr spezifizieren. Das ganze soll auf einem
> Arduino
> entwickelt/getestet werden und später auf einem ATtiny laufen. Ich will
> die Fähigkeit Des AD-Wandlers laufend zu messen geschickt nutzen, so
> dass das Hauptprogramm nicht warten muss.

Auch kein Problem.

von StefanK (stefanka)


Lesenswert?

Rainer W. schrieb:

> Welche ADCs kommen in Frage, wie hoch muss die Auflösung mindestens
> sein, welche µCs kommen in Frage, was ist der Mindestwert für "so
> schnell wie möglich", was darf es kosten?

Interner ADC des ATMega328P zum entwickeln und wenn fertig auf Target 
ATtiny13 portieren, Auflösung 10bit. Kein extra AD-Wandler.

Wichtig ist mir, dass das Hauptprogramm nicht warten muß, bis der AD die 
Wandlungen beendet hat. Und da hapert es mit dem Beispiel im o.g. 
Tutorial.

von StefanK (stefanka)


Lesenswert?

S. L. schrieb:
>   Woher sollte der ADC wissen, ob er im Hauptprogramm oder in der ISR
> gestartet wird?

Das weiß der AD natürlich nicht. Aber bis die Messung des neuen Kanals 
von der Interruptroutine angestossen ist, hat der AD vlt schon mit der 
Messung des alten Kanals weitergemacht.

von S. L. (sldt)


Lesenswert?

Sie verwenden für diesen Fall natürlich den 'Single Conversion'- und 
nicht den 'Free Running'-Modus.

von StefanK (stefanka)


Lesenswert?

Auch Ulli auf seiner Roboterseite wartet:
https://ullisroboterseite.de/avr-libs-adc.html#avg-source

for(i=0; i< AdcAvgCount; i++)
  { // Eine Wandlung
  ADCSRA |= (1<<ADSC);
  // Auf Ergebnis warten...
  while(ADCSRA & (1<<ADSC));

  result += ADCW;
  }

warten ist doof!

von S. L. (sldt)


Lesenswert?

Vorschlag: ausprobieren!
  Also:
1. Ihr Beispiel (von wem auch immer) mit dem Warten.
2. Umschreiben auf Interrupt nach Wandlung, d.h. ohne Warten.
3. mehrere Kanäle mit dem Umschalten in der ISR.

von Georg M. (g_m)


Angehängte Dateien:

Lesenswert?

Warten muss man nicht.

von StefanK (stefanka)


Lesenswert?

S. L. schrieb:
> Vorschlag: ausprobieren!
>   Also:
> 1. Ihr Beispiel (von wem auch immer) mit dem Warten.
> 2. Umschreiben auf Interrupt nach Wandlung, d.h. ohne Warten.
> 3. mehrere Kanäle mit dem Umschalten in der ISR.

Klingt nach einem guten Vorschlag. Danke, auch an Florian.

von Rainer W. (rawi)


Lesenswert?

StefanK schrieb:
> Wichtig ist mir, dass das Hauptprogramm nicht warten muß, bis der AD die
> Wandlungen beendet hat.

Das Hauptprogramm muss nicht warten. Es kann während dessen beliebigen 
anderen Aktionen nachgehen und dann mit einem Interrupt auf das ADIF 
reagieren.

Was dein "so schnell wie möglich" betrifft, hast du mit einem ATmega328 
das Problem, dass er nur einen einzigen ADC besitzt, d.h. du kannst den 
Kanal sowieso erst umschalten und die nächste Messung starten, wenn die 
erste Wandlung fertig ist. Parallele Messung ist damit nicht möglich. 
Die Wandlungszeit beträgt 13 ADC Clock Zyklen, da lässt sich nichts dran 
abkürzen, wenn du die volle Auflösung nutzen möchtest.

: Bearbeitet durch User
von Arduino F. (Firma: Gast) (arduinof)


Angehängte Dateien:

Lesenswert?

Beispiel aus meiner Wühlkiste, leicht modifiziert!
Tuts für die üblichen Arduino AVR Boards und dem t45 und t85

Zeigt den grundsätzlichen Ablauf.
Wenn gewünscht, gibts auch die Lib, die ist aber noch relativ 
unaufgeräumt.

von Florian (flori_n)


Lesenswert?

StefanK schrieb:
> ...und genau das "warten" will ich vermeiden:
> while (ADCSRA & (1<<ADSC) ) {   // auf Abschluss der Konvertierung
> warten
>   }
Mir war nicht klar, dass diese Warteschleife der Kern der Frage ist. 
Deshalb gingen meine Antworten etwas daran vorbei.
Aber mit den anderen Antworten sollte es jetzt ja klar sein.

von Cyblord -. (cyblord)


Lesenswert?

Ja mein Gott dann mach doch einfach mal. Einfach mal was ohne ein 
Beispielcode, ohne Copy&Paste ohne Vorlage MACHEN.
Schau in das scheiß Datenblatt.

Aber nööööö, bevor man 5 Zeilen Code schreibt erstmal Thread im Forum 
aufmachen.

: Bearbeitet durch User
von Wastl (hartundweichware)


Lesenswert?

Cyblord -. schrieb:
> erstmal Thread im Forum aufmachen.

.... und 100 Beiträge generieren/provozieren. Tagelang
warten bis einem die gebratenen Tauben in den Mund fliegen.

von Rainer W. (rawi)


Lesenswert?

Cyblord -. schrieb:
> Aber nööööö, bevor man 5 Zeilen Code schreibt erstmal Thread im Forum
> aufmachen.

Was erwartest du?
Es reicht ja nicht einmal für eine vernünftige gestellte Frage, aus der 
wenigstens die Randbedingungen klar hervor gehen - aber ist ja 
einfacher, irgendwelche Anforderungen ins Forum zu kippen, als selber zu 
denken.

: Bearbeitet durch User
von Hugo H. (hugo_hu)


Lesenswert?


von S. L. (sldt)


Lesenswert?

Leute, die (zugegeben etwas dürftigen) Voraussetzungen waren doch gleich 
zu Beginn offensichtlich - es wurde niemand gezwungen weiterzulesen.

Erinnert mich an Watzlawicks 'alte Jungfer' in 'Anleitung zum 
Unglücklichsein'.

von Sherlock 🕵🏽‍♂️ (rubbel-die-katz)


Lesenswert?

Wenn die ISR ausgeführt wird, ist der ADC schon mit der nächsten Messung 
beschäftigt. Wenn die ISR den Kanal nun wechselt, gilt das erst für die 
danach folgende Messung (die übernächste).

von Ralf K. (kurtx)


Lesenswert?

Mi N. (msx) schrieb:

> ATTiny und möglichst schnell geht eher in Richtung schwarzer Schimmel.

Der TO hatte "mehr spezifiziert" und einen Arduino als Hardware genannt. 
Somit ist ein Mega328 als µC anzunehmen.
Was soll da z.B. auf einem Tiny25 langsamer laufen?

Bei beiden ist 200 kHz ADC-Takt das Limit für volle Auflösung.
Bei beiden dauert eine Wandlung 13 ADC-Takte.
Bei beiden fällt bei der max. Speed von 20 MHz die Rechnerei (Summierung 
und Mittelwert) kaumt in's Gewicht.

????

von Falk B. (falk)


Lesenswert?

Was meint ChatGPT dazu? ;-)

von S. L. (sldt)


Lesenswert?

> Wenn die ISR ausgeführt wird, ist der ADC schon mit der
> nächsten Messung beschäftigt.

Im 'Single Conversion Mode'?
  Na, Stefan Frings ...

von Falk B. (falk)


Lesenswert?

ChatGPT meint dazu

"Super! Der ATmega328 (wie auf dem Arduino Uno) hat einen eingebauten 
ADC (Analog-Digital-Wandler), den man effizient nicht-blockierend mit 
Interrupts benutzen kann. Damit kannst du Messungen durchführen, ohne 
dass dein Programm anhalten muss.
🛠️ Ziel:

Nicht-blockierende ADC-Messung auf dem ATmega328 mit Interrupts. 
Ergebnis soll z. B. in einer globalen Variable gespeichert werden.
✅ So funktioniert es:

    ADC wird im Hintergrund gestartet.

    Wenn die Wandlung fertig ist, löst der ADC einen Interrupt aus.

    Im ISR (Interrupt Service Routine) holst du das Ergebnis ab und 
speicherst es z. B. in einer globalen Variable.

📜 Beispielcode in C (für Atmel Studio oder avr-gcc)"
1
#define F_CPU 16000000UL
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
5
volatile uint16_t adc_result = 0;
6
7
void adc_init(void) {
8
    ADMUX = (1 << REFS0); // AVcc als Referenz, ADC0 als Eingang
9
    ADCSRA = (1 << ADEN)  | // ADC einschalten
10
             (1 << ADIE)  | // Interrupt einschalten
11
             (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Prescaler 128
12
    sei(); // globale Interrupts aktivieren
13
}
14
15
void adc_start_conversion(void) {
16
    ADCSRA |= (1 << ADSC); // Start ADC-Konvertierung
17
}
18
19
ISR(ADC_vect) {
20
    adc_result = ADC; // Ergebnis in globale Variable speichern
21
    // Optional: adc_start_conversion(); // Neue Messung direkt starten (Dauerbetrieb)
22
}
23
24
int main(void) {
25
    adc_init();
26
    adc_start_conversion(); // erste Messung starten
27
28
    while (1) {
29
        // Hauptprogramm läuft weiter, ohne zu blockieren
30
        // z. B. LED steuern, andere Tasks bearbeiten
31
    }
32
}

Naja, prinzipiel erstmal richtig, wenn gleich unvollständig.

von Mi N. (msx)


Lesenswert?

Ralf K. schrieb:
> Der TO hatte "mehr spezifiziert" und einen Arduino als Hardware genannt.
> Somit ist ein Mega328 als µC anzunehmen.
> Was soll da z.B. auf einem Tiny25 langsamer laufen?
>
> Bei beiden ist 200 kHz ADC-Takt das Limit für volle Auflösung.

Bei 1 MHz kann man auch 6 Bit erhalten.
Wo hatte der TO denn volle Auflösung gefordert?

Eine Antwort zeigte 12 Bit Auflösung bei 375 ksps, eine andere dann 
'adcCallCack' bei Arduino und selbst "Ulli auf seiner Roboterseite 
wartet", weil alles so schwierig ist.

Schon klar, alles ein kleiner Spaß zum Freitag ;-)

von Falk B. (falk)


Lesenswert?

Etwas besser, wenn gleich nicht gut

"Ah, das macht Sinn! Du möchtest den Mittelwert der Messungen bilden und 
gleichzeitig den ADC mit maximaler Geschwindigkeit betreiben. Kein 
Problem – beides lässt sich leicht einbauen!
🔧 Ziel:

    Maximale ADC-Datenrate: Der ADC des ATmega328 läuft mit einer 
maximalen Taktfrequenz von 200 kHz bei einer Referenzfrequenz von 16 
MHz. Um dies zu erreichen, muss der ADC mit einem Prescaler von 2 
betrieben werden.

    Mittelwertbildung: Du willst mehrere Messungen sammeln und den 
Mittelwert berechnen, um Störungen zu glätten.

🏎️ Maximale ADC-Geschwindigkeit:

    Der ADC benötigt bei einem Prescaler von 2 nur 13 Takte pro Messung. 
Bei einem 16 MHz Systemtakt läuft der ADC mit 16 MHz / 2 = 8 MHz, was 
eine maximal mögliche Frequenz von 200 kHz ergibt."

FALSCH! Soviel zum Thema KI! Ein mit Exabyte aufgepumpter 
"Zauberlagorithums" fabuliert einfach was zusammen, das in Teilen 
korrekt ist, in Summe logisch aber falsch. Naja . . .

"🧮 Mittelwert berechnen:

Wir sammeln eine feste Anzahl an Messungen, addieren sie und teilen sie 
durch die Anzahl der Messungen, um den Mittelwert zu erhalten.
📜 Code mit Mittelwert und maximaler Geschwindigkeit:"
1
#define F_CPU 16000000UL
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
5
#define NUM_SAMPLES 10   // Anzahl der Messungen für den Mittelwert
6
7
volatile uint16_t adc_result = 0; // Aktuelles ADC-Ergebnis
8
volatile uint16_t adc_sum = 0;    // Summe der Messungen
9
volatile uint8_t sample_count = 0; // Zähler für gesammelte Messungen
10
11
// ADC initialisieren
12
void adc_init(void) {
13
    ADMUX = (1 << REFS0); // AVcc als Referenz, ADC0 als Eingang
14
    ADCSRA = (1 << ADEN)  | // ADC einschalten
15
             (1 << ADIE)  | // Interrupt einschalten
16
             (1 << ADPS0);  // Prescaler auf 2 (maximale Geschwindigkeit)
17
    sei(); // globale Interrupts aktivieren
18
}
19
20
// ADC-Konvertierung starten
21
void adc_start_conversion(void) {
22
    ADCSRA |= (1 << ADSC); // Start ADC-Konvertierung
23
}
24
25
// ISR für den ADC-Interrupt
26
ISR(ADC_vect) {
27
    adc_result = ADC; // ADC-Ergebnis holen
28
    adc_sum += adc_result; // Messung zur Summe hinzufügen
29
30
    sample_count++; // Zähler erhöhen
31
32
    if (sample_count >= NUM_SAMPLES) {
33
        uint16_t average = adc_sum / NUM_SAMPLES; // Mittelwert berechnen
34
        adc_sum = 0; // Summe zurücksetzen
35
        sample_count = 0; // Zähler zurücksetzen
36
37
        // Mittelwert weiterverwenden (z. B. über serielle Ausgabe)
38
        // Serial.println(average); // Wenn du in der Arduino IDE arbeitest
39
    }
40
41
    adc_start_conversion(); // Neue Messung starten
42
}
43
44
int main(void) {
45
    adc_init();
46
    adc_start_conversion(); // erste Messung starten
47
48
    while (1) {
49
        // Hauptprogramm läuft weiter, ohne zu blockieren
50
        // Hier kannst du die Mittelwerte weiterverarbeiten
51
    }
52
}

: Bearbeitet durch User
von Sherlock 🕵🏽‍♂️ (rubbel-die-katz)


Lesenswert?

S. L. schrieb:
> Im 'Single Conversion Mode'?

Der TO hatte nach dem free running Modus gefragt.

StefanK schrieb:
> ich will drei ADC-Kanäle (0 bis 2) so schnell wie möglich hinter
> einander abfragen

und

> Die Wandlungen sollen ... den Prozessor
> nicht warten lassen.

von Falk B. (falk)


Lesenswert?

Mit dem Hinweis auf den Free running modus schafft es auch ChatGPT. Hmm, 
not bad. Aber ist da WIRKLICH die Zukunft der Softwareentwicklung? Ich 
meine, ich musste erst die entscheidenden Stichworte geben? Wenn ich die 
aber nicht kenne, weil mir das Problem bzw. dessen Lösung unbekannt 
sind, was macht man dann?

Beispielcode mit Free Running Modus und Mittelwertbildung in der ISR:
1
#define F_CPU 16000000UL
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
5
#define NUM_SAMPLES 10   // Anzahl der Messungen für den Mittelwert
6
7
volatile uint16_t adc_result = 0; // Aktuelles ADC-Ergebnis
8
volatile uint16_t adc_sum = 0;    // Summe der Messungen
9
volatile uint8_t sample_count = 0; // Zähler für gesammelte Messungen
10
11
// ADC initialisieren
12
void adc_init(void) {
13
    ADMUX = (1 << REFS0);  // AVcc als Referenz, ADC0 als Eingang
14
    ADCSRA = (1 << ADEN)   | // ADC einschalten
15
             (1 << ADIE)   | // Interrupt einschalten
16
             (1 << ADATE)  | // Free Running Modus aktivieren
17
             (1 << ADPS0);   // Prescaler auf 2 (maximale Geschwindigkeit)
18
    sei(); // globale Interrupts aktivieren
19
}
20
21
// ISR für den ADC-Interrupt
22
ISR(ADC_vect) {
23
    adc_result = ADC; // ADC-Ergebnis holen
24
    adc_sum += adc_result; // Messung zur Summe hinzufügen
25
    sample_count++; // Zähler erhöhen
26
27
    if (sample_count >= NUM_SAMPLES) {
28
        uint16_t average = adc_sum / NUM_SAMPLES; // Mittelwert berechnen
29
        adc_sum = 0; // Summe zurücksetzen
30
        sample_count = 0; // Zähler zurücksetzen
31
32
        // Mittelwert weiterverwenden (z. B. über serielle Ausgabe)
33
        // Beispiel:
34
        // Serial.println(average); // Wenn du in der Arduino IDE arbeitest
35
    }
36
37
    // Keine Notwendigkeit, eine neue Messung zu starten, 
38
    // der ADC läuft im Free Running Modus weiter.
39
}
40
41
int main(void) {
42
    adc_init(); // ADC initialisieren
43
44
    while (1) {
45
        // Hauptprogramm läuft weiter, ohne zu blockieren
46
        // Hier kannst du andere Aufgaben erledigen
47
    }
48
}

von S. L. (sldt)


Lesenswert?

Stefan Frings vermutete:
> Der TO hatte nach dem free running Modus gefragt.

Ich denke, StefanK hatte bis heute abend den Unterschied zwischen 'free 
running' und 'single conversion' gar nicht gekannt - Sie haben das 
hineininterpretiert.

Beitrag #7880748 wurde vom Autor gelöscht.
von Rainer W. (rawi)


Lesenswert?

S. L. schrieb:
> Stefan Frings vermutete:
>> Der TO hatte nach dem free running Modus gefragt.

Lass die Finger von Dingen, die du nicht verstehst.

Mit deiner Editiererei hast du als Alleinstellungsmerkmal erreicht, dass 
der Link auf den zitierten Beitrag nicht mehr funktioniert.

von Cyblord -. (cyblord)


Lesenswert?

S. L. schrieb:
>> Wenn die ISR ausgeführt wird, ist der ADC schon mit der
>> nächsten Messung beschäftigt.
>
> Im 'Single Conversion Mode'?
>   Na, Stefan Frings ...

Ja ihm fehlen so viele Grundlagen...

von Helmut H. (helmuth)


Lesenswert?

Falk B. schrieb:
> Aber ist da WIRKLICH die Zukunft der Softwareentwicklung? Ich
> meine, ich musste erst die entscheidenden Stichworte geben?

Bin gespannt, wann es den ersten Studiengang mit Abschluss
Dipl. KI-Prompter gibt.

von Georg M. (g_m)


Angehängte Dateien:

Lesenswert?

ATtiny mit 2x ADC.

von N. M. (mani)


Lesenswert?

Georg M. schrieb:
> ATtiny mit 2x ADC.

Bringen einem 2 ADC so viel mehr wenn man eigentlich 3 braucht? 😄

StefanK schrieb:
> Ich will drei ADC-Kanäle (0 bis 2)

Wenn man es richtig schnell haben will, soll er bei den G von STM32 oder 
so vorbei schauen. Die haben teilweise schon Mittelwert Filter in HW und 
3-5 komplette ADCs mit bis 4MSPS. Da muss die CPU garnichts machen.

Ich bin mir nicht ganz sicher, aber ich meine dass es auch ein 
Peripheral gab das summieren kann (könnte aber auch der H7 gewesen sein 
bin ich nicht sicher). Wenn das der Fall ist würden 3 DMA und das 
Peripheral voll den Rest machen. Ohne CPU.

Viel Spaß beim Datenblatt lesen 😁

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Das Problem beim AVR ADC ist, dass nach dem Kanalwechsel extra Zyklen 
anfallen, i.W. dauert die erste ADC Konvertierung so lange wie die erste 
Konvertierung nach Aktivierung des ADC.

Ist also recht langsam.

In den Datenblättern steht dazu nix.  Hatte ich vor Jahren mal beim 
Atmel-Support nachgefragt.

von Roland F. (rhf)


Lesenswert?

Hallo,
Johann L. schrieb:
> In den Datenblättern steht dazu nix.

Datenblatt ATmega8/L (2486AA-AVR-02/2013), Kapitel "ADC Input Channels", 
Seite 194:
"In Free Running mode, always select the channel before starting the 
first conversion. The channel selection may be changed one ADC clock 
cycle after writing one to ADSC. However, the simplest method is to wait 
for the first conversion to complete, and then change the channel 
selection. Since the next conversion has already started automatically, 
the next result will reflect the previous channel selection. Subsequent 
conversions will reflect the new channel selection."

rhf

von Gunnar F. (gufi36)


Lesenswert?

N. M. schrieb:
> Viel Spaß beim Datenblatt lesen 😁

och, das ist ja noch recht kompakt im Vergleich zum Referenzmanual!

von Rainer W. (rawi)


Lesenswert?

N. M. schrieb:
> Wenn man es richtig schnell haben will, soll er bei den G von STM32 oder
> so vorbei schauen. Die haben teilweise schon Mittelwert Filter in HW und
> 3-5 komplette ADCs mit bis 4MSPS. Da muss die CPU garnichts machen.

Da es hier um den ATmega328 mit seinem doch eher gemächlichen ADC Clock 
geht, spielt die CPU-Zeit für die Mittelung, in Relation zur 
Wandlungszeit, für die erreichbare Abtastrate fast keine Rolle.

: Bearbeitet durch User
von S. L. (sldt)


Lesenswert?

Johann L. schrieb:
> Das Problem beim AVR ADC ist, dass nach dem Kanalwechsel extra Zyklen
> anfallen, i.W. dauert die erste ADC Konvertierung so lange wie die erste
> Konvertierung nach Aktivierung des ADC.
>
> Ist also recht langsam.

Ist das so?
  Die komplette Messsequenz 3*4 benötigt hier bei einem ADC-Teiler /64 
rund 10800 Takte, also pro Messung 900 System- bzw. 14 ADC-Takte. Laut 
Datenblatt dauert eine Wandlung 13 ADC-Takte, die Differenz von ca. 1 
ADC-Takt bzw. 64 Systemtakte geht beim Interrupthandling verloren.

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Falk B. schrieb:
> Beispielcode mit Free Running Modus und Mittelwertbildung in der ISR:
Halbiert die Abfragerate bei mehr als einem Kanal, da jede 2te Messung 
verworfen werden muss.

Sherlock 🕵🏽‍♂️ schrieb:
> Der TO hatte nach dem free running Modus gefragt.
Nur in deiner Fantasie.

von N. M. (mani)


Lesenswert?

Gunnar F. schrieb:
> och, das ist ja noch recht kompakt im Vergleich zum Referenzmanual!

Erst das eine, dann das andere 😄

Rainer W. schrieb:
> Da es hier um den ATmega328 mit seinem doch eher gemächlichen ADC Clock
> geht, spielt die CPU-Zeit für die Mittelung, in Relation zur
> Wandlungszeit, für die erreichbare Abtastrate fast keine Rolle.

Ja, er hatte es erst sehr allgemein geschrieben und wollte so schnell 
wie möglich 3 ADC Werte haben.

StefanK schrieb:
> ich will drei ADC-Kanäle (0 bis 2) so schnell wie möglich hinter
> einander abfragen

Erst später wurde dann ein ATMega/Tiny gesetzt.

von Mi N. (msx)


Lesenswert?

N. M. schrieb:
> Ja, er hatte es erst sehr allgemein geschrieben und wollte so schnell
> wie möglich 3 ADC Werte haben.
> ...
> Erst später wurde dann ein ATMega/Tiny gesetzt.

Das merkt jedoch nur der Leser, der alle Beiträge in der Reihenfolge 
ihres Entstehens gelesen hat.
Vermutlich sind die Anforderungen (mal wieder) ganz trivial, sodaß es 
egal ist, ob ADC-Werte 'möglichst schnell', 'sofort' oder 'unmittelbar' 
zur Verfügung stehen.

Ich denke, der TO weiß selber nicht, was er braucht oder will. Sonst 
könnte er das ja einfach mal mitteilen.

von Sherlock 🕵🏽‍♂️ (rubbel-die-katz)


Lesenswert?

"Möglichst schnell" erfordert jedenfalls den Free-running Mode denn nur 
dann arbeitet der ADC ohne Pausen zwischen den Messungen.

von Mi N. (msx)


Lesenswert?

Sherlock 🕵🏽‍♂️ schrieb:
> "Möglichst schnell" erfordert jedenfalls den Free-running Mode denn nur
> dann arbeitet der ADC ohne Pausen zwischen den Messungen.

Nein!

von Sherlock 🕵🏽‍♂️ (rubbel-die-katz)


Lesenswert?

Mi N. schrieb:
> Nein!

In der Kürze liegt die Würze, aber man kann es auch übertreiben. So ganz 
ohne Begründung hilft der Kommentar nur dir.

von Mi N. (msx)


Lesenswert?

Stichwort: gesperrte Interrupts.
In welcher Phase befindet sich der ADC? Wann darf ein neuer Kanal 
gewählt werden? Welcher Wert gehört dann zu welchem Kanal?

Nach der Eingangsfrage des TO hätte ich in Bezug auf 'möglichst schnell' 
beispielsweise einen STM32F/G/Hxyz vorgeschlagen. Ein einzelner ADC im 
'scan modus' und Ablage der Einzelwert per DMA wäre 'recht schnell'.

Ein kleiner, feiner µC ist schon der STM32G031, der neben dem 'scan 
modus' auch noch 'oversampling' zur Filterung bietet.
Das nutzt aber nur, wenn man weiß, was man will.

von Sherlock 🕵🏽‍♂️ (rubbel-die-katz)


Lesenswert?

Mi N. schrieb:
> Wann darf ein neuer Kanal gewählt werden?

Jederzeit. Der neue Kanal gilt dann für die nächste Messung, die nach 
der gerade laufenden kommt. Also für das übernächste Messergebnis. Damit 
kann man lückenlos Kanalwechsel implementieren, so dass der ADC ohne 
Pause mit seiner maximalen Geschwindigkeit durch arbeitet.

: Bearbeitet durch User
von Mi N. (msx)


Lesenswert?

Sherlock 🕵🏽‍♂️ schrieb:
> Der neue Kanal gilt dann für die nächste Messung, die nach
> der gerade laufenden kommt. Also für das übernächste Messergebnis.

'Übernächstes Messergebnis'? Und das soll schnell sein?

von Sherlock 🕵🏽‍♂️ (rubbel-die-katz)


Lesenswert?

Mi N. schrieb:
> 'Übernächstes Messergebnis'? Und das soll schnell sein?

Ja das ist schnell. Beispiel:

Du startest den ADC im free-running Modus auf Kanal 1 und gibst ihm 
direkt danach (genauer gesagt: einen ADC Takt später) den Befehl, zum 
Kanal 2 zu wechseln.

Wenn er Kanal 1 gemessen hat, wird er die ISR zum ersten mal aufrufen. 
Während diese ausgeführt wird, misst der ADC bereits den Kanal 2 und du 
kannst schon den Befehl zum Wechsel auf Kanal 3 eben.

Wenn er Kanal 2 gemessen hat, wird er die ISR zum zweiten mal aufrufen. 
Während diese ausgeführt wird, misst der ADC bereits den Kanal 3.

Wenn er Kanal 3 gemessen hat, wird er die ISR zum dritten mal aufrufen.

Das alles passiert, ohne den ADC zwischenzeitlich anzuhalten 
(free-running). Ohne den free-running Modus müsste der ADC nach jeder 
Messung pausieren und per Software zur Fortsetzung getriggert werden. 
Das dauert länger.

: Bearbeitet durch User
von Mi N. (msx)


Lesenswert?

Mi N. schrieb:
> Stichwort: gesperrte Interrupts.

Was hast Du daran nicht verstanden?
Es ist mir jetzt auch egal!

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?


von Sherlock 🕵🏽‍♂️ (rubbel-die-katz)


Lesenswert?

Mi N. schrieb:
>> Stichwort: gesperrte Interrupts.
> Was hast Du daran nicht verstanden?

Das habe ich ignoriert, weil der TO das nicht gefordert hat. Vermutlich 
hast du den Aspekt nur eingebracht, um mir widersprechen zu können.

von Sherlock 🕵🏽‍♂️ (rubbel-die-katz)


Lesenswert?

Arduino F. schrieb:
> Du irrst!

Auch für dich:

Sherlock 🕵🏽‍♂️ schrieb:
> In der Kürze liegt die Würze, aber man kann es auch übertreiben. So ganz
> ohne Begründung hilft der Kommentar nur dir.

von Gunnar F. (gufi36)


Lesenswert?

Das ist so typisch für dieses Forum. Irgendwer rotzt eine unüberlegte 
und schlampig hingeworfene Frage rein und dann streiten sich tagelang 
die Experten. Immerhin Respekt vor soviel Hilfsbereitschaft. Ich erwarte 
mehr Sorgfalt von einem Fragesteller.

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Sherlock 🕵🏽‍♂️ schrieb:
> Auch für dich:
Ja ja...

Ich möchte dein übersteigertes Selbstbewusstsein nicht mit Fakten 
belasten die dir offensichtlich nicht schmecken.

von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

Johann L. schrieb:
> Das Problem beim AVR ADC ist, dass nach dem Kanalwechsel extra Zyklen
> anfallen, i.W. dauert die erste ADC Konvertierung so lange wie die erste
> Konvertierung nach Aktivierung des ADC.

Das kann ich nicht bestätigen. Siehe Anhang. Arduino UNO mit ATmega328P. 
Ich messe 38,459kHz am Testpin PB0. Das macht 76,918 KHz ISR-Frequenz. 
x13x16=16MHz. D.h. jede Messung braucht wie im Datenblatt beschrieben 13 
ADC-Takte. Und das mit Wechsel des ADC-Kanals nach jeder Messung. Das 
Testsignal ist sogar jitterfrei (auch durch Nutzung von sleep_mode()).

Mit Single Shot Betrieb und Neustart per CPU in der ISR kommt man nur 
auf 29,4099kHz am Testpin, weil der ADC ja halt ein paar Takte inaktiv 
ist, bis die ISR angesprungen der ADC neu gestartet worden ist.

> In den Datenblättern steht dazu nix.  Hatte ich vor Jahren mal beim
> Atmel-Support nachgefragt.

Gilt das für ALLE AVR oder nur für sehr alte Modelle?

Wenn man also mal eine Zeitbasis braucht und alle Timer belegt sind, der 
ADC kann das auch!

PS Laut Datenblätter ist ein KANALwechsel ohne "Strafzeit" möglich. Nur 
das Einschalten des ADC (ADEN) bedingt eine Messzeit von 25 statt 13 
Takten. Ebenso ist ein Umschalten der ADC-Referenz mit zusätzlichen 
Verzögerungen behaftet, das liegt aber an der Referenz, nicht direkt am 
ADC.

: Bearbeitet durch User
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Falk B. schrieb:
> Johann L. schrieb:
>> Das Problem beim AVR ADC ist, dass nach dem Kanalwechsel extra Zyklen
>> anfallen, i.W. dauert die erste ADC Konvertierung so lange wie die erste
>> Konvertierung nach Aktivierung des ADC.
>
> Das kann ich nicht bestätigen. Siehe Anhang.

Bei gleicher Genauigkeit?

von Sherlock 🕵🏽‍♂️ (rubbel-die-katz)


Lesenswert?

Johann L. schrieb:
> dass nach dem Kanalwechsel extra
> Zyklen anfallen...
> In den Datenblättern steht dazu nix.

Das steht nicht im Datenblatt, weil es nicht stimmt. Es fallen keine 
Extrazyklen an.

von Sherlock 🕵🏽‍♂️ (rubbel-die-katz)


Lesenswert?

Arduino F. schrieb:
> Ich möchte dein übersteigertes Selbstbewusstsein nicht mit Fakten
> belasten die dir offensichtlich nicht schmecken.

Sieht mir eher nach einem Fall aus, wo jemand persönlich wird, nachdem 
ihm die Argumente ausgegangen sind.

von Falk B. (falk)


Lesenswert?

Johann L. schrieb:
>> Das kann ich nicht bestätigen. Siehe Anhang.
>
> Bei gleicher Genauigkeit?

Das war doch gar nicht die Frage. Nein, die hab ich nicht gemessen.

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Sherlock 🕵🏽‍♂️ schrieb:
> Sieht mir eher nach einem Fall aus, wo jemand persönlich wird, nachdem
> ihm die Argumente ausgegangen sind.
Du irrst!

von Fenton G. (fenton_g)


Lesenswert?

Eine Atmel Application Note AVR126
https://www.professordan.com/avr/techlib/techlib8/appnotes/pdf_avr/AVR126.pdf

Seite 7, dritter Punt von unten:
"It is recommended to discard the first conversion result (like whenever 
there is a
change in ADC configuration like voltage reference / ADC channel 
change)"

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Sherlock 🕵🏽‍♂️ schrieb:
> Johann L. schrieb:
>> dass nach dem Kanalwechsel extra
>> Zyklen anfallen...
>> In den Datenblättern steht dazu nix.
>
> Das steht nicht im Datenblatt, weil es nicht stimmt. Es fallen keine
> Extrazyklen an.

Ok, danke für die Information.

Dann hat mir der Atmel Support damals Käse erzählt.

von S. L. (sldt)


Lesenswert?

Johann L. schrieb:
> Falk B. schrieb:
>> Johann L. schrieb:
>>> Das Problem beim AVR ADC ist, dass nach dem Kanalwechsel extra Zyklen
>>> anfallen, i.W. dauert die erste ADC Konvertierung so lange wie die erste
>>> Konvertierung nach Aktivierung des ADC.
>>
>> Das kann ich nicht bestätigen. Siehe Anhang.
>
> Bei gleicher Genauigkeit?

Ja.

Zumindest bei meinem ATmega328P von '1545'.

von Falk B. (falk)


Lesenswert?

Johann L. schrieb:
> Ok, danke für die Information.
>
> Dann hat mir der Atmel Support damals Käse erzählt.

Sie haben dich getrollt! Logisch, waren ja Norweger! ;-)

https://trollland.eu/wp-content/uploads/norwegen-troll.jpg

von S. L. (sldt)


Lesenswert?

Sherlock 🕵🏽‍♂️ schrieb:
> Ja das ist schnell. Beispiel:
>
> Du startest den ADC im free-running Modus auf Kanal 1 und gibst ihm
> direkt danach (genauer gesagt: einen ADC Takt später) den Befehl, zum
> Kanal 2 zu wechseln ...

Da stellt sich die Frage: wie sieht das konkret aus? Sprich: das 
dazugehörende Programm zeigen, gemäß der Anforderung 'Messsequenz 3*4' - 
wieviele Systemtakte werden benötigt?

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

S. L. schrieb:
> Da stellt sich die Frage: wie sieht das konkret aus?
Da ist keine Frage, denn Arduino ist als eine der Ziel/Testplattformen 
genannt.
Damit sind die Diversen Interrupts mit im Spiel
UART millis() I2C und wohl noch weitere.

von S. L. (sldt)


Lesenswert?

Mal unabhängig von Arduino - Stefan Frings kann als alter Hase sicher 
ohne dieses Hilfsmittel programmieren.
  Nach seiner Theorie müsste er mit dem 'free running mode' auf eine 
Taktanzahl von 3  4  13 * ADC_Teiler plus ein Bisschen kommen - das 
würde ich gerne sehen; und gegebenenfalls dazulernen, denn ich komme, 
wie oben geschrieben, auf rund 10800 Takte.

PS:
 3 mal 4 mal 13 mal ADC_Teiler plus ein Bisschen

 single conversion mode: 10800 Takte bei einem ADC-Teiler von 64

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

S. L. schrieb:
> Mal unabhängig von Arduino - Stefan Frings kann als alter Hase sicher
> ohne dieses Hilfsmittel programmieren.
>   Nach seiner Theorie müsste er mit dem 'free running mode' auf eine
> Taktanzahl von 3  4  13 * ADC_Teiler plus ein Bisschen kommen - das
> würde ich gerne sehen; und gegebenenfalls dazulernen,

Das steht praktisch schon hier. Ich habe nur das Auslesen und Speichern 
der ADC-Werte für den Test entfernt.

Beitrag "Re: ADC-Kanäle sukzessive abfragen"

> denn ich komme,
> wie oben geschrieben, auf rund 10800 Takte.

Es sind
1
3*4*13*64=9984

3 ADC-Kanäle
4 Samples / Kanal
13 ADC-Takte/Messung
64 Teilerfaktor für ADC-Takt

Es wird im Freerun Mode KEIN zusätzlicher ADC-Takt für Interrupts 
verschwendet! Nur im manuellen Modus, wenn die CPU immer wieder den 
Startschuß geben muss.

von S. L. (sldt)


Lesenswert?

Erstmal danke - das Programm (hatte ich völlig übersehen) ist ja sehr 
kompakt.

Sehe ich das richtig: der ADC-Kanal wird mitten im 1. ADC-Takt 
umgeschaltet?

> Ich habe nur das Auslesen und Speichern
> der ADC-Werte für den Test entfernt.

Wie sehen die ADC-Werte für die 3 Kanäle aus?

PS:
"Once the conversion starts, the channel and reference selection is 
locked ..."
Okay, damit ist der 1. Punkt geklärt und eigentlich auch der 2.

Nochmals danke, einen schönen Abend noch ...

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

S. L. schrieb:
> Erstmal Danke - das Programm (hatte ich völlig übersehen) ist ja sehr
> kompakt.
>
> Sehe ich das richtig: der ADC-Kanal wird mitten im 1. ADC-Takt
> umgeschaltet?

Nö. Das MUX-Register wird mit dem neuen Kanal geladen. Das hat aber in 
dem Moment keinen Einfluß auf den laufenden ADC-Vorgang. Denn der Wert 
wird beim Start intern in einen "unsichtbaren" Speicher übernommen und 
die MUX damit eingestellt.

Siehe Datenblatt, ADMUX.

"If these bits are changed during a conversion, the change will not go 
in effect until this conversion is complete (ADIF in ADCSRA is set)."

"The MUXn and REFS1:0 bits in the ADMUX Register are single buffered 
through a temporary register to which the CPU has random access. This 
ensures that the channels and reference selection only takes place at a 
safe point during the conversion. The channel and reference selection is 
continuously updated until a conversion is started. Once the conversion 
starts, the channel and reference selection is locked to ensure a 
sufficient sampling time for the ADC."

>> Ich habe nur das Auslesen und Speichern
>> der ADC-Werte für den Test entfernt.
>
> Wie sehen die ADC-Werte für die 3 Kanäle aus?

Was meinst du damit?

von Ob S. (Firma: 1984now) (observer)


Lesenswert?

Falk B. schrieb:

> Siehe Datenblatt, ADMUX.
>
> "If these bits are changed during a conversion, the change will not go
> in effect until this conversion is complete (ADIF in ADCSRA is set)."

Die Sache ist relativ einfach. Nehmen wir mal an, die ADC-ISR wird 
aufgerufen, während die Wandlung mit der Kanalnummer n läuft. Dann 
enthält das ADC-Ergebnisregister den Wert des Kanals n - 1. Und die ISR 
muß die Parameter für den Kanal n + 1 setzen. Plus und Minus sind 
natürlich zyklisch entsprechend der Anzahl der Kanäle zu 
betrachen/benutzen.

Da fehlt dann aber noch ein kleines (aber wichtiges) Stück Wahrheit. Zu 
Beginn einer "conversion" gibt es leider eine kleine Zeitspanne, in der 
trotz formal bereits laufender Wandlung noch wirksam am Setup der 
"aktuellen" Wandlung manipuliert werden kann. Zumindest bei einigen 
Devices war das so. Sprich: Hardware-Bug beim Register-Buffering, die 
Übernahme der gepufferten Konfigwerte in die ADC-Hardware erfolgte zum 
falschen Zeitpunkt im Wandlerzyklus, nicht zum Zeitpunkt der 
Interuptauslösung sondern erst etwas später. Das verkompliziert die 
Sache etwas. Zumindest bei den Devices, die von diesem Bug betroffen 
sind.

von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

Hier die vollständige Version mit Mittelwert und Ende der Messung nach 
der Mittelwertbildung.

von S. L. (sldt)


Lesenswert?

Danke für die Bereitstellung des Programms.

Vielleicht mache ich ja etwas falsch, aber:

Ich lege auf: ADC0 0.0 V, ADC1 3.0 V, ADC2 2.5 V.
Erwarte also die Werte 0, 614, 512.
Erhalte in adc_avg[0] 380, adc_avg[1] 0, adc_avg[2] 608.

Es scheint also mit adc_avg[0] (der Wert für ADC2) etwas nicht zu 
stimmen.

PS:
bei Ucc= 5.0 V

: 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.