Arduino Mega Server und Echtzeituhr

Bild

In diesem Artikel erfahren Sie, wie Arduino Mega Server im Laufe der Zeit funktioniert und wie Sie Projekte auf Arduino erstellen können, die in Echtzeit verknüpft sind, unabhängig davon, ob ein RTC-Modul auf Eisenbasis installiert ist oder nicht. Alle Fragen der Echtzeitarbeit mit Arduino werden ausführlich besprochen und nach dem Lesen dieses Artikels werden Sie zu einem echten „Uhrmacher“.


Essenz der Frage


Jedes mehr oder weniger ernsthafte Projekt auf Arduino sollte eine Vorstellung von der aktuellen Echtzeit haben. Beispielsweise sollten die Sensorwerte zeitgebunden sein (andernfalls können keine Statistiken und sogar elementare Diagramme erstellt werden). Der Controller sollte abhängig von der aktuellen Tageszeit, den Wochenenden, Feiertagen usw. bestimmte Aktionen ausführen. Wenn Ihr Controller keine Ahnung hat In Echtzeit wird daraus eine einfache Maschine, die nur grundlegende Aktionen mit einem fest definierten Programm ausführen kann.

Seit Arduino Mega ServerEs ist ein leistungsfähiges und entwickeltes System, dann könnte dieser Zustand (mangelnde Arbeit mit Echtzeit) nicht zu mir und allen anderen Benutzern des Systems passen. Daher war das Thema Integration in das RTC-System eines der ersten auf der Tagesordnung.

Virtuelle Echtzeituhr


Alles wäre in Ordnung, aber weder ich noch die meisten AMS-Benutzer hatten das gleiche „eiserne“ RTC-Modul. Daher wurde beschlossen, einen „Ausritt“ zu machen und als vorübergehende Maßnahme Echtzeituhren zu organisieren, die innerhalb des Systems arbeiten, ohne echtes physikalisches Modul. Welches wurde erfolgreich implementiert.

So organisieren Sie eine virtuelle RTC ohne ein reales Modul. Es gibt eine wunderbare Zeitbibliothek, die den Löwenanteil der Arbeit leistet, um uns genaue Zeit zu liefern. Um damit arbeiten zu können, müssen Sie es herunterladen, entpacken und am Standardspeicherort aller Bibliotheken der Arduino-Umgebung ablegen, nämlich im Ordner:

\rduino\libraries\

Danach stehen uns alle Möglichkeiten zur Verfügung, mit der Zeit zu arbeiten, die sie zur Verfügung stellt.

Wie es funktioniert


Das Prinzip ist sehr einfach. Die Bibliothek "startet" die virtuelle Uhr "innerhalb" des Controllers und bietet die Möglichkeit, sie auf verschiedene Arten zu synchronisieren und auszuwählen. Sie können die Methode auswählen, die am besten zu Ihnen passt. Da der Arduino Mega Server ein Netzwerkgerät ist, wurde die Option ausgewählt, die Uhr über das Netzwerk mit den genauen Zeitservern zu synchronisieren. Dies können Server im Internet oder Server im lokalen Netzwerk sein, auf denen der entsprechende Dienst ausgeführt wird. In der Basisversion von AMS ist die Uhr beispielsweise mit dem MajorDoMo- Server synchronisiert , und Sie müssen hierfür nichts konfigurieren. Alles funktioniert sofort .

Damit dies funktioniert, müssen Sie die entsprechenden Bibliotheken am Anfang der Skizze verbinden.

#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <Time.h> 

Die Time.h-Datei ist eigentlich eine Bibliothek zum Arbeiten mit der Zeit, und der Rest der Dateien ist für das Arbeiten mit dem Netzwerk und zum Synchronisieren der Zeit mithilfe des NTP-Protokolls erforderlich (die Ethernet-Bibliothek muss auch auf Ihrem Computer installiert sein).

Als Nächstes müssen Sie die IP-Adresse des Servers angeben, mit dem Sie die Zeit synchronisieren möchten

IPAddress timeServer(192, 168, 2, 8); //   MajorDoMo  

und entsprechender Port

unsigned int localPort = 8888;

Es gibt jedoch einen Punkt: Port 8888 eignet sich für die Synchronisierung in einem lokalen Netzwerk, und die meisten Server im Internet reagieren nicht darauf. Wenn Sie also die Zeit mit Servern mit genauer Zeit im Internet synchronisieren möchten, ist es besser, Port 123 festzulegen:

unsigned int localPort = 123;

Es bleibt nur die Zeitzone anzugeben

const int timeZone = 4;

und erstellen Sie ein EthernetUDP-Objekt

EthernetUDP Udp;

In diesem Fall können vorbereitende Vorgänge als abgeschlossen betrachtet werden und Sie können die Funktionen beschreiben, die Sie benötigen, um mit der Zeit zu arbeiten. Initialisierungsfunktion:

void rtcInit() {
  Udp.begin(localPort);
  Serial.println("Waiting for NTP sync...");
  setSyncProvider(getNtpTime);
}

Hier müssen Sie auf die Funktion achten

setSyncProvider(getNtpTime);

Diese Funktion legt die Zeitsynchronisationsquelle fest (in diesem Fall die NTP-Synchronisation über das Netzwerk). Es kann sich aber auch um eine andere Quelle handeln, beispielsweise um das physische RTC-Modul. Die Leistung dieser Funktion führt zur Installation einer Synchronisationsquelle (für die Zukunft) und gleichzeitig zur Zeitsynchronisation selbst über diese Quelle. Im Moment der Ausführung dieser Funktion wird die genaue Zeit in Ihrem System angezeigt.

Die Bibliothek selbst hat eine weitere interessante Funktion:

setSyncInterval(interval);

Hiermit können Sie das gewünschte Intervall zwischen den Synchronisierungen festlegen (in Sekunden eingestellt, erfolgt die Synchronisierung selbst automatisch, ohne dass Sie daran teilnehmen müssen).

Bild

Jetzt können Sie die genaue Zeit in der Skizze von Arduino verwenden. Beispielsweise ist die Anzeige von Ereignissen auf dem seriellen Monitor nicht einfach, sondern an eine bestimmte genaue Zeit gebunden. Dies erfolgt mit der Funktion timeStamp ():

void timeStamp() {
  serialRTC();
  Serial.print(" ");
}

Dies ist ein Wrapper für die Funktion serialRTC ():

void serialRTC() {
  Serial.print(year()); 
  Serial.print("-");
  printDigits(month());
  Serial.print("-");
  printDigits(day());
  Serial.print(" ");
  printDigits(hour());
  Serial.print(":");
  printDigits(minute());
  Serial.print(":");
  printDigits(second());
}

Die Analyse des Mechanismus zum Übertragen und Anzeigen von Zeit in der AMS-Weboberfläche geht über den Rahmen dieser Geschichte hinaus und verdient einen separaten Artikel. Bei Interesse können wir eine Fortsetzung schreiben und detailliert erklären, wie die „Magie“ der Zeitanzeige in der Arduino Mega-Weboberfläche ist Server

Bild

Eigentlich ist das alles. Auf diese Weise wurden virtuelle Echtzeituhren in AMS bis einschließlich Version 0.12 organisiert, und Sie können die Arbeit in Ihren Projekten auch zeitgenau organisieren, selbst wenn Sie kein physisches Modul für Echtzeituhren haben. Dies ist jedoch nicht das Ende der Geschichte, sondern nur der Anfang.

Vollständiger RTC-Modulcode von Arduino Mega Server 0.12
/*
Modul Virtual RTC
part of Arduino Mega Server project
*/

// Virtual RTC

IPAddress timeServer(192, 168, 2, 8);
unsigned int localPort = 8888; // local port to listen for UDP packets
EthernetUDP Udp;

const int timeZone = 4;
time_t prevDisplay = 0; // when the digital clock was displayed

void rtcInit() {
Udp.begin(localPort);
Serialprint(«Waiting for NTP sync… \n»);
setSyncProvider(getNtpTime);
modulRtc = 1;
}

void rtcWorks() {
if (timeStatus() != timeNotSet) {
if (now() != prevDisplay) { // update the display only if time has changed
setLifer();
prevDisplay = now();
//digitalClockDisplay();
}
}
}

void printDigits(int digits) {
if(digits < 10) {
Serial.print('0');
}
Serial.print(digits);
}

void serialRTC() {
Serial.print(year());
Serial.print("-");
printDigits(month());
Serial.print("-");
printDigits(day());
Serial.print(" ");
printDigits(hour());
Serial.print(":");
printDigits(minute());
Serial.print(":");
printDigits(second());
}

void timeStamp() {
serialRTC();
Serial.print(" ");
}

void printRTC(){
serialRTC();
Serial.println();
}

// NTP code

const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message
byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packets

#ifdef RTC_FEATURE

time_t getNtpTime() {
while (Udp.parsePacket() > 0); // discard any previously received packets
Serialprint(«Transmit NTP request\n»);
sendNTPpacket(timeServer);
uint32_t beginWait = millis();
while (millis() — beginWait < 1500) {
int size = Udp.parsePacket();
if (size >= NTP_PACKET_SIZE) {
Serialprint(«Receive NTP response\n»);
Udp.read(packetBuffer, NTP_PACKET_SIZE); // read packet into the buffer
unsigned long secsSince1900;
// convert four bytes starting at location 40 to a long integer
secsSince1900 = (unsigned long)packetBuffer[40] << 24;
secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
secsSince1900 |= (unsigned long)packetBuffer[43];
return secsSince1900 — 2208988800UL + timeZone * SECS_PER_HOUR;
}
}
Serialprint(«No NTP response\n»);
return 0; // return 0 if unable to get the time
}

// send an NTP request to the time server at the given address
void sendNTPpacket(IPAddress &address) {
// set all bytes in the buffer to 0
memset(packetBuffer, 0, NTP_PACKET_SIZE);
// Initialize values needed to form NTP request
// (see URL above for details on the packets)
packetBuffer[0] = 0b11100011; // LI, Version, Mode
packetBuffer[1] = 0; // Stratum, or type of clock
packetBuffer[2] = 6; // Polling Interval
packetBuffer[3] = 0xEC; // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
packetBuffer[12] = 49;
packetBuffer[13] = 0x4E;
packetBuffer[14] = 49;
packetBuffer[15] = 52;
// all NTP fields have been given values, now
// you can send a packet requesting a timestamp:
Udp.beginPacket(address, 123); //NTP requests are to port 123
Udp.write(packetBuffer, NTP_PACKET_SIZE);
Udp.endPacket();
}

#endif

// Duration

void showDuration(time_t duration) {
// prints the duration in days, hours, minutes and seconds
Serialprint(" (duration ");
if(duration >= SECS_PER_DAY){
Serial.print(duration / SECS_PER_DAY);
Serialprint(" day ");
duration = duration % SECS_PER_DAY;
}
if(duration >= SECS_PER_HOUR){
Serial.print(duration / SECS_PER_HOUR);
Serialprint(" hour ");
duration = duration % SECS_PER_HOUR;
}
if(duration >= SECS_PER_MIN){
Serial.print(duration / SECS_PER_MIN);
Serialprint(" min ");
duration = duration % SECS_PER_MIN;
}
Serial.print(duration);
Serialprint(" sec) \n");
}

void checkEvent(time_t* prevEvent) {
time_t duration = 0;
time_t timeNow = now();

if (*prevEvent > 0) {
duration = timeNow — *prevEvent;
}
if (duration > 0) {
showDuration(duration);
}
*prevEvent = timeNow;
}



Eine angenehme Überraschung


Ich habe mich lange Zeit nicht mit der Integration von RTC-Modulen in das System beschäftigt (viele andere dringende Aufgaben), aber hier hat die Firma CHIPSTER im Rahmen der technologischen Zusammenarbeit mit unserem Projekt beim AMS-Test und der Integration von Geräten vorgesehen, darunter die Ethernet-Module auf dem Chip W5500 und ... das Echtzeituhrmodul auf dem DS3231- Chip , das sich als das günstigste herausstellte und als Anstoß für die Integration von RTC-Modulen in das System diente.

Es stellte sich heraus, dass die Firma CHIPSTER nicht nur elektronische Geräte verkauft, sondern auch eigene Produkte für Arduino und Automatisierung unter dem Markennamen Geegrow entwickeltund hat große Pläne für die Zukunft in dieser Richtung, insbesondere hat sie ein Projekt für die Veröffentlichung einer speziellen Version des Arduino Mega 2560 mit erweiterten Funktionen und speziell für den Arduino Mega Server "geschärft". Und wenn dieses Board veröffentlicht wird, wird es eine sehr interessante Veranstaltung. Aber zurück zur Echtzeituhr.

Echtzeituhr


Da das RTC-Modul immer zur Hand war, wäre es eine Sünde, es nicht in das System zu integrieren. Glücklicherweise stellte sich heraus, dass dies dank derselben Zeitbibliothek recht einfach war. Aber das Wichtigste zuerst.

Für diejenigen, die es nicht wissen, gibt es zwei Arten von Echtzeitmodulen - "normal" (normalerweise auf einem DS1307-Chip) und "fortgeschritten" (auf einem DS3231-Chip, den ich bekommen habe). Der Unterschied zwischen den beiden besteht darin, dass die ersten nicht sehr genau sind und sehr schnell und sehr stark „weglaufen“ können, und die zweite ist eine hochpräzise Uhr mit normalisierter Pflege von nicht mehr als zwei Minuten pro Jahr, dh tatsächlich in der Praxis anwendbar. Die Genauigkeit wird durch ein komplexeres Schaltungsdesign und eine integrierte Wärmekompensation erreicht.

Programmatisch sind jedoch beide Versionen der Module kompatibel und beide funktionieren mit der Bibliothek und dem Code. Der Unterschied liegt nur in der Genauigkeit.

Und natürlich ist eine der Haupteigenschaften einer Echtzeituhr die Fähigkeit, aufgrund der eingebauten Batterie bei ausgeschaltetem Strom zu arbeiten.

Physische Verbindung


Lassen Sie uns nun darüber sprechen, wie Sie das RTC-Modul physisch mit dem Arduino Mega Server oder Ihrem Arduino-Projekt verbinden. Ich muss sagen, dass dies sehr einfach ist und Sie nur zwei Widerstände und ein paar Drähte benötigen.

Die Verbindung ist trivial: Sie müssen vier Kontakte an Ihrem Modul finden - GND (Masse), VCC (Versorgungsspannung), SCL (Taktsignal), SDA (Daten). Andere Kontakte werden in seltenen und speziellen Fällen verwendet und können ignoriert werden.

Bild

Also verbinden wir den GND-Pin mit Masse, den VCC-Pin mit der Versorgungsspannung des Controllers. Hier ist alles einfach und es sollten keine Fragen auftauchen.

Der Rest der Schlussfolgerungen ist nicht viel komplizierter. Das RTC-Modul kommuniziert mit dem Controller über die I2C-Schnittstelle, die nur aus zwei Drähten besteht: Synchronisation und Daten. Arduino-Controller verfügen bereits über Kontakte zum Anschließen dieser Schnittstelle. Das Arduino Uno ist A4 (SDA) und A5 (SCL), während das Arduino Mega D20 (SDA) und D21 (SCL) ist.

Die einzige Subtilität besteht darin, dass die SCL- und SDA-Pins über 4,7-kΩ-Widerstände zur Stromquelle „gezogen“ werden müssen. Wenn Sie nicht genau diese Bewertung haben, können Sie Widerstände im Bereich von 2 KOhm - 10 KOhm verwenden.

Bild

Software-Unterstützung


Jetzt müssen Sie nur noch die Unterstützung für das Modul im AMS-Code oder in Ihrem Projekt hinzufügen. Wie gesagt, es wird sehr einfach sein, da dieselbe Zeitbibliothek mit dem Modul funktioniert. Richtig , wir müssen eine weitere Bibliothek hinzufügen, nämlich die DS1307RTC-Bibliothek . Wir entpacken es auch und legen es im Standardbibliotheksordner ab:

\rduino\libraries\

Fügen Sie Ihrem Skizzencode die folgenden Zeilen hinzu

#include <Wire.h>
#include <DS1307RTC.h>

Jetzt sind wir voll ausgestattet und können mit dem Schreiben des Codes für die Skizze selbst beginnen, wobei wir mit dem physischen RTC-Modul arbeiten. In Funktion

void rtcInit() {
  Udp.begin(localPort);
  Serial.println("Waiting for NTP sync...");
  setSyncProvider(getNtpTime);
}

Zeichenfolge ersetzen

setSyncProvider(getNtpTime);

auf der

setSyncProvider(RTC.get);

und die interne Zeit des Arduino Mega Servers (oder Ihres Controllers) wird mit dem "eisernen" RTC-Controller synchronisiert und nicht mit Servern im Internet oder im lokalen Netzwerk. Durch Aufrufen der Funktionen setSyncProvider (getNtpTime) und setSyncProvider (RTC.get) können Sie also die Quellen der Zeitsynchronisation manipulieren und die Zeit nach Belieben synchronisieren, abhängig von verschiedenen Bedingungen.

Eine weitere Funktion, die Sie kennen müssen, ist

if (timeStatus() != timeNotSet) {

}

Auf diese Weise können Sie herausfinden, ob die Zeit synchronisiert ist, und abhängig von dieser Bedingung die erforderlichen Maßnahmen ergreifen.

Subtiler Moment


Sie müssen zwischen zwei Dingen unterscheiden: der Zeit, die im „Eisen“ -RTC-Modul vergeht, und der Zeit, die in Ihrem Controller vergeht. Das ist nicht dasselbe. Die „Hauptsache“ für Sie ist die Zeit in der Steuerung, und die Zeit im Modul ist nur eine Quelle für die Synchronisation.

Aber! Da die Zeit in der physischen RTC ebenfalls allmählich abläuft, muss sie auch durch Synchronisierung mit genaueren Quellen, z. B. Servern im Internet, angepasst werden.

Der optimale Algorithmus sollte daher folgender sein: Wenn möglich, synchronisieren Sie alle Uhren mit den Servern im Internet. Wenn das Netzwerk nicht verfügbar ist, beginnen wir, die Zeit in der Steuerung mit dem RTC-Modul zu synchronisieren. Sobald das Netzwerk angezeigt wird, kehren Sie zur Synchronisierung über das Internet zurück.

Wenn Sie sich in extremen Bedingungen befinden und keinen Zugriff auf Synchronisationsquellen haben, können Sie den Verlauf der Eisenuhr von Zeit zu Zeit manuell anpassen.

Betrachten wir zum Beispiel die Synchronisationsfunktion der internen Uhr der Steuerung und des RTC-Moduls über das Netzwerk:

void rtcSync() {
  setSyncProvider(getNtpTime);
  Serial.println("...getNtpTime...");
  if (timeStatus() != timeNotSet) {
    Serial.println("...set!...");
    time_t t = getNtpTime();
    RTC.set(t);
    setSyncProvider(RTC.get);
  }
}

Hier erhalten wir zunächst die genaue Zeit über das Netzwerk.

setSyncProvider(getNtpTime);

Wenn dies erfolgreich ist, installieren Sie es im RTC-Modul

RTC.set(t);

und dann stellen wir von diesem Modul aus die Reglerzeit ein

setSyncProvider(RTC.get);

Erster Start


Das ist aber noch nicht alles. Es gibt auch das Problem des anfänglichen Starts, wenn das RTC-Modul nur angeschlossen ist, aber die Zeit darin nicht eingestellt ist und es daher unmöglich ist, mit ihm zu synchronisieren. Sie müssen irgendwie den richtigen Zeitpunkt einstellen. Es gibt zwei Möglichkeiten, um dieses Problem im Arduino Mega Server zu lösen: Sie können die physische RTC über das Netzwerk synchronisieren (sofern der Zeitserver verfügbar ist) oder das Dienstprogramm Arduino Serial Commander verwenden.

Um die Uhrzeit im RTC-Modul einzustellen, klicken Sie einfach auf die Schaltfläche. Alles andere erledigen zwei junge Männer namens Arduino Mega Server und Arduino Serial Commander für Sie. Wenn Sie kein AMS verwenden, aber ein eigenes Projekt entwickeln, können Sie den Code aus dem Arduino Mega Server-Distributionskit (der Code ist verfügbar und völlig kostenlos) entnehmen oder im Internet nach einer Lösung für dieses Problem suchen (es gibt verschiedene Lösungen).

Bild

Version mit echter RTC-Unterstützung


Arduino Mega Server unterstützt ab Version 0.13 "Iron" RTC. Sie können die neueste aktuelle Version von der offiziellen Website des Projekts herunterladen und Ihre Fragen im Forum stellen .

Und natürlich danke ich CHIPSTER für die Zusammenarbeit und die Ausrüstung zum Testen und Integrieren (ich werde Ihnen in einem der folgenden Artikel etwas über das W5500-Modul und die Beschleunigung des AMS-Netzwerkbetriebs erzählen).

Ergänzung . Ein Youtube-Kanal ist geöffnet und hier ist ein Promo-Video des Arduino Mega Servers, das zeigt, wie man mit einem realen System arbeitet.

Source: https://habr.com/ru/post/de385349/


All Articles