back to top

Arduino ve C# ile Mini Hava İstasyonu Yapalım – 5. Ders

Arkadaşlar merhaba, bu yazımızda Arduino’dan seri haberleşme ile birden fazla veriyi nasıl alabileceğimizi göreceğiz. Grafik kullanacağımız bir C# form uygulaması oluşturacağız ve bu grafik üstünden basınç, nem ve sıcaklık değerlerini zamana bağlı olarak takip edebileceğiz.

Mini Hava İstasyonu Projesi

Hava istasyonumuzu oluşturmak için iki sensörden faydalanacağız. Önceki yazılarımızda çokça kullandığımız DHT11 sensörünü sıcaklık ve nem verilerini almak için; BMP180 sensörünü de basıncı ölçmek için kullanacağız.

Daha önce dijital saat projemizde de DHT11 sensörünü kullanmıştık >> Dot Matrix ve Arduino ile Saat Yapalım

**BMP180 sensörü 300-1100 hPa arası basınç ölçümlerini ve 500-9000 metre arası yüksekliği ölçebilmektedir. Oldukça küçük bir boyuta sahip olan bu sensör I2C protokolünü desteklemektedir.

Arduino ve Sensörler Bağlantı Şeması

Gerekli Malzemeler:

Arduino Kodu

Bu proje için 3 kütüphaneyi kodumuza eklememiz gerekiyor. I2C protokolünü kullanacağımız için “Wire.h” kütüphanesini ekliyoruz. Bu kütüphane IDE ile beraber yüklenen kütüphaneler arasında mevcut, dışarıdan eklememize gerek yok. BMP180 ve DHT11 için gerekli kütüphaneleri indiriyoruz.

  #include <Wire.h>
  #include <Adafruit_BMP085.h>
  #include "DHT.h"
  #define DHTPIN 2 //DHT pin tanımlaması
  #define DHTTYPE DHT11 //DHT modeli tanımlaması
  Adafruit_BMP085 bmp;
  DHT dht(DHTPIN, DHTTYPE);
  void setup() {
    Serial.begin(9600);
    dht.begin();
    bmp.begin();
  }
  void loop() {
    int h = dht.readHumidity(); //Nem değerini oku
    int t = dht.readTemperature(); //Sıcaklık değerini oku
    long int p = bmp.readPressure() / 100; //Basınç değerini oku (Pa -> hPa birim dönüşümü için 100'e bölüyoruz)
    Serial.print(h); //Nem değerini seri porta gönder
    Serial.print("/");
    Serial.print(t); //Sıcaklık değerini seri porta gönder
    Serial.print("/");
    Serial.println(p); //Basınç değerini seri porta gönder
    delay(500); //500 milisaniye bekleme süresi
  }
Seri Port Ekranı

Kod içinde göndermek istediğimiz verilerin arasına ayraç ekledik. Bunu verileri birbirinden ayırmak için kullandık, C# kısmında bunun sebebini daha iyi anlayacağız.

C# Arayüz Tasarımı

Arayüz tasarımında diğer yazılardan farklı olarak “Chart” yani grafik kullanımını göreceğiz. Bu proje için gelen veriyi takip etmenin en iyi yolu grafik kullanmak olacaktır. Grafik kullanarak gün boyu değişen meteorolojik verileri kolaylıkla yorumlayabiliriz. Elbette grafikler de kendi içlerinde çeşitlere sahip, bu proje için en uygun grafik olan çizgi grafiğini kullanacağız.

ToolBox Chart Seçimi

Forma grafik eklemek için Araç Kutusu içinden Chart’ı sürüklüyorum. Karşımıza bir sütun grafiği çıkacak, grafik tipini “çizgi” olacak şekilde ayarlamamız gerekiyor. Bunun için eklediğimiz grafiğin özellikler kısmına gelerek Series kısmındaki ayarlarda kendimize göre bazı değişiklikler yapacağız.

Chart özellikleri

Bu kısımda hemen solda üyeler bölümü karşımıza çıkıyor, buradaki üye sayısını 3’e çıkarıyoruz. Üye isimlerini de basınç, nem ve sıcaklık olacak şekilde değiştiriyorum. Ardından her bir üyenin üstüne tıklayarak “Grafik” başlığının altındaki ChartType kısmını “Spline” olarak değiştiriyorum, “Line” da kullanabilirsiniz.

Grafik tipi değişikliği

Farklı tipteki üç değişkeni tek grafik üzerinde kullanmak aslında çok da sağlıklı bir gösterim değil. İkinci bir Y ekseni ile grafiği daha okunabilir hale getirebiliriz. Basınç değerleri genel olarak 950 -1050 hPa arasında seyredecektir, ikinci ekseni basınç için kullanacağız. Nem ve sıcaklığı ilk eksen üzerinden okuyacağız. Bu projedeki asıl amacımız grafik kullanımını görmek olacağından tek grafik üzerinden devam ediyoruz. Siz 3 ayrı grafik oluşturarak da projeyi gerçekleştirebilirsiniz.

Basınç değerini ikinci Y ekseni ile kullanmak için yine Series kısmındaki özelliklerden “YAxisType” kısmını “Secondary” olarak seçiyoruz. Bu sayede grafik bu eksene bağlı olarak şekillenecek.

Basınç için Y ekseni ayar değişikliği

Series kısmındaki ayarları tamamladıktan sonra anlık veriyi ve aldığımız en yüksek değerleri okuyabileceğimiz textBoxları ekliyorum. Port seçimi için gerekli araçları da ekleyerek kod kısmına geçiyorum. Tasarımdaki tüm araçları görsel üstünde görebilirsiniz.

C# Form Tasarımı

C# Proje Kodu

Kod kısmına data değişkenini ve maksimum verileri kaydedeceğim değişkenleri tanımlayarak başlıyorum.

private string data;     
double maxTemp=0, maxHum=0, maxPres=0;

Bu yazıda da önceki veri alma işlemlerinde yapmış olduğumuz gibi porttan gelen verileri “DataReceived” kullanarak alacağız. Eğer önceki yazıları okumadıysanız veri alma işlemi yaptığımız yazılara dönerek daha detaylı bilgiye ulaşabilirsiniz. Burada oluşturduğumuz “displayData” fonksiyonu içinde önceki yazılarda görmediğimiz birkaç işlem yapacağız, daha ayrıntılı bir şekilde bakalım.

Veri okuma ile alakalı yazımız >> Arduino ve C# ile Veri Okuma ve Kaydetme

displayData_event

Hatırlayacağınız üzere Arduino kısmında göndereceğimiz verilerin arasına ‘/’ eklemiştik. İşte bu kısımda verileri birbirinden ayırmak için bu ayraçtan faydalanacağız. “Split()”, bir karakter dizisini belli ayraçları kullanarak parçalara bölmeyi sağlayan bir fonksiyon. Burada “data.Split(‘/’)” ifadesi ile gelen data içindeki ‘/’ karakterini ayraç olarak kullanarak veriyi parçalıyoruz ve bir dizi içine yerleştiriyoruz. Ardından bu dizideki elemanları güncel değerleri takip edebileceğimiz textBoxlara yazdırıyoruz.

 string[] value = data.Split('/');         
 textBox1.Text = value[1];        
 textBox2.Text = value[0];        
 textBox3.Text = value[2];

String tipindeki bir değişkeni grafikte kullanamayacağımız için dizideki değerleri double tipindeki değişkenlere döndürmemiz gerekiyor. Ardından bu değişkenleri güncel zaman verisi ile beraber X ve Y eksenlerine atıyoruz.

this.chart.Series[0].Points.AddXY(myDateValue.ToString("d/M/yyyy HH:mm:ss"), temp);
this.chart.Series[1].Points.AddXY(myDateValue.ToString("d/M/yyyy HH:mm:ss"), humidity);
this.chart.Series[2].Points.AddXY(myDateValue.ToString("d/M/yyyy HH:mm:ss"), pressure);   

Bildiğiniz gibi forma tasarım kısmında maksimum değerleri gösterecek textBoxlar eklemiştik ve kod kısmında da değişkenleri tanımlamıştık. Maksimum değerleri bulmak için “maksimumBul()” adından basit bir fonksiyon oluşturabiliriz. İçine gelen değerlerin maksimumdan büyük olup olmadığını kontrol eden ve eğer büyükse maksimum değeri değiştirerek textBoxlara yazdıran bir fonksiyon oluşturduk. Bu sayede seri iletişimi başlattığımız andan itibaren bilgisayara gelen en büyük değerleri takip edebileceğiz.

maksimumBul() fonksiyonu

Bu kısımda yalnızca “DateTime”dan bahsetmedik, bu daha önceden gördüğümüz bir konu olduğu için ayrıntılı değinmedim. Burada da her data geldiğinde güncel zaman verisini almak için “DateTime.Now” kodunu kullandık ve form içinde tarih-saati gösterecek label’a yazdırdık.

Form_Load kısmında grafikteki Y eksenlerinin minimum, maksimum değerlerini ve değerler arasındaki aralığı ayarlıyoruz. X ekseni için de format ve grid ayarını yaparak bu kısmı da tamamlıyoruz. Eksen görünümü ve özellikleri ile alakalı yapılabilecek çok fazla değişiklik var. Bunları kendinize göre değiştirebilirsiniz.

Grafik axis ayarı

Kodun değinmediğimiz kısımları neredeyse her yazıda yaptığımız ve aşina olduğumuz işlemlerden oluştuğu için buralara değinmiyorum. Kodu yorum satırları ile beraber detaylı bir şekilde inceleyebilirsiniz.

using System;
using System.Windows.Forms;
using System.IO.Ports;
namespace arduino_hava_istasyonu {
  public partial class Form1: Form {
    private string data;
    double maxTemp = 0, maxHum = 0, maxPres = 0;
    public Form1() {
      InitializeComponent();
    }
    private void Form1_Load(object sender, EventArgs e) {
      string[] ports = SerialPort.GetPortNames(); //Port isimlerini al
      foreach(string port in ports)
      comboBox1.Items.Add(port); //Port isimlerini comboBox içine yaz
      chart.ChartAreas[0].AxisY2.Minimum = 850; //İkinci Y ekseni minimum değeri
      chart.ChartAreas[0].AxisY2.Maximum = 1250; //İkinci Y ekseni maksimum değeri
      chart.ChartAreas[0].AxisY2.Interval = 40; //İkinci Y ekseni aralığı
      chart.ChartAreas[0].AxisY.Minimum = 0; //Y ekseni minimum değeri
      chart.ChartAreas[0].AxisY.Maximum = 100; //Y ekseni maksimum değeri
      chart.ChartAreas[0].AxisY.Interval = 10; //Y ekseni aralığı
      chart.ChartAreas[0].AxisX.MajorGrid.LineWidth = 0; //X ekseni için grid kaldır
      chart.ChartAreas[0].AxisX.LabelStyle.Format = "d/M/yyyy HH:mm:ss"; //X eksenindeki metin formatı
    }
    private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e) {
      data = serialPort1.ReadLine(); //Gelen veriyi okuma
      this.Invoke(new EventHandler(displayData_event));
    }
    private void displayData_event(object sender, EventArgs e) {
      DateTime myDateValue = DateTime.Now; //Güncel zaman bilgisini al
      label8.Text = myDateValue.ToString(); //Güncel zaman bilgisini label8'e yaz
      string[] value = data.Split('/'); //'/' gördüğün yerlerden stringi ayır ve diziye ata
      textBox1.Text = value[1];
      textBox2.Text = value[0];
      textBox3.Text = value[2];
      double humidity = Convert.ToDouble(value[0]); //String değişkenlerini double'a dönüştür
      double temp = Convert.ToDouble(value[1]);
      double pressure = Convert.ToDouble(value[2]);
      maksimumBul(temp, humidity, pressure); //Maksimum değerleri bulmak için
      this.chart.Series[0].Points.AddXY(myDateValue.ToString("d/M/yyyy HH:mm:ss"), temp); //Zaman ve sıcaklık değerlerini eksenlere ata
      this.chart.Series[1].Points.AddXY(myDateValue.ToString("d/M/yyyy HH:mm:ss"), humidity); //Zaman ve nem değerlerini eksenlere ata
      this.chart.Series[2].Points.AddXY(myDateValue.ToString("d/M/yyyy HH:mm:ss"), pressure); //Zaman ve basınç değerlerini eksenlere ata        
    }
    private void maksimumBul(double t, double h, double p) {
      if (t > maxTemp) //Güncel sıcaklık değeri maksimumdan büyükse
        maxTemp = t;
      if (h > maxHum) //Güncel nem değeri maksimumdan büyükse
        maxHum = h;
      if (p > maxPres) //Güncel basınç değeri maksimumdan büyükse
        maxPres = p;
      textBox4.Text = maxTemp.ToString(); //Maksimum sıcaklığı yazdır
      textBox5.Text = maxHum.ToString(); //Maksimum nemi yazdır
      textBox6.Text = maxPres.ToString(); //Maksimum basıncı yazdır
    }
    private void baglan_Click(object sender, EventArgs e) {
      try {
        serialPort1.PortName = comboBox1.Text; //Port ismini comboBox1'in text'i olarak belirle
        serialPort1.BaudRate = 9600; //BaudRate'i 9600 olarak ayarla
        serialPort1.Parity = Parity.None; //Eşlik biti yok
        serialPort1.DataBits = 8; //Byte başına bit uzunluğu
        serialPort1.StopBits = StopBits.One;
        serialPort1.Open(); //Seri portu aç
        kes.Enabled = true; //"Kes" butonunu tıklanabilir yap
        baglan.Enabled = false; //"Bağlan" butonunu tıklanamaz yap 
        label9.Text = "Bağlantı sağlandı";
        label9.ForeColor = System.Drawing.Color.Green;
      } catch (Exception ex) {
        MessageBox.Show(ex.Message, "Hata"); //Hata mesajı
      }
    }
    private void kes_Click(object sender, EventArgs e) {
      try {
        serialPort1.Close(); //Seri portu kapa
        kes.Enabled = false; //"Kes" butonunu tıklanamaz yap
        baglan.Enabled = true; //"Bağlan" butonunu tıklanabilir yap
        label9.Text = "Bağlantı kesildi";
        label9.ForeColor = System.Drawing.Color.Red;
      } catch (Exception ex2) {
        MessageBox.Show(ex2.Message); //Hata mesajı
      }
    }
    private void Form1_FormClosed(object sender, FormClosedEventArgs e) {
      if (serialPort1.IsOpen) serialPort1.Close(); //Seri port açıksa kapat
    }
  }
}
Mini Hava İstasyonu Arayüzü

Bir dersin daha sonuna gelmiş olduk. Mini bir meteoroloji istasyonu kurduk diyebiliriz. Umarım faydalı olmuştur, fikirlerinizi yorumlarda bekliyorum. Sonraki yazıda seri iletişimi kablosuz olarak gerçekleştireceğiz, bunun için Bluetooth modülünden faydalanacağız. Bu projeyi de kablosuz hale getirmek güzel bir fikir olabilir. Proje fikirlerinizi yazabilirsiniz, bir sonraki yazıda görüşünceye dek, hoşça kalın. 🙂

Son Çıkan Yazılar

23 YORUMLAR

  1. merhabalar projenizin aynı şekilde yaptım ancak arduino için gerekli kütüphaneleri eklememe rağmen sürekli arduino kartı için derleme hatası alıyorum yardımcı olursanız çok sevinirim…

  2. Merhabalar projenizi aynı şekilde yaptım fakat c# bağlantı sağlamama rağmen arduino ile grafik olduğu kısım boş olarak çalışıyor.Aynı zamanla label 8 deki günlük tarihi ve zamanı göstermiyor neden olabilir.iyi çalışmalar

    • Merhaba, seri port ekranı üzerinden verilerin geldiğini görüyor musunuz, yani sensörlerden sağlıklı bir veri akışı var mı?

        • Bu sorunu çözdüm teşekkür ederim ama bu seferde An exception of type ‘System.IndexOutOfRangeException’ occurred in arduino_hava_durumu.exe but was not handled in user code

          Additional information: Dizin, dizi sınırlarının dışındaydı.
          bu hatayı veriyor neden olabilir acaba ? iyi çalışmalar

          • Oluşturduğunuz dizi ile ilgili bir hata var sanırım. Projede 3 elemanlı bir dizi oluşturuyoruz, yani 0, 1 ve 2. elemanlara değer atıyoruz. Dizi sınırları dışına değer atamaya çalışmadığınızdan emin olun.

          • Bu sorunu nasıl çözdüğünüzü sorabilir miyim acaba. Aynı sorunu yaşıyorumda.

  3. file:///C:/Users/Furkan%20Kara%C3%BCz%C3%BCm/Desktop/Yeni%20klas%C3%B6r/Ekran%20Al%C4%B1nt%C4%B1s%C4%B1.PNG

    yukarıda paylaştıgım linkte ekran görüntüsünü aldım hatanın sizce bu derleme hatası neden oluyor yardımınız için şimdiden teşekkürler

  4. BMP180 Dijital Barometre Hava Basınç Sensörü kullanmamız durumunda da proje sağlıklı çalışır mı? Malzeme listesinde verdiğiniz ürün ile arasında ne fark var?

    • Basınç sensörü olarak BMP180 kullandık bu projede, listedeki biraz daha pahalı orijinal bir versiyonu. BMP180 bulunan herhangi bir sensör kartı kullanabilirsiniz, 3.3 V ile beslemeyi unutmayın. 🙂

  5. Projeyi gerçekleştirdim, yardımınız için teşekkür ederim. Şöyle bir ekleme yapmak nasıl olur. Herhangi bir parametrenin değeri belirlenen sınırı aştığında sesli (Buzzer ile) veya ekranda uyarı biçiminde kullanıcıyı uyarmalı. Bu konuda fikrinizi merak ediyorum. Hayırlı günler dilerim.

    • Merhaba, projeyi yapmanıza sevindim. 🙂 Dediğiniz gibi bir ekleme yapılabilir tabii devreye buzzer ekleyip Arduino kodunda birkaç ekleme yapmanız gerekir. Projeye yapılacak donanım veya yazılım eklemeleri tamamen hayal gücünüze bağlı. Hatta serinin son yazısında bir e-mail uyarı sistemi yapmıştık, parametrelerdeki değer artışına bağlı olarak mail ile uyarı alabileceğiniz bir sistem de yapabilirsiniz, güzel olabilir. 🙂

  6. Merhabalar projenizi aynı şekilde yaptım fakat grafik kısmı, tarihin yazılı olduğu label ve textboxlar boş görünüyor. Arduino IDE de seri port ekranında akış var. İki farklı arduino ile denesem de sonuç aynı. Sorun nereden kaynaklı olabilir?

    • Merhaba, sorun Arduino ile ilgili değil. C# tarafında kodları doğrudan aldıysanız böyle problemler çıkabiliyor, varsayılan değişken isimleri ile bizim projedekiler farklı olunca böyle sıkıntılar olabiliyor. Adım adım gitmeye çalışın önce verileri bir labela ardından grafiğe döktürmeyi deneyerek gidebilirsiniz. Hatanın nerede olduğunu en rahat böyle anlarsınız.

  7. merhaba. Arduino tarafındaki delay komutunu kaldırdığımda veya süresini azalttığımda bu uygulama en fazla 10 saniye sonra donuyor. Hiçbir butona tıklanmıyor ve textbox’lardaki veriler değişmiyor. Bu sorun nasıl düzeltilebilir?

CEVAP VER

Lütfen yorumunuzu giriniz!
Lütfen isminizi buraya giriniz