Forum: Mikrocontroller und Digitale Elektronik Direkte Messung von Wechselspannung mittels ADC


von Julian (gurkenfresser)


Lesenswert?

Moin!
Ich möchte die Spannung einer Sinus-Wechselspannung bestimmen.
- Spannungsfrequenz: Variabel 1-1000 Hz
- Spannungsbereich: 1-15 V
- Genauigkeit der Messung ca. 50 mV
- Häufigkeit: 1 - 10 Messungen / Sekunde (je nach Frequenz)

Hauptprozessor wird ein ESP32 sein. Mein aktueller Ansatz ist grob der 
folgende:

          Sinus
            o
            |
           .-.
           | |
           | |
           '-'
            |
       -----+---------oADC
       |    |     |
       |   .-.    |
       -   | |   ---
       /\  | |   ---
       |   '-'    |
       |    |     |
      GND  GND   GND

Der Gedanke ist, dass der ESP32 direkt die Wechselspannung durch einen 
passenden Spannungsteiler heruntergeteilt auf seinen ADC bekommt. Eine 
Diode verhindert negative Spannungen am ADC-Eingang, ein kleiner 
Kondensator senkt den Innenwiderstand der Schaltung für den ADC. Durch 
einen (nicht eingezeichneten) Trigger, weiß der ESP, wann das Maximum 
der Spannung erreicht ist und startet die Konvertierung passend zum 
Maximum (oder kurz davor).

Ich habe den Aufbau bereits ausprobiert und grundsätzlich funktioniert 
es auch, dass Problem ist, dass der gemessene Spannungswert 
frequenzabhängig ist. Ich gehe davon aus, dass es damit zu tun hat, dass 
die Messung gut 300us lang dauert und die Spannung bei hohen Frequenzen 
dann bereits nennenswert abgefallen ist. Eigentlich wäre ich davon 
ausgegangen, dass der ADC die Spannung zum Messstart "einfriert", dem 
scheint aber nicht so?

Nun verwendet der ESP32 einen SAR-ADC. Ist das Verhalten bei einem 
Delta-Sigma-ADC wie dem AD1115 vergleichbar? Oder brauche ich noch 
andere ADCs?

Hintergrundgedanke bei der Art der Messung ist dessen Einfachheit. 
Natürlich könnte ich auch eine Spitzenwertgleichrichtung vollziehen, 
dass ganze filtern und dann wandeln, allerdings scheitert es in der 
Regel an der variablen Frequenz und einer sinnvollen Filterung, die über 
den gesamten Frequenzbereich sinnvoll funktioniert. Aus diesem Grund 
hoffe ich auf eine einfache Lösung, wie die oben beschriebene.

von meh (Gast)


Lesenswert?

Du hast einen Tiefpass gebaut - natürlich ist der gemessene 
Spannungswert frequenzabhängig.

von Julian (gurkenfresser)


Lesenswert?

meh schrieb:
> Du hast einen Tiefpass gebaut - natürlich ist der gemessene
> Spannungswert frequenzabhängig.

Danke für den Hinweis. Allerdings habe ich den Tiefpass so ausgelegt, 
dass dessen Grenzfrequenz deutlich oberhalb von 1000 Hz liegt. Und 
selbst ohne Kondensator misst der ADC eine deutlich geringere Spannung. 
Darüber hinaus habe ich die Spannung am ADC mit einem Oszilloskop 
gemessen. Das Oszi hat bei allen Frequenzen ca. 1V am ADC gemessen. 
Hingegen hat der ADC Werte im Bereich von 1000 (von 4095) bei 100 Hz und 
300 (von 4095) bei 1 kHz.

von Georg G. (df2au)


Lesenswert?

Wie viel Zeit vergeht zwischen Triggerung und Start der Wandlung?

von Falk B. (falk)


Lesenswert?

Julian N. schrieb:
> Moin!
> Ich möchte die Spannung einer Sinus-Wechselspannung bestimmen.

Was meinst du damit GENAU?
Willst den Spitzen oder Effektivwert bestimmen?


> Der Gedanke ist, dass der ESP32 direkt die Wechselspannung durch einen
> passenden Spannungsteiler heruntergeteilt auf seinen ADC bekommt.

OK.

> Eine
> Diode verhindert negative Spannungen am ADC-Eingang,

Weniger OK.

> ein kleiner
> Kondensator senkt den Innenwiderstand der Schaltung für den ADC.

Jain, er liefert die Ladung für die kurzen Meßpulse des ADC.

> Durch
> einen (nicht eingezeichneten) Trigger, weiß der ESP, wann das Maximum
> der Spannung erreicht ist und startet die Konvertierung passend zum
> Maximum (oder kurz davor).

OK. Also willst du den Spitzenwert messen.

> Ich habe den Aufbau bereits ausprobiert und grundsätzlich funktioniert
> es auch, dass Problem ist, dass der gemessene Spannungswert
> frequenzabhängig ist. Ich gehe davon aus, dass es damit zu tun hat, dass
> die Messung gut 300us lang dauert

300us? Ist das die MESSUNG oder die Abtastung. Eigentlich ist die 
Abtastung sehr schnell, wenige Mikrosekunden. Die anschließende 
AD-Wandlung kann deutlich länger dauern, das ist aber egal, weil der 
Meßwert durch die Sample & Hold Stufe eingefroren wurde.

>und die Spannung bei hohen Frequenzen
> dann bereits nennenswert abgefallen ist. Eigentlich wäre ich davon
> ausgegangen, dass der ADC die Spannung zum Messstart "einfriert", dem

Tut er auch.

> Nun verwendet der ESP32 einen SAR-ADC. Ist das Verhalten bei einem
> Delta-Sigma-ADC wie dem AD1115 vergleichbar?

Jain.

> Oder brauche ich noch
> andere ADCs?

Nö.

> den gesamten Frequenzbereich sinnvoll funktioniert. Aus diesem Grund
> hoffe ich auf eine einfache Lösung, wie die oben beschriebene.

Ich tippe auf ein Softwareproblem. Deine CPU verpennt den Trigger und 
mißt zu spät. Dein Trigger müßte einen hochpriorisierten Interrupt 
auslösen, der ohne Firlefanz die Messung startet. Das sollte ein 32 Bit 
COntroller mit vielen MHz in kaum mehr als 1-2us hinkriegen. Das mußt du 
prüfen. Setze ein IO-Signal auf HIGH, wenn der Meßvorgang beginnt. Miß 
die Verzögerung zwischen Trigger und Testsignal mit dem Oszilloskop.

von Julian (gurkenfresser)


Lesenswert?

Georg G. schrieb:
> Wie viel Zeit vergeht zwischen Triggerung und Start der Wandlung?

Ich habe einen Operationsverstärker mit + auf dem Sinus-Signal, Minus an 
einem Spannungsteiler, der Ausgang an einem ESP32-Pin als Interrupt. 
Immer wenn die Sinus-Spannung eine Spannung x übersteigt, geht dessen 
Ausgang auf High und ein Interrupt wird im ESP ausgelöst. Sinkt die 
Spannung, unter x, geht der OPV-Ausgang auf Low und ein zweiter 
Interrupt wird ausgelöst. Der ESP32 speichert die Mikrosekunden beider 
Triggerungen ab, berechnet dessen Differenz sowie die sich über mehrere 
Rise-Interrupts ergebene Frequenz. In einer Endlosschleife wird dann 
überprüft, ob sie sich zeitlich gerade im Bereich um +-5us um den 
berechneten nächsten Mittelpunkt befindet und startet dann die Messung 
mittels adc1_get_raw. Während der ADC-Messung wird ein Pin auf High 
gesetzt, was ich mit dem Oszilloskop auch sehen kann und das bestätigt, 
dass die Messung ca. 5-10 us nach dem Hochpunkt gestartet wird und ca. 
170 us dauert. Zu diesem Zeitpunkt ist die Spannung dann um ca. 50 % 
abgefallen (1000 Hz).

Hier der Code

     const uint16_t Pin_Interrupt = 33;
     const uint16_t Pin_Measuring = 27;

     volatile uint32_t t_start;
     volatile uint32_t t_duration;
     volatile uint32_t frequency_measured;
     volatile bool adc_now = false;

     void ADC(void* pvParameters) {
       bool next_measure = true;
       adc1_config_width(ADC_WIDTH_BIT_12);
       adc1_config_channel_atten(ADC1_CHANNEL_4, ADC_ATTEN_11db);

       while (1) {
         if (next_measure && digitalRead(Pin_Interrupt) && micros() > 
t_start + t_duration / 2 - 10 && micros() < t_start + t_duration / 2 + 
0) {
           last_time = micros();
           digitalWrite(Pin_Measuring, HIGH);
           last_value = adc1_get_raw(ADC1_CHANNEL_4);
           digitalWrite(Pin_Measuring, LOW);
           next_measure = false;
         } else if (next_measure && micros() > t_start + t_duration / 2 
+ 10) {
           next_measure = false;
         }

         if (!digitalRead(Pin_Interrupt))
           next_measure = true;
         vTaskDelay(1 / portTICK_PERIOD_MS);
       }
     }

     void IRAM_ATTR ISR_Int() {
       const uint32_t t_start_new = micros();
       if (digitalRead(Pin_Interrupt)) {
         frequency_measured = 1000000 / (t_start_new  - t_start);
         t_start = t_start_new ;
         adc_now = true;
       } else {
         t_duration = t_start_new - t_start;
         adc_now = false;
       }
     }

     void setup(void) {
       [...]
       xTaskCreatePinnedToCore(ADC, "ADC", 10000, NULL, 1, &DAC, 1);
       pinMode(Pin_Interrupt, INPUT);
       attachInterrupt(digitalPinToInterrupt(Pin_Interrupt), ISR_Int, 
CHANGE);
     }

von Julian (gurkenfresser)


Lesenswert?

Falk B. schrieb:
> Julian N. schrieb:
>> Moin!
>> Ich möchte die Spannung einer Sinus-Wechselspannung bestimmen.
>
> Was meinst du damit GENAU?
> Willst den Spitzen oder Effektivwert bestimmen?
An sich wäre es mir gleich, weil beides ineinander überführbar ist. In 
diesem konkreten Fall möchte ich die Spitzenspannung bestimmen.

>> Eine
>> Diode verhindert negative Spannungen am ADC-Eingang,
>
> Weniger OK.
Weil? Theoretisch verzehrt sie mir aufgrund des Stromes bei positivem 
Signal minimal meine gemessene Spannung, allerdings ist der Effekt 
aufgrund des geringen Stromes insgesamt zu vernachlässigen.

>> ein kleiner
>> Kondensator senkt den Innenwiderstand der Schaltung für den ADC.
>
> Jain, er liefert die Ladung für die kurzen Meßpulse des ADC.
Ist das nicht letztlich gleichbedeutend?

> 300us? Ist das die MESSUNG oder die Abtastung. Eigentlich ist die
> Abtastung sehr schnell, wenige Mikrosekunden. Die anschließende
> AD-Wandlung kann deutlich länger dauern, das ist aber egal, weil der
> Meßwert durch die Sample & Hold Stufe eingefroren wurde.
Okay, schon Mal vielen Dank für diese Info!

> Ich tippe auf ein Softwareproblem. Deine CPU verpennt den Trigger und
> mißt zu spät. Dein Trigger müßte einen hochpriorisierten Interrupt
> auslösen, der ohne Firlefanz die Messung startet. Das sollte ein 32 Bit
> COntroller mit vielen MHz in kaum mehr als 1-2us hinkriegen. Das mußt du
> prüfen. Setze ein IO-Signal auf HIGH, wenn der Meßvorgang beginnt. Miß
> die Verzögerung zwischen Trigger und Testsignal mit dem Oszilloskop.
Siehe meinen letzten Post, in dem ich nun auch das Programm geteilt 
habe.

Eine weitere Überlegung meinerseits ist die Nichtlinearität des 
ESP-ADCs. Aus diesem Grund habe ich bewusst Spannungen im "mittleren" 
Messbereich gewählt. Laut der Seite 
https://docs.espressif.com/projects/esp-idf/en/v3.3/api-reference/peripherals/adc.html 
bei ADC_ATTEN_11db zwischen 150 und 2450mV.

Konkret ein paar Messwerte:

     | Frequenz | Gemessene Spannung | Gemessener |
     |          |    (Oszi) in V     |  ADC-Wert  |
     | -------- | ------------------ | ---------- |
     |   0      |       1.335        |    1174    |
     |   100    |       1.230        |    1067    |
     |   1000   |       1.255        |    585     |
     |   0      |       0.722        |    572     |
     |   100    |       0.668        |    515     |
     |   1000   |       0.678        |    260     |

Die mit dem Oszilloskop gemessene Spannung ist jeweils zum Zeitpunkt der 
steigenden Flanke meines ADC-Start-Signals (Pin_Measuring) gemessen.

: Bearbeitet durch User
von Julian (gurkenfresser)


Lesenswert?

Um auf den Pufferkondensator noch einmal einzugehen. Ich habe hinter den 
Spannungsteiler einen weiteren Operationsverstärker als Spannungsfolger 
geschaltet. Dahinter ein 120 Ohm Widerstand mit einem 100 nF Kondensator 
in Reihe gegen Masse. Zwischen Widerstand und Kondensator liegt der ADC. 
Die Grenzfrequenz müsste nach meinem Verständnis bei 13 kHz liegen und 
somit weit über meine zu messenden 1 kHz. Die gemessenen ADC-Werte 
stabilisieren sich so auch minimal und steigen etwas, sind allerdings 
weiterhin ca. 40 % niedriger als erwartet.

von Michael M. (Gast)


Lesenswert?

Hallo,

musste mal ein Druckgeber retative genau Auswerten.
Hab das driften (über Zeit) und Abweicheungen (verglichen mit Oszi) beim 
ESP32-ADC auch nicht im griff bekommen. Hab mir dann ein ADS1115 besogt 
und mit bisschen digital Filtern klappte es dann sehr gut :)

Gruß
Michael

von Julian (gurkenfresser)


Lesenswert?

Falk B. schrieb:
> Ich tippe auf ein Softwareproblem. Deine CPU verpennt den Trigger und
> mißt zu spät. Dein Trigger müßte einen hochpriorisierten Interrupt
> auslösen, der ohne Firlefanz die Messung startet. Das sollte ein 32 Bit
> COntroller mit vielen MHz in kaum mehr als 1-2us hinkriegen. Das mußt du
> prüfen. Setze ein IO-Signal auf HIGH, wenn der Meßvorgang beginnt. Miß
> die Verzögerung zwischen Trigger und Testsignal mit dem Oszilloskop.

Damit liegst du wohl tatsächlich richtig! Ich habe das Skript noch ein 
wenig überarbeitet, sodass der geplante Messzeitpunkt relativ zum 
Triggermittelpunkt verschoben werden kann. Hierbei stellte sich heraus, 
dass wenn ich 150 us vor dem Mittelpunkt ein 10 us/(Frequenz/1Hz) langes 
Fenster eröffne, um zu messen, dann werden die Werte bei 1000 Hz genauso 
hoch gemessen, wie bei 1 Hz!

von Georg G. (df2au)


Lesenswert?

Julian schrieb:
> Hierbei stellte sich heraus

Also hast du anfangs nicht das Maximum erwischt sondern warst schon auf 
der fallenden Flanke.

Wie wäre es mit einem anderen Ansatz: Am vermuteten Maximum messen. 
Nächste Messung etwas früher. Messwert ist höher: Wir sind nach dem 
Maximum. Weiter in diese Richtung. Messwert ist niedriger: Wir sind noch 
vor dem Maximum. Etwas später messen. Das Ganze so lange, bis der 
Unterschied zwischen zwei Messungen kleiner als xxx ist.

Eventuell die Messzeitpunkte über der Frequenz merken. Dann geht es beim 
nächsten Versuch schneller. Die Frequenz misst du ja ohnehin.

von Julian (gurkenfresser)


Lesenswert?

Georg G. schrieb:
> Wie wäre es mit einem anderen Ansatz: Am vermuteten Maximum messen.
> Nächste Messung etwas früher. Messwert ist höher: Wir sind nach dem
> Maximum. Weiter in diese Richtung. Messwert ist niedriger: Wir sind noch
> vor dem Maximum. Etwas später messen. Das Ganze so lange, bis der
> Unterschied zwischen zwei Messungen kleiner als xxx ist.
>
> Eventuell die Messzeitpunkte über der Frequenz merken. Dann geht es beim
> nächsten Versuch schneller. Die Frequenz misst du ja ohnehin.

Gefällt mir! In die Richtung wird es auf jeden Fall gehen! Aktuell muss 
ich nur erst den Schaltungsaufbau fertig bekommen, sodass bestellt 
werden kann und dann ist genug Zeit zum Programmieren :D Wenn ich dran 
denke, werde ich das Ergebnis hier auch nochmal teilen :)

von Falk B. (falk)


Lesenswert?

Julian schrieb:
> Georg G. schrieb:
>> Wie viel Zeit vergeht zwischen Triggerung und Start der Wandlung?
>
> Ich habe einen Operationsverstärker mit + auf dem Sinus-Signal, Minus an
> einem Spannungsteiler, der Ausgang an einem ESP32-Pin als Interrupt.

Was soll diese Lyrik? Zeig uns einen gescheiten Schaltplan!

> Immer wenn die Sinus-Spannung eine Spannung x übersteigt, geht dessen
> Ausgang auf High und ein Interrupt wird im ESP ausgelöst. Sinkt die
> Spannung, unter x, geht der OPV-Ausgang auf Low und ein zweiter
> Interrupt wird ausgelöst.

Nennt sich Komparator.

> Der ESP32 speichert die Mikrosekunden beider
> Triggerungen ab, berechnet dessen Differenz sowie die sich über mehrere
> Rise-Interrupts ergebene Frequenz. In einer Endlosschleife wird dann
> überprüft, ob sie sich zeitlich gerade im Bereich um +-5us um den
> berechneten nächsten Mittelpunkt befindet und startet dann die Messung
> mittels adc1_get_raw.

Ganz falsch. Die ADC-Messung muss in der ISR erfolgen. Alles anders ist 
deutlich schlechter zeitlich definiert.

> Während der ADC-Messung wird ein Pin auf High
> gesetzt, was ich mit dem Oszilloskop auch sehen kann und das bestätigt,
> dass die Messung ca. 5-10 us nach dem Hochpunkt gestartet wird und ca.
> 170 us dauert. Zu diesem Zeitpunkt ist die Spannung dann um ca. 50 %
> abgefallen (1000 Hz).

1kHz sind 1ms Periodendauer, die Halbwelle nur 500us. Wenn man die 
Spitze auf deine 50mV genau treffen will, kann man sich grob geschätzt 
kaum 5us Fehler leisten.

>
> Hier der Code

Entweder als Anhang oder in Klammern, damit das besser formatiert wird.

>        while (1) {
>          if (next_measure && digitalRead(Pin_Interrupt) && micros() >
> t_start + t_duration / 2 - 10 && micros() < t_start + t_duration / 2 +
> 0) {

Viel zu kompliziert. Wenn schon, dann muss EINE Bedingung in einer 
Variable definiert werden, welche dann hier ein GO gibt.

>            last_time = micros();
>            digitalWrite(Pin_Measuring, HIGH);
>            last_value = adc1_get_raw(ADC1_CHANNEL_4);

Wie bereits gesagt, ist das hier falsch. Die ADC-Messung gehört in den 
Interrupt. Allein die sehr schnelle CPU mit vielen MHz rettet dich hier, 
gibt dir aber die falsche Sicherheit, ein gutes Konzept zu haben.

von Falk B. (falk)


Lesenswert?

Julian schrieb:
>> Eventuell die Messzeitpunkte über der Frequenz merken. Dann geht es beim
>> nächsten Versuch schneller. Die Frequenz misst du ja ohnehin.
>
> Gefällt mir! In die Richtung wird es auf jeden Fall gehen! Aktuell muss
> ich nur erst den Schaltungsaufbau fertig bekommen, sodass bestellt
> werden kann und dann ist genug Zeit zum Programmieren

Falsch! Du glaubt, das alles mal schnell-schnell neben zu lösen und dann 
einfach nur bissel Programmieren zu müssen. Ein verbreiteter Irrtum. Du 
mußt dein Konzept sowie deine Schaltung auf den Prüfstand stellen und 
vermutlich deutlich verbessern. Allein schon dein Komparator zur 
Generierung des Triggers für die Maximummessung ist so nicht gut.

> :D Wenn ich dran
> denke, werde ich das Ergebnis hier auch nochmal teilen :)

Jaja . . .

von Frank K. (fchk)


Lesenswert?


von Falk B. (falk)


Lesenswert?

Frank K. schrieb:
> Wenn man es richtig machen möchte...

Einfach mal lesen. Er will den Spitzenwert messen, nicht RMS. Es ist 
anscheinend auch ein reiner Sinus, da brauch es keinen High Tec RMS-DC 
Wandler.

von Julian (gurkenfresser)


Lesenswert?

Falk B. schrieb:
>> Der ESP32 speichert die Mikrosekunden beider
>> Triggerungen ab, berechnet dessen Differenz sowie die sich über mehrere
>> Rise-Interrupts ergebene Frequenz. In einer Endlosschleife wird dann
>> überprüft, ob sie sich zeitlich gerade im Bereich um +-5us um den
>> berechneten nächsten Mittelpunkt befindet und startet dann die Messung
>> mittels adc1_get_raw.
>
> Ganz falsch. Die ADC-Messung muss in der ISR erfolgen. Alles anders ist
> deutlich schlechter zeitlich definiert.
Also mein Wissen über ISRs besagt, dass diese möglichst KURZ sein 
sollten. Eine 300 us lange dauernde Messung zähle ich sicherlich nicht 
dazu. Mal davon abgesehen, dass ich überhaupt kein Interrupt zum 
Zeitpunkt der maximalen Spannung habe, sondern einen vor dem Maximum und 
einem nach dem Maximum. Das Maximum befindet sich in der Mitte der 
beiden und ist sehr wohl ausreichend präzise "zeitlich definiert". Wie 
kommst du darauf, das dem nicht so wäre? Meine Oszilloskop-Messung (von 
der ich oben sprach) bestätigt diese These ja eindeutig! Zudem habe ich 
den Vorteil, den Zeitpunkt der Messung beliebig um das Maximum herum zu 
verschieben. Also "Ganz falsch" sicherlich nicht...

> 1kHz sind 1ms Periodendauer, die Halbwelle nur 500us. Wenn man die
> Spitze auf deine 50mV genau treffen will, kann man sich grob geschätzt
> kaum 5us Fehler leisten.
Bei 1 V und 1 kHz habe ich einen Spannungsbfall von 50 mV nach über 50 
us. (cos(2*PI*1000Hz*50us)=0.95) Entsprechend habe ich praktisch sogar 
ein Zeitfenster von +-50 us um das Maximum. Eine Abweichung von 5 us ist 
somit völlig unproblematisch.


> Entweder als Anhang oder in Klammern, damit das besser formatiert wird.
Mache ich nächstes Mal besser.


>>        while (1) {
>>          if (next_measure && digitalRead(Pin_Interrupt) && micros() >
>> t_start + t_duration / 2 - 10 && micros() < t_start + t_duration / 2 +
>> 0) {
>
> Viel zu kompliziert. Wenn schon, dann muss EINE Bedingung in einer
> Variable definiert werden, welche dann hier ein GO gibt.
Weil? Hast du für diese These irgendwelche Gründe?


>>            last_time = micros();
>>            digitalWrite(Pin_Measuring, HIGH);
>>            last_value = adc1_get_raw(ADC1_CHANNEL_4);
>
> Wie bereits gesagt, ist das hier falsch. Die ADC-Messung gehört in den
> Interrupt. Allein die sehr schnelle CPU mit vielen MHz rettet dich hier,
> gibt dir aber die falsche Sicherheit, ein gutes Konzept zu haben.
Nein ist es nicht, wie bereits oben geschrieben. Und du irrst dich. Mit 
einem AtMega128 hätte ich weit weniger Probleme als mit dem ESP32. Einem 
AtMega mit 20 MHz könnte ich einfach endlos in einer Schleife warten 
lassen und würde den Zeitpunkt deutlich präziser treffen. Beim ESP32 
hingegen habe ich Multitasking, sodass es passieren kann, dass die 
ADC-Messung überhaupt nicht aufgerufen wird, wenn der Zeitpunkt gekommen 
ist. Unabhängig davon ändert dies nichts an der Präzision des 
Messzeitpunktes. Diesen stelle ich mit der Größe meines Fensters ein, 
indem die Messung gestartet wird. Es kann lediglich passieren, dass ich 
eine Messung verpasse, dann nehme ich halt die nächste, ich brauche 
sowieso keine 1000 in der Sekunde (wie oben geschrieben). Ungenauer wird 
es dadurch aber sicherlich nicht, weder zeitlich noch werttechnisch!

von Julian (gurkenfresser)


Lesenswert?

Frank K. schrieb:
> https://www.analog.com/media/en/technical-documentation/data-sheets/AD8436.pdf
> https://www.analog.com/media/en/technical-documentation/data-sheets/1968f.pdf
Danke für den Tipp, die habe ich mir auch schon angeschaut. Allerdings 
habe ich keine einfache und funktionierende Filterung hinbekommen, 
welche die 1 Hz bis 1000 Hz Ausgangssignale der Chips ausreichend 
geglättet bekommt. Da ist mein gewählter Ansatz m.E. einfacher und 
funktioniert ja genauso?

von Michael M. (Gast)


Lesenswert?

Hallo,

Julian schrieb:
>>>          if (next_measure && digitalRead(Pin_Interrupt) && micros() >
>>> t_start + t_duration / 2 - 10 && micros() < t_start + t_duration / 2 +
>>> 0) {

als alternative.

Timer auf 1ms (jeh nach Genugigkeit) interrupt stellen -> Timer stoppen 
-> Timer durch interrupt starten -> Werte von mehreren Wellen ins Array 
schreiben -> danach kannste zwei maxima suchen array prosition 
entspricht dann ja zeitangabe (vergangene Zeit) --> Frequenz.

Wenn du das driften und abweichung (gemessen zum oszi) im griff bekommst 
hast. ADC-Wert x Kurrector = Scheitelspannung.

Gruß
Michael

von foobar (Gast)


Lesenswert?

Wenn ich das richtig sehe, ist der Task eh in einer Busy-Loop und wartet 
(pollend) auf den passenden Zeitpunkt.  Dann sample doch stattdessen 
ständig und bestimm den Spitzenwert in Software.

von Frank K. (fchk)


Lesenswert?

Julian schrieb:
> Frank K. schrieb:
>> https://www.analog.com/media/en/technical-documentation/data-sheets/AD8436.pdf
>> https://www.analog.com/media/en/technical-documentation/data-sheets/1968f.pdf
> Danke für den Tipp, die habe ich mir auch schon angeschaut. Allerdings
> habe ich keine einfache und funktionierende Filterung hinbekommen,
> welche die 1 Hz bis 1000 Hz Ausgangssignale der Chips ausreichend
> geglättet bekommt. Da ist mein gewählter Ansatz m.E. einfacher und
> funktioniert ja genauso?

Du weißt schon, dass diese Chips Wechselspannung reinbekommen und 
Gleichspannung am Ausgang ausgeben? Und diese Gleichspannung kannst Du 
einfach mit einem ADC messen. Einfach so. Ohne Interrupt usw.

fchk

von Grummler (Gast)


Lesenswert?

Falk B. schrieb:

>> Während der ADC-Messung wird ein Pin auf High gesetzt,
>> was ich mit dem Oszilloskop auch sehen kann und das
>> bestätigt, dass die Messung ca. 5-10 us nach dem
>> Hochpunkt gestartet wird und ca. 170 us dauert. Zu
>> diesem Zeitpunkt ist die Spannung dann um ca. 50 %
>> abgefallen (1000 Hz).
>
> 1kHz sind 1ms Periodendauer, die Halbwelle nur 500us.
> Wenn man die Spitze auf deine 50mV genau treffen will,
> kann man sich grob geschätzt kaum 5us Fehler leisten.

Die Theorie sagt, dass man die Spitze gar nicht treffen
muss. Leider interessiert sich niemand für die Theorie...

von Grummler (Gast)


Lesenswert?

Frank K. schrieb:

> Du weißt schon, dass diese Chips Wechselspannung
> reinbekommen und Gleichspannung am Ausgang ausgeben?

Ohne Integrationskondensator und ohne Frequenzabhängigkeit?
Träum' weiter...

Einfach mal das Diagramm auf Seite 12 des ersten Daten-
blattes angucken...

von Jester (Gast)


Lesenswert?

Julian schrieb:
> Durch
> einen (nicht eingezeichneten) Trigger, weiß der ESP, wann das Maximum
> der Spannung erreicht ist und startet die Konvertierung passend zum
> Maximum (oder kurz davor).

Ja - das wird was hingeben...

Nur gut, dass Du den (Hardware-) Trigger "nicht eingezeichnet" hast, 
denn genau da liegt der Hund begraben. Einfach mal drauf los 
programmieren, ohne dass das Konzept auch nur in die Nähe von 
"tragfähig" kommt - das kann nicht gut gehen.

Jedenfalls könnte das noch sehr spannend werden. Soll ich schon mal 
popcorn holen?

von Falk B. (falk)


Lesenswert?

Julian schrieb:

>> Ganz falsch. Die ADC-Messung muss in der ISR erfolgen. Alles anders ist
>> deutlich schlechter zeitlich definiert.
> Also mein Wissen über ISRs besagt, dass diese möglichst KURZ sein
> sollten. Eine 300 us lange dauernde Messung zähle ich sicherlich nicht
> dazu.

Stimmt. Aber keine Regel ohne Ausnahme. Außerdem müssen ISRs nicht 
extrem kurz sein, sondern nur so kurz, als daß sie andere Interrupts 
bzw. die Hauptschleife nicht zu viel ausbremsen. Das kann im Einzelfall 
auch viele Millisekunden sein.

> Mal davon abgesehen, dass ich überhaupt kein Interrupt zum
> Zeitpunkt der maximalen Spannung habe, sondern einen vor dem Maximum und
> einem nach dem Maximum. Das Maximum befindet sich in der Mitte der
> beiden und ist sehr wohl ausreichend präzise "zeitlich definiert".

Wie präzise? Selbst wenn man den Nullpunkt als schaltschwelle nimmt, ist 
das zwar theoretisch sehr genau, aber praktisch nicht ganz so einfach 
wie du denkst. Schon gar nicht mit deiner naiven Arduino-Denkweise.

< Wie
> kommst du darauf, das dem nicht so wäre? Meine Oszilloskop-Messung (von
> der ich oben sprach) bestätigt diese These ja eindeutig! Zudem habe ich
> den Vorteil, den Zeitpunkt der Messung beliebig um das Maximum herum zu
> verschieben. Also "Ganz falsch" sicherlich nicht...

Falsch genug, als daß man da noch einiges machen muss.

>> Viel zu kompliziert. Wenn schon, dann muss EINE Bedingung in einer
>> Variable definiert werden, welche dann hier ein GO gibt.
> Weil? Hast du für diese These irgendwelche Gründe?

Weil du selber nur schlecht durchsiehst und auch die Berechnung Zeit 
braucht, wenn gleich daß bei deiner schnellen CPU kaum ins Gewicht 
fällt.

>> Wie bereits gesagt, ist das hier falsch. Die ADC-Messung gehört in den
>> Interrupt. Allein die sehr schnelle CPU mit vielen MHz rettet dich hier,
>> gibt dir aber die falsche Sicherheit, ein gutes Konzept zu haben.
> Nein ist es nicht, wie bereits oben geschrieben. Und du irrst dich. Mit
> einem AtMega128 hätte ich weit weniger Probleme als mit dem ESP32. Einem
> AtMega mit 20 MHz könnte ich einfach endlos in einer Schleife warten
> lassen und würde den Zeitpunkt deutlich präziser treffen. Beim ESP32
> hingegen habe ich Multitasking,

Hast du das? Läuft da wirklich (pääemtives) Multitasking? Das 
Arduino-Framework macht keins, da läuft bestenfalls ein 1ms Timer.

> sodass es passieren kann, dass die
> ADC-Messung überhaupt nicht aufgerufen wird, wenn der Zeitpunkt gekommen
> ist.

Unsinn.

> sowieso keine 1000 in der Sekunde (wie oben geschrieben). Ungenauer wird
> es dadurch aber sicherlich nicht, weder zeitlich noch werttechnisch!

Wenn du meinst. Mach mal.

von Jester (Gast)


Lesenswert?

foobar schrieb:
> Wenn ich das richtig sehe, ist der Task eh in einer Busy-Loop und wartet
> (pollend) auf den passenden Zeitpunkt.  Dann sample doch stattdessen
> ständig und bestimm den Spitzenwert in Software.

Damit umschipperst man ein Problem, holt Dir dafür ein neue ins Boot:
Wie schnell muss man sampeln, damit innerhalb der Messzeit der 
Spitzenwert garantiert hinreichend genau (0.33% ?) getroffen wird.

Zusatzfrage: Wer entscheidet wann über die Messzeit, also 100 ... 
1000ms?

von Norbert (Gast)


Lesenswert?

Jester schrieb:
> foobar schrieb:
>> Wenn ich das richtig sehe, ist der Task eh in einer Busy-Loop und wartet
>> (pollend) auf den passenden Zeitpunkt.  Dann sample doch stattdessen
>> ständig und bestimm den Spitzenwert in Software.
>
> Damit umschipperst man ein Problem, holt Dir dafür ein neue ins Boot:
> Wie schnell muss man sampeln, damit innerhalb der Messzeit der
> Spitzenwert garantiert hinreichend genau (0.33% ?) getroffen wird.

Bei maximaler Aussteuerung eines 12bit Wandlers:
(90° - arcsin(4095/4096)) × 2
Das wäre dann ein Bereich von ~ 2,5° um den Scheitelwert.

Aber mal ganz ehrlich, so ein ESP hat/ist doch schon ein erwachsener 
Prozessor. Den lässt man einfach mit maximaler Geschwindigkeit im Kreis 
laufen und gut iss. Selbst ein AVR braucht nur wenige Prozent 
Prozessorleistung wenn er 15000 Mal pro Sekunde den ADC bedient.

von Julian (gurkenfresser)


Lesenswert?

@fchk Wie der Grummler bereits richtig feststellte, ist leider auch bei 
diesen Chips ein dahintergeschalteter Filter notwendig.

Falk B. schrieb:
> Stimmt. Aber keine Regel ohne Ausnahme. Außerdem müssen ISRs nicht
> extrem kurz sein, sondern nur so kurz, als daß sie andere Interrupts
> bzw. die Hauptschleife nicht zu viel ausbremsen. Das kann im Einzelfall
> auch viele Millisekunden sein.
Richtig, im Einzelfall. Und wer hätte es gedacht, ich nehme einen ESP32 
nicht, weil ich scheiße programmiere, sondern weil ich weitere 
Funktionen von ihm benötige, wie WLAN, diverse ADCs, beide DACs, SPI, 
I²C, etc. Da passiert im Hintergrund weit mehr als du glaubst und 
entsprechend werde ich mich an meinem allgemein sinnvollen Grundsatz 
halten, ISRs kurz zu halten!


> Wie präzise? Selbst wenn man den Nullpunkt als schaltschwelle nimmt, ist
> das zwar theoretisch sehr genau, aber praktisch nicht ganz so einfach
> wie du denkst. Schon gar nicht mit deiner naiven Arduino-Denkweise.
Offen präzise genug!? Wenn mein ADC die RICHTIGEN Werte mit MEINER 
Methode im Experiment bestimmt, dann ist es ganz offensichtlich präzise 
genug... Und was auch von der Theorie nur logisch ist! Keine Ahnung, 
weshalb du diese gewaltigen Ungenauigkeiten erwartest. Aber bestimmt, 
kommt jetzt eh wieder nur eine inhaltlose Antwort, dass ich zu dumm sei, 
meinen Fehler zu erkennen, ohne Mal wirklich INHALT zu schreiben. Wenn 
du ach so toll, intelligent und allwissend bist, dann teile uns doch 
dein Wissen, dass wir davon lernen können oder lass es einfach ganz 
bleiben. Deine leeren Phrasen bringen niemanden weiter -.-


Falk B. schrieb:
> Julian schrieb:
>> Nein ist es nicht, wie bereits oben geschrieben. Und du irrst dich. Mit
>> einem AtMega128 hätte ich weit weniger Probleme als mit dem ESP32. Einem
>> AtMega mit 20 MHz könnte ich einfach endlos in einer Schleife warten
>> lassen und würde den Zeitpunkt deutlich präziser treffen. Beim ESP32
>> hingegen habe ich Multitasking,
>
> Hast du das? Läuft da wirklich (pääemtives) Multitasking? Das
> Arduino-Framework macht keins, da läuft bestenfalls ein 1ms Timer.
Ja auf einem ESP32 arbeitet präemtives Multitasking. Siehe 
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/freertos.html 
Offenbar habe ich mit meiner "naiven Arduino" Denkweise mehr Plan von 
dem, was ich hier tue als du glaubst... Aber mach ruhig weiter mit 
deinen unbegründeten Thesen ala "ist eh alles sche*** was du machst".


Das restliche Gesülze erspare ich mir zu beantworten. Falls noch 
konstruktive Hinweise und Ideen kommen, immer gerne her damit! Wie 
gesagt, ich danke dir für deinen Hinweis mit dem zeitlichen Verzug der 
Messung! Dessen Herkunft ist mir leider weiterhin unklar, aber letztlich 
problemlos lösbar. Übrigens, die oben gezeigte Software ist eine rein 
für das Experiment geschriebene Software, um die Machbarkeit zu 
beweisen. Das hat sie getan. Fehlerfrei oder gar perfekt ist sie 
sicherlich nicht, ist auch nicht notwendig. Das wird Aufgabe sein, wenn 
die Hardware steht. Übrige inhaltlose Kommentare werde ich ignorieren... 
Falls Langeweile besteht, tob dich (oder @Jester) gerne weiter aus.

von Jester (Gast)


Lesenswert?

Norbert schrieb:
> Jester schrieb:
>> foobar schrieb:
>>> Wenn ich das richtig sehe, ist der Task eh in einer Busy-Loop und wartet
>>> (pollend) auf den passenden Zeitpunkt.  Dann sample doch stattdessen
>>> ständig und bestimm den Spitzenwert in Software.
>>
>> Damit umschipperst man ein Problem, holt Dir dafür ein neue ins Boot:
>> Wie schnell muss man sampeln, damit innerhalb der Messzeit der
>> Spitzenwert garantiert hinreichend genau (0.33% ?) getroffen wird.
>
> Bei maximaler Aussteuerung eines 12bit Wandlers:
> (90° - arcsin(4095/4096)) × 2
> Das wäre dann ein Bereich von ~ 2,5° um den Scheitelwert.

Hut ab - Du bist der Erste, der das Problem mal mathematisch angegangen 
ist!

Angenommen, die 2.5° würden stimmen, würde sich daraus ein 
Sample-Intervall (bzw. Sample-Jitter) von 2.5°/360° x 1ms = 6.8us 
ableiten lassen - unabhängig davon, ob die Methode nach "foobar" oder 
"Julian" zum Einsatz kommt.

In Beitrag "Re: Direkte Messung von Wechselspannung mittels ADC" geht Julian von 
50us aus, in Beitrag "Re: Direkte Messung von Wechselspannung mittels ADC" 
schätzt Falk B. 5us wären richtig, in 
Beitrag "Re: Direkte Messung von Wechselspannung mittels ADC" meint Grummeler, 
dass das eh alles schei*egal sei.

Bei so viel „Unsicherheit“ hätte ich noch keine einzige Zeile Code 
generiert, ja mich noch nicht mal für einen uC entschieden.

Wobei die Frage nach der Messzeit, also 100 ... 1000ms immer noch nicht 
entschieden ist - geschweige denn, wie die Methode "Julian" die 
(toleranzbehaftete) Signalfrequenz bestimmen will. Schießlich braucht er 
diese, um den optimalen Sample-Zeitpunkt im Voraus festzulegen.

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.