Autor Beitrag
Knulli
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 109
Erhaltene Danke: 2

Win2k
D5, D2005, D2006, D2007
BeitragVerfasst: Mo 05.09.16 10:55 
Hi Leute,
ich will bei einen Microcontroller die Echtzeituhr (RTC) kalibrieren.
Nur meine Uhr auf dem PC ist ja selber auch nicht genau.
Also will ich mich der Atomzeit bedienen, die ich auf diversen Zeitservern ja bestimmt nutzen darf.

Ich suche also noch eine kleine und schlanke Lösung um mir von irgendeinem Zeitserver die Zeit möglichst genau zu holen.
Zur Not mache ich das an zwei aufeinanderfolgenden Tagen um so die Ungenauigkeit zu reduzieren.
Zum Schluss will ich einen Faktor/Offset haben, mit dem ich die Now() Funktion präzisiere. Dass will ich dann zum kalibrieren nehmen.

Was ich jetzt also noch suche ist eine Funktion, der ich als String den Zeitserver übergebe und die mir die Zeit (als TDateTime) zurückgibt.

Hat jemand sowas schon gemacht?

Ich suche eine einfache und kleine Lösung.
Warum: Wenn ich bei meiner Mutter die Glühbirne wechseln soll, will ich nicht erst mit dem Fahrrad zur Garage, den Jeep holen, damit zum Flughafen, den Jumbo aus dem Hangar holen, nach Moskau fliegen, Werkzeug holen, ... ich hoffe Ihr versteht was ich meine. Darf also WSAxxx drin stehen. Zor Not auch die "ScktComp" von Delphi. Aber Indy wäre schon der Jumbo...

PS: mit ScktComp hats übrigens nicht geklappt. Was mich auch an Lösungen mit Komponenten stört, man braucht ein Bezug zu nem Fenster. Ist also keine sehr universelle Lösung.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
//------------------------------------------------------------------------------
function GetAtomTime(): TDateTime;
//------------------------------------------------------------------------------
var
  Start: Int64;
begin
  //result := Now();
  //FMain.ClientSocket1.Host := 'time.windows.com';
  //FMain.ClientSocket1.Port := 37;

  FMain.ClientSocket1.Host := 'time-a.nist.gov';
  FMain.ClientSocket1.Port := 13;
  FMain.ClientSocket1.Active := true;
  //FMain.ClientSocket1.Open();

  Start := QPJetzt();
  while FMain.stOnRead = '' do
  begin
    Application.ProcessMessages;
    if IsTimeOver(Start, 5 * QPSec) then
    begin
      FMain.stOnRead := '0';
      break;
    end;
  end;
end;


Da kam dann Asynchroner Socket Fehler 10060, was auch immer das bedeuten mag...

Knulli

_________________
Echte Männer schreiben Windows-Programme in Assembler unter edlin.
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 9547
Erhaltene Danke: 862

W2k .. W7pro
TP3 .. D7pro .. D10.1
BeitragVerfasst: Mo 05.09.16 12:59 
Moin!

user profile iconKnulli hat folgendes geschrieben Zum zitierten Posting springen:
ich will bei einen Microcontroller die Echtzeituhr (RTC) kalibrieren.
[...]
Aber Indy wäre schon der Jumbo...
Hm, leider ist das die "einfachste" Lösung, da du hier eine fertige NTP-Protokoll-Implementation hast. :nixweiss: Die Frage ist, brauchst du NTP denn in Richtung der Kommunikation mit dem MC? Weil die Zeit aktuell halten kann Windows ja auch alleine... :P

user profile iconKnulli hat folgendes geschrieben Zum zitierten Posting springen:
Was ich jetzt also noch suche ist eine Funktion, der ich als String den Zeitserver übergebe und die mir die Zeit (als TDateTime) zurückgibt.
Warum sollte man das selbst machen wollen? S.o., das kann Windows doch schon alleine. ;)

user profile iconKnulli hat folgendes geschrieben Zum zitierten Posting springen:
Was mich auch an Lösungen mit Komponenten stört, man braucht ein Bezug zu nem Fenster.
Bei den Socket-Komponenten braucht man das nur, wenn man asynchron (mit Messages / Ereignishandlern) arbeiten möchte. Wenn man die auf blocking schaltet, ist das nicht nötig. :idea:

user profile iconKnulli hat folgendes geschrieben Zum zitierten Posting springen:
mit ScktComp hats übrigens nicht geklappt.
[...]
Da kam dann Asynchroner Socket Fehler 10060, was auch immer das bedeuten mag...
Das ist erstmal nicht verwunderlich, weil du die (vermutlich) asynchron eingestellten Kompos synchron (konzeptionell) benutzt. ;)

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
Knulli Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 109
Erhaltene Danke: 2

Win2k
D5, D2005, D2006, D2007
BeitragVerfasst: Mo 05.09.16 15:21 
Also ich will das in etwa so machen:

Ich kann dem Controller (STM32F1xx) einen Zeitkalibrierwert geben, der die Uhr schneller / langsamer werden läßt.
Ich kann den Controller nach seiner Uhrzeit fragen (Genauigkeit 1sec) und ich kann Delphi nach der Zeit fragen ( Now() ).

Der Benutzer soll in meiner (Delphi-)SW nur auf einen Button klicken und dann Feierabend machen oder Kaffe trinken gehen.

In der Zeit soll sich der PC und Controller solange gegenseitig "beschnuppern", bis beide Uhren synchron laufen (Abweichung < 1sec/d).

Sinngemäß:
Ich lasse mir so schnell es geht die Zeit vom Microcontroller geben. Wenn der von einer auf die nächste Sekunde umschaltet gucke ich schnell auf meine PC Uhr.
Damit habe ich erstmal die Zeitdifferenz zwischen beiden Uhren.

Ähnlich mache ich es beim Setzen der Uhrzeit auf dem Controller:
Ich warte, bis auf dem PC eine neue Sekunde anfängt und nehm dann die neue Zeit und sage sie dem Controller.
Auf diese Weise schaffe ich es, beide Uhren bis auf <= 1ms zu syncronisieren.

Dann lese ich solange beide Zeiten aus, bis die Zeitdifferenz einen nennens(rechnens-)werten Unterschied aufweist (+/-10ms). Das dauert so ein paar Minuten.
Dann bestimme ich die Zeit, die es gedauert hat, diese 10ms Differenz zu bekommen und kann dann hochrechnen, wie groß die Differenz an Tag sein wird.
Ist sie kleiner 1sec breche ich ab und lasse den letzten Kalibrierwert stehen.

Das blöde ist nun, dass ich noch eine zusätzlichen Korrektur brauche, mit der ich die PC Zeit (ist ja auch ungenau) korrigieren kann. Und dies will ich mit Hilfe der Atomzeit machen.
Ich will aber nicht unbedingt die Uhr auf dem PC korrigieren. Ich will nur wissen, wie ungenau sie ist.
Ganz im Gegenteil: Ich denke, ich müsste zum Kalibrieren die automatische Korrektur von Windows (zumindest zeitweise) deaktivieren.
Denn was wäre, wenn mitten im Kalibriervorgang Window's Zeitkorrektur zuschlägt?

Also würde ich gerne, ähnlich wie beim Controller zyklisch einen Zeitserver abfragen und mir die dazugehögigen lokalen PC Zeiten merken. Daraus dann ne Kennlinie berechnen und dann kann ich die PC-Zeit korrigieren.

Die Event-Handler hatte ich übrigend "hinterlegt". Ich dachte, sowas ist dann asynchron...
Da kamen folgende events:
- ClientSocket1Lookup
- ClientSocket1Connecting
und dann irgendwann
- ClientSocket1Error

Was aber leider eben nicht kam war
- ClientSocket1Read
Dort hatte ich erwartet, kommt irgendwas mit der Zeit drin.

Wie wäre denn die Lösung mit Indy oder hab ich bei den ScktComps was vergessen?

Knulli

_________________
Echte Männer schreiben Windows-Programme in Assembler unter edlin.
t.roller
ontopic starontopic starontopic starontopic starontopic starofftopic starofftopic starofftopic star
Beiträge: 40
Erhaltene Danke: 9



BeitragVerfasst: Mo 05.09.16 18:12 
Knulli Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 109
Erhaltene Danke: 2

Win2k
D5, D2005, D2006, D2007
BeitragVerfasst: Mo 05.09.16 18:25 
Ich glaub ich krieg Haue, wenn ich als SW-Entwickler mit so ner Idee komme. :motz:
Ausserdem wüsste ich keine Antwort auf die Frage, wozu ich den Quarz damals haben wollte. :gruebel:

Controllerplatine iss schon fertig .

_________________
Echte Männer schreiben Windows-Programme in Assembler unter edlin.
jfheins
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 812
Erhaltene Danke: 127

Win7
VS 2013, VS2015
BeitragVerfasst: Mo 05.09.16 21:28 
Wäre es nicht sinniger, vielleicht einmal am Tag zu synchronisieren?

Du holst dir (bspw. mittels Indys) per NTP die Atomzeit und schreibst die dem Mikrocontroller. Dieser kann dann bestimmen, wie viel seine seine eigene Uhr falsch geht (Phasenoffset) und wie schnell die falsch geht (Rateoffset). Das heißt, du bekommst einen sehr präzisen Wert, dass dein µC 3s pro Tag zu schnell läuft und kannst diesen Korrekturwert speichern.

Was ich sagen will: Für eine qualitativ gute Kalibrierung solltest du das Zeitintervall länger als eine Kaffeepause gestalten ;-)
Knulli Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 109
Erhaltene Danke: 2

Win2k
D5, D2005, D2006, D2007
BeitragVerfasst: Di 06.09.16 09:30 
Der Controller ist nicht immer am PC.
Aber es stimmt, ich kann auch gleich die Zeit vom Zeitserver nehmen und dem Controller sagen. Dann brauche ich mich nur mit zwei Uhren beschäftigen.
Aber letztendlich bleibt die Frage: Wie hole ich mir die Zeit von nem Zeitserver? Und mittlerweile ist es mir auch egal, ob mit Indy...

Knulli

_________________
Echte Männer schreiben Windows-Programme in Assembler unter edlin.
t.roller
ontopic starontopic starontopic starontopic starontopic starofftopic starofftopic starofftopic star
Beiträge: 40
Erhaltene Danke: 9



BeitragVerfasst: Di 06.09.16 11:07 
Net.exe time

Die Syntax dieses Befehls lautet:

NET TIME

[\\Computername | /DOMAIN[:Domänenname] | /RTSDOMAIN[:Domänenname]] [/SET]

NET TIME synchronisiert die Uhr des Computers mit der eines anderen Computers
oder einer anderen Domäne oder zeigt die Uhrzeit für einen Computer oder eine
Domäne an. Wird dieser Befehl ohne Optionen für eine Windows Server-Domäne
ausgeführt, wird damit das aktuelle Datum und die aktuelle Uhrzeit des
Computers angezeigt, der als Zeitserver für die Domäne festgelegt wurde.

\\Computername Der Name des Computers, den Sie überprüfen oder
synchronisieren möchten.

/DOMAIN[:Domänenname] Gibt an, dass die Uhrzeit mit dem primären
Domänencontroller von "Domänenname" synchronisiert wird.

/RTSDOMAIN[:Domänenname] Gibt an, dass die Uhrzeit mit einem zuverlässigen
Zeitserver aus "Domänenname" synchronisiert wird.

/SET Synchronisiert die Uhrzeit des Computers mit der Uhrzeit des
angegebenen Computers oder der angegebenen Domäne.

Die Optionen "/QUERYSNTP" und "/SETSNTP" sind veraltet. Verwenden Sie die Datei
"w32tm.exe", um den Windows-Zeitdienst zu konfigurieren.

"NET HELP Befehl | MORE" zeigt Hilfeinformationen auf jeweils einer Seite an.

Beispiel-Aufruf in DELPHI:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
procedure TNetTimeSync.SyncTime;
var P1: PChar;
    P2: PChar;
    R : Integer;
begin
  GetMem(P1, 100);
  GetMem(P2, 50);
  P1 := StrPCopy(P1, 'TIME ' + TServer + ' /SET /YES');
  P2 := StrPCopy(P2, TPath);

  R := ShellExecute(0NIL'NET.EXE', P1, P2, SW_SHOWMINNOACTIVE);
  if (R <= 32then
  begin
    MessageBeep(MB_ICONEXCLAMATION);
    P1 := StrPCopy(P1, 'Timesync errorcode: ' + IntToStr(R));
    MessageBox(0, P1, 'Timesync error', MB_OK + MB_ICONEXCLAMATION);
  end;
  FreeMem(P1, 100);
  FreeMem(P2, 50);
  if (csDesigning in ComponentState) then Exit;
  if (Assigned(FSync)) then FSync(Self);
end;

Für diesen Beitrag haben gedankt: Knulli
t.roller
ontopic starontopic starontopic starontopic starontopic starofftopic starofftopic starofftopic star
Beiträge: 40
Erhaltene Danke: 9



BeitragVerfasst: Di 06.09.16 11:24 
Mit INDY:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
procedure TForm1.ButtonClick(Sender: TObject);
var
  AtomZeit: String;
begin
  IdDayTime1.Host := 'ptbtime1.ptb.de';
  AtomZeit := IdDayTime1.DayTimeStr;
  IdTime1.SyncTime;
  IdTime1.Disconnect;
  try
     Label1.Caption := AtomZeit;
  except
    ShowMessage('Fehler beim Lesen des Zeit-Servers ');
  end;
end;

Für diesen Beitrag haben gedankt: Knulli
Knulli Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 109
Erhaltene Danke: 2

Win2k
D5, D2005, D2006, D2007
BeitragVerfasst: Di 06.09.16 11:44 
:zustimm: :zustimm: :zustimm:

Werd ich gleich mal probieren...

_________________
Echte Männer schreiben Windows-Programme in Assembler unter edlin.
Knulli Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 109
Erhaltene Danke: 2

Win2k
D5, D2005, D2006, D2007
BeitragVerfasst: Di 06.09.16 13:04 
:bawling: :bawling: :bawling:

TIdDayTime geht auch nicht:
Socket Error # 10060
beim Zugriff auf DayTimeStr

Hab dann aber mal etwas mehr in den Indys rumgestochert. Da gibts noch was anderes als TIdDayTime: IdSNTP!!

Damit gings dann. Danke an alle...

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
//------------------------------------------------------------------------------
function GetAtomTime(): TDateTime;
//------------------------------------------------------------------------------
var
  //IdDayTime: TIdDayTime;
  //st: String;
  IdSNTP: TIdSNTP;
begin
  (*
  IdDayTime := TIdDayTime.Create(Nil);
  IdDayTime.Host := 'ptbtime1.ptb.de';
  st := IdDayTime.DayTimeStr; // hier knallts: Socket Error 10060
  //IdDayTime.SyncTime; // ggf. lokale Uhr synchronisieren
  IdDayTime.Disconnect();
  FreeAndNil(IdDayTime);
  Result := GetDateTimeFromText(st, '');
  *)

  IdSNTP := TIdSNTP.Create(Nil);
  IdSNTP.Host := 'ptbtime1.ptb.de'// time-a.nist.gov, pool.ntp.org, time.windows.com, ptbtime1.ptb.de, pool.ntp.org, time.uni-bonn.de
  result := IdSNTP.DateTime;
  FreeAndNil(IdSNTP);
end;

_________________
Echte Männer schreiben Windows-Programme in Assembler unter edlin.