Hallo Zusammen,
ich habe ein Arduino Pro Mini (3,3V 8MHz). Am Analogeingang habe ich ein
Signal mit einer Frequenz von 50Hz (Sinus) angelegt (siehe Bild).
Ich versuche aktuell den "Nullpunkt" (570mV) zu erkennen und
auszuwerten.
Habe schon vieles Versucht, aber schaffe es einfach nicht.
Hier der Code:
1
#include<Wire.h>
2
#include<LiquidCrystal_I2C.h>
3
LiquidCrystal_I2Clcd(0x27,20,4);
4
5
6
intanalogPin=A0;//Analogsignal am Pin A0
7
8
intin1=0;
9
floatUin1=0;
10
floatU1=0;
11
constfloatzero=0.57;
12
unsignedlongZeit=0;
13
14
inti=0;
15
16
17
voidsetup(){
18
Serial.begin(500000);
19
analogReference(INTERNAL);
20
lcd.init();
21
lcd.backlight();
22
}
23
24
25
voidloop(){
26
in1=analogRead(analogPin);// Pin einlesen
27
Uin1=(((1.1/1023.0)*in1));// Umwandeln in 0V bis 1,1V
28
U1=(Uin1-zero)*(671989.0/989.0);//Umwandeln in -350V bis + 350V
29
30
lcd.setCursor(0,2);
31
lcd.print(i);
32
33
if(U1==0)i=i+1;
34
35
36
if(i==10000){
37
lcd.setCursor(0,1);
38
lcd.print("TEST");
39
i=0;
40
delay(2000);
41
lcd.clear();}
42
43
}
Ist der AVR oder ADC im AVR zu langsam um den Nullpunkt bei 50HZ
Freqeuenz zu erkennen? Habe das ganze mit einem Zähler versucht. Was
mache ich falsch?
Gruß Dominik
Dominik W. schrieb:> Ist der AVR oder ADC im AVR zu langsam um den Nullpunkt bei 50HZ> Freqeuenz zu erkennen? Habe das ganze mit einem Zähler versucht. Was> mache ich falsch?
Der sollte das schaffen.
Deine LCD-Ausgabe verlangsamt die Messung.
Manfred schrieb:> Ohne Deinen Code vollständig nachzuvollziehen bin ich mir ziemlich> sicher, dass>>if (U1==0)niemals zutreffen wird, prüfe auf 'kleiner null komma null null> sonstwas' - passend zu Deinem erwarteten Wertebereich.
Richtig.
Hallo Dominik,
wie meine Vorredner schon richtig geschrieben haben sollte man keinen
"== "Vergleich bei float vornehmen.
Weiterhin würde ich das Suchkriterium für den Nullpunkt nicht bei jedem
Schleifendurchlauf berechnen.
Da Du den genauen Wert abhängig von der Beschaltung sowieso nicht genau
berechnen kannst, würde ich die 570 mV konstant anlegen und den AD Wert
notieren. Dieser Wer ist dann in der Schleife Dein Suchkriterium.
Später kannst Du den Wert natürlich im Setupteil auch für andere
Bedingungen berechnen.
Als letzte Änderung schlage ich vor nicht bei jedem Schleifendurchgang
eine LCD Ausgabe zu machen.
Grüße
Roland
Bei Floats niemals auf == vergleichen.
Am besten den letzen Wert merken, und wenn
letzer <= 0.0 && aktuell >0.0
Dann hat ein Nulldurchgang in positiver Richtung stattgefunden.
Dominik W. schrieb:> Ich versuche aktuell den "Nullpunkt" (570mV) zu erkennen und> auszuwerten.
Der ATMega328P hat einen eingebauten Komparator.
Was spricht gegen dessen Verwendung?
Roland F. schrieb:> Als letzte Änderung schlage ich vor nicht bei jedem Schleifendurchgang> eine LCD Ausgabe zu machen.
Auch hier kannst Du Dich langsam vortasten:
Zunächst mal nur bei erreichen des Suchkriteriums eine Ausgabe machen,
wenn das klappt sehen wir weiter...
Arduino Fanboy D. schrieb:> Der ATMega328P hat einen eingebauten Komparator.
Super das wusste ich auch nicht, wieder etwas gelernt, da hat sich der
Tag ja schon gelohnt. :-)
Ich wollte Dominik schon vorschlagen einen externen Komparator
einzusetzen aber Dein Vorschlag ist natürlich der bessere.
Grüße
Roland
Roland F. schrieb:> wie meine Vorredner schon richtig geschrieben haben sollte man keinen> "== "Vergleich bei float vornehmen.
Float in Zusammenhang mit einem AD-Wandler, der von Natur aus nur
Ganzzahlwerte liefern kann, ist für effiziente Erkennung vom
Nulldurchgang sowieso Unfug.
Man rechnet sich seinen Schwellwert mit der Skalierung einmal auf
Ganzzahl um und vergleicht das ADC-Ergebnis nur mit diesem ganzzahligen
Wert. Das spart die ganze unselige Float-Rechnerei in der Schleife.
Hallo Zusammen,
erstmal vielen Dank für die ganzen Antworten und die verschiedenen
Lösungsideen!
Ich habe den Code mal etwas angepasst und erkenne jetzt die
Nulldurchgänge (vor der positiven Halbwelle).
LiquidCrystal_I2Clcd(0x27,20,4);//Hier wird festgelegt um was für einen Display es sich handelt. In diesem Fall eines mit 16 Zeichen in 2 Zeilen und der HEX-Adresse 0x27. Für ein vierzeiliges I2C-LCD verwendet man den Code "LiquidCrystal_I2C lcd(0x27, 20, 4)"
4
5
6
intanalogPin=A0;// Pin, der gelesen werden soll: Pin A0
7
8
intin1=0;// Variable, die den gelesenen Wert speichert
9
floatUin1=0;
10
floatU1=0;
11
floatU1alt=0;
12
constfloatzero=0.57;
13
floatZeit=0;
14
unsignedlongStartzeit=0;
15
inti=0;
16
17
18
19
voidsetup(){
20
Serial.begin(9600);// Setup der seriellen Verbindung
21
analogReference(INTERNAL);
22
lcd.init();//Im Setup wird der LCD gestartet
23
lcd.backlight();//Hintergrundbeleuchtung einschalten (lcd.noBacklight(); schaltet die Beleuchtung aus).
24
}
25
26
27
voidloop(){
28
//Spannung berechnen//
29
U1alt=U1;
30
in1=analogRead(analogPin);// Pin einlesen
31
Uin1=(((1.1/1023.0)*in1));// Umwandeln in 0V bis 1,1V
32
U1=(Uin1-zero)*(671989.0/989.0);//Umwandeln in -350V bis + 350V
33
34
//Nulldurchgang erkennen//
35
if(U1>0.0&&U1alt<=0.0)i=i+1;
36
37
//Periodendauer ermitteln//
38
if(i==1)Startzeit=micros();
39
40
if(i==501){
41
Zeit=(micros()-Startzeit);
42
43
lcd.setCursor(0,3);
44
lcd.print(Zeit/500000.0,4);
45
lcd.setCursor(0,2);
46
lcd.print(1/(Zeit/500000000.0),2);
47
Serial.println(Zeit/500000.0,4);
48
49
i=0;
50
}
51
52
}
Leider ist das Ganze noch etwas ungenau. Die Periodendauer sollte bei
50Hz ja bei 20ms liegen.
Ich komme erst in Richtung 20ms, sobald ich mehrere 100 Perioden zähle
und dann den Mittelwert errechne. Bei einer, 10 oder 20 liege ich extrem
stark daneben und bekomme eine zu kurze Periodendauer (z.b. 16ms bei 10
Perioden).
Da die Periodendauer zu kurz ist, ist der AVR ja nicht zu langsam.
Kann es am micros() liegen, oder ist meine Erkennung zu ungenau?
Wollte das ganze gerne im AVR ohne noch mehr externe Beschaltung lösen.
Der interne Komparator ist auch eine Idee, dafür müsste ich mir jedoch
meine 570mV nochmal erzeugen und auf einen anderen AI geben.
Gruß Dominik
Mach Dir mal Gedanken, wie lange wohl die Display Ausgabe dauern wird.
Lösungsvorschlag: Messe in regelmäßigen Abständen mit einem
freilaufenden ADC (unterstützt Arduino vermutlich nicht direkt).
Ich würde gerne wissen, wozu der Nulldurchgang dann verwendet wird. Wenn
es nur um Triggern geht, dann gibt es dazu viel einfachere Methoden, die
auch deutlich pegelunabhängiger sind, als das Jonglieren mit float
Werten.
Dominik W. schrieb:> Der interne Komparator ist auch eine Idee, dafür müsste ich mir jedoch> meine 570mV nochmal erzeugen und auf einen anderen AI geben.
Nö, musst du nicht. Du kannst den Sinus mit einem RC Tiefpass glätten
und auf den anderen Komparatoreingang geben. Das ist dann auch gleich
eine Autolevel Erkennung, weil sich nach dem Tiefpass die ganze Nummer
sowieso auf die Nulllinie einpendelt.
Dominik W. schrieb:> Ich habe den Code mal etwas angepasst und erkenne jetzt die> Nulldurchgänge (vor der positiven Halbwelle).
Aber den wertvollsten / effektivsten Rat hast du nicht befolgt:
Wolfgang schrieb:> Man rechnet sich seinen Schwellwert mit der Skalierung einmal auf> Ganzzahl um und vergleicht das ADC-Ergebnis nur mit diesem ganzzahligen> Wert. Das spart die ganze unselige Float-Rechnerei in der Schleife.
Dieses unsägliche Rechnen mit float ist ein Wahnsinn, und die
Ausgabe in float ist auch nicht der Renner. Siehe auch Stefans
Hinweis.
Hallo Zusammen,
die Ausgabe auf dem Display erfolgt ja erst nach dem ermitteln der Zeit
und vor dem Zurücksetzen meiner Zählvariable i.
Habe den Code nochmal angepasst und arbeite jetzt nur noch mit dem
Int-Wert vom Analogeingang ohne Umrechnungen.
LiquidCrystal_I2Clcd(0x27,20,4);//Hier wird festgelegt um was für einen Display es sich handelt. In diesem Fall eines mit 16 Zeichen in 2 Zeilen und der HEX-Adresse 0x27. Für ein vierzeiliges I2C-LCD verwendet man den Code "LiquidCrystal_I2C lcd(0x27, 20, 4)"
4
5
6
intanalogPin=A0;// Pin, der gelesen werden soll: Pin A0
7
8
intin1=0;// Variable, die den gelesenen Wert speichert
9
intU1alt=0;
10
constfloatzero=0.57;
11
floatZeit=0;
12
unsignedlongStartzeit=0;
13
inti=0;
14
15
16
17
voidsetup(){
18
Serial.begin(9600);// Setup der seriellen Verbindung
19
analogReference(INTERNAL);
20
lcd.init();//Im Setup wird der LCD gestartet
21
lcd.backlight();//Hintergrundbeleuchtung einschalten (lcd.noBacklight(); schaltet die Beleuchtung aus).
22
}
23
24
25
voidloop(){
26
27
U1alt=in1;
28
in1=analogRead(analogPin);// Pin einlesen
29
30
//Nulldurchgang erkennen//
31
if(in1>522&&U1alt<=522)i=i+1;
32
33
//Periodendauer ermitteln//
34
if(i==1)Startzeit=micros();
35
36
if(i==110){
37
Zeit=(micros()-Startzeit);
38
39
lcd.setCursor(0,3);
40
lcd.print(Zeit/110000.0,4);
41
lcd.setCursor(0,2);
42
lcd.print(1/(Zeit/110000000.0),2);
43
Serial.println(Zeit/110000.0,4);
44
45
i=0;
46
}
47
48
}
Ich möchte gerne die Periodendauer von einem (später mehreren) 50Hz
Sinussignalen messen und die Nulldurchgänge erkennen können.
RC-Tiefpass mit niedriger Grenzfrequenz ist natürlich auch noch eine
gute Idee, danke Matthias!
Gruß Dominik
Dominik W. schrieb:> später mehreren
Dann ist dein aktueller Ansatz so gar nicht mehr geeignet.
Lies mal im Datenblatt des Mikrocontrollers nach, was "freilaufender
ADC" bedeutet. In Kombination mit einer ISR kannst du dafür sorgen, dass
deine Messwerte in schön regelmäßigen Intervallen in Arrays eingetragen
werden. Die kannst du dann in der loop() nacheinander auswerten.
Dominik W. schrieb:> Ich möchte gerne die Periodendauer von einem (später mehreren) 50Hz> Sinussignalen messen und die Nulldurchgänge erkennen können.
Die Salami, wie ich sie liebe!
Wo der problem?
- sample mit relativ hoher Rate alle Eingänge die du haben willst
- merke dir für jeden Eingang den jeweils höchsten und niedrigsten Wert
(gern auch als Mittel über die letzten x Werte, dann wandert das auch
bei Schwankungen mit)
- rechne "(low + high)/2" als "zero"
- aktueller Wert über/unter "zero"? (Oder "<zero-3 or >zero+3" oder so)
????
- profit
Kein float, schnell, einfach, Pegelunabhängig.
Jens M. schrieb:> Wo der problem?
Die Periodendauer eines 50Hz Signals braucht man nicht zu messen, die
berechnet man.
Da stecken noch Geheimnisse im Hintergrund.
(die wir offensichtlich nicht erfahren dürfen)