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.
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 }
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.
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.
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.
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.
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# 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
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.
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.
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 } } }
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. 🙂
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…
hatanın tamamını paylaşır mısınız?
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ı?
evet sensörlerden arduino seri port ekranına veri akışı var.
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.
Merhaba iyi günler. Bu sorunu nasıl çözdünüz acaba?
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
ayrıca c# daki kodu çalıştırdığımda grafik ekranda gözükmüyor
Sorunu çözdüm alperen abi Adafruit_Sensor kütüphanesini eklememişim bundan dolayı derleme hatası geliyormus
Çok sevindim Furkan başarılar diliyorum 🙂
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. 🙂
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. 🙂
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.
Merhaba.C# Kodlarını github’tan paylaşabilir misiniz?
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?
Onları kaldırmayınız. Veri kopukluğuna sebebiyet verecektir 🙁
Merhaba projenizde kullanılacak malzemeleri adeti ile birlikte detaylı bir şekilde söyleyebilir misiniz acaba