Hallo community, folgendes Projekt:
Das Ticken eines Sekundenpendels soll über eine Lichtschranke (ein Impuls je Sekunde, ca. 60ms lang) mit dem Impuls eines (funk synchronisierten) Quarzwerkes (ein Impuls aller 2 Sekunden, ca. 40ms lang) verglichen werden.
Im festgelegten Intervall soll kumulierend zum Startwert der Vor-oder Nachgang des Pendels ausgegeben bzw. später gespeichert werden.
Problem dabei ist, dass erstens beim Lichtschrankensignal nur jedes zweite erfasst werden soll, und zweitens nur jeweils die aufsteigenden Flanken der Impulse einmal erfasst werden sollen.
Und genau das klappt nicht, irgendwo habe ich sicher einen Logikfehler.
Delays möchte ich natürlich vermeiden.
int Sensorfunk = A1;
int Sensorspu = A0;
int LEDfunk = 6;
int LEDspu = 7;
int Grenzfunk = 30;
int Grenzspu = 500;
int Intervall = 1; // zum testen 1 (2sec), später 10 minütlich oder stündlich
int Startfunk = 0;
int Startspu = 0;
int Startverz = 0;
int Gang = 0;
unsigned long Millisfunk = 0;
unsigned long Millisspu = 0;
unsigned long counterfunk = 0;
unsigned long counterspu = 0;
bool LS_detect = 0;
bool Funk_detect = 0;
bool Tic = 0;
void setup()
{
Serial.begin(250000);
delay(100);
#ifndef ESP8266
while (!Serial); // wait for serial port to connect. Needed for native USB
#endif
pinMode(LEDfunk, OUTPUT);
pinMode(LEDspu, OUTPUT);
pinMode(Sensorfunk, INPUT);
pinMode(Sensorspu, INPUT);
// Anfangswert Startverzögerung ermitteln und ausgeben
while (analogRead(Sensorfunk)<Grenzfunk)
Startfunk = millis();
while (analogRead(Sensorspu)<Grenzspu)
Startspu = millis();
Startverz = Startspu - Startfunk;
Serial.print("Startfunk:");
Serial.print(Startfunk);
Serial.print(" ");
Serial.print("Startspu:");
Serial.print(Startspu);
Serial.print(" ");
Serial.print("Startverz:");
Serial.println(Startverz);
}
void loop()
{
//****************************************************************
// Erfassen Impulse Funkuhr
// Funk_detect zur Filterung Impulsflanke
if (analogRead(Sensorfunk)>Grenzfunk && Funk_detect == 0)
{
digitalWrite(LEDfunk, HIGH);
Funk_detect = 1;
counterfunk++;
if ((counterfunk) == (Intervall))
{
Millisfunk = millis();
counterfunk=0;
}
}
if (analogRead(Sensorfunk)<Grenzfunk && Funk_detect == 1)
{
digitalWrite(LEDfunk, LOW);
Funk_detect = 0;
}
//****************************************************************
// Erfassen Impulse Lichtschranke
// LS_detect zur Filterung Impulsflanke
// Tic Herausfilterung des zweiten LS Impulses
if (analogRead(Sensorspu)>Grenzspu && LS_detect == 0 && Tic ==1)
{
digitalWrite(LEDspu, HIGH);
LS_detect = 1;
counterspu++;
if ((counterspu) == (Intervall))
{
Millisspu = millis();
Gang = (Millisspu - Millisfunk - Startverz);
counterspu=0;
Serial.print("Funk:");
Serial.print(counterfunk);
Serial.print("*");
Serial.print(Millisfunk);
Serial.print(" * ");
Serial.print("SPU:");
Serial.print(counterspu);
Serial.print("*");
Serial.print(Millisspu);
Serial.print(" * ");
Serial.println(Gang);
}
}
if (analogRead(Sensorspu)<Grenzspu && LS_detect == 1 && Tic ==1)
{
digitalWrite(LEDspu, LOW);
LS_detect = 0;
Tic = 0;
}
if (analogRead(Sensorspu)>Grenzspu && Tic ==0)
{
Tic = 1;
}
//****************************************************************
}
Hallo,
ändere Deinen Eingangspost noch so ab das der codetag (das mit der eckigen Klammern ) in einer eigenen Zeile steht, das kannst Du auch nachträglich noch machen.
Verstanden habe Dein Problem nicht. Du sollst die Flanke der Lichtschranke auswerten und nur jede zweite Flanke nutzen. Flanke auswerten , das ist doch recht einfach . mit jeder Flanke invertierst du einen bool variable , oder meinetwegen einen Zähler von 0-1-0-1. Dann geschickt logisch verknüpfen und als start für die Zeitmessung nutzen.
Sorry, da ich noch bissel unsicher auf den Arduino-Füßen bin, ist das so eine Sache mit dem "Logisch verknüpfen" Habe ich hier auch versucht...
Findest Du den Weg über die beiden Variablen Tic und LS_detect denn falsch oder umständlich?
Könntest du mir mit kurzen Code Schnipseln zeigen, was Du meinst?
Ich wäre super dankbar!!!
Bisher habe ich nur die Analogeingänge des A. genutzt...Denke ich mal drüber nach.
Hallo
Na ja , mein Fehler, da ist auch noch vor dem Codetag das ' und hinter dem codeTag ein ' zuviel.
Du kannst alle analogen Eingänge auch digital wie alle anderen Eingänge nutzen.
Also was ich verstanden habe ist , das Du letztlich die Zeit zwischen zwei Lichtschrank Impulsen messen willlst. Gleiches für die Funkuhr. Die Differenz zischen beiden Ist das was Du letztlich haben willst.
Eigentlich kann ja das Signal der Lichtschranke nicht prellen , dennoch schadet es nichts. Zudem macht es Sinn das testen zu können. Weil es nun mal einfacher ist habe ich eine Lib dazu benutzt. Wozu das Rad neu erfinden.
Die Testfunktion Ausgabe dient nur dazu das testen zu können, kannst Du letztlich weg lassen.
#include <Bounce2.h>
const byte LS_pin = A3;
bool count;
uint32_t altzeit,messzeit;
Bounce2::Button LS = Bounce2::Button();
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
LS.attach(LS_pin, INPUT);
LS.interval(10);
LS.setPressedState(LOW);
pinMode(4,OUTPUT); // testfrequenz
}
void loop() {
// put your main code here, to run repeatedly:
LS.update();
ausgabe();
if (LS.changed() && LS.pressed()) { // steigende Flanke
count = !count;
Serial.println("Flanke erkannt ");
if (count){
Serial.print("zweite Flanke erkannt Messzeit ms ");
messzeit=millis()-altzeit;
altzeit=millis();
Serial.println(messzeit);
}
}
}
void ausgabe(){ // zum testen eine Brücke von pin4 auf den LS Eingang
static uint32_t altzeit;
static bool status =false;
if( millis()-altzeit >=500){
altzeit=millis() ;
status=!status;
digitalWrite(4,status);
}
}
Ah, jetzt hab ich das erstmal mit der ordentlichen Code Anzeige. Der Apostroph wurde automatisch beim Hochladen erstellt, deswegen dachte ich, der muss so. Aber jetzt ist es schöner.
Ich guck gleich mal deinen Vorschlag an und teste mal. Melde mich dann wieder. Vielen Vielen Dank schon mal!!!!
Hallo, @my_xy_projekt vermutlich ist es sowas in der Art, allerdings werden die Flanken bei Start nicht synchron sein, und sie werden auseinander driften. d.h beide Frequenzen laufen unsynchron vor sich hin.
darum der Ansatz beide Zeiten messen und die voneinander abziehen und dann das einer Stunde aufsummieren
Ich war da noch nicht eingestiegen - aber wenn es keinen Zustand gibt, an dem ein sync stattfindet, dann ist alles reine Theorie.
Bei 40 und 60ms Impulslänge sollte das auch ohne ISR gehen, aber was wenn nicht?
Ansonsten ist das keine Herausforderung.
Grüße.
Nachtrag. Ich hab das mal versucht von Grund aufzuzeigen:
Im Setup warten.
QuarzFlanke erkennen
Zeit merken
Auf Pendelflanke warten
Pendelflanke erkannt
Zeit merken
Was kommt als nächstes?
Quarzflanke erkannt ->
Läuft das Pendel jetzt vor oder nach?
Also ist zum StartZeitpunkt etwas festzulegen.
Ich würde im Setup das mit der Quarzbasis nehmen und warten um von dort weiterzumachen wenn ich irgendetwas habe, was ich als Basis benutzen kann..
Super Super! Ich habe es hinbekommen dank Rentner's Beispiel.
Bouncing ist kein Problem, die Bibliothek spare ich mir. Geholfen hat die Invertier Funktion count=!count mit nachfolgender if schleife.
Also Vielen Vielen Dank! @my_xy_projekt Danke auch fürs Mittüfteln. Genau, es geht nicht darum, die Zeit zwischen 2 gleichen Flanken zu messen, sondern 2 verschiedenen. (Flanke Funk, Flanke spu, wobei spu für Sekundenpendeluhr steht))
Hier das Oszi Bild der Ausgabe an den LEDs.
Also ich subtrahiere die Flanke Funk millis von Flanke spu millis und bekomme damit den Wert, den das Pendel der Realzeit nachläuft. Wenn ich die Start verzögerung auch noch abziehe, bekomme ich den exakten Wert, der über die Zeit kumuliert.
Hier der laufende Code, als nächstes binde ich LCD und SD shield wieder ein.
int Sensorfunk = A1;
int Sensorspu = A0;
int LEDfunk = 6;
int LEDspu = 7;
int Grenzfunk = 30;
int Grenzspu = 500;
int Intervall = 1; // zum testen 1 (2sec), später 10 minütlich oder stündlich
int Startfunk = 0;
int Startspu = 0;
int Startverz = 0;
int Gang = 0;
unsigned long Millisfunk = 0;
unsigned long Millisspu = 0;
unsigned long counterfunk = 0;
unsigned long counterspu = 0;
bool LS_detect = 0;
bool Funk_detect = 0;
bool Tic = 0;
void setup()
{
Serial.begin(250000);
delay(100);
#ifndef ESP8266
while (!Serial); // wait for serial port to connect. Needed for native USB
#endif
pinMode(LEDfunk, OUTPUT);
pinMode(LEDspu, OUTPUT);
pinMode(Sensorfunk, INPUT);
pinMode(Sensorspu, INPUT);
// Anfangswert Startverzögerung ermitteln und ausgeben
while (analogRead(Sensorfunk)<Grenzfunk)
Startfunk = millis();
while (analogRead(Sensorspu)<Grenzspu)
Startspu = millis();
Startverz = Startspu - Startfunk;
Serial.print("Startfunk:");
Serial.print(Startfunk);
Serial.print(" ");
Serial.print("Startspu:");
Serial.print(Startspu);
Serial.print(" ");
Serial.print("Startverz:");
Serial.println(Startverz);
}
void loop()
{
//****************************************************************
// Erfassen Impulse Funkuhr
// Funk_detect zur Filterung Impulsflanke
if (analogRead(Sensorfunk)>Grenzfunk && Funk_detect == 0)
{
digitalWrite(LEDfunk, HIGH);
Funk_detect = 1;
counterfunk++;
if ((counterfunk) == (Intervall))
{
Millisfunk = millis();
counterfunk=0;
}
}
if (analogRead(Sensorfunk)<Grenzfunk && Funk_detect == 1)
{
digitalWrite(LEDfunk, LOW);
Funk_detect = 0;
}
//****************************************************************
// Erfassen Impulse Lichtschranke
// LS_detect zur Filterung Impulsflanke
// Tic Herausfilterung des zweiten LS Impulses
if (analogRead(Sensorspu)>Grenzspu && LS_detect == 0)
{
Tic = !Tic;
LS_detect = 1;
if (Tic)
{
digitalWrite(LEDspu, HIGH);
counterspu++;
if ((counterspu) == (Intervall))
{
Millisspu = millis();
Gang = (Millisspu - Millisfunk - Startverz);
counterspu=0;
Serial.print("Funk:");
Serial.print(counterfunk);
Serial.print("*");
Serial.print(Millisfunk);
Serial.print(" * ");
Serial.print("SPU:");
Serial.print(counterspu);
Serial.print("*");
Serial.print(Millisspu);
Serial.print(" * ");
Serial.println(Gang);
}
}
}
if (analogRead(Sensorspu)<Grenzspu)
{
digitalWrite(LEDspu, LOW);
LS_detect = 0;
}
//****************************************************************
}
na denn. - Ich hätte es fair gefunden, wenn Du @Rentner seinen Vorschlag, den Du nicht mal vollständig gelesen/verstanden/übernommen hast, als solution markiert hättest.
Hallo ,
Na ,dann mach aus dem analogRead noch ein digitalRead.
verstanden hab ich immer noch nicht was Du vorhast.
ich vermute es geht darum die Gangenauigkeit der Pendeluhr mit der Funkuhr zu ermitteln. Letztlich kannst Du auch messen wie lange 7200 Pendel dauern, das sollten ja 3600s sein. Die Zeit für 3600 Impuse der FunkUhr entspricht dann ja genau einer Stunde, also 3600.000ms . Wenn dann bei den Pendeluhr was anderes rauskommt als 360.000 dann ist die Differenz das was die Pendeluhr falsch geht.
Heinz
Hallo,
ok dann eben genau anders herum, das Prinzip ist das Gleiche eine Stunde lang messen , damit es was unterschiedliches zu messen gibt, und sich keine Fehler aufsummieren können.
Allerdings ist mir das mit der Funkuhr ??? warum keine RTC als Zeitbasis nehmen.
Gruß Heinz
guter Einwand.
Da würde sogar der SQW-Tik reichen. Und wäre genauer...
Ich hab grad nochmal drüber nachgedacht...
Das aufsummieren würde ja nur funktionieren, wenn die Basis nicht das Messintervall syncronisieren würde.
Da der Tik der Quarzuhrbasis alle 2Sek. kommt, ist das - bei richtiger Implementierung - eigentlich unmöglich.
Sonst wäre auch der 1sek-SQW-Tik nutzlos.
Ok. Sorry für die Missverständnisse. Lösung und Herzchen sind gesetzt Nochmal zum Projekt, nur falls es Euch interessiert:
Eine sehr präzise SPU soll vermessen werden in Abhängigkeit von verschiedenen Umgebungsvariablen (Temp, Druck etc.) Bis jetzt gehe ich täglich zu Zeitpunkt X zur Uhr, lese den Gang (+/- zur Funkuhr, 2.Funkuhr als Kontrolle) ab, außerdem Luftdruck und Temperatur und notiere den in einem Gangbuch.
Die Ziel-Genauigkeit dieser SPU ca. +/- 3 sec Jahr. Das ist natürlich viel genauer als RTC oder SQW. Deshalb fallen die aus. Auch fällt eine Kurzzeitmessung innerhalb eines kleinen Intervalls aus.
(Dafür gibt es schon sogenannte "Zeitwaagen" für Uhrmacher.)
Aber hier soll der Vor-oder Nachgang des Pendels über Monate zum Start der Messung angezeigt werden. Die Zwischenwerte (stündlich oder täglich) werden gespeichert, außerdem dazu die Umgebungsvariablen. So kann ich später in der Auswertung die verbleibenden Gangschwankungen mit der Änderung der einzelnen Umgebungsvariablen vergleichen (über xls Diagramm).
Natürlich war auch unser erster Ansatz, ein DCF Modul auszuwerten und die Lichtschrankenimpulse zu einer "SPU-Zeit" umzurechnen. Diese dann im Intervall zu vergleichen (kumulierend).
Das scheiterte aber erstens am sehr fehleranfälligen Empfang des Moduls und an der doch sehr aufwändigen Programmierung bzw. meinen fehlenden Kenntnissen.
Aber keine Frage, wäre das der noblere Weg gewesen.
Zum Behelf nehme ich mir nun ein einfaches Funkuhrwerk und greife die 2-sekündlichen Schrittmotorimpulse ab. Diese werden im Intervall hochgezählt, wie Heinz auch schon vorgeschlagen hat, und dann die millis verglichen ( z.B. counter 3600 von Funk zu counter 3600 von LS)
Die Genauigkeit kommt dann nicht durch die millis, sondern über die Verbindung der counters und millis. Selbst bei kleinen Schwankungen innerhalb des Intervalls, ist die Anzeige des Gangs ber längere Zeit immer genauer.
Könnt Ihr jetzt nachvollziehen, was ich vorhabe?
Soweit zur Theorie, aber @my_xy_projekt hat Recht, der Code läuft noch nicht richtig. Irgendwo ist der Wurm drin, wenn ich das Intervall vergrößere. Ich habe die Messung über Nacht laufen lassen im Intervall 30, also 60 Sekunden.
Die Lichtschranke lief dank der vorgeschlagenen Invertierung von Heinz @Rentner stabil. Auch die Ermittlung der Startverzögerung war richtig. (Kontrolle über das Oszi) @my_xy_projekt : was läuft Deiner Meinung nach in der while Funktion falsch?
Allerdings verhedderte Sich scheinbar die Zählfunktion der Funkimpulse bzw. die Art und Weise der Rechnung. Auch immer mal aller paar Stunden. Es sollen ja eigentlich immer Impulse gleichen Counters verglichen werden.
Hallo,
Sorry mir ist da immer noch nicht klar warum du das sychronisieren willst.
Du willst die Ganggenauigkeit der Pendeluhr messen. Bisher hast Du dazu zu einem bestimmten Zeitpunkt eine "Uhrenvergleich" gemacht und die Differenz als Ergebnis genutzt, um zusammen mit den übrigen Daten zu einer Aussage zu kommen. Dabei hat Dich nicht interessiert ob Pendel und Referenzuhr zum gleichen Zeitpunkt "ticken". Du wolltest wissen wie weit sie innerhalb einen festgelegten Zeit auseinander gelaufen sind. Mal nebenbei wie konntest Du das überhaupt ablesen. ? Oder hast Du tatsächlich mit einem Oscar die Zeitdifferenz zwischen den beiden Signalen gemessen?.
Technisch geht es meiner Meinung darum zu messen wie lange es dauert bis z.B 3600 Impulse bei der einen und 7200 bei der anderen gedauert haben.( Je länger je besser) Das Verhältnis ist in dem Fall fest , es kann nicht anders sein. Ansonsten wäre die Gangenauigkeit einer Uhr innerhalb einer Stunde schlechter als 1 Sekunde. Die Messung kann völlig unabhängig und unsyschron voneinander gemacht werden. Entscheidend ist nur die Differenz der beiden Zeiten. Die Differenzzeit wird jetzt auch nicht absolut richtig sein, da die millis() und (micros() ) ja u.U. auch nicht absolut sind. Es geht aber ja um einen Vergleiche bei unterschiedlichen Umwelt Bedingung.
Noch mal zur Messgenauigkeit , wir reden von +-3s im Jahr das sind 3000ms /365 Tage =8,2ms/Tag. Wenn Du da in einer Stunde einen Unterschied messen willst solltest Du auf micros() wechseln. da könnte etwa im Mittel ein Unterschied von 350us/h auftreten.
Kann aber auch sein das ich es immer noch nicht verstanden, oder das Problem nicht erkannt habe.
Heinz
Ist eigentlich nicht so kompliziert. Vielleicht bissel ein Uhrmacher-Ding
Am besten versteht man es mit der Analogie zum täglichen Ablesen der Uhr mit dem Gangbuch.
Die Erfassung des permanenten Gangs einer Uhr ist nicht dasselbe, wie das messen des Gangs in einem bestimmten Zeitraum. Du musst Dir den Gang wie eine Welle vorstellen, die Uhr geht mal + und mal -. Genau diese Welle interessiert mich. Aber immer in Verbindung mit dem absoluten Gang, also wieviel Vor oder Nachgang zum Start der Messung.
Da die Impulse nie "gleich" ticken, erfasse ich vor dem Loop den anfängliche Startverzögerung, also wie lange läuft der LS Impuls dem Funk Impuls hinterher.
Zum experimentieren habe ich momentan eine ungenaue Uhr, die läuft 20 sec / Tag nach. Da reichen die millis total. Aber Du hast Recht, wir haben auch vor, später mal in micros zu messen.
Ist aber noch die totale Theorie, momentan bin ich mal wieder am verzweifeln. Wenn ich das Intervall < 1 mache, läuft etwas schief beim countern. Eigentlich müsste doch beim Start des Loops gleich der erste Funk Impuls mit 1 zu zählen beginnen, gleich der darauffolgende LS Impuls muss dann mit 1 hochzählen. Wenn beide bei 5 sind sollen die "Millis" ausgegeben werden.
Tun sie aber nicht. Der Counter in der Ausgabe ist 0 oder mal irgendwas anderes.
Entweder meine Programmlogik ist falsch oder es gibt vielleicht ein Problem mit den Variablen?