اليوم أريد أن أشارك أحد مشاريع Arduino الخاصة بي. ذات مرة ، منذ وقت ليس ببعيد ، في مكان ما على الإنترنت ، اكتشفت عن اردوينو. انضممت إلى هذا العمل بسرعة كبيرة ، ومستوى الدخول ليس مرتفعًا. بعد مرور بعض الوقت ، وبعد أن جمعت بالفعل مجموعة من المستشعرات ، بدأت المستشعرات الخاصة بالمنزل الذكي تصطاد نفسي ، معتقدًا أن الأمر كان بطريق الخطأ.
وحدات ، مربعات عادي كبير ، مجموعة من الأسلاك والغراء الساخن :). عند النظر إلى الصندوق الخاص بي باستخدام مستشعر درجة الحرارة ، وعلى سبيل المثال ، مستشعر درجة الحرارة في نفس Xiaomi ، أدركت أنني أود أن أبدو مثل Xiaomi ، لكن في الوقت نفسه ، يمكنك إعادة برمجةه مثل مربع في صندوق بطول 10 سم × 6 سم بالأسلاك والمواد اللاصقة الساخنة. وربما بعد ذلك وضعت بداية مشاريعي اردوينو DIY على لوحات ثنائي الفينيل متعدد الكلور.
في مقال اليوم ، سنتحدث عن مستشعر درجة الحرارة والرطوبة استنادًا إلى معالج atmega328p-mu. هذه نسخة "أصغر" (تناظرية مطلقة) لمعالج atmega328p-au (Arduino Uno ، Pro Mini ، Nano) معروفة لجميع مطوري arduino. إذا قام شخص ما بقراءة مقالاتي من قبل ، فإنهم يعرفون أنني أفضل Mysensors. ما هذا هذه مكتبة بسيطة جدًا ومصممة جيدًا ، والأهم من ذلك ، مكتبة جيدة الوصف لـ Arduino IDE (وليس فقط) لإنشاء شبكات راديو IOT بترددات 2.4 غيغاهرتز و 915 و 868 و 433 ميجاهرتز ، بالإضافة إلى شبكات سلكية على واجهة 485 ، ربما لم يتم ذكرها جميعًا. البروتوكول يتطور باستمرار ، يتم إضافة شيء في كل وقت.
أول ما تم القيام به هو الاستشعار نفسه على لوحة PCB. لقد فعلت ذلك دون النظر إلى الحالة ، وفقًا للمبدأ ، فإن الشيء الرئيسي هو صنع مجس ، وسأطبع القضية بطريقة ما ... نعم ، لا تفعل ذلك :). في الواقع ، فإن المستشعر نفسه هو نفس arduinka Pro Mini ، وحدة راديو nRF24l01 ، ومستشعر درجة الحرارة والرطوبة SHT20 ، فقط بدون أسلاك وغراء ساخن. من بين "الأجراس والصفارات" ، يعد هذا محرك أقراص فلاش SPI خارجيًا ليومض عبر الهواء (وحدة تحميل BootOptibut مطلوبة للتشغيل ، فيما بعد توقفت عن وضعها (محركات أقراص فلاش) على حزم الدوائر ، حيث لا توجد برامج ثابتة على الهواء ونصف البطارية) و "ميكروفون التشفير" ATSHA204A طقم الأجهزة (في Mysensors ، لتنشيط التواقيع ، التشفير ، وما إلى ذلك ، تحتاج فقط إلى تحديد # def اللازمة في بداية الرسم).

تم صنع اللوحة نفسها في برنامج Diptrace ، بعد مشاهدة مقاطع الفيديو التعليمية على YouTube ، بدا الأمر في البداية وكأنه شيء "جهنمي" ، لكن في الواقع ، لم يكن الأمر صعبًا. لقد طلبت اللوحات في الصين على jlcpcb.com ، 2 دولارات ، أي لون ، وبعد أسبوعين تحصل بالفعل على 10 قطع من "إبداعك الخاص" بين يديك :).


والخطوة التالية هي تطوير الجسم. أوه ، اتضح أن هذا هو نفس المشكلة. بشكل عام ، لم أكن أبحث عن طرق سهلة ، فقد قررت إتقان Solid Works. كما اتضح ، هذا ليس مثل الإطلاق مع Deeptrace. ومع ذلك ، أوصي هذا المحرر للدراسة. استمرت عملية التعلم لمدة شهر من مشاهدة مهل لدروس الفيديو على YouTube وتكرار الدرس في المحرر. في عملية تطوير الحالة ، أصبح من الواضح أن صنع لوحة الجهاز دون مراعاة معلمات الحالة المستقبلية هو قرار سيئ ، من السلسلة نقوم بإدراج العصي في عجلاتنا الخاصة. وفقًا لنتائج إصدارات اللوحة ، خرج ثلاثة منها ، مع الأخذ في الاعتبار تثبيت اللوحة في هذه القضية ، وأعتقد أن هذا ليس هو الخيار الأخير.
في بداية تطوير المبنى ، كانت الفكرة هي طباعته على طابعة FDM ثلاثية الأبعاد ، ولكن كلما زاد تواجده في الغابة ، أصبح من الواضح أنه لم يكن قادراً على إعادة إنتاج كل ما لدي من قائمة الأمنيات. بحلول الوقت الذي جاء فيه هذا الفهم ، تعلمت بالفعل تقنية الطباعة ثلاثية الأبعاد - SLA. دون التفكير مرتين وتأثرت بجودة الطباعة ، تم إصدار قائمة الامنيات على Ali -
ANYCUBIC فوتون . (رابط آنا علي ، وليس الإعلان ، وليس التابعة ، ... مجرد رابط).
سأكتب على الفور ، الآن ، بناءً على تجربتي في وقت كتابة هذا التقرير ، ... أوه ، هذا الشيء الرائع شيء رائع !!! الحالة التي تم تصميمها في المحرر بالطبع ولم تتم طباعتها لأول مرة وكان هناك الكثير من التحسينات. حسنًا ، ربما ليس هذا هو الاتجاه الآخر. نتيجة لذلك ، حصلت على النتيجة التي أردت. لا بأس به جهاز صغير ، وحالة DIY جيدة مع تفاصيل دقيقة للغاية ، والأزرار ، والخطوط ، كل شيء كما هو موضح في الرأس. تم إضافة المغناطيس إلى الغطاء الخلفي ، والآن يمكن تركيبه بسهولة على الأسطح الحديدية.








هذه محاولات لطباعة النموذج نفسه على طابعة FDM:


نظرًا لأن الجهاز أصبح صغيراً ، لكنه لا يزال arduinka ، فقد شعرت بالحيرة من إخراج الموصلات المصغرة للبرمجة. ووفقًا لذلك ، تم تصنيع محول صغير للموصلات للاتصال المريح مع مبرمج ومحول TTL.

تم شراء كل شيء على علي (نعم ، ليست هناك وحدات اردوينو كاملة فقط)
SMD التنتالوم مكثف 4.7uF - 4.7uF | 10 فولت | 10 ٪ - C1
SMD السيراميك مكثف 100nF | Y5V - 100nF | 50 فولت | + 80-20 ٪ - C2 ، C3 ، C4 ، C5 ، C6 ، C7
الصمام - الصمام الجانبي - D1
رأس الدبوس أنثى - 2x3P | 6pin | 1.27 ملم - J1 ، J2
SMD المقاوم 20K أوم - 20K | 5 ٪ - R1
SMD المقاوم 4.7K أوم - 4.7K | 5 ٪ - R2 ، R3 ، R4
SMD المقاوم 470K أوم - 470 | 1 ٪ - R5
SMD المقاوم 1M أوم - 1M | 1 ٪ - R6
SMD المقاوم 18K أوم - 18K | 5 ٪ - R7
SMD المقاوم 10K أوم - 10K | 5 ٪ - R8
زر جانبي SMD رباعي السنون - SW1 ، SW2
ذاكرة فلاش تسلسلية SPI بسعة 512 كيلوبايت و 1.65 فولت - AT25DF512C-SSHN-B - U1
Mini NRF24L01 + 2.4GHz 1.27MM RF - nRF24l01 1.27 SMD - U2
ATMEGA328P-MU QFN32 - U3
كريبتو للتوثيق ، سلك واحد - ATSHA204A-STUCZ-T - U4
جهاز استشعار الرطوبة ودرجة الحرارة IC - SHT20 - U5
حامل البطاريات ل CR2477-1 - L-KLS5-CR2477-1 - U6
رمز البرنامج بسيط للغاية. تم استخدام مثال لمكتبة DFRobot للعمل مع جهاز استشعار SHT20. من حيث المبدأ ، يمكن تحويل أي مخطط ، لأي جهاز استشعار ، إلى مخطط للعمل في شبكة Mysensors خلال 5 دقائق.
قائمة رمز#include <Wire.h>
#include "DFRobot_SHT20.h"
DFRobot_SHT20 sht20;
#define MY_DEBUG
#define MY_RADIO_RF24
#define MY_PASSIVE_NODE
#define MY_NODE_ID 200
#define MY_PARENT_NODE_ID 0
#define MY_PARENT_NODE_IS_STATIC
#define MY_TRANSPORT_UPLINK_CHECK_DISABLED
#define TEMP_SENS_ID 1
#define HUM_SENS_ID 2
#define SETTING_LED_SENS_ID 100
#define DELAY_TIME_SENS_ID 101
#define BATTARY_SEND_SENS_ID 102
#define BATTARY_DATA_SENS_ID 103
#define BAT_COOF 3.04
#define BAT_MIN 195
#define BAT_MAX 295
#define ON 1
#define OFF 0
float humd;
float temp;
float oldhumd;
float oldtemp;
float tempThreshold = 0.5;
float humThreshold = 10.0;
static uint32_t lightMillis;
static uint32_t previousMillis;
uint32_t send_batteryTime;
uint32_t w_battetyTime = 0;
static uint8_t led_pin = 4;
static uint8_t mode_pin = 2;
uint32_t delayTime;
int8_t battery;
int8_t old_battery;
uint8_t set_led;
boolean sleep_mode;
boolean configMode = 0;
int8_t timer_status = 0;
bool flag_mode_button = 0;
bool sleep_flag = 0;
bool listen_flag = 0;
#include <MySensors.h>
MyMessage msg_temp(TEMP_SENS_ID, V_TEMP);
MyMessage msg_hum(HUM_SENS_ID, V_HUM);
MyMessage msg_setting_led(SETTING_LED_SENS_ID, V_VAR1);
MyMessage msg_delay_time(DELAY_TIME_SENS_ID, V_VAR1);
MyMessage msg_battary_send(BATTARY_SEND_SENS_ID, V_VAR1);
MyMessage powerMsg(BATTARY_DATA_SENS_ID, V_VAR1);
void preHwInit()
{
pinMode(led_pin, OUTPUT);
digitalWrite(led_pin, OFF);
pinMode(mode_pin, INPUT_PULLUP);
}
void before()
{
set_led = loadState(100);
if (set_led > 1) {
set_led = 1;
saveState(100, set_led);
}
delayTime = loadState(101);
if (delayTime > 60) {
delayTime = 3;
saveState(101, delayTime);
}
send_batteryTime = loadState(102);
if (send_batteryTime > 48) {
send_batteryTime = 6;
saveState(102, send_batteryTime);
}
digitalWrite(led_pin, ON);
}
void presentation()
{
sendSketchInfo("Temp & Hum Sensor CR2477", "1.0");
wait(100);
present(TEMP_SENS_ID, S_TEMP, "TEMPERATURE DATA");
wait(100);
present(HUM_SENS_ID, S_HUM, "HUMIDITY DATA");
wait(100);
present(SETTING_LED_SENS_ID, S_CUSTOM, "LED MODE");
wait(100);
present(DELAY_TIME_SENS_ID, S_CUSTOM, "DELAY TIME/MIN");
wait(100);
present(BATTARY_SEND_SENS_ID, S_CUSTOM, "BATTERY SEND TIME/H");
wait(100);
present(BATTARY_DATA_SENS_ID, S_CUSTOM, "BATTERY DATA");
}
void setup()
{
digitalWrite(led_pin, OFF);
wait(500);
digitalWrite(led_pin, ON);
wait(75);
digitalWrite(led_pin, OFF);
wait(50);
digitalWrite(led_pin, ON);
wait(75);
digitalWrite(led_pin, OFF);
wait(50);
digitalWrite(led_pin, ON);
wait(75);
digitalWrite(led_pin, OFF);
TRANSPORT_DEBUG(PSTR("MyS: OPERATING MODE\n"));
wait(100);
readBatLev();
wait(100);
sht20.initSHT20();
wait(100);
send_data();
wait(100);
send(msg_delay_time.set(delayTime));
wait(100);
send(msg_setting_led.set(set_led));
wait(100);
send(msg_battary_send.set(send_batteryTime));
}
void loop()
{
if (configMode == 0) {
if (sleep_flag == 0) {
timer_status = sleep(digitalPinToInterrupt(mode_pin), FALLING, delayTime * 60 * 1000, false);
sleep_flag = 1;
}
if (timer_status == -1) {
w_battetyTime = w_battetyTime + (delayTime * 60 * 1000);
if (w_battetyTime >= send_batteryTime * 60 * 60 * 1000) {
readBatLev();
w_battetyTime = 0;
}
send_data();
sleep_flag = 0;
}
if (timer_status == 0) {
if (digitalRead(2) == LOW && flag_mode_button == 0)
{
flag_mode_button = 1;
previousMillis = millis();
wait(50);
}
if (digitalRead(2) == LOW && flag_mode_button == 1) {
if ((millis() - previousMillis > 0) && (millis() - previousMillis <= 2000)) {
if (millis() - lightMillis > 50) {
lightMillis = millis();
digitalWrite(led_pin, !digitalRead(led_pin));
}
}
if ((millis() - previousMillis > 2000) && (millis() - previousMillis <= 2500)) {
digitalWrite(led_pin, OFF);
}
if ((millis() - previousMillis > 2500) && (millis() - previousMillis <= 4500)) {
if (millis() - lightMillis > 25) {
lightMillis = millis();
digitalWrite(led_pin, !digitalRead(led_pin));
}
}
if (millis() - previousMillis > 4500) {
digitalWrite(led_pin, OFF);
}
}
if (digitalRead(2) == HIGH && flag_mode_button == 1)
{
if ((millis() - previousMillis > 0) && (millis() - previousMillis <= 2000)) {
configMode = !configMode;
flag_mode_button = 0;
TRANSPORT_DEBUG(PSTR("MyS: CONFIGURATION MODE\n"));
sleep_flag = 0;
digitalWrite(led_pin, OFF);
}
if ((millis() - previousMillis > 2000) && (millis() - previousMillis <= 2500)) {
flag_mode_button = 0;
sleep_flag = 0;
}
if ((millis() - previousMillis > 2500) && (millis() - previousMillis <= 4500))
{
flag_mode_button = 0;
sleep_flag = 0;
digitalWrite(led_pin, OFF);
}
if (millis() - previousMillis > 4500) {
flag_mode_button = 0;
sleep_flag = 0;
wait(50);
}
}
}
} else {
if (listen_flag == 0) {
RF24_startListening();
listen_flag = 1;
}
if (millis() - lightMillis > 1000) {
lightMillis = millis();
digitalWrite(led_pin, !digitalRead(led_pin));
}
if (digitalRead(2) == LOW && flag_mode_button == 0)
{
flag_mode_button = 1;
wait(50);
}
if (digitalRead(2) == LOW && flag_mode_button == 1) {
}
if (digitalRead(2) == HIGH && flag_mode_button == 1)
{
configMode = !configMode;
listen_flag = 0;
flag_mode_button = 0;
TRANSPORT_DEBUG(PSTR("MyS: OPERATING MODE\n"));
digitalWrite(led_pin, OFF);
wait(50);
}
}
}
void receive(const MyMessage & message)
{
if (message.sensor == SETTING_LED_SENS_ID) {
if (message.type == V_VAR1) {
if (message.getByte() <= 1) {
set_led = message.getBool();
saveState(100, set_led);
send(msg_setting_led.set(set_led));
if (set_led == 0) {
TRANSPORT_DEBUG(PSTR("MyS: STATUS LED: OFF\n"));
}
if (set_led == 1) {
TRANSPORT_DEBUG(PSTR("MyS: STATUS LED: ON\n"));
if (set_led == 1) {
digitalWrite(led_pin, ON);
wait(50);
digitalWrite(led_pin, OFF);
}
}
}
}
}
if (message.sensor == DELAY_TIME_SENS_ID) {
if (message.type == V_VAR1) {
if (message.getULong() <= 60 && message.getULong() != 0) {
delayTime = message.getULong();
saveState(101, delayTime);
send(msg_delay_time.set(delayTime));
TRANSPORT_DEBUG(PSTR("MyS: THE NEW INTERVAL TEMP&HUM SEND VALUE IS SET: %d MIN.\n"), delayTime);
if (set_led == 1) {
digitalWrite(led_pin, ON);
wait(50);
digitalWrite(led_pin, OFF);
}
} else if (message.getULong() > 60) {
delayTime = 60;
saveState(101, delayTime);
send(msg_delay_time.set(delayTime));
TRANSPORT_DEBUG(PSTR("MyS: THE NEW INTERVAL TEMP&HUM SEND VALUE IS SET: %d MIN.\n"), delayTime);
if (set_led == 1) {
digitalWrite(led_pin, ON);
wait(50);
digitalWrite(led_pin, OFF);
}
} else if (message.getULong() == 0) {
delayTime = 1;
saveState(101, delayTime);
send(msg_delay_time.set(delayTime));
TRANSPORT_DEBUG(PSTR("MyS: THE NEW INTERVAL TEMP&HUM SEND VALUE IS SET: %d MIN.\n"), delayTime);
if (set_led == 1) {
digitalWrite(led_pin, ON);
wait(50);
digitalWrite(led_pin, OFF);
}
}
}
}
if (message.sensor == BATTARY_SEND_SENS_ID) {
if (message.type == V_VAR1) {
if (message.getULong() <= 168) {
send_batteryTime = message.getULong();
saveState(102, send_batteryTime);
send(msg_battary_send.set(send_batteryTime));
TRANSPORT_DEBUG(PSTR("MyS: THE NEW INTERVAL BATTERY SEND IS SET: %d HOUR\n"), send_batteryTime);
if (set_led == 1) {
digitalWrite(led_pin, ON);
wait(50);
digitalWrite(led_pin, OFF);
}
}
}
}
}
void send_data()
{
humd = sht20.readHumidity();
temp = sht20.readTemperature();
int t_humd = (int)humd;
int t_temp = (int)temp;
if (abs(temp - oldtemp) >= tempThreshold) {
send(msg_temp.set(temp, 1));
oldtemp = temp;
if (set_led == 1) {
digitalWrite(led_pin, ON);
wait(50);
digitalWrite(led_pin, OFF);
}
}
wait(100);
if (abs(humd - oldhumd) >= humThreshold) {
send(msg_hum.set(humd, 1));
oldhumd = humd;
if (set_led == 1) {
digitalWrite(led_pin, ON);
wait(50);
digitalWrite(led_pin, OFF);
}
}
TRANSPORT_DEBUG(PSTR("MyS: DATA - TEMPERATURE: %d, HUMIDITY %d\n"), t_temp, t_humd);
}
void readBatLev() {
ADMUX = _BV(REFS1) | _BV(REFS0) | _BV(MUX0);
wait(100);
RF24_startListening();
wait(200);
ADCSRA |= _BV(ADSC);
while (bit_is_set(ADCSRA, ADSC));
uint8_t low = ADCL;
uint8_t high = ADCH;
long temp = (high << 8) | low;
float vcc = temp * 1.1 / 1023 * BAT_COOF * 100;
battery = map((int)vcc, BAT_MIN, BAT_MAX, 0, 100);
if (battery < 0) {
battery = 0;
}
if (battery > 100) {
battery = 100;
}
TRANSPORT_DEBUG(PSTR("MyS: BATTERY LEVEL: %d, PREVIUS BATTERY LEVEL: %d\n"), battery, old_battery);
TRANSPORT_DEBUG(PSTR("MyS: BATTERY LEVEL ADC: %d\n"), temp);
wait(100);
sendBatteryLevel(battery);
wait(100);
send(powerMsg.set(temp));
TRANSPORT_DEBUG(PSTR("MyS: SEND BATTERY LEVEL\n"));
}
:
:
( ), Mysensors( Mysensors )

. , , , 3d
www.openhardware.io. , Mysensors —
t.me/mysensors_rus.