Gibt es eine Möglichkeit, Millisekunden aus DS1307 zu berechnen

Ich habe einen DS1307 und ich habe sein Programm gemacht und Zeit daraus genommen. In meinem Programm habe ich sec1,sec2die Ziffern von Sekunden und gleich für min1,min2& hr1,hr2. Ich speichere alles in einer VariablenTIME

sprintf(TIME,"%s%s:%s%s:%s%s",hr2,hr1,min2,min1,sec2,sec1);

Enthält jetzt TIMEden Wert von Hour, Minutes, Seconds. Aber ich brauche auch den Wert von milliseconds.

Gibt es eine Logik, die ich im Code oder auf andere Weise verwenden kann, um Werte zu berechnen?milliseconds

CODE FÜR MilliSekunde

 //MSECOND is variable to hold millisecond
   int count = 0;
    do
    {
        count++;
        sprintf(MSECOND,"%d",count);
        sprintf(TIME,"%s%s:%s%s:%s%s:%s",hr2,hr1,min2,min1,sec2,sec1,MSECOND);
        putsUART1("Time: ");
        putsUART1(TIME);
        putsUART1(" \n ");
    }while(count<=999);

BEARBEITEN

Diese Frage bezieht sich auf meine ältere Frage: Wo kann das DS1307-Programm gespeichert werden, um einen Echtzeitwert zu erhalten? . Ich verwende PIC32MX795F512LMCU. Ich habe nicht den vollständigen Code gepostet. Steht im Link.

Ist dieser Code wirklich alles? Es scheint nichts zu haben, was eine konsistente Zeit hält, außer der Baudrate von UART1. Ich habe in meiner Antwort auf den Code reagiert. Wie genau muss die Millisekundenzählung sein? Welchen Mikrocontroller verwendest du?
@gbulmer Ich habe meine Frage mit dem Link bearbeitet, der Code enthält. Ich dachte daran, eine Art Zähler zu verwenden, um von 0-999 und innerhalb einer Sekunde zu zählen und ihn mit der RTC-Zeit zu synchronisieren.

Antworten (2)

Gemäß dem DS1307-Datenblatt kann der SQW/OUT-Pin eine Rechteckwelle bei 1 Hz, 4,096 kHz, 8,192 kHz, 32,768 kHz erzeugen.

Die Datenblätter sagen:

STEUERREGISTER ...
Bit 4: Rechteckwellenfreigabe (SQWE). Wenn dieses Bit auf logisch 1 gesetzt ist, gibt es den Oszillatorausgang frei. Die Frequenz der Rechteckwellenausgabe hängt vom Wert der RS0- und RS1-Bits ab. Wenn der Rechteckwellenausgang auf 1 Hz eingestellt ist, werden die Taktregister an der fallenden Flanke der Rechteckwelle aktualisiert. Beim erstmaligen Anlegen von Strom an das Gerät wird dieses Bit typischerweise auf 0 gesetzt.

Wenn Sie also einen freien MCU-Pin haben, könnte Ihr System dieses Signal eingeben. AFAICT, dieses Signal / diese Information ist nicht über I2C verfügbar, es ist nur Hardware.

Es hängt immer noch davon ab, wie genau Sie Millisekunden benötigen und wie viel Ersatzprozessor Sie haben. Sie könnten eines der Rechteckwellensignale mit höherer Frequenz verwenden und in der Software auf Millisekunden herunterteilen.

Eine einfache binäre Verschiebung (Division durch Zweierpotenz) wäre billig, hätte aber einen Fehler von wenigen %. Eine genauere Aufteilung würde etwas mehr Verarbeitung erfordern.

Bearbeiten:
Reicht diese Genauigkeit für Ihren Zweck aus?

Etwas zu tun, das einige Zeit in Anspruch nimmt, und das Zählen ist eine potenziell fragile Methode, um die Zeit zu verfolgen. Ihr Code zeigt nichts, was irgendeine andere zeitgesteuerte Einschränkung als die Geschwindigkeit des UART hat. Da der Code möglicherweise eine andere Anzahl von Zeichen druckt (z. B. in putsUART1(TIME);), ist er nicht sehr genau. Schlimmer noch, wenn eine andere Verarbeitung erforderlich ist, driftet die Zeitschleife möglicherweise unvorhersehbar ab.

Wenn ein System keine Echtzeituhr hat, verwenden wir normalerweise einen Hardware-Timer, um die Zeit einigermaßen genau zu halten. Sie haben jedoch eine ziemlich genaue Uhr im DS1307, und die einzige Hardware, die benötigt wird, um sie zu verfolgen, ist ein Eingangspin mit einem Interrupt.

Sie haben geschrieben: "Es funktioniert, aber ich weiß nicht, warum es 1 Sekunde fehlt, als würde es nach der 34. Sekunde direkt auf die 36. Sekunde springen."

Es scheint die 35. Sekunde komplett zu verpassen. Das funktioniert nicht wirklich. Es druckt einige Zahlen, die wie die richtige Sequenz aussehen, aber das bedeutet nicht viel. Es ist ziemlich einfach, einen Codepreis zu schreiben, der bis 999 zählt und gedruckt wird. Das bedeutet nicht, dass jede Zahl eine Millisekunde brauchte, um zu erscheinen.

Wenn Sie spezifischere Hilfe benötigen, müssen Sie uns mitteilen, wie genau der Millisekunden-Timer sein muss und welche anderen Verarbeitungs- und Peripheriegeräte Ihr System verwendet.

Ich habe PIC32 vor Jahren (als sie zum ersten Mal auftauchten) nur auf sehr triviale Weise verwendet.

Der PIC32MX795F512L verfügt jedoch über eine Reihe von Hardware-Timern. Diese könnten also so programmiert werden, dass sie einen einigermaßen genauen, stabilen Millisekunden-Timer erstellen. Sie sind nicht nur Timer, sondern können auch externe Ereignisse zählen. So könnte ein Timer zur Synchronisierung mit dem DS1307 verwendet werden.

Ich würde jedoch einfach einen Timer so programmieren, dass er beispielsweise ein 0,5-Millisekunden-Timer ist, und diesen gelegentlich mit dem DS1307 synchronisieren. Wenn der PIC32MX795F512L von einem Quarz läuft, wird er ziemlich genau sein. Ich würde es ein paar Stunden laufen lassen und mit dem DS1307 vergleichen, um die Drift zwischen den beiden Zeitquellen zu verstehen.

Die Verwendung des Hardware-Zeitgebers vermeidet das grundlegende Problem der Verwendung einer "Besetztschleife", um das Timing zu erhalten.

Danke für deine Antwort. Aber ich dachte daran, einen Zähler zu verwenden und seinen Wert innerhalb einer Sekunde von 0-999 zu erhöhen. Es funktioniert, aber ich weiß nicht, warum es 1 Sekunde fehlt, wie nach 34 Sekunden springt es direkt auf 36 Sekunden. Ich habe meine Frage mit dem von mir verwendeten Code bearbeitet. Bitte guck dir das an.
Ich sehe in Ihrem Code nichts, was tatsächlich die Zeit misst - außer der inhärenten Geschwindigkeit des UART, die wahrscheinlich zu Ihrer verpassten Sekunde beiträgt.

Ich hatte vor einiger Zeit die gleiche Frage und meine aktuelle Lösung (am einfachsten) ist die folgende:

  1. Weisen Sie den SQW-Pin einem Interrupt-Pin zu (Arduino-Pin 2 und 3);
  2. Stellen Sie DS1307 so ein, dass die Rechteckwelle bei 1 Hz ausgegeben wird;
  3. Schreiben Sie auf Setup attachInterrupt(digitalPinToInterrupt("pin number"),"ISR name",FALLING)(in meinem Fall erhöhen sich die Sekunden, wenn das sqw-Signal fällt);
  4. In die ISR nur schreiben timeref = millis()(timeref ist ein globales unsigned long);
  5. Schließlich können Sie in Ihrem Code so etwas tun:

Setup(){ tref = timeref; //needed in case timeref is updated meanwhile elapseref = millis(); (do some work); elapse = millis(); //in my case I want to index time to the previous work ReadRTC(); } void ReadRTC(){ byte tens; byte units; byte income; Wire.beginTransmission(rtc_addr); Wire.write(0); Wire.endTransmission(false); Wire.requestFrom(rtc_addr,7,true); elaspertc = millis(); for(byte i = 0; i<7; i++){ income = Wire.read(); tens = income >> 4; units = income & 15; rtdata[i+2] = tens * 10 + units; // milliseconds will be store on the 1st 2 } ms = (elapse - elapseref) / 2 + elapseref - tref; //the formula can be optimize but it can also lead to overflow. As mention, in my case, I want to index time to (do some work) s = elapsertc - tref; //It is needed to correct time case s is equal or greater then 1000 ms (1s) if(s>=1000){ if(ms>=1000){ ms -= 1000; } else{ rtcdata[2] -= 1 } } rtcdata[0] = ms >> 8; rtcdata[1] = ms & 255; }

Ich arbeite mit einem Redboard (Arduino), aber auf jeden Fall soll es eine Idee geben. Hoffe, es funktioniert für Sie.