ich habe folgendes Problem: Mein Versuchsaufbau besteht aus zwei Arduinos:
Arduino 1 (Mega): LED wird gepulst angesteuert, mittels Rotary Encoder kann ich die Frequenz zwischen 1 und 100 Hz regeln
Arduino 2 (Uno): Eine Fotodiode (liegt direkt neben der LED) mit Transimpedanzverstärkung ist an einen Digitalpin angeschlossen und erkennt das gepulste Signal der LED
Sobald ich nun an Arduino 1 die Frequenz höher als ~63 Hz drehe, werden an Arduino Uno nur noch Werte mit großen Sprüngen dazwischen angezeigt, z.B. LED Frequenz: 90 Hz, erkannte Frequenz des Arduino 2: 80Hz.
Die Frequenzerkennung läuft über pulseIn von HIGH und LOW des Digitalpins, die Pulse werden zusammengerechnet (1x an und aus) und dann in die Frequenz umgerechnet.
Hat jemand eine Idee wie man das beheben könnte? Ich bin noch blutiger Anfänger auf dem Gebiet also wäre ich froh wenn ihr eure Antworten idiotensicher formuliert
Richtig, diese Antwort paßt immer wenn der Fragesteller alle wichtigen Informationen für sich behält. Siehe Topics am Anfang des Forums, was für Angaben für eine erfolgreiche Beratung notwendig sind.
Meine Analyse: Verbessere die Fehler in Deinem Code, dann funktioniert das wahrscheinlich. Mehr läßt sich bis jetzt nicht sagen.
const int pinLED = 7;
const int pinSensor = 5;
int highTime; //integer for storing high time
int lowTime; //integer for storing low time
float period; // integer for storing period
float f = 0;
void setup() {
Serial.begin(57600);
while (! Serial) {
delay(1);
}
pinMode(pinSensor, INPUT);
pinMode(pinLED, OUTPUT);
digitalWrite(pinLED, HIGH);
}
void loop() {
highTime=pulseIn(pinSensor,HIGH); //read high time
lowTime=pulseIn(pinSensor,LOW); //read low time
period = highTime+lowTime; // Period = Ton + Toff
f=1000000/period;
Serial.println(f);
}
Die LED zeigt einfach nur an, dass die Fotodiode gerade misst, sollte doch kein Problem sein oder?
HotSystems:
Und wer lesen kann ist klar im Vorteil.
Mensch, hier wird man aber freundlich empfangen
Ich dachte meine kurze Beschreibung:
ecxabyte:
Die Frequenzerkennung läuft über pulseIn von HIGH und LOW des Digitalpins, die Pulse werden zusammengerechnet (1x an und aus) und dann in die Frequenz umgerechnet.
Würde eventuell schon reichen für ein paar Denkanstösse, Schande über mich
millis() oder micros()
Serielle Ausgaben mit einer VIEL HÖHEREN Geschwindigkeit.
Bei 9600 Baud braucht EIN Zeichen 1ms - wenn Du 'Frequenz: .....' ausgibst, sind Das schon einige ms Wartezeit, Die zum delay() noch dazu kommen.
Das passiert Dir bei millis() nicht, Die zählen weiter, solange die Interrupts nicht gesperrt werden (und wenn nicht zu lang gesperrt wird, holen Die das Zählen nach).
Da Du für 100Hz 5ms Pause brauchst, dürfte millis() aber schon zu ungenau werden - spätestens nach 5ms ist eben nicht genau nach 5ms.
Dort könnte micros() besser sein, zählt in 4er Schritten die µs, also pro Sekunde bis 1.000.000 - dort wird mit >5000µs die 5ms wesentlich genauer getroffen, als mit millis();
Interrupts sind auch falsch verwendet. Kein volatile. Kein atomares Auslesen (evtl. nur char verwenden statt int, dann braucht man das nicht). Serial und delay() in einer ISR!
Du kannst ja das Ausgangssignal des 1. Arduinos an den Eingang des 2.Arduino schalten und so die LED/Fotodiode als Fehlerquelle ausgeschlossen. Masse verbinden.
Grüße Uwe
millis() oder micros()
Serielle Ausgaben mit einer VIEL HÖHEREN Geschwindigkeit.
Bei 9600 Baud braucht EIN Zeichen 1ms - wenn Du 'Frequenz: .....' ausgibst, sind Das schon einige ms Wartezeit, Die zum delay() noch dazu kommen.
Das passiert Dir bei millis() nicht, Die zählen weiter, solange die Interrupts nicht gesperrt werden (und wenn nicht zu lang gesperrt wird, holen Die das Zählen nach).
Da Du für 100Hz 5ms Pause brauchst, dürfte millis() aber schon zu ungenau werden - spätestens nach 5ms ist eben nicht genau nach 5ms.
Dort könnte micros() besser sein, zählt in 4er Schritten die µs, also pro Sekunde bis 1.000.000 - dort wird mit >5000µs die 5ms wesentlich genauer getroffen, als mit millis();
Schaue Dir blink_without_delay in der IDE an.
MfG
Danke, probiere ich mal aus War mir nicht bewusst, dass die "Ausgabe" so viel Zeit in Anspruch nimmt
Serenifly:
Interrupts sind auch falsch verwendet. Kein volatile. Kein atomares Auslesen (evtl. nur char verwenden statt int, dann braucht man das nicht). Serial und delay() in einer ISR!
Serial in der Button ISR nehme ich in Kauf, den Rest lösche ich noch. Beim Rest der Antwort verstehe ich nur Bahnhof, kannst du die nochmal einfacher formulieren?
uwefed:
Du kannst ja das Ausgangssignal des 1. Arduinos an den Eingang des 2.Arduino schalten und so die LED/Fotodiode als Fehlerquelle ausgeschlossen. Masse verbinden.
Grüße Uwe
Geht natürlich auch, ist aber nicht Sinn des Versuchsaufbaus. Hätte ich vllt konkret dazuschreiben sollen
Ich habe die Pulserzeugung jetzt über micros() gelöst, und alle Serial Ausgaben erfolgen jetzt nur noch 1x pro halbe Sekunde Code folgt:
loop() und blinken() vom Arduino 1 (Mega):
void loop() {
rotating = true; // reset the debouncer
if (lastReportedPos != encoderPos)
{
//Serial.print("Index: ");
//Serial.println(encoderPos, DEC);
lastReportedPos = encoderPos;
}
if(on){
f = calcFreq(encoderPos);
blinken(f);
if(currentMicros - serialMicros >= 500000)
{
Serial.println(f);
serialMicros = currentMicros;
}
}
}
void blinken(float freq) {
float d = 1000000/(freq*2);
currentMicros = micros();
if (currentMicros - previousMicros >= d) {
// save the last time you blinked the LED
previousMicros = currentMicros;
// if the LED is off turn it on and vice-versa:
if (ledState == LOW) {
ledState = HIGH;
} else {
ledState = LOW;
}
// set the LED with the ledState of the variable:
digitalWrite(pinLED, ledState);
}
}
kompletter Code vom Arduino 2 (Uno):
int test;
const int pinLED = 7;
const int pinSensor = 5;
unsigned long duration = 0;
unsigned long previousMillis = 0;
unsigned long currentMillis = 0;
int highTime; //integer for storing high time
int lowTime; //integer for storing low time
float period; // integer for storing period
float f = 0;
void setup() {
Serial.begin(57600);
while (! Serial) {
delay(1);
}
pinMode(pinSensor, INPUT);
pinMode(pinLED, OUTPUT);
digitalWrite(pinLED, HIGH);
}
void loop() {
highTime=pulseIn(pinSensor,HIGH); //read high time
lowTime=pulseIn(pinSensor,LOW); //read low time
period = highTime+lowTime; // Period = Ton + Toff
f=1000000/period;
currentMillis = millis();
if (currentMillis - previousMillis >= 500) {
// save the last time you blinked the LED
previousMillis = currentMillis;
Serial.println(f);
}
/*
test = digitalRead(pinSensor);
Serial.println(test);
*/
}
Das klappt soweit auch ganz gut, jedoch zeigt die Fotodiode immer eine etwas niedrigere Frequenz an, Bsp.: LED: 981 Hz; Fotodiode: 961 Hz.
Sobald ich jenseits der 1000 Hz gehe ist der Effekt noch deutlich stärker und irgendwann misst er nur noch jeden zweiten Puls (halbe Frequenz).
Hat jemand noch Verbesserungsvorschläge? Danke nochmal für den Vorschlag mit millis
Generell braucht man für einen Encoder auch nicht zwei Interrupts. Du musst nur eine Flanke abfragen und bei Änderung den Zustand des anderen Pins
Danke für die Erklärung! Habe die entsprechenden Variablen jetzt auf volatile geändert
Ich hatte die Interrupt Lösung im Internet gefunden und fand sie recht elegant, zum Glück hat der Arduino Mega ja genug Pins also werde ich das denke ich so lassen.
ecxabyte:
Das klappt soweit auch ganz gut, jedoch zeigt die Fotodiode immer eine etwas niedrigere Frequenz an, Bsp.: LED: 981 Hz; Fotodiode: 961 Hz.
Sobald ich jenseits der 1000 Hz gehe ist der Effekt noch deutlich stärker und irgendwann misst er nur noch jeden zweiten Puls (halbe Frequenz).
Hat jemand noch Verbesserungsvorschläge? Danke nochmal für den Vorschlag mit millis
Ich habe statt pulseIn() nun mal die Library FreqCount getestet, da gibt es jedoch dasselbe Problem: Die Messung zeigt konstant weniger an als der Ardunio mit der LED und ab 1kHz sind die Messungen leider gar nicht mehr zu gebrauchen. Ist das einfach das Limit der Kombination aus Fotodiode, Transimpedanzverstärkung und Arduino?