Arduino Mega Server et horloge en temps réel

image

Dans cet article, vous apprendrez comment fonctionne Arduino Mega Server au fil du temps et comment créer des projets sur Arduino qui sont liés en temps réel, qu'ils aient ou non un module RTC «iron» installé. Toutes les questions de travail en temps réel sur Arduino seront discutées en détail et après avoir lu cet article, vous deviendrez un véritable "horloger".


Essence de la question


Tout projet plus ou moins sérieux sur Arduino devrait avoir une idée du temps réel actuel. Par exemple, les lectures des capteurs doivent être limitées dans le temps (sinon il serait impossible de générer des statistiques et même des graphiques élémentaires), le contrôleur doit effectuer certaines actions en fonction de l'heure actuelle de la journée, des week-ends, des vacances, etc. Si votre contrôleur n'a aucune idée en temps réel, il se transforme en une machine simple qui ne peut effectuer des actions de base que sur un programme défini de manière rigide.

Depuis Arduino Mega Serverc'est un système puissant et développé, alors cet état de fait (manque de travail en temps réel) ne pouvait pas me convenir, ainsi qu'à tous les autres utilisateurs du système. Par conséquent, la question de l'intégration dans le système RTC était l'une des premières à l'ordre du jour.

Horloge virtuelle en temps réel


Tout irait bien, mais ni moi, ni la plupart des utilisateurs d'AMS ne disposions du même module RTC «de fer», il a donc été décidé de faire une «balade à cheval» et, à titre temporaire, d'organiser des horloges en temps réel fonctionnant à l'intérieur du système, sans véritable module physique. Qui a été mis en œuvre avec succès.

Alors, comment organiser un RTC virtuel, sans véritable module. Il y a une merveilleuse bibliothèque de temps qui fait la part du lion du travail de nous fournir l'heure exacte. Pour commencer à travailler avec lui, vous devez le télécharger, le décompresser et le placer sur l'emplacement standard de toutes les bibliothèques de l'environnement Arduino, à savoir dans le dossier:

\rduino\libraries\

Après cela, toutes les possibilités de travailler avec le temps qu'il nous offre deviennent disponibles pour nous.

Comment ça fonctionne


Le principe est très simple. La bibliothèque «lance» l'horloge virtuelle «à l'intérieur» du contrôleur et offre la possibilité de les synchroniser de différentes manières, au choix. Vous pouvez choisir la méthode qui vous convient le mieux. Étant donné que l'Arduino Mega Server est un périphérique réseau, l'option de synchronisation de l'horloge via le réseau avec l'heure exacte des serveurs a été choisie. Il peut s'agir de serveurs sur Internet ou de serveurs sur le réseau local sur lequel le service correspondant s'exécute. Par exemple, dans la version de base d'AMS, l'horloge est synchronisée avec le serveur MajorDoMo , et vous n'avez rien à configurer pour cela, tout fonctionne par défaut .

Donc, pour que cela fonctionne, vous devez connecter les bibliothèques appropriées au début de l'esquisse.

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

Le fichier Time.h est en fait une bibliothèque pour travailler avec le temps, et le reste des fichiers est nécessaire pour travailler avec le réseau et pour synchroniser l'heure en utilisant le protocole NTP (la bibliothèque Ethernet doit également être installée sur votre ordinateur).

Ensuite, vous devez spécifier l'adresse IP du serveur avec lequel vous souhaitez synchroniser l'heure

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

et port correspondant

unsigned int localPort = 8888;

mais il y a un point: le port 8888 convient à la synchronisation sur un réseau local, et la plupart des serveurs sur Internet n'y répondent pas, donc si vous prévoyez de synchroniser l'heure avec des serveurs de temps exacts sur Internet, il est préférable de définir le port 123:

unsigned int localPort = 123;

il ne reste plus qu'à indiquer le fuseau horaire

const int timeZone = 4;

et créer un objet EthernetUDP

EthernetUDP Udp;

À ce sujet, les opérations préparatoires peuvent être considérées comme terminées et vous pouvez décrire les fonctionnalités dont vous avez besoin pour travailler avec le temps. Fonction d'initialisation:

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

Ici, vous devez faire attention à la fonction

setSyncProvider(getNtpTime);

Cette fonction définit la source de synchronisation horaire (dans ce cas, la synchronisation NTP via le réseau). Mais il pourrait s'agir de n'importe quelle autre source, par exemple, le module RTC physique. La performance de cette fonction conduit à l'installation d'une source de synchronisation (pour l'avenir) et, en même temps, à la synchronisation de l'heure elle-même via cette source. C'est au moment de l'exécution de cette fonction que l'heure exacte «apparaît» dans votre système.

La bibliothèque elle-même a une autre fonctionnalité intéressante,

setSyncInterval(interval);

ce qui vous permet de définir l'intervalle souhaité entre les synchronisations (défini en secondes, la synchronisation elle-même se produit automatiquement, sans aucune participation de votre part).

image

Vous pouvez maintenant utiliser l'heure exacte à l'intérieur de l'esquisse d'Arduino, par exemple, afficher les événements sur le moniteur série n'est pas facile, mais lié à une heure exacte précise. Cela se fait en utilisant la fonction timeStamp ():

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

qui est un wrapper pour la fonction 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());
}

L'analyse du mécanisme de transmission et d'affichage du temps dans l'interface Web AMS dépasse le cadre de cette histoire et mérite un article séparé et, s'il y a un intérêt, nous pouvons écrire une suite et expliquer en détail comment la «magie» du temps s'affiche dans l'interface Web Arduino Mega. Serveur

image

En fait, c'est tout. C'est ainsi que les horloges virtuelles en temps réel étaient organisées dans AMS jusqu'à la version 0.12 incluse, et vous pouvez également organiser le travail avec une heure précise dans vos projets, même si vous n'avez pas de module physique pour les horloges en temps réel. Mais ce n'est pas la fin de l'histoire, mais plutôt le début.

Code de module RTC complet d'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;
}



Une agréable surprise


Je n'aurais pas été occupé à intégrer des modules RTC dans le système depuis longtemps (il y a aussi suffisamment d'autres tâches urgentes), mais ici, dans le cadre de la coopération technologique avec notre projet, CHIPSTER a fourni des équipements de test et d'intégration dans AMS, parmi lesquels il y avait des modules Ethernet basés sur la puce W5500 et ... le module d'horloge en temps réel sur la puce DS3231 , qui s'est avéré être le plus opportun et a servi d'impulsion pour l'intégration des modules RTC dans le système.

Il s'est avéré que la société CHIPSTER vend non seulement des équipements électroniques, mais développe également ses propres produits pour Arduino et l'automatisation sous la marque Geegrowet a de grands projets pour l'avenir dans cette direction, en particulier, elle a un projet pour la sortie d'une version spécialisée de l'Arduino Mega 2560 avec des fonctionnalités avancées et "affûtées" spécifiquement pour l'Arduino Mega Server. Et, si ce forum sort, ce sera un événement très intéressant. Mais revenons à l'horloge en temps réel.

Horloge temps réel


Étant donné que le module RTC était à portée de main, ce serait un péché de ne pas l'intégrer dans le système. Heureusement, cela s'est avéré assez simple grâce à la même Time Library. Mais tout d'abord.

Pour ceux qui ne connaissent pas, il existe deux types de modules en temps réel - «ordinaire» (généralement sur une puce DS1307) et «avancé» (sur une puce DS3231, que j'ai). La différence entre les deux est que les premières ne sont pas très précises et peuvent «s'enfuir» très rapidement et très fortement, et la seconde est une montre de haute précision avec un soin normalisé de pas plus de deux minutes par an, c'est-à-dire, réellement applicable dans la pratique. Et la précision est obtenue grâce à une conception de circuit plus complexe et à une compensation thermique intégrée.

Mais par programme, les deux versions des modules sont compatibles et les deux fonctionneront avec la bibliothèque et le code. La différence ne sera que dans la précision.

Et bien sûr, l'une des principales propriétés d'une horloge en temps réel est la capacité de fonctionner lorsque l'alimentation est coupée, en raison de la batterie intégrée.

Connexion physique


Voyons maintenant comment connecter physiquement le module RTC au Arduino Mega Server ou à votre projet Arduino. Je dois dire que c'est très simple et que vous n'aurez besoin que de deux résistances et de quelques fils.

La connexion est triviale: vous devez trouver quatre contacts sur votre module - GND (masse), VCC (tension d'alimentation), SCL (signal d'horloge), SDA (données). D'autres contacts sont utilisés dans des cas rares et spécifiques et vous pouvez les ignorer.

image

Ainsi, nous connectons la broche GND à la masse, la broche VCC à la tension d'alimentation du contrôleur. Ici, tout est simple et aucune question ne devrait se poser.

Le reste des conclusions n'est pas beaucoup plus compliqué. Le module RTC communique avec le contrôleur via l'interface I2C, qui n'a que deux fils: synchronisation et données, et les contrôleurs Arduino ont déjà des contacts pour connecter cette interface. L'Arduino Uno est A4 (SDA) et A5 (SCL), tandis que l'arduino Mega est D20 (SDA) et D21 (SCL).

La seule subtilité est que les broches SCL et SDA doivent être «tirées» vers la source d'alimentation via des résistances de 4,7 kΩ. Si vous n'avez pas exactement cette cote, vous pouvez utiliser des résistances de la gamme 2 KOhm - 10 KOhm.

image

Support logiciel


Il ne reste plus qu'à ajouter la prise en charge du module dans le code AMS ou votre projet. Comme je l'ai dit, ce sera très simple car la même Time Library fonctionnera avec le module. Certes, nous devrons ajouter une autre bibliothèque, à savoir la bibliothèque DS1307RTC . Nous le déballons également et le mettons dans le dossier de bibliothèque standard:

\rduino\libraries\

Ajoutez les lignes suivantes à votre code d'esquisse

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

Maintenant, nous sommes entièrement équipés et nous pouvons commencer à écrire le code du croquis lui-même, en travaillant avec le module physique RTC. En fonction

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

remplacer la chaîne

setSyncProvider(getNtpTime);

sur le

setSyncProvider(RTC.get);

et l'heure interne de l'Arduino Mega Server (ou de votre contrôleur) sera synchronisée avec le contrôleur RTC "iron", et non avec les serveurs sur Internet ou le réseau local. Ainsi, en appelant les fonctions setSyncProvider (getNtpTime) et setSyncProvider (RTC.get), vous pouvez manipuler les sources de synchronisation de l'heure et synchroniser l'heure comme vous le souhaitez, en fonction de diverses conditions.

Une autre fonction que vous devez connaître est

if (timeStatus() != timeNotSet) {

}

ce qui vous permet de savoir si l'heure est synchronisée et, selon cette condition, de prendre les mesures nécessaires.

Moment subtil


Vous devez distinguer deux choses: le temps qui passe dans le module RTC «iron» et le temps qui passe dans votre contrôleur. Ce n'est pas la même chose. La chose «principale» pour vous est le temps dans le contrôleur, et le temps dans le module n'est qu'une source de synchronisation.

Mais! étant donné que le temps dans le RTC physique s'épuise également progressivement, il doit également être ajusté en se synchronisant avec des sources plus précises, par exemple, des serveurs sur Internet.

Par conséquent, l'algorithme optimal devrait être le suivant: si possible, synchronisez ensuite toutes les horloges avec les serveurs sur Internet, si le réseau n'est pas disponible, puis nous commençons à synchroniser l'heure dans le contrôleur avec le module RTC, dès que le réseau apparaît, revenez à la synchronisation via Internet.

Si vous êtes dans des conditions extrêmes, sans accès à aucune source de synchronisation, vous pouvez ajuster manuellement le cours de l'horloge de fer de temps en temps.

Considérons par exemple la fonction de synchronisation de l'horloge interne du contrôleur et du module RTC via le réseau:

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

Ici, nous obtenons d'abord l'heure exacte sur le réseau.

setSyncProvider(getNtpTime);

puis, en cas de succès, installez-le dans le module RTC

RTC.set(t);

puis à partir de ce module, nous définissons le temps du contrôleur

setSyncProvider(RTC.get);

Lancement initial


Mais ce n'est pas tout. Il y a aussi le problème du démarrage initial, lorsque le module RTC est uniquement connecté, mais que l'heure n'est pas définie et qu'il est donc impossible de se synchroniser avec lui. Vous devez en quelque sorte régler le bon moment. Il y a deux façons de résoudre ce problème dans l'Arduino Mega Server: vous pouvez synchroniser le RTC physique sur le réseau (si le serveur de temps est disponible) ou en utilisant l'utilitaire Arduino Serial Commander.

Pour régler l'heure dans le module RTC, il suffit de ... cliquer sur le bouton. Tout le reste sera fait pour vous par deux jeunes hommes nommés Arduino Mega Server et Arduino Serial Commander. Si vous n'utilisez pas AMS, mais développez votre propre projet, vous pouvez prendre le code du kit de distribution Arduino Mega Server (le code est disponible et entièrement gratuit) ou chercher une solution à ce problème sur Internet (il existe plusieurs solutions).

image

Version avec véritable support RTC


Arduino Mega Server, à partir de la version 0.13, prend en charge le «fer» RTC. Vous pouvez télécharger la dernière version actuelle sur le site officiel du projet , et vous pouvez poser des questions sur le forum .

Et, bien sûr, j'exprime ma gratitude à CHIPSTER pour la coopération et l'équipement fourni pour les tests et l'intégration (je vais vous parler du module W5500 et de l'accélération du fonctionnement du réseau AMS dans l'un des articles suivants).

Addition . Une chaîne Youtube est ouverte et voici une vidéo promo du Arduino Mega Server, qui montre comment travailler avec un vrai système.

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


All Articles