Ich habe einen DS1307 und ich habe sein Programm gemacht und Zeit daraus genommen. In meinem Programm habe ich sec1,sec2
die 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 TIME
den 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 PIC32MX795F512L
MCU. Ich habe nicht den vollständigen Code gepostet. Steht im Link.
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.
Ich hatte vor einiger Zeit die gleiche Frage und meine aktuelle Lösung (am einfachsten) ist die folgende:
attachInterrupt(digitalPinToInterrupt("pin number"),"ISR name",FALLING)
(in meinem Fall erhöhen sich die Sekunden, wenn das sqw-Signal fällt);timeref = millis()
(timeref ist ein globales unsigned long);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.
gbulmer
Benutzer007