Arduino ile Kablosuz Hava Durumu İstasyonu Projesi Yapımı
Merhaba arkadaşlar, bu yazımızda Arduino tabanlı bir Kablosuz Hava Durumu İstasyonu (Hava Tahmin Projesi) yapmayı öğreneceğiz. Aşağıdaki videoyu izleyebilir veya aşağıdaki yazılı eğitimi okuyabilirsiniz.
Genel Bakış
Hava durumu istasyonu projesinde ortam sıcaklığı ve nem, DHT22 nem sensörü kullanılarak ölçülür ve bu veriler NRF24L01 alıcı-verici modülleri kullanılarak kablosuz olarak iç üniteye gönderilir. İç ünitede, iç sıcaklık ve nemi ölçmek için başka bir DHT22 sensörü ve Arduino güç kaybetse bile zamanı takip edebilen bir DS3231 Gerçek Zaman Saati modülü vardır. Tüm bu veriler 0.96 inç OLED ekran veya elinizde bulunan farklı tür ekran üzerinde yazdırılır.
Arduino Kablosuz Hava İstasyonu Devre Şeması
Hava durumu istasyonu devre şemasına ve bu projenin nasıl çalıştığına bakalım. Bu modüllerin her birinin nasıl çalıştığı hakkında ayrıntılı eğitimlere sahip olmak için bunları kontrol edebilirsiniz: NRF24L01 Eğitimi, DHT22 Eğitimi, DS3231 Eğitimi.
Bu proje için gerekli bileşenleri aşağıdaki bağlantılardan alabilirsiniz:
Hem gerçek zamanlı saat modülü hem de OLED ekran, Arduino ile iletişim için I2C protokolünü kullanır, böylece I2C pinlerine veya Arduino Nano kartındaki 4 ve 5 numaralı analog pinlere bağlanırlar. NRF24L01 alıcı-verici modülünün hemen yanında, güç kaynağını daha kararlı tutmak için bir kapasitör vardır. Ayrıca sensörün düzgün çalışması için DHT22 veri pinine bağlı bir çekme direnci vardır.
Güç kaynağına gelince, iç ünite için 12V DC güç adaptörü kullandım ve diğer tarafta, dış üniteye güç vermek için 7.5V civarında iki Li-on pil kullandım. Sistem, bu konfigürasyon ile yaklaşık 10 gün çalışabilir, çünkü verileri periyodik olarak iletiriz ve bu arada Arduino’yu güç tüketiminin sadece 7mA olduğu uyku moduna geçiririz.
Özel Tasarım PCB
Elektronik bileşenleri düzenli tutmak için devre şemasına göre EasyEDA ücretsiz çevrimiçi devre tasarım yazılımını kullanarak özel bir PCB tasarladım. Aynı PCB’nin hem iç hem de dış ünite için kullanılabileceğini not edebiliriz. Sadece Arduino kartı farklı programlanmalıdır.
Tasarımı burada bitirdikten sonra, PCB’yi üretmek için kullanılan Gerber dosyasını dışa aktarabiliriz. Arduino kablosuz hava istasyonu EasyEDA proje dosyalarını kontrol edebilirsiniz BURADA.
Burada Gerber dosyasını sürükleyip bırakabiliriz ve yüklendikten sonra PCB’yi Gerber görüntüleyicide inceleyebiliriz. Her şey yolundaysa, PCB’imiz için istediğimiz özellikleri seçebilir ve PCB’imizi makul bir fiyata sipariş edebiliriz. JLCPCB’den ilk siparişinizse, sadece 2 $ karşılığında 10 PCB alabileceğinizi unutmayın.
Bununla birlikte, birkaç gün sonra PCB’ler geldi. PCB’lerin kalitesi mükemmel ve her şey tasarımdakiyle aynı.
Bu projenin elektronik bileşenlerini PCB’ye pim başlıklarını lehimleyerek monte etmeye başladım. Bu şekilde, gerektiğinde bileşenleri kolayca bağlayabilir ve bağlantısını kesebiliriz.
Sonra da kondansatörü ve çekme direncini yerleştirdim ve lehimledim. Bu adım tamamlandığında, bileşenleri basitçe PCB’nin pim başlıklarına bağlayabiliriz.
Sonra, proje için kutu hazırladım. Bu amaçla 8mm MDF tahta kullandım ve dairesel bir testere kullanarak tüm parçaları boyuta göre kestim.
Doğru sıcaklık ve nem ölçümlerine sahip olmak için kasaların yanları kasaya hava girmesine izin vermek zorundadır. Böylece, bir matkap ve törpü kullanarak hem iç hem de dış ünitelerin yan panellerinde birkaç yuva yaptım.
Ayrıca ön paneldeki OLED ekran için bir yuva yaptım, ayrıca daha sonra ön panele bir dekorasyon olarak ekleyeceğim küçük bir alüminyum parçasını kestim.
Kutuları monte etmek için ahşap tutkalı ve vida kullandım.
Kutuları bir sprey boya ile boyadım. Dış ünite için beyaz boya, iç ünite için siyah boya kullandım. Boya kuruduktan sonra PCB’leri kasalara yerleştirdim.
İç ünitenin arka tarafına bir güç girişi ve bir güç anahtarı taktım ve dış ünitede güç anahtarı olarak basit bir jumper teli kullandım.
Artık arduino kablosuz hava istasyonumuz çalışmaya hazır. Ancak programın nasıl çalıştığına bir göz atmak gerekiyor.
Arduino Kablosuz Hava İstasyonu Kodu
/* Arduino Wireless Communication Tutorial Outdoor unit - Transmitter by Dejan Nedelkovski, www.HowToMechatronics.com Libraries: NRF24L01 - TMRh20/RF24, https://github.com/tmrh20/RF24/ DHT22 - DHTlib, https://github.com/RobTillaart/Arduino/tree/master/libraries/DHTlib LowPower - https://github.com/rocketscream/Low-Power */ #include <SPI.h> #include <nRF24L01.h> #include <RF24.h> #include <dht.h> #include <LowPower.h> #define dataPin 8 // DHT22 data pin dht DHT; // Creates a DHT object RF24 radio(10, 9); // CE, CSN const byte address[6] = "00001"; char thChar[32] = ""; String thString = ""; void setup() { radio.begin(); radio.openWritingPipe(address); radio.setPALevel(RF24_PA_MIN); radio.stopListening(); } void loop() { int readData = DHT.read22(dataPin); // Reads the data from the sensor int t = DHT.temperature; // Gets the values of the temperature int h = DHT.humidity; // Gets the values of the humidity thString = String(t) + String(h); thString.toCharArray(thChar, 12); // Sent the data wirelessly to the indoor unit for (int i = 0; i <= 3; i++) { // Send the data 3 times radio.write(&thChar, sizeof(thChar)); delay(50); } // Sleep for 2 minutes, 15*8 = 120s for (int sleepCounter = 15; sleepCounter > 0; sleepCounter--) { LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF); } }
Açıklama: Dış ünite, kablosuz iletişimin vericisidir. Bu yüzden burada önce Arduino’yu uyku moduna geçirmek için kullanılan RF24 kütüphanesini , DHT kütüphanesini ve LowPower kütüphanesini eklememiz gerekir.
Modüllerin bağlı olduğu pimleri ve bazı değişkenleri tanımladıktan sonra, kurulum bölümünde kablosuz iletişim adresini başlatmamız gerekir. Sonra döngü bölümünde, önce DHT22 sensöründen verileri okuyoruz. Başlangıçta bu değerler tamsayıdır ve ayrılmıştır, bu yüzden onları tek bir String değişkenine dönüştüreceğiz ve radio.write () işlevini kullanarak bu verileri iç üniteye göndereceğiz. For döngüsünü kullanarak, denetleyicinin gönderme sırasında meşgul olması durumunda alıcının veri alabildiğinden emin olmak için verileri 3 kez göndeririz.
Sonunda güç tüketimini en aza indirgemek için Arduino’yu belirli bir süre uyku moduna geçiririz.
Arduino hava istasyonu iç ünite kodu:
/* Arduino Wireless Communication Tutorial Indoor unit - Receiver by Dejan Nedelkovski, www.HowToMechatronics.com Libraries: DS3231 - http://www.rinkydinkelectronics.com/library.php?id=73 U8G2 - https://github.com/olikraus/u8g2 */ #include <SPI.h> #include <nRF24L01.h> #include <RF24.h> #include <dht.h> #include <DS3231.h> #include <U8g2lib.h> #include <Wire.h> #define dataPin 8 // DHT22 sensor dht DHT; // Creats a DHT object DS3231 rtc(SDA, SCL); U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); RF24 radio(10, 9); // CE, CSN const byte address[6] = "00001"; char text[6] = ""; int readDHT22, t, h; String inTemp, inHum, outTemp, outHum; String rtcTime, rtcDate; int draw_state = 0; unsigned long previousMillis = 0; long interval = 3000; #define Temperature_20Icon_width 27 #define Temperature_20Icon_height 47 static const unsigned char Temperature_20Icon_bits[] U8X8_PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00, 0xc0, 0xe1, 0x00, 0x00, 0xe0, 0xc0, 0x01, 0x00, 0x60, 0x80, 0xf9, 0x03, 0x60, 0x80, 0x01, 0x00, 0x60, 0x80, 0x01, 0x00, 0x60, 0x80, 0x79, 0x00, 0x60, 0x80, 0x01, 0x00, 0x60, 0x80, 0x01, 0x00, 0x60, 0x80, 0xf9, 0x03, 0x60, 0x80, 0x01, 0x00, 0x60, 0x80, 0x01, 0x00, 0x60, 0x8c, 0x79, 0x00, 0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0xf9, 0x03, 0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0x79, 0x00, 0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0xf9, 0x03, 0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0x01, 0x00, 0x70, 0x9e, 0x03, 0x00, 0x38, 0x1e, 0x07, 0x00, 0x18, 0x3e, 0x0e, 0x00, 0x1c, 0x3f, 0x0c, 0x00, 0x0c, 0x7f, 0x18, 0x00, 0x8c, 0xff, 0x18, 0x00, 0x8e, 0xff, 0x38, 0x00, 0xc6, 0xff, 0x31, 0x00, 0xc6, 0xff, 0x31, 0x00, 0xc6, 0xff, 0x31, 0x00, 0x8e, 0xff, 0x38, 0x00, 0x8c, 0xff, 0x18, 0x00, 0x0c, 0x7f, 0x1c, 0x00, 0x3c, 0x1c, 0x0e, 0x00, 0x78, 0x00, 0x06, 0x00, 0xe0, 0x80, 0x07, 0x00, 0xe0, 0xff, 0x03, 0x00, 0x80, 0xff, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #define Humidity_20Icon_width 27 #define Humidity_20Icon_height 47 static const unsigned char Humidity_20Icon_bits[] U8X8_PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, 0xdc, 0x01, 0x00, 0x00, 0x8e, 0x01, 0x00, 0x00, 0x86, 0x03, 0x00, 0x00, 0x06, 0x03, 0x00, 0x00, 0x03, 0x07, 0x00, 0x80, 0x03, 0x06, 0x00, 0x80, 0x01, 0x0c, 0x00, 0xc0, 0x01, 0x1c, 0x00, 0xc0, 0x00, 0x18, 0x00, 0xe0, 0x00, 0x38, 0x00, 0x60, 0x00, 0x30, 0x00, 0x70, 0x00, 0x70, 0x00, 0x30, 0x00, 0xe0, 0x00, 0x38, 0x00, 0xc0, 0x00, 0x18, 0x00, 0xc0, 0x01, 0x1c, 0x00, 0x80, 0x01, 0x0c, 0x00, 0x80, 0x03, 0x0e, 0x00, 0x80, 0x03, 0x06, 0x00, 0x00, 0x03, 0x06, 0x00, 0x00, 0x03, 0x07, 0x00, 0x00, 0x07, 0x03, 0x00, 0x00, 0x06, 0x03, 0x00, 0x00, 0x06, 0x03, 0x00, 0x00, 0x06, 0x63, 0x00, 0x00, 0x06, 0x63, 0x00, 0x00, 0x06, 0x63, 0x00, 0x00, 0x06, 0xe3, 0x00, 0x00, 0x06, 0xc7, 0x00, 0x00, 0x06, 0xc6, 0x01, 0x00, 0x07, 0x86, 0x03, 0x00, 0x03, 0x0e, 0x1f, 0x00, 0x03, 0x0e, 0x1e, 0x80, 0x01, 0x1c, 0x00, 0xc0, 0x01, 0x38, 0x00, 0xe0, 0x00, 0x78, 0x00, 0x70, 0x00, 0xf0, 0x00, 0x38, 0x00, 0xe0, 0x07, 0x1f, 0x00, 0x80, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00 }; void setup() { radio.begin(); radio.openReadingPipe(0, address); radio.setPALevel(RF24_PA_MIN); radio.startListening(); u8g2.begin(); rtc.begin(); } void loop() { if (radio.available()) { radio.read(&text, sizeof(text)); // Read incoming data outTemp = String(text[0]) + String(text[1]) + char(176) + "C"; // Outdoor Temperature outHum = String(text[2]) + String(text[3]) + "%"; // Outdoor Humidity } unsigned long currentMillis = millis(); if (currentMillis - previousMillis > interval) { previousMillis = currentMillis; u8g2.firstPage(); do { switch (draw_state ) { case 0: drawDate(); break; case 1: drawInTemperature(); break; case 2: drawInHumidity(); break; case 3: drawOutTemperature(); break; case 4: drawOutHumidity(); break; } } while ( u8g2.nextPage() ); draw_state++; if (draw_state > 4) { draw_state = 0; } } } void drawDate() { String dowa = rtc.getDOWStr(); dowa.remove(3); rtcDate = dowa + " " + rtc.getDateStr(); u8g2.setFont(u8g2_font_timB14_tr); u8g2.setCursor(0, 15); rtcTime = rtc.getTimeStr(); // DS3231 RTC time rtcTime.remove(5); u8g2.print(rtcDate); u8g2.setFont(u8g2_font_fub30_tf); u8g2.setCursor(8, 58); u8g2.print(rtcTime); } void drawInTemperature() { readDHT22 = DHT.read22(dataPin); // Reads the data from the sensor t = DHT.temperature; // Gets the values of the temperature inTemp = String(t) + char(176) + "C"; u8g2.setFont(u8g2_font_helvR14_tr); u8g2.setCursor(24, 15); u8g2.print("INDOOR"); u8g2.setFont(u8g2_font_fub30_tf); u8g2.setCursor(36, 58); u8g2.print(inTemp); u8g2.drawXBMP( 0, 17, Temperature_20Icon_width, Temperature_20Icon_height, Temperature_20Icon_bits); } void drawInHumidity() { h = DHT.humidity; // Gets the values of the humidity inHum = String(h) + "%"; u8g2.setFont(u8g2_font_helvR14_tr); u8g2.setCursor(24, 15); u8g2.print("INDOOR"); u8g2.setFont(u8g2_font_fub30_tf); u8g2.setCursor(36, 58); u8g2.print(inHum); u8g2.drawXBMP( 0, 17, Humidity_20Icon_width, Humidity_20Icon_height, Humidity_20Icon_bits); } void drawOutTemperature() { u8g2.setFont(u8g2_font_helvR14_tr); u8g2.setCursor(12, 15); u8g2.print("OUTDOOR"); u8g2.setFont(u8g2_font_fub30_tf); u8g2.setCursor(36, 58); u8g2.print(outTemp); u8g2.drawXBMP( 0, 17, Temperature_20Icon_width, Temperature_20Icon_height, Temperature_20Icon_bits); } void drawOutHumidity() { u8g2.setFont(u8g2_font_helvR14_tr); u8g2.setCursor(12, 15); u8g2.print("OUTDOOR"); u8g2.setFont(u8g2_font_fub30_tf); u8g2.setCursor(36, 58); u8g2.print(outHum); u8g2.drawXBMP( 0, 17, Humidity_20Icon_width, Humidity_20Icon_height, Humidity_20Icon_bits); }
Açıklama: Diğer tarafta, iç ünitede veya alıcıda, biri DS3231 gerçek zamanlı saat modülü ve diğeri OLED ekran için U8G2 kütüphanesi olmak üzere iki kitaplık daha eklememiz gerekiyor. Daha önce olduğu gibi, aşağıdaki program için gereken örnekleri, pinleri ve bazı değişkenleri tanımlamamız gerekir. Ayrıca burada sıcaklık ve nem simgelerini bitmap olarak tanımlamamız gerekir.
Sıcaklık Simgesi Bitmap:
#define Temperature_20Icon_width 27 #define Temperature_20Icon_height 47 static const unsigned char Temperature_20Icon_bits[] U8X8_PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00, 0xc0, 0xe1, 0x00, 0x00, 0xe0, 0xc0, 0x01, 0x00, 0x60, 0x80, 0xf9, 0x03, 0x60, 0x80, 0x01, 0x00, 0x60, 0x80, 0x01, 0x00, 0x60, 0x80, 0x79, 0x00, 0x60, 0x80, 0x01, 0x00, 0x60, 0x80, 0x01, 0x00, 0x60, 0x80, 0xf9, 0x03, 0x60, 0x80, 0x01, 0x00, 0x60, 0x80, 0x01, 0x00, 0x60, 0x8c, 0x79, 0x00, 0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0xf9, 0x03, 0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0x79, 0x00, 0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0xf9, 0x03, 0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0x01, 0x00, 0x70, 0x9e, 0x03, 0x00, 0x38, 0x1e, 0x07, 0x00, 0x18, 0x3e, 0x0e, 0x00, 0x1c, 0x3f, 0x0c, 0x00, 0x0c, 0x7f, 0x18, 0x00, 0x8c, 0xff, 0x18, 0x00, 0x8e, 0xff, 0x38, 0x00, 0xc6, 0xff, 0x31, 0x00, 0xc6, 0xff, 0x31, 0x00, 0xc6, 0xff, 0x31, 0x00, 0x8e, 0xff, 0x38, 0x00, 0x8c, 0xff, 0x18, 0x00, 0x0c, 0x7f, 0x1c, 0x00, 0x3c, 0x1c, 0x0e, 0x00, 0x78, 0x00, 0x06, 0x00, 0xe0, 0x80, 0x07, 0x00, 0xe0, 0xff, 0x03, 0x00, 0x80, 0xff, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
Bu amaçla, açık kaynak kodlu bir resim editörü olan GIMP’i kullanabiliriz. Bu sayede her şeyi çizebilir ve bitmap (.xbm) olarak dışa aktarabiliriz.
Sonra bu dosyayı bir not defteri kullanarak açabiliriz ve oradan bitmap’i Arduino koduna kopyalayabiliriz.
Burada bitmap’i PROGMEM değişkenini kullanarak sabit olarak tanımlayabileceğimizi ve bu şekilde bitmap’in Arduino kartının SRAM yerine flash bellekte saklanacağını unutmayın.
static const unsigned char Temperature_20Icon_bits[] U8X8_PROGMEM // Save in the Flash memory static unsigned char Temperature_20Icon_bits[] // Save in the SRAM
Kurulum bölümünde OLED ekranı ve gerçek zamanlı saat modülünü başlatmanın yanı sıra kablosuz iletişimi başlatmamız gerekiyor.
Sonra döngü bölümünde sürekli olarak NRF24L01 modülleri aracılığıyla okunabilecek bir veri olup olmadığını kontrol ediyoruz. True ise, radio.read () işlevini kullanarak okuruz ve ilk iki karakteri temperature String değişkenine ve sonraki iki karakteri humidity String değişkenine kaydederiz.
Ardından, 3 saniyeye ayarladığım aralık değişkeni ile tanımlanan aralıklarda çeşitli verileri ekranda görüntülemek için millis () işlevini kullanırız. Millis () işlevini kullanıyoruz, çünkü bu şekilde kodun geri kalanı tekrar tekrar çalıştırılabilirken, delay () işlevini kullanmamız durumunda, program bu dönemi bekler.
Ardından, U8G2 kütüphanesinin firstPage () ve nextPage () işlevini kullanarak, özel işlevlerle tanımlanan beş farklı ekranı yazdırırız.
DrawDate () özel işlevi, tarih ve saat bilgilerini gerçek zamanlı saat modülünden alır ve uygun şekilde ekrana yazdırır. DrawInTemperature () işlevi iç sıcaklığı okur ve uygun şekilde ekrana yazdırır. Aslında, aynı yöntem tüm verileri ekrana yazdırmak için kullanılır.
Hepsi bu kadar. Umarım makalemizi beğenmiş ve yeni bir şeyler öğrenmişsinizdir.
Memnun kaldıysanız aşağıda bulunan “yukarı ok” işaretine tıklayarak +1 puan verebilirsiniz.
Diğer Güncel Arduino Projeleri için BURAYA TIKLAYABİLİRSİNİZ.
Sizde Robotlara ve Maker’lığa Meraklıysanız Robotik Marketimiz ROBOCOMBO‘yu Ziyaret Edebilirsiniz.
Robot El Yapımı – İlginç Arduino Projeleri
Videodaki Robot El Ürünümüzü Satın Almak İsterseniz Bağlantıya Göz Atabilirsiniz.
Okuduğunuz İçin Teşekkürler.
Kaynak: howtomechatronics.com/tutorials/arduino/arduino-wireless-weather-station-project/