توقيت وتعدد المهام على اردوينو

الصورة

سنتحدث اليوم عن موضوع ذي صلة مثل المؤقتات والمهام المتعددة على Arduino. كان سبب كتابة هذا المقال هو المحاضرات التي كتبها Oleg Artamonovolartamonov لطلاب MIREA في أكاديمية Samsung IoT ، أو بالأحرى ، تصريح Oleg ، الاقتباس (المحاضرة الثانية ، 1:13:08):
"هناك ، على سبيل المثال ، مهام يمكن أن يتم كسر معظم برامج تشغيل arduino ، خاصة المبتدئين ، واطلب منهم أن يومض بخمسة مصابيح LED مختلفة بترددات وفترات مختلفة ، بحيث يمكن تغيير فترة أخرى بشكل فردي لكل LED ..."

إذا حكمنا من خلال تصريحات أوليغ ، فإن لديه فكرة خاطئة جدًا عن أردوينو بشكل عام وعن "أردوينو" بشكل خاص. يعتبر وميض خمسة مصابيح LED في الأوضاع التي أشار إليها مهمة تافهة تمامًا لـ Arduino ، وبالنسبة إلى Arduino Mega Server ، فهي ليست مهمة على الإطلاق ، ولكن سوء فهم حقيقي - يتم تنظيم المهام المتعددة بوسائلها العادية ، والتي تتحكم بسهولة في مئات الكيانات المختلفة (LEDs ، الماكينات ، المحركات الخطوة ، إلخ.). د.) في الوقت الحقيقي.

دعونا نكتشف كيفية تنظيم تعدد المهام على Arduino معًا ، وفي نفس الوقت مساعدة طلاب MIREA على التخلص من الصور النمطية للإدراك المفروض عليهم فيما يتعلق بالظاهرة الاجتماعية والثقافية والتكنولوجية في عصرنا والتي تسمى Arduino .

محاضرات أوليغ أرتامونوف


يجب أن نشيد ، محاضرات أوليغ نفسها جيدة - فهي توفر الكثير من المعلومات المفيدة والمنظمة جيدًا حول المتحكمات الدقيقة ، وأود أن أوصي جميع الأشخاص المهتمين بهذه المشكلة بالتعرف عليهم. بدا لي أن العيب الوحيد في هذه المحاضرات بدا وكأنه توبيخ علني صريح فيما يتعلق بآردوينو ، الذي يعمل فيها كـ "فتى مخنوق".

على وجه الخصوص ، في جميع المحاضرات ، أدلى أوليغ بتصريحات قطعية حول عدم ملاءمة Arduino لبناء أنظمة معقدة متعددة المهام ، والتي تتعارض ببساطة مع الحقيقة والممارسة الحقيقية.

على Arduino ، يمكنك إنشاء أنظمة مذهلة متعددة المهام حيث تعمل عشرات ومئات الكيانات (LEDs ، وأجهزة الاستشعار ، والمشغلات ، والمؤازرات ، ومحركات السائر ، والواجهات اللاسلكية والسلكية ، وما إلى ذلك) في وقت واحد في وضع (تزييف ، طبيعي) لتعدد المهام.

لن نذهب بعيدا للحصول على أمثلة. هذا هو مشروع الحديقة الشتوية ("Smart Greenhouse") الذي تعمل فيه الكيانات التالية في الوقت الفعلي في وضع تعدد المهام:

الصورة

طوبولوجيا وحدة تحكم nRF24 الموزعة مع عدد كبير من المعدات المتصلة وفي الوقت الحقيقي. يتعامل المستخدم فقط مع "القاعدة" ، وعمل الشريك nRF24 شفاف له تمامًا. ونعم ، هذا اردوينو.

في "القاعدة":

- 7 أجهزة
- 9 محركات السائر
- 6 مرحلات
- 3 أجهزة استشعار رطوبة التربة
- عدد 2 حساس للضوء
- مستشعر مستوى الماء
- جهاز استشعار الرطوبة ودرجة حرارة الهواء

في nRF24 للجزء البعيد:

- 12 مجس لرطوبة التربة
- 12 مرحل
- 3 محركات السائر
- عدد 2 حساس للضوء
- مستشعر مستوى الماء

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

في المجموع ، في الوقت الفعلي ، في وضع تعدد المهام ، يعمل 60 كيانًا على الأقل على 8-bit Mega (وهذا لا يحسب العديد من خدمات نظام تشغيل AMS نفسه ، حيث سيقترب عدد الكيانات من مائة). الأمر الذي لا يتفق بوضوح مع البيان القائل بأن "تعدد المهام الحقيقي مستحيل على Arduino ومن الصعب أن تطرف حتى مع وجود خمسة مصابيح LED".

بضع كلمات دفاعا عن اردوينو


(على الرغم من أنه من الواضح أن Arduino كظاهرة اجتماعية ثقافية وتكنولوجية مع جيش من ملايين المشجعين والعديد من الآلاف من المشاريع المدهشة لا تحتاج إلى الحماية.)

لقد قلت عدة مرات وسوف أكرر مرة أخرى أن Arduino في مكون البرنامج الخاص به هو ، في الواقع ، مجرد مستوى من مستويات التجريد الممكنة (مثل أي أخرى) مع مزاياه وعيوبه. ولا يوجد فرق على الإطلاق بالنسبة للمستخدم ما هو "الدوران" داخل قطعة السيليكون الصغيرة الخاصة به - Arduino "النقي" أو RTOS أو RIOT OS أو AMS أو أي تجريد رياضي آخر لتمثيل وإدارة موارد الحديد في وحدة التحكم.

من المهم بالنسبة للمستخدم أن يحل مشاكله - لوحدة التحكم في سقي النباتات ، وتشغيل الضوء ، والتحكم في الستائر ، وما إلى ذلك. والمشكلة الرئيسية ليست في الأدوات المستخدمة في التطوير ، ولكن في القدرة على استخدامها ، وفي الواقع ، في الخيال والرؤية الهندسية للمطور نفسه.

كيف يعمل؟


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

الصورة

هذا مؤشر على حوالي مائة كيان من نظام nRF24 الموزع ، تتم إدارته بشكل مستقل في الوقت الحقيقي. انتبه إلى آخر مؤشرين من وحدات المعالجة المركزية - حتى في 8-bit Mega ، يكون حمل المعالج صفرًا (أي أن النظام مجاني تمامًا).

قليلا عن الموقتات


لتنظيم التحكم في الأنظمة المعقدة ، لا يكفي فقط نقل التحكم بين العمليات بدوره ، إلى جانب نقل التحكم التلقائي إلى AMS ، يتم استخدام أنواع مختلفة من المؤقتات: دوري ، دوري مع عدد معين من التكرارات (دفعة) ، فردي ، عشوائي ، مختلط ، إلخ. كل هذا منظم الوسائل الأصلية لاردوينو ولا تستخدم المقاطعات أو البرمجة المباشرة لمؤقتات الميكروكونترولر (ولكن المقاطعات ، بالطبع ، تستخدم من قبل النظام "للغرض المقصود").

الأمر الذي يتناقض بشكل مباشر مع البيان: "سيكون هناك ما يكفي من مؤقتات الحديد لـ 3 مصابيح LED ، من الآن فصاعدًا ، سيواجه علماء الإردين مشاكل". لا تبدأ. تتوفر لنا أي أنواع من أجهزة ضبط الوقت بأي كمية. وإذا لزم الأمر ، يمكننا أن نجعل أنفسنا أكثر غرابة وتعسفية.

القضية الرئيسية


الحالة الرئيسية لهذا النوع من تنظيم تعدد المهام هي إنشاء ما يسمى رمز "عدم حظر" ، أي رمز لا يستخدم وظيفة delay () ، والتي ببساطة توقف البرنامج مؤقتًا لفترة معينة.

الوقت الحقيقي


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

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

هذا هو وصف نظري عام لعمل تعدد المهام في Arduino بشكل عام وفي AMS بشكل خاص ، ننتقل الآن إلى النظر في الأمثلة العملية.

توقيت الدورة



الصورة

خذ بعين الاعتبار تنفيذ أبسط الموقتات الدورية. هذه هي أجهزة ضبط الوقت (في مصطلحات "دورات" AMS) ، التي يتم تنشيطها على فترات زمنية محددة ومحددة مسبقًا وتستخدم لتفعيل العمليات الدورية.

بشكل عام ، من الأفضل تصميم الموقتات بشكل برمجي ككائنات ، ولكن في تسليم Arduino Mega Server القياسي ، يتم تنفيذ هذه الموقتات كوظائف ، لذلك ، في البداية ، سننظر فيها في هذا الأقنوم.

يعد استخدام المؤقتات الدورية أمرًا بسيطًا للغاية: ما عليك سوى وضع الكود الذي يجب تنفيذه بشكل دوري بين أقواس العبارة if. إذا كنت بحاجة إلى استخدام فترة تشغيل مختلفة ، فما عليك سوى استخدام المتغير المطلوب بدلاً من cycle1s. يمكنك عمل العديد من الدورات المختلفة كما تشاء - يمكن لنظام حتى على 8-bit Mega التعامل بسهولة مع المئات من هذه المؤقتات (فقط ، بالطبع ، عليك أن تتذكر أن الرمز الذي تم استدعاؤه لا يحظر).

  if (cycle1s) {
    // ,   , ,  
  }

. :

// Cycles
bool cycle1s  = false;
bool cycle5s  = false;
bool cycle20s = false;
bool cycle30s = false;
bool cycle1m  = false;
bool cycle3m  = false;
bool cycle5m  = false;

.

«Timers»:

/*
  Module Timers
  part of Arduino Mega Server project
*/

// Cycles
unsigned long timeSec;
unsigned long timer1s;
unsigned long timer5s;
unsigned long timer20s;
unsigned long timer30s;
unsigned long timer1m;
unsigned long timer3m;
unsigned long timer5m;

void timersInit() {
  unsigned long uptimeSec = millis() / 1000;
  timeSec  = uptimeSec;
  timer1s  = uptimeSec;  
  timer5s  = uptimeSec; 
  timer20s = uptimeSec;
  timer30s = uptimeSec;
  timer1m  = uptimeSec;
  timer3m  = uptimeSec;
  timer5m  = uptimeSec;
}

void timersWorks() {
  timeSec = millis() / 1000;
    if (timeSec - timer1s  >=  1)  {
                                    timer1s  = timeSec; cycle1s  = true;
    if (timeSec - timer5s  >=  5)  {timer5s  = timeSec; cycle5s  = true;}
    if (timeSec - timer20s >= 20)  {timer20s = timeSec; cycle20s = true;}
    if (timeSec - timer30s >= 30)  {timer30s = timeSec; cycle30s = true;}
    if (timeSec - timer1m  >= 60)  {timer1m  = timeSec; cycle1m  = true;}
    if (timeSec - timer3m  >= 180) {timer3m  = timeSec; cycle3m  = true;}
    if (timeSec - timer5m  >= 300) {timer5m  = timeSec; cycle5m  = true;}
  }
}

void eraseCycles() {
  cycle1s  = false;
  cycle5s  = false;
  cycle20s = false;
  cycle30s = false;
  cycle1m  = false;
  cycle3m  = false;
  cycle5m  = false;
}

. - , . , , .

void loop() {
  timersWorks();

  //   

  eraseCycles();
}


, , . myCycle.

, :

/*
  myCycle Library
  part of Arduino Mega Server project
*/

#ifndef _MYCYCLE_H
#define _MYCYCLE_H

#define MS_500       500
#define MS_01S      1000
#define MS_02S      2000
#define MS_05S      5000
#define MS_10S     10000
#define MS_13S     13000
#define MS_17S     17000
#define MS_20S     20000
#define MS_30S     30000
#define MS_01M     60000
#define MS_03M    180000
#define MS_05M    300000
#define MS_01H   3600000
#define MS_06H  21600000
#define MS_12H  43200000
#define MS_01D  86400000

class myCycle {
  private:
    bool          _go;
    bool          _active;
    unsigned long _start;
    unsigned long _period;
  
  public:
    myCycle(unsigned long per, bool act);
    void reInit(unsigned long per, bool act);
    void reStart();
    bool check();
    bool go();
    void clear();
    
    // active
    bool active();
    void setActive(bool act);
    // period
    unsigned long period();
    void setPeriod(unsigned long per);
}; // class myCycle

#endif // _MYCYCLE_H

:

/*
  myCycle Library
  part of Arduino Mega Server project
*/

#include "myCycle.h"
#include <Arduino.h>

myCycle::myCycle(unsigned long per, bool act) {
  _go     = false;
  _active = act;
  _period = per;
  _start  = millis();
}

// Methods

void myCycle::reInit(unsigned long per, bool act) {
  _go     = false;
  _active = act;
  _period = per;
  _start  = millis();
}

void myCycle::reStart() {
  _start = millis();
}

bool myCycle::check() {
  if (millis() - _start >= _period) {
    _start = millis();
    if (_active) {
      _go = true;
    }
  }
  return _go;
}

bool myCycle::go() {
  return _go;
}

void myCycle::clear() {
  _go = false;
}

// Active

bool myCycle::active() {
  return _active;
}

void myCycle::setActive(bool act) {
  _active = act;
}

// Period

unsigned long myCycle::period() {
  return _period;
}

void myCycle::setPeriod(unsigned long per) {
  _period = per;
}

«» : « ».

:

:

#include "myCycle.h"

:

// Cycles
myCycle cycle500(MS_500, true);
myCycle cycle2s(MS_02S, true);
myCycle cycle5s(MS_05S, true);

:

void timersWorks() {
  cycle500.check();
  cycle2s.check();
  cycle5s.check();
}

void eraseCycles() {
  cycle500.clear();
  cycle2s.clear();
  cycle5s.clear();
}

:

void loop() {
  timersWorks();

  //   

  if (cycle5s.go()) {
    Serial.println(F("cycle5s!"));
  }

  eraseCycles();
}

, , . , / , , , .

Arduino



image

, — . , . , AMS .

()


, . , 3 nRF24. 3 .

/ . .


«», - - .


- , , .

, , . , , , 20 , «», «» , . , «» .

, . — Arduino Mega Server .


, , / , « » . .

— , 8- .


, , Arduino - — — , .

, Arduino Mega Server .


, , Arduino , , , Arduino () .

, , .

P.S.
, 0.17 Arduino Mega Server Arduino Mega, Due, 101 M0, . , , .

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


All Articles