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.

Yazıda Neler Var? 100TL üzeri %7 indirim kodunu unutma! maker7 gizle

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. 🙂

CEVAP VER

Please enter your comment!
Please enter your name here