Arduino Mega Server و Real Time Clock

صورة

في هذه المقالة ، سوف تتعلم كيف يعمل Arduino Mega Server بمرور الوقت وكيف يمكنك إنشاء مشاريع على Arduino مرتبطة في الوقت الفعلي ، بغض النظر عما إذا كان لديهم وحدة RTC قائمة على الحديد مثبتة أم لا. سيتم مناقشة جميع قضايا العمل في الوقت الفعلي على Arduino بالتفصيل وبعد قراءة هذه المقالة ستصبح "صانع ساعات" حقيقي.


جوهر السؤال


أي مشروع أكثر أو أقل جدية في Arduino يجب أن يكون لديه فكرة عن الوقت الحقيقي الحالي. على سبيل المثال ، يجب أن تكون قراءات المستشعر محددة بالوقت (وإلا سيكون من المستحيل إنشاء أي إحصائيات وحتى الرسوم البيانية الأولية) ، يجب على وحدة التحكم تنفيذ إجراءات معينة اعتمادًا على الوقت الحالي من اليوم ، وعطلات نهاية الأسبوع ، والعطلات ، وما إلى ذلك. حول الوقت الفعلي ، يتحول إلى آلة بسيطة يمكنها فقط تنفيذ الإجراءات الأساسية على برنامج محدد بدقة.

منذ خادم اردوينو ميجاإنه نظام قوي ومتطور ، فإن هذه الحالة (عدم وجود العمل في الوقت الحقيقي) لا يمكن أن تناسبني ، وجميع المستخدمين الآخرين للنظام. لذلك ، كانت مسألة الاندماج في نظام RTC واحدة من الأولى على جدول الأعمال.

ساعة افتراضية في الوقت الحقيقي


سيكون كل شيء على ما يرام ، ولكن لا أنا ولا معظم مستخدمي AMS لديهم نفس وحدة RTC "الحديدية" ، لذلك تقرر القيام بـ "ركوب الخيل" ، وكإجراء مؤقت ، تنظيم ساعات في الوقت الحقيقي تعمل داخل النظام ، دون الوحدة المادية الحقيقية. الذي تم تنفيذه بنجاح.

لذا ، كيفية تنظيم RTC افتراضي ، بدون وحدة حقيقية. هناك مكتبة زمنية رائعة تقوم بنصيب الأسد من مهمة تزويدنا بوقت دقيق. لبدء العمل معه ، تحتاج إلى تنزيله وفك ضغطه ووضعه في الموقع القياسي لجميع مكتبات بيئة Arduino ، أي في المجلد:

\rduino\libraries\

بعد ذلك ، أصبحت جميع إمكانيات العمل مع الوقت الذي توفره متاحة لنا.

كيف تعمل


مبدأ بسيط جدا. تقوم المكتبة "بإطلاق" الساعة الافتراضية "داخل" وحدة التحكم وتوفر القدرة على مزامنتها بطرق متنوعة ، للاختيار من بينها. يمكنك اختيار الطريقة التي تناسبك. نظرًا لأن خادم Arduino Mega Server هو جهاز شبكة ، فقد تم اختيار خيار مزامنة الساعة من خلال الشبكة مع خوادم الوقت الدقيقة. يمكن أن تكون هذه خوادم على الإنترنت أو خوادم على الشبكة المحلية التي تعمل عليها الخدمة المقابلة. على سبيل المثال ، في الإصدار الأساسي من AMS ، تتم مزامنة الساعة مع خادم MajorDoMo ، ولا تحتاج إلى تكوين أي شيء لهذا ، كل شيء يعمل خارج الصندوق.

لذلك ، لكي يعمل هذا ، تحتاج إلى توصيل المكتبات المناسبة في بداية الرسم التخطيطي.

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

ملف Time.h هو في الواقع مكتبة للعمل مع الوقت ، وبقية الملفات ضرورية للعمل مع الشبكة ولمزامنة الوقت باستخدام بروتوكول NTP (يجب أيضًا تثبيت مكتبة Ethernet على جهاز الكمبيوتر الخاص بك).

بعد ذلك ، تحتاج إلى تحديد عنوان IP للخادم الذي تريد مزامنة الوقت معه

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

والمنفذ المقابل

unsigned int localPort = 8888;

ولكن هناك نقطة واحدة: المنفذ 8888 مناسب للمزامنة على شبكة محلية ، ومعظم الخوادم على الإنترنت لا تستجيب له ، لذلك إذا كنت تخطط لمزامنة الوقت مع خوادم الوقت الدقيقة على الإنترنت ، فمن الأفضل تعيين المنفذ 123:

unsigned int localPort = 123;

يبقى فقط للإشارة إلى المنطقة الزمنية

const int timeZone = 4;

وإنشاء كائن EthernetUDP

EthernetUDP Udp;

في هذا الصدد ، يمكن اعتبار العمليات التحضيرية مكتملة ويمكنك وصف الوظيفة التي تحتاجها للعمل مع الوقت. وظيفة التهيئة:

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

هنا تحتاج إلى الانتباه إلى الوظيفة

setSyncProvider(getNtpTime);

تحدد هذه الوظيفة مصدر تزامن الوقت (في هذه الحالة ، تزامن NTP عبر الشبكة). ولكن يمكن أن يكون أي مصدر آخر ، على سبيل المثال ، وحدة RTC المادية. يؤدي أداء هذه الوظيفة إلى تثبيت مصدر مزامنة (للمستقبل) ، وفي الوقت نفسه ، إلى مزامنة الوقت نفسها من خلال هذا المصدر. في لحظة أداء هذه الوظيفة "يظهر" الوقت بالضبط في نظامك.

المكتبة نفسها لديها ميزة أخرى مثيرة للاهتمام ،

setSyncInterval(interval);

الذي يسمح لك بتعيين الفاصل الزمني المطلوب بين المزامنات (يتم تعيينه في ثوانٍ ، تحدث المزامنة نفسها تلقائيًا ، دون أي مشاركة من جانبك).

صورة

الآن يمكنك استخدام الوقت الدقيق داخل رسم Arduino ، على سبيل المثال ، عرض الأحداث في الشاشة التسلسلية ليس سهلاً ، ولكنه مرتبط بوقت محدد. يتم ذلك باستخدام وظيفة timeStamp ():

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

وهو مجمع للدالة 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());
}

تحليل آلية إرسال وعرض الوقت في واجهة الويب AMS خارج نطاق هذه القصة ويستحق مقالة منفصلة ، وإذا كان هناك اهتمام ، يمكننا كتابة تكملة وشرح بالتفصيل كيف "سحر" عرض الوقت في واجهة الويب Arduino Mega الخادم

صورة

في الواقع ، هذا كل شيء. هذه هي الطريقة التي تم بها تنظيم الساعات الافتراضية في الوقت الفعلي في AMS حتى الإصدار 0.12 شاملاً ، ويمكنك أيضًا تنظيم العمل بوقت دقيق في مشاريعك ، حتى إذا لم يكن لديك وحدة فعلية للساعات في الوقت الفعلي. لكن هذه ليست نهاية القصة ، بل هي البداية فقط.

كود كامل لوحدة RTC من 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;
}



مفاجأة سارة


لم أكن مشغولًا بدمج وحدات RTC في النظام لفترة طويلة (هناك أيضًا مهام عاجلة أخرى كافية) ، ولكن هنا ، في إطار التعاون التكنولوجي مع مشروعنا ، قدمت CHIPSTER معدات للاختبار والاندماج في AMS ، من بينها وحدات Ethernet تعتمد على شريحة W5500 و ... وحدة الساعة في الوقت الحقيقي على شريحة DS3231 ، والتي تبين أنها الأكثر ملاءمة وعملت كحافز لدمج وحدات RTC في النظام.

اتضح أن شركة CHIPSTER لا تبيع المعدات الإلكترونية فحسب ، بل تطور أيضًا منتجاتها الخاصة لـ Arduino والأتمتة تحت اسم العلامة التجارية Geegrowولديها خطط كبيرة للمستقبل في هذا الاتجاه ، على وجه الخصوص ، لديها مشروع لإصدار نسخة متخصصة من Arduino Mega 2560 مع ميزات متقدمة و "شحذ" خصيصًا لخادم Arduino Mega Server. وإذا تم إصدار هذا المنتدى ، فسيكون هذا حدثًا مثيرًا للاهتمام. ولكن نعود إلى ساعة الوقت الحقيقي.

ساعة الوقت الحقيقي


نظرًا لأن وحدة RTC كانت في متناول يدي ، فسيكون من الخطأ عدم دمجها في النظام. لحسن الحظ ، تبين أن هذا بسيط للغاية بفضل مكتبة الوقت نفسها. لكن أول الأشياء أولاً.

بالنسبة لأولئك الذين لا يعرفون ، هناك نوعان من الوحدات في الوقت الفعلي - "عادي" (عادةً على شريحة DS1307) و "متقدمة" (على شريحة DS3231 ، التي حصلت عليها). الفرق بين الاثنين هو أن الأولى ليست دقيقة للغاية ويمكن أن "تهرب" بسرعة كبيرة وبقوة كبيرة ، والثانية هي ساعة عالية الدقة مع رعاية طبيعية لا تزيد عن دقيقتين في السنة ، أي أنها قابلة للتطبيق في الواقع. ويتم تحقيق الدقة بفضل تصميم الدوائر الأكثر تعقيدًا والتعويض الحراري المدمج.

ولكن برمجيًا ، يتوافق كلا الإصدارين من الوحدات وسيعمل كلاهما مع المكتبة والتعليمات البرمجية. سيكون الفرق في الدقة فقط.

وبالطبع ، فإن إحدى الخصائص الرئيسية للساعة في الوقت الحقيقي هي القدرة على العمل عند إيقاف الطاقة ، بسبب البطارية المدمجة.

اتصال مادي


الآن لنتحدث عن كيفية توصيل وحدة RTC فعليًا بخادم Arduino Mega أو بمشروع Arduino. يجب أن أقول أن هذا بسيط للغاية ولن تحتاج إلا إلى مقاومين وبضعة أسلاك.

الاتصال تافه: تحتاج إلى العثور على أربع جهات اتصال على وحدتك - GND (أرضي) ، VCC (جهد الإمداد) ، SCL (إشارة ساعة) ، SDA (بيانات). يتم استخدام جهات الاتصال الأخرى في حالات نادرة ومحددة ويمكنك تجاهلها.

صورة

لذا ، نقوم بتوصيل دبوس GND بالأرض ، دبوس VCC بجهد إمداد وحدة التحكم. كل شيء بسيط هنا ولا يجب أن تطرح أسئلة.

بقية الاستنتاجات ليست أكثر تعقيدًا. تتواصل وحدة RTC مع وحدة التحكم عبر واجهة I2C ، التي تحتوي على سلكين فقط: المزامنة والبيانات ، ووحدات تحكم Arduino لديها بالفعل جهات اتصال لتوصيل هذه الواجهة. Arduino Uno هو A4 (SDA) و A5 (SCL) ، في حين أن arduino Mega هو D20 (SDA) و D21 (SCL).

الدقة الوحيدة هي أن دبابيس SCL و SDA تحتاج إلى "سحب" إلى مصدر الطاقة من خلال مقاومات 4.7 كيلو أوم. إذا لم يكن لديك هذا التصنيف بالضبط ، فيمكنك استخدام المقاومات من نطاق 2 KOhm - 10 KOhm.

صورة

دعم البرمجيات


الآن يبقى فقط لإضافة دعم للوحدة النمطية في كود AMS أو مشروعك. كما قلت ، سيكون الأمر بسيطًا جدًا لأن مكتبة الوقت نفسها ستعمل مع الوحدة النمطية. صحيح أننا سنحتاج إلى إضافة مكتبة أخرى ، وهي مكتبة DS1307RTC . نقوم أيضًا بفك ضغطه ووضعه في مجلد المكتبة القياسي:

\rduino\libraries\

أضف الأسطر التالية إلى رمز الرسم الخاص بك

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

الآن نحن مجهزون بالكامل ويمكننا البدء في كتابة الرمز للرسم نفسه ، بالعمل مع الوحدة المادية RTC. فى مهمة

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

استبدال السلسلة

setSyncProvider(getNtpTime);

على ال

setSyncProvider(RTC.get);

وسيتم مزامنة الوقت الداخلي لخادم Arduino Mega Server (أو وحدة التحكم الخاصة بك) مع وحدة تحكم RTC "الحديدية" ، وليس مع الخوادم على الإنترنت أو الشبكة المحلية. وبالتالي ، عن طريق استدعاء الدالتين setSyncProvider (getNtpTime) و setSyncProvider (RTC.get) ، يمكنك معالجة مصادر مزامنة الوقت ومزامنة الوقت كما تريد ، اعتمادًا على الظروف المختلفة.

وظيفة أخرى تحتاج إلى معرفتها هي

if (timeStatus() != timeNotSet) {

}

مما يتيح لك معرفة ما إذا كان الوقت متزامنًا ، واعتمادًا على هذا الشرط ، واتخاذ الإجراءات اللازمة.

لحظة خفية


تحتاج إلى التمييز بين شيئين: الوقت الذي يمر في وحدة RTC "الحديدية" والوقت الذي يمر في وحدة التحكم الخاصة بك. هذه ليست نفس الشئ. الشيء "الرئيسي" بالنسبة لك هو الوقت في وحدة التحكم ، والوقت في الوحدة هو مجرد مصدر للمزامنة.

لكن! نظرًا لأن الوقت في RTC الفعلي "ينفد" أيضًا تدريجيًا ، فإنه يحتاج أيضًا إلى التعديل من خلال المزامنة مع مصادر أكثر دقة ، على سبيل المثال ، الخوادم على الإنترنت.

لذلك ، يجب أن تكون الخوارزمية المثلى هي: إذا أمكن ، ثم مزامنة جميع الساعات مع الخوادم على الإنترنت ، إذا كانت الشبكة غير متاحة ، ثم نبدأ في مزامنة الوقت في وحدة التحكم مع وحدة RTC ، بمجرد ظهور الشبكة ، نعود إلى المزامنة عبر الإنترنت.

إذا كنت في ظروف قاسية ، دون الوصول إلى أي مصادر التزامن ، يمكنك ضبط مسار الساعة الحديدية يدويًا من وقت لآخر.

لنأخذ ، على سبيل المثال ، في الاعتبار وظيفة المزامنة للساعة الداخلية لوحدة التحكم ووحدة RTC عبر الشبكة:

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

هنا نحصل أولاً على الوقت المحدد عبر الشبكة.

setSyncProvider(getNtpTime);

ثم ، إذا نجحت ، قم بتثبيته في وحدة RTC

RTC.set(t);

ثم من هذه الوحدة نقوم بتعيين وقت التحكم

setSyncProvider(RTC.get);

الإطلاق الأولي


ولكن هذا ليس كل شيء. هناك أيضًا مشكلة بدء التشغيل الأولي ، عندما تكون وحدة RTC متصلة فقط ، ولكن لم يتم تعيين الوقت فيها وبالتالي من المستحيل المزامنة معها. تحتاج إلى تعيين الوقت المناسب بطريقة أو بأخرى. هناك طريقتان لحل هذه المشكلة في Arduino Mega Server: يمكنك مزامنة RTC الفعلي عبر الشبكة (في حالة توفر خوادم الوقت بالضبط) أو استخدام الأداة المساعدة Arduino Serial Commander.

لضبط الوقت في وحدة RTC ، فقط ... انقر على الزر. كل شيء آخر سيتم القيام به لك من قبل شابين يدعى Arduino Mega Server و Arduino Serial Commander. إذا كنت لا تستخدم AMS ، ولكنك تقوم بتطوير مشروعك الخاص ، فيمكنك أخذ الرمز من مجموعة توزيع Arduino Mega Server (الرمز متاح مجانًا تمامًا) أو البحث عن حل لهذه المشكلة على الإنترنت (هناك العديد من الحلول).

صورة

نسخة مع دعم RTC حقيقي


Arduino Mega Server ، بدءًا من الإصدار 0.13 ، يدعم RTC "الحديد". يمكنك تنزيل أحدث إصدار حالي من الموقع الرسمي للمشروع ، ويمكنك طرح أسئلتك على المنتدى .

وبالطبع ، أشكر CHIPSTER على التعاون والمعدات المقدمة للاختبار والتكامل (سأخبرك عن وحدة W5500 وتسريع تشغيل شبكة AMS في إحدى المقالات التالية).

إضافة . قناة Youtube مفتوحة وهنا فيديو ترويجي لخادم Arduino Mega ، والذي يوضح كيفية العمل مع نظام حقيقي.

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


All Articles