لا يحتوي المشروع على اردوينوكان يجب أن يبدو هذا المشروع مختلفًا في الأصل - هيكل ضخم يتكون من قاعدة مع علب ومضخات ، ومربى مائي مثبت عليه واحة طماطم فوقه. تم التخطيط لشلال في جنة واحة الطماطم ، وأشكال الحياة السمكية في الحوض ، وكان الشرط الرئيسي هو القدرة على أكل سكان الحوض غير المخطط له والحفاظ على نظافة الزجاج ؛ المرشحين الرئيسيين هم somiki و gourami. كما كنت قد خمنت ، شعاري هو "الكسل هو محرك التقدم" (وما الذي يمكنك فعله حتى لا تنظف الحوض ولا تسقي الطماطم).ربما تم نصب تذكاري لهذا الشعار لو لم يكن قد انهار بالفعل في مرحلة تنسيق مخططات المسودة مع زوجته. لم تكن مستوحاة من فكرة جعل هذه البندورة الزخرفة الرئيسية لغرفة المعيشة ، وحتى الشلال لم يقنعها بذلك. لكن فكرة النظام المستقل ، وهو تكافل بين علم الأحياء والإلكترونيات ، لم يرغب في أن أطير من رأسي ، وتقلص المشروع إلى حجم وعاء زهور - تحولت الزراعة المائية إلى زراعة مائية ، تم إنقاذ حياة الأسماك.الفكرة الرئيسية للزراعة المائية هي استخدام محلول مائي من المغذيات بدلاً من التربة. هذا يسمح لأمر من الحجم لتسريع نمو النبات. ومع ذلك ، لا يمكن للمرء فقط خفض الجذور في الماء - يحتاجون إلى الأكسجين ، والذي بدونه سيبدأون في الموت. في هذا الصدد ، هناك خيارات - تهب الماء باستمرار بضاغط ، كما هو الحال في الحوض ، أو غمر الجذور بشكل دوري بمحلول مغذى ، وتصريفها بعد مرور بعض الوقت. الخيار الأول له عيب - طنين الضاغط المستمر. الخيار الثاني له ميزة - معظم الجذور في الهواء ، وتتنفس بنشاط ، ويجب أن يكون تأثير تسارع النمو أكبر. علاوة على ذلك ، يتم غمرهم في ركيزة من الحبيبات المسامية الخاصة التي تحتفظ بالرطوبة. كان الخيار واضحا ، لقد اتخذت الخيار الثاني كأساس.في حالة الأسماك ، يمكن أن يكون النظام مغلقًا بالكامل تقريبًا - تتم معالجة إفرازات الأسماك بواسطة بكتيريا خاصة في الفلتر الحيوي ، ويتم تغذية المنتج المجهز للنباتات ، وتقوم طبقة من الرمل بتصفية المياه ، وعودة المياه النظيفة إلى الحوض. في حالة مثالية ، يتم رش الأعلاف في بعض الأحيان في وحدة تغذية تلقائية ، وتتجمع الطماطم من الشجيرات. لكنها لم تنمو معًا ، ربما للأفضل - من يدري كيف سينتهي الطلب عن طريق سلالة من البكتيريا الضرورية.ونتيجة لذلك ، أخذ جهاز نبات الطماطم الخطوط العريضة. سفينتان - السفلية بالماء ، والسفلى بركيزة ومصنع. بالنسبة للفيضانات ، سنستخدم مضخة صينية صغيرة بمحرك DC ، وللصرف سنستخدم سيفون أوتوماتيكي. مبدأ تشغيل السيفون في الفيديو:الزراعة المائية مع سيفون مماثل:دماغ الجهاز هو متحكم ATMEGA328P (ببساطة لأن الغريزة كانت في متناول اليد). تشمل مهامه إدارة الفيضان والتفريغ وفقًا لجدول زمني ، ومراقبة مستوى المياه في الخزان والإشارة إلى نقصه ، والتحكم في إضاءة المصنع (نريد أن يكون لدينا حد أدنى معين من ضوء النهار ؛ عندما ينتهي الضوء الطبيعي ، يتم تشغيل الضوء الاصطناعي تدريجيًا) ، واجهة مستخدم للعرض حالة وإدارة وتكوين هذا الاقتصاد بأكمله. من الواضح أن هذا يتطلب نوعًا من الحل لمستشعر مستوى المياه ومستشعرات الضوء وساعة في الوقت الفعلي ونوعًا من محطة المستخدم.قبل وصف التفاصيل ، قائمة بموارد المشروع:هنا يمكنك رؤية صور للنتيجة وعملية التصنيع.فيديو قصير:المشروع متاح على جيثب . هناك ، في الإصدارات ، تم وضع ملف بمشروع الجزء الإلكتروني في KiCAD ومشاريع أجراس التصميم والصفير في SolidWorks (يتم إرفاق ملفات STL للطباعة).ميزات تجميع البرامج الثابتة—
« ». , , , USB AVR (, , , , ), . - , , 'ADK_ROOT' , 'scons'.
مخطط الجزء الإلكتروني:
مزيد من التفاصيل ، وصفا للمزالق وقليلا من التعليمات البرمجية. وصف مشكلات البرامج في النهاية . ربما يكون شخص ما مهتمًا بمشاهدة مثال جديد للعمل مع I2C ، و valcoder ، ووحدة RTC ، وعرض رسومي. تمت كتابة جميع التعليمات البرمجية في المشروع "من البداية" دون استخدام حلول الطرف الثالث (لأنني أستطيع).مستشعر مستوى الماء
تم تحديد القضية الأكثر حساسية أولاً. بالطبع ، كان هناك نوع من نوع من العوامة بحيث ، على سبيل المثال ، ستقوم بتحريك السكة التي تم تطبيق الرمز الرمادي عليها ، وستتم قراءة أجهزة الاستشعار الضوئية. لكنها بدت غير موثوقة حقا. لم يعط البحث على eBay نتيجة - كانت هناك إما مفاتيح تعويم (وصلت إلى المستوى المطلوب أم لا) ، أو أقطاب وقراءات مغمورة بناءً على موصلية الوسط ، ولكن لوحظ هذا على الفور ، حيث أن تكوين الماء سيتغير باستمرار إلى جانب التوصيل من الأسمدة المضافة والذوبان الشوائب من الركيزة. ونتيجة لذلك ، ظهرت الفكرة لاستخدام محدد المدى بالموجات فوق الصوتية ، أحد تلك التي يتم وضعها عادة على روبوتات مختلفة. كما هو مخطط ، يتم وضع المستشعر في غطاء الخزان وتنعكس الإشارة مباشرة من سطح الماء. تم شراء HC-SR04 (اختيار أصغر قيمة من الحد الأدنى لمسافة العمل - لديه 2 سم) ،وتم فحص المفهوم على دلو من الماء. اتضح أنه يعمل من أجل نفسه (كانت هناك مخاوف من أنه لن يكون هناك انعكاس طبيعي من سطح الماء ، أو أنه لن يكون هناك ما يكفي من اتجاه الشعاع وسيكون هناك انعكاسات غير مرغوب فيها من جدران الخزان). بالمناسبة ، كان جهاز ضبط المدى أيضًا خيارًا احتياطيًا ، ولكن بالأشعة تحت الحمراء. على سطح الماء كان من المفترض أن تطفو بعاكس. المشكلة الوحيدة هي الحد الأدنى لمسافة عملهم التي تبلغ 10 سم (من تلك التي وجدتها) ، والتي تعد بالفعل كبيرة قليلاً للأبعاد المحددة.على سطح الماء كان من المفترض أن تطفو بعاكس. المشكلة الوحيدة هي الحد الأدنى لمسافة عملهم التي تبلغ 10 سم (من تلك التي وجدتها) ، والتي تعد بالفعل كبيرة قليلاً للأبعاد المحددة.على سطح الماء كان من المفترض أن تطفو بعاكس. المشكلة الوحيدة هي الحد الأدنى لمسافة عملهم التي تبلغ 10 سم (من تلك التي وجدتها) ، والتي تعد بالفعل كبيرة قليلاً للأبعاد المحددة.
وفقًا لنتائج المشروع ، فإن هذا النهج يعمل ، ويمكن استخدامه عمليًا ، ولم يلاحظ أي مشاكل. يجدر اتخاذ تدابير لعزل اللوحة من الرطوبة (الختم في الحالة). هذا مجرد أجهزة الاستشعار نفسها تظل مفتوحة ، ربما لا تزال موجودة.واجهة المستشعر بسيطة - يتم إرسال نبضة إلى إدخال الزناد ، مما يؤدي إلى تشغيل إشارة الصدى. يتم إنشاء نبضة عند خرج الصدى ، والذي يساوي طوله الوقت من بداية الإشعاع إلى قبول إشارة الصدى المنعكسة. من خلال قياس طول النبض ، ومعرفة سرعة الصوت وحقيقة أن الإشارة تذهب إلى الجسم والعودة ، يمكنك حساب المسافة. في المشروع ، يتم تنفيذ ذلك في فئة LevelGauge. لقياس طول النبض ، يتم استخدام قدرة أجهزة MK AVR "التقاط المدخلات". في هذه الحالة ، يتم إعادة ضبط موقت الأجهزة على الحافة الصاعدة للنبض ، وعلى القيمة السفلية للمؤقت ، يتم تخزين الجهاز في تسجيل ICR1 ، ويتم إنشاء مقاطعة. وبالتالي ، من الممكن قياس مدة النبض بدقة كافية والحد الأدنى من استهلاك وقت المعالج.حتى مع هذا النموذج من المستشعر ، لوحظ خلل - عندما تم تطبيق الطاقة ، ظل خط الصدى نشطًا باستمرار. تجاوز بتطبيق نبض على الزناد والانتظار حتى مرت دورة موقع الصدى الأولى.الإضاءة الخلفية
يتكون الضوء الخلفي من ثلاثة مصابيح LED قبضة. قمت بثني الإطار الثلاثي من ملف الألمنيوم ، وقمت بلصق الصمامات عليه بالإيبوكسي. أمرت استقرار الصين الحالي في 700mA للطاقة. يسقط حوالي ثلاثة فولت على كل صمام ثنائي ، يتطلب المثبت فرقًا بين جهد الدخل والإخراج لاثنين على الأقل من الفولت ، وكنت سأشغل الرقاقة الكاملة من مصدر طاقة 12 فولت. من هنا من السهل حساب سبب ثلاثة مصابيح LED بالضبط.الثنائيات بيضاء دافئة. بدا لي طبيعيا ، الطيف الشمسي وكل ذلك. ولكن كما اكتشفت لاحقًا ، بعد أن طلبت منهم ، تستخدم النباتات عادةً مزيجًا من الأحمر والأزرق. بقدر ما أفهم ، فإن السؤال كله هو فقط في الكفاءة. إذا كان لديك مزرعة كبيرة مع إضاءة على مدار الساعة ، فأنت مهتم بأن كل الطاقة المستهلكة تنفق من أجل الخير. تحت الإضاءة البيضاء ، ستعكس الأوراق الخضراء المكون الأخضر ، وسيتم إهدار جزء كبير من الطاقة المستهلكة في الإضاءة.

ميزة مهمة للمثبت هي وجود إدخال لتنظيم PWM ، والذي أستخدمه لضبط السطوع. هنا أشعل النار صيني آخر. أولاً ، تبين أنها مجرد وظيفة تشغيل / إيقاف تشغيل حالية. أي ، توقعت ألا يتم تعديل تيار الإخراج ، وستعتمد قيمته على دورة العمل لإشارة PWM ، لكن التيار ببساطة يكرر النبضات عند إدخال التحكم. لكن هذا ليس سيئًا للغاية ، فقد كان كمينًا آخر هو أن المنظم يتفاعل بشكل غير مناسب مع PWM بتردد عالٍ إلى حد ما. اضطررت إلى خفضه إلى 300 هرتز ، حيث كان يعمل بشكل أكثر أو أقل بشكل طبيعي. يتم إنشاء إشارة PWM بواسطة متحكم في الأجهزة باستخدام أحد أجهزة ضبط الوقت.
جزء آخر مهم من مجموعة الإضاءة الخلفية هو مستشعرات الضوء. تم اختيار الترانزستورات الضوئية في هذا الدور. ونعم ، هناك اثنان منهم - واحد فوق LEDs لقياس الضوء الطبيعي ، والثاني تحت LED لتوفير التغذية المرتدة. صحيح أن وظيفة تمديد ضوء النهار التلقائي لم يتم تنفيذها بعد ، كما كانت في فصل الصيف ، ولم تكن ضرورية (والتحفيز أمر خطير). تم افتراض أنه بمجرد أن يكتشف المستشعر الأول انخفاضًا في مستوى الإضاءة (ولم ينتهي الوقت المخصص لساعات النهار) ، يتم تنظيم الضوء بحيث ينتج المستشعر الثاني مستوى مناظر للإضاءة المطلوبة. للقيام بذلك ، تحتاج إلى تنفيذ وحدة تحكم PID بسيطة في التعليمات البرمجية. ولكن أثناء وجودك في الواجهة ، يمكنك فقط رؤية قراءات المستشعر الحالية ، وإبراز سطوع الإضاءة الخلفية المطلوب يدويًا.انتبه إلى توصيل المستشعرات. لكل منها نطاقان ثابتان ، يتم اختيارهما عن طريق توصيل المقاوم المقاوم بصفر. يتم نقل قدم المتحكم الدقيق ، المتصل بالمقاوم الثاني ، في هذا الوقت إلى حالة مقاومة عالية. يمكنك تشغيل كلا المقاومين في وقت واحد ، ثم سيكون هناك ثلاثة نطاقات قياس ثابتة. يتم تمرير الإشارة من المقاومات الباعثة من خلال دائرة RC لتصفية نبضات التحوير - ينبض الضوء من LEDs مع إشارة PWM على المنظم الحالي.مضخة
أرخص الصينية ، والعتاد ، مع محرك DC. الكمائن ، بالطبع ، متاحة. على الرغم من حقيقة أنه يقول 12V ، إلا أنه لا يعمل لفترة طويلة عند هذا الجهد. أحرق واحد قبل تجميع الهيكل. يوفر المخطط لـ PWM لذلك ، يتم تكوين الحد الأقصى من الطاقة في الواجهة ، في الواقع لم يتم تعيينه فوق 70 ٪. بالفعل في هذا المستوى ، يصرخ بعنف في العمل ، ولكن في معظم الوقت يعمل بقوة أقل بكثير - حوالي 30 ٪ ويهتز بهدوء تام. حول أوضاع التشغيل أدناه ، في وصف منطق الفيضانات. يجب وضع المكثف الأكبر (C8 في الرسم التخطيطي) بالقرب من دائرة طاقة المضخة ، وإلا سيكون هناك تداخل كبير في الدائرة بأكملها (في الممارسة العملية ، اتضح أن المنظم الحالي لمصابيح LED أكثر حساسية لهم ، تبدأ الموسيقى الخفيفة).ساعة الوقت الحقيقي
كانت هناك فكرة مجنونة لاستخدام موارد المتحكم الدقيق لهذه الأغراض. يتمتع مولد ساعة الكوارتز بدقة جيدة جدًا ، وفي مشروع آخر نجح هذا النهج بشكل جيد. لكن المشكلة هي أن جميع أجهزة ضبط الوقت تم التقاطها بالفعل لأغراض أخرى. لم يكن هناك خيار سوى العثور على وحدة RTC الخارجية. مدح الصينيين ، إنهم هناك وهم رخيصون.
تحتوي الوحدة القائمة على DS3231 على واجهة I2C ، وإمدادات الطاقة الزائدة الخاصة بها - لن يضيع الوقت في التعتيم. يوجد خرج متعرج عند عدة ترددات ثابتة - 1 كيلو هرتز و 4 كيلو هرتز و 8 كيلو هرتز. كان هذا مفيدًا جدًا للإشارات الصوتية - مرة أخرى ، لست بحاجة إلى تحميل MCU ، ولم يكن هناك مؤقتات مجانية لهذا الغرض. 32Kbit EEPROM هي مكافأة ، لكنها لا تستخدم في هذا المشروع.والمثير للدهشة ، أنها دقيقة للغاية - في غضون بضعة أشهر فقدت قوتها لعدة ثوان. وذكر أنه يأخذ في الاعتبار تأثير درجة الحرارة على تردد المولد ، ويبدو أن هذا يعمل. ومع ذلك ، إذا اختفى الوقت ، فهناك احتمال لتصحيح تردد البرنامج. تتوفر قراءات مستشعر درجة الحرارة ، ويتم عرض هذا المشروع في الواجهة.إن فئة Rtc مسؤولة عن العمل مع هذه الوحدة في الكود.عرض
لطالما أردت أن أفعل شيئًا مع عرض رسومي. البحث عن أرخص مع واجهة I2C أعطى هذا الخيار.
شاشة OLED أحادية اللون مقاس 128 × 64 بكسل استنادًا إلى وحدة التحكم الشائعة إلى حد ما SSD1306. عند الاختيار ، تحتاج إلى إلقاء نظرة على الوصف بعناية - تدعم نفس الشريحة واجهات أخرى ، باستثناء I2C ، وهناك خيارات بدونها. أو يكتبون أنه عالمي ، ويدعم I2C أيضًا ، ولكن في الواقع سيكون من الضروري تعديل اللوحة قليلاً عن طريق إعادة ترتيب القيم الخالية إلى مواقع أخرى. لذلك ، إذا كنت تخطط لاستخدام I2C ، فمن الأفضل اختيار واحد حيث يتم عرض I2C فقط على اللوحة ، فستكون هناك ضجة أقل مع لوحة لا تحتوي على أي وثائق تقريبًا (وثائق للشريحة فقط). يعمل هذا الإصدار من 5V ، يحتوي اللوحة على منظم 3.3V مطلوب للتحكم. التقيت بالمراجعات التي قد لا تكون في بعض الإصدارات.العرض راض بشكل عام. لاحظت ميزة واحدة غير سارة - يعتمد سطوع صف البكسل على عدد وحدات البكسل المضاءة فيه. كلما زاد الإضاءة ، انخفض السطوع. قد يكون التباين بين السطور واضحًا إذا كانت هناك مناطق مليئة تمامًا ببعض العناصر الضيقة بالتناوب على الشاشة. لكن من الناحية العملية ، هذا غير مرئي في صوري ولا يثير الدهشة.يمكن تكوين وحدة التحكم للعمل في أوضاع مختلفة لعرض محتويات ذاكرة الشاشة على مصفوفة بكسل. كان الأمر أكثر ملاءمة بالنسبة لي عندما يتم تعيين كل بايت على عمود رأسي بارتفاع ثمانية بكسل ، وتتجه الأعمدة أفقيًا من اليسار إلى اليمين ، وتملأ الشاشة بخطوط بارتفاع ثمانية بكسل. في هذا الوضع ، من الأنسب رسم نص.غالبًا ما يتم تطبيق نهج يتم فيه تكرار ذاكرة العرض في RAM MCU - أولاً ، يتم تنفيذ جميع الإجراءات مع الصورة في ذاكرة الوصول العشوائي ، ثم يتم نسخ جميع وحدات البكسل المتغيرة إلى ذاكرة العرض. في هذا المشروع ، لا يتم استخدام هذا النهج لتوفير الموارد. يتم إعادة رسم جميع الأماكن التي تم تغييرها على الفور في ذاكرة العرض.كما هو مقترح في التعليقات ، فإن شاشة OLED تتلاشى بمرور الوقت. كما شككت في ذلك (تذكرت ما هي شاشة التوقف) ، وقدمت للعرض لإيقاف التشغيل بعد بضع دقائق من آخر نشاط على عناصر التحكم. يتم تشغيله عند تشغيل التشفير أو الضغط عليه.في الكود ، يتم تنفيذ العمل مع العرض في فئة العرض.فالكودر:
في رأيي ، فإن valcoder هو أفضل خيار للتحكم في هذه الأجهزة التي تحتوي على بعض واجهة المستخدم على الأقل. إنه مضغوط ومريح للغاية. من الملائم لهم التنقل عبر عناصر القائمة وتحديدها ، وتغيير قيم أي معلمات ، وتبديل أوضاع ، وما إلى ذلك.للتوصيل ، يلزم وجود ثلاثة أرجل إدخال لجهاز التحكم الدقيق. واحد للزر (يمكنك الضغط على المقبض) ، واثنان للمبرمج نفسه. هناك إشارة رمز رمادي من التشفير . في كل خطوة ، يتغير بت واحد على خطين. يحدد التسلسل اتجاه الدوران.يبدو أن كل شيء بسيط ، ولكن ، على ما يبدو ، لا يستطيع المطورون دائمًا تقديم دعم عالي الجودة لمثل هذا الجهاز. على سبيل المثال ، على طابعتي ثلاثية الأبعاد ، توجد لوحة RAMPS ولوحة بها شاشة ويتم توصيل جهاز التشفير نفسه بالضبط. تعمل البرامج الثابتة Marlin معها ، ولكن تجربة استخدامها سيئة للغاية - لا يوجد شعور بالموثوقية - عند النقر فوق المفتاح عند تشغيل المفتاح ، غالبًا ما تتوقف الواجهة عند عنصر القائمة أو قيمة المعلمة الخطأ التي كان متوقعًا لها. مع الدوران السريع ، يبدو أن النقرات يتم تخطيها. في مرحلة ما ، لا يبدأ التبديل أثناء النقرات ، ولكن في مكان ما بينهما ، يكون مزعجًا للغاية. نعم ، ما هو مارلين ، لدي أحيانًا نفس الشعور على نظام الوسائط المتعددة المدمج في السيارة. في هذا الصدد ، بعض النصائح (وبالطبع ، انظر إلى الرمز الموجود بالقرب من فئة RotEnc).أولاً ، نقطة واضحة إلى حد ما لأي شخص يربط أي أزرار بوحدة التحكم الدقيقة - تحتاج إلى التعامل مع الارتداد. هذا التشفير الميكانيكي وخطوط الإشارة الخاصة به ، في الواقع ، هي نفس الأزرار ، ولديهم أيضًا ثرثرة. أولاً ، نقوم بتصفية الثرثرة ، ثم نعالج تسلسل حالات خطوط الإشارة. قد يكون هناك فالكودر مع أجهزة استشعار بصرية ، وهو يعتمد بالفعل على مخططات معالجة الإشارات منها. إذا تم إخراج أرجل الترانزستور الضوئي مباشرة ، فقد يكون هناك خشخشة بالدوران البطيء ، ولكن إذا كان هناك أي مخطط معالجة يقدم التباطؤ ، فلن يكون هناك حاجة لقمع البرمجيات. لكن هذه الأجهزة أكثر تكلفة ونادرًا ما تستخدم في أجهزة الهواة ، والأكثر شيوعًا هي الأجهزة الميكانيكية ، وعدد قليل من الدولارات.ثانيًا ، نقطة أقل وضوحًا ، ربما واحدة من تلك التي أحرق فيها مارلين - يحتوي المقبض على أوضاع ثابتة أثناء الدوران - النقرات (النقرات). يحتوي هذا النموذج على أربع خطوات لتسلسل رمز لكل نقرة. لذا ، تحتاج إلى الاستجابة للنقرات ، وليس لخطوات التسلسل. وأهم شيء هو المزامنة مع المواقف المستقرة. يدخل الكثير منهم ببساطة STEPS_PER_CLICK الثابت ، ويستجيبون ، على سبيل المثال ، لكل خطوة رابعة. لكن المشكلة هي أن الإشارة ليست مثالية ، وقد لا تكون التسلسلات صحيحة تمامًا. مع هجاء معين ، قد "تفسد" الشفرة ، ونتيجة لذلك ، سيتم الحصول على كل خطوة رابعة في مكان ما في منتصف النقرة ، والتي ستكون غير مريحة للمستخدم. في الوقت نفسه ، يتوافق الموضع الثابت للمقبض لنموذج معين مع قيمة رمز ثابتة ،يجب أن تعلق عليه.ثالثًا ، مرة أخرى ، نقطة واضحة إلى حد ما لمطوري أنظمة متحكم أكثر أو أقل خبرة - استخدم مقاطعات الأجهزة لتغيير حالة خطوط الإدخال. كحد أدنى ، سيكون هناك خطر أقل من "فقدان" خطوات التسلسل. ولكن بشكل عام ، كما تعلمون ، الانقطاعات هي كل شيء لدينا. يجب أن تنام MCU كلما أمكن ذلك ، وتستيقظ فقط على الانقطاعات - إما من المحيط الخارجي ، أو من جهاز توقيت لأداء مهمة متأخرة. هذه هي مبادئ تصميم بنية النظام الجيد.التصميم ككل
وهي مصنوعة من مواد مرتجلة وأجزاء مختلفة مطبوعة على طابعة ثلاثية الأبعاد من ABS.يتم توضيح مبدأ تشغيل السيفون في الفيديو أعلاه. بالنسبة لي ، هو أنبوب PVC خارجي ، وأنبوب داخلي مع قمع في النهاية. بالنسبة للسيفون الكلاسيكي ، هناك حاجة إلى ركبة أخرى ، ولكن كان من الصعب بالفعل صنعها لي بشكل بنّاء. عندما تم العثور على مشاكل في التصريف ، تم تعليق حمام صغير على جدار الخزان السفلي ، حيث تم غمر نهاية الأنبوب الداخلي ، وخلق مقاومة للتصريف ، بحيث يمكن أن يعمل السيفون.اتضح أن ABS مادة مسعور للغاية. لا تتدفق المياه حرفياً من خلاله ؛ حتى أنني اضطررت إلى إعادة قمع السيفون. يجدر النظر في هذه الخاصية ، من المستحيل إنشاء بعض الأنظمة الهيدروليكية المصغرة (على سبيل المثال ، أردت عمل أسطح إرشادية على قمع السيفون ، لتحريف الماء ، لتحسين استجابة السيفون. ولكن مع مثل هذه الأبعاد ومقاومة الماء لـ ABS هذا لا معنى له) .كما حاولت أولاً لصقها كلها بمسدس الغراء الساخن. لا يعمل - في البداية بدا كل شيء ثابتًا ، ولكن بعد بضعة أيام سقط من تلقاء نفسه. الخيار الأفضل هو آسيا الوسطى. التفاصيل ، حتى تحت الماء ، تمسك بشدة.أكبر خطأ في التصميم هو حاويات شفافة. لقد نسيت تمامًا حقيقة أن الماء يزهر في الضوء. اضطررت إلى لفه بمواد غير شفافة. حسنًا ، يمكنك إضافة برمنجنات البوتاسيوم بشكل دوري للتطهير ، وهذا لا يبدو أنه يضر النباتات.خوارزمية الفيضان هي كما يلي - أولاً يتم تشغيل المضخة بطاقة منخفضة وتملأ بهدوء الخزان العلوي بأكمله. تتم مراقبة العملية بواسطة مستشعر مستوى. عندما يبدأ الماء في التدفق عبر قمع السيفون ، يتوقف انخفاض المستوى في الخزان السفلي ، والذي يتم اكتشافه بواسطة المستشعر. تدفق صغير تم إنشاؤه بطاقة منخفضة لا يكفي لإطلاق سيفون. تتوقف المضخة ، يتم تذكر الحجم الذي يتم ضخه في الخزان العلوي. يتم الاحتفاظ بالجذور في المحلول لعدة دقائق ، وبعدها يتم تشغيل المضخة مرة أخرى. أولاً ، عند طاقة منخفضة ، حتى تصل المياه إلى القمع مرة أخرى (خلال فترة التوقف ، تنخفض أقل بسبب تأثير السيفون) ، وعندما يتم الوصول إلى مستوى القمع ، يتم تشغيل المضخة لزيادة الطاقة ، مما يوفر تدفقًا كافيًا لتشغيل السيفون. يضمن أن يكون التدفق عبر السيفون أعلى من تدفق المضخة ،ونتيجة لذلك ، يبدأ المستوى في الخزان السفلي في الارتفاع ، ويتم اكتشاف ذلك بواسطة المستشعر وتتوقف المضخة.تبدأ دورات الفيضان بشكل دوري ، على فترات زمنية ثابتة قابلة للتكوين ، من الفجر إلى الغسق. وفقًا للخطة ، كان من المفترض أن يتم إصلاح الفجر بواسطة مستشعر الضوء ، وتم تمديد طول ضوء النهار ، إذا لزم الأمر ، إلى القيمة المحددة ، ولكن حتى ذلك الحين لم تصل اليدين. يتم ضبط وقت الفجر ببساطة في الإعدادات.وأين C ++ 11؟
ربما يشك أحد في أن C ++ 11 يمكن أن يكون مفيدًا في برمجة المتحكم الدقيق (من بين أولئك الذين يدركون بشكل عام أنه يمكن برمجة المتحكم الدقيق في C ++). سأحاول تقديم أمثلة محددة لفوائد C ++ 11 في هذا المجال (بالإضافة إلى الأشياء الصغيرة الواضحة مثل constexpr ، الإلغاء ، التقصير ، إلخ).وضع موارد السلسلة
يعرف الكثير من الناس أن ذاكرة الوصول العشوائي في وحدات التحكم الدقيقة هي مورد محدود للغاية. يمكن أن يكون هذا مشكلة إذا كان التطبيق الخاص بك ، على سبيل المثال ، يحتوي على واجهة مستخدم ويستخدم برنامجك عددًا كبيرًا من الأسطر. إذا في التعليمات البرمجية لكتابة شيء مثلPromptUser("Are you sure you want to format SD-card?");
ثم سيتم وضع السطر الذي تم تمريره في الوسيطات في قسم البيانات الأولية (من الآن فصاعدًا ، سلوك المترجم GCC لمنصة AVR) - أي في منطقة ذاكرة الوصول العشوائي ، والتي يتم عند بدء التشغيل (قبل استدعاء الوظيفة الرئيسية) من ذاكرة فلاش البرنامج. سيتم تمرير الدالة PromptUser () مؤشر إلى الموقع المطلوب في ذاكرة الوصول العشوائي. إذا كنت تستخدم نهجًا مشابهًا في جميع أنحاء البرنامج ، فستنتهي ذاكرة الوصول العشوائي بسرعة كبيرة (في ATMEGA328P المستخدم في هذا المشروع ، يبلغ حجمه 2 كيلوبايت فقط ، وهذا أيضًا لـ BSS ، والكومة والمكدس). للتغلب على هذا القيد ، تتعلم وظائف مثل PromptUser () العمل ليس مع مؤشرات ذاكرة الوصول العشوائي ، ولكن مع مؤشرات إلى منطقة في ذاكرة فلاش البرنامج. يمكنك القراءة من هناك فقط بمساعدة تعليمات خاصة ، على سبيل المثال ، في avr-libc ملفوفة في وظائف eeprom_read_ family [byte | word | dword | ...].في هذه الحالة ، يجب أولاً وضع السلسلة في متغير مجهز بسمة PROGMEM ، التي تخبر المترجم أنه يجب وضعها في ذاكرة البرنامج .char prompt[] PROGMEM = "Are you sure you want to format SD-card?";
PromptUser(prompt);
هذا غير مريح إذا كنت تريد إعلان جميع الخطوط مركزيًا. ثم يتعين عليك أولاً الإعلان عن إعلانهم في ملف الرأس:extern char prompt[] PROGMEM;
وفي ملف .cpp منفصل ، حدد:char prompt[] PROGMEM = "Are you sure you want to format SD-card?";
ازدواجية الشفرة ، وهي ليست جيدة ، وغير مريحة للغاية عندما يكون هناك الكثير من هذه الأسطر. نعم ، يمكن التحايل على ذلك من خلال إنشاء ماكرو صعب ، وتضمين ملف الرأس في ملف .cpp منفصل ، حيث سيتم توسيع الماكرو في التعريف ، بينما سيتم توسيعه في سياقات أخرى إلى الإعلان. ولكن مع C ++ 11 ، هناك خيار أنظف إذا كنت تستخدم تهيئة أعضاء الصف عند الإعلان. في ملف الرأس ، قم بتعريف الفصل بالخطوط:#define DEF_STR(__name, __text) \
const char __name[sizeof(__text)] = __text;
class Strings {
public:
DEF_STR(Prompt, "Are you sure you want to format SD-card?")
DEF_STR(OtherString, "...")
…
} __attribute__((packed));
extern const Strings strings PROGMEM;
في ملف .cpp:const Strings strings PROGMEM;
يتم الآن الإعلان عن جميع الخطوط في مكان واحد ، ووضعها في ذاكرة البرنامج ، ويمكنك الوصول إليها على النحو التالي:PromptUser(strings.prompt);
في هذا المشروع ، يتم استخدام نهج قائم على نفس المبدأ لتحديد الصور النقطية - صور مختلفة معروضة على عرض رسومي.
struct Bitmap {
const u8 *data;
u8 numPages,
numColumns;
} __PACKED;
template<u8... data>
constexpr static u8
Bitmap_NumDataBytes()
{
return sizeof...(data);
}
#define DEF_BITMAP(__name, __numPages, ...) \
const u8 __CONCAT(__name, __data__) \
[Bitmap_NumDataBytes<__VA_ARGS__>()] = { __VA_ARGS__ }; \
const Bitmap __name { \
reinterpret_cast<const u8 *>(OFFSETOF(Bitmaps, __CONCAT(__name, __data__))), \
__numPages, \
sizeof(__CONCAT(__name, __data__)) / __numPages};
class Bitmaps {
public:
DEF_BITMAP(Thermometer, 1,
0b01101010,
0b10011110,
0b10000001,
0b10011110,
0b01101010
)
DEF_BITMAP(Sun, 1,
0b00100100,
0b00011000,
0b10100101,
0b01000010,
0b01000010,
0b10100101,
0b00011000,
0b00100100
)
...
};
extern const Bitmaps bitmaps PROGMEM;
الفرق هو أنه بالإضافة إلى بيانات الصورة نفسها ، من الضروري أيضًا وضع السمات (أحجام الصور). يحدد كل بايت عمودًا من ثمانية بكسل. يمكن أن تملأ الأعمدة صفًا واحدًا أو أكثر ، ويشار إلى رقمها بواسطة المعلمة الثانية بعد الاسم. اتضح أن ارتفاع الصور النقطية يجب أن يكون مضاعفًا لثمانية عرضًا عشوائيًا ، وهو أمر مقبول تمامًا لهذا المشروع.حرفي ثنائي
ربما تكون قد لاحظت بالفعل أن الصور النقطية في المثال السابق تستخدم حرفيًا ثنائيًا للتحديد. هذا حقًا مناسب جدًا - يمكنك تعديل الصور النقطية البسيطة مباشرةً في الشفرة ، خاصةً إذا كان المحرر يسمح بتمييز تلك الصور النقطية. على سبيل المثال ، تعريفات أحرف الخط في ملف font.h:
قوالب متغيرة
فأين بدونهم إذن. حسنًا ، على سبيل المثال ، يمكن أن يبلغ طول أوامر وحدة التحكم في العرض من بايت واحد إلى عدة بايت. مرسلة بالرمز التالي:SendCommand(Command::DISPLAY_ON);
SendCommand(Command::SET_COM_PINS, COM_PINS | COM_PINS_ALTERNATIVE);
SendCommand(Command::SET_COLUMN_ADDRESS, curVp.minCol, curVp.maxCol);
مريحة ، أليس كذلك؟
template <typename... TByte>
void
SendCommand(TByte... bytes)
{
cmdSize = sizeof...(bytes);
controlSent = false;
cmdInProgress = true;
SetCmdByte(sizeof...(bytes) - 1, bytes...);
i2cBus.RequestTransfer(DISPLAY_ADDRESS, true,
CommandTransferHandler);
}
template <typename... TByte>
inline void
SetCmdByte(int idx, u8 byte, TByte... bytes)
{
cmdBuf[idx] = byte;
SetCmdByte(idx - 1, bytes...);
}
inline void
SetCmdByte(int, u8 byte)
{
cmdBuf[0] = byte;
}
يصف ملف variant.h فئة تشبه بشكل غامض خاصية variant باستخدام قوالب متنوعة. يتم استخدامه لتنظيم صفحات واجهة المستخدم. هذا مرة أخرى مسألة حفظ للذاكرة - حيث إدارة الذاكرة الديناميكية هي رفاهية غير مقبولة ، عليك التهرب (على الرغم من أن 2K لا تزال كثيرة ، لا يمكنك التهرب ، ولكن في نفس خط ATMEGA يصل حجمها إلى 512 بايت ، وكل بايت لكل الحساب). في واجهتي ، يتم عرض صفحة واحدة على الشاشة في أي وقت. وفقًا لذلك ، بالنسبة لجميع الصفحات ، يمكنك استخدام نفس جزء من الذاكرة ، ما يسمى الوحدة في C. بالنسبة للفصول في C ++ ، عادة ما يسمى هذا البديل. على عكس الاتحاد ، نحتاج إلى أن نتذكر استدعاء مدمر المحتوى السابق قبل استدعاء مُنشئ المحتوى الجديد. Variant<MainPage,
Menu,
LinearValueSelector,
TimeSelector> curPage;
...
template <class TPage>
static constexpr u8
GetPageTypeCode()
{
return decltype(curPage)::GetTypeCode<TPage>();
}
...
curPage.Engage(nextPageTypeCode, page);
للتجميع ، يتم استخدام binutils GCC و GNU لمنصة AVR (في Ubuntu توجد حزمة جاهزة gcc-avr). تم إعطاء تفاصيل عملية التجميع أعلاه. تبدو معلمات المحول البرمجي شيئًا مثل هذا (تم حذف أوجه القصور والتضمينات الخاصة بالمشروع): الرابط: تحويل قسم الشفرة إلى تنسيق سداسي عشري: إنشاء صورة EEPROM: البرامج الثابتة للمتحكم الدقيق: PS كانت الطماطم الأولى ناضجة بالفعل ، ولم تكن جيدة المذاق. على ما يبدو ، لم يعجبهم شيء في النظام الغذائي. ربما يجب تغيير الثقافة.avr-g++ -o build/native-debug/src/firmware/cpu/lighting.cpp.o -c -fno-exceptions -fno-rtti -std=c++1y -Wall -Werror -Wextra -ggdb3 -Os -mcall-prologues -mmcu=atmega328p -fshort-wchar -fshort-enums src/firmware/cpu/lighting.cpp
avr-g++ -o build/native-debug/src/firmware/cpu/cpu -mmcu=atmega328p build/native-debug/src/firmware/cpu/adc.cpp.o build/native-debug/src/firmware/cpu/application.cpp.o …
avr-objcopy -j .text -j .data -O ihex build/native-debug/src/firmware/cpu/cpu build/native-debug/src/firmware/cpu/cpu_rom.hex
avr-objcopy -j .eeprom --change-section-lma .eeprom=0 -O ihex build/native-debug/src/firmware/cpu/cpu build/native-debug/src/firmware/cpu/cpu_eeprom.hex
avrdude -p atmega328p -c avrisp2 -P /dev/avrisp -U flash:w:build/native-debug/src/firmware/cpu/cpu_rom.hex:i