Uzunca bir zaman sonra merhaba. İhtiyaç duyduğum bir proje için en iyi prototipleme aracı olduğunu düşündüğüm Arduino’dan yardım almam gerekti. Enson 2 yıl kadar önce hafif birşeyler çalıştığım Arduino ile ilgili neredeyse hiç not tutmamam sebebiyle yaptığım çalışmaları buraya not düşerek ilerlemeye karar verdim.
Projemde PC ile haberleşme ihtiyacı olmasa da 2 yılın verdiği hamlığı atmak ve bu güzel cumartesiyi güzel bir etkinlikle geçirmek için işin içine bilgisayarla haberleşmeyi de kattım. Projemin önemli detaylarından birisi sıcaklık ve nem verileri ile ilişkili karar mekanizmaları oluşturmak. Bu yazının konusu da sıcaklık ve nem sensörü olan DHT22 üzerinden C#üzerine değer almaya çalışmak. (bir sonraki step/görev Android olsun)
Önce internette bilgilerine kolayca ulaşabileceğiniz DHT22 sensörünü kabaca tanıyalım;
3.3 – 6 V besleme gerilimde kullanılabilir
Maksimum 1.5mA akım tüketimi
%0 – %100 arası nem ölçümünde %2 – (Max%5) doğruluk
-40 / +80°C arası sıcaklık ölçümünde ±0.5°C doğruluk (DS18B20)
Maksimum 0.5 Hz örnekleme hızı (Min 2 saniyede bir okuma yapılabilir)
Robotistan’ın sayfasında datasheet’i detaylı inceleyebilirsiniz : LINK
DHT22 ‘nin kullanım için pin dağılımı şöyledir ;
Bu tabloya göre pin dağılımı;
#1 – VCC : 3.3V – 6V arası kullanılabilir. Biz Arduino üzerinde 5V’luk pini kullanacağız
#2 – Data in/out
#3 – Boş pin
#4 – GND : Toprak
Fritzing’de hazırladığım sketch ise şöyle;
ilk bacağı 5V pinine, 4.bacağı GND (toprak) pinine bağlıyoruz. Data pini olarak 2 nolu pini 10K’lık bir dirençle kullanıyoruz. Sketch’de de görmüşsünüzdür, direncin bi ucu Arduino’nun 2 nolu pini ile sensörün 2 nolu bacağını 1 nolubacak ile güç kaynağımız olan 5V pin arasına uyguluyoruz. Eğer bunu yapmazsak veri alamıyoruz.
Benim çalışmamın son görüntüsü şu şekilde;
Skecth’i hazırladıktan sonra sensörün çalışabilmesi için sensör kullanım kütüphanesini indirip, programımızın kurulu olduğu dizin altında library’e açmamız gerekiyor.
Kütüphanenin son halini güncel olarak şu adreste bulabilirsiniz;
http://playground.arduino.cc/Main/DHTLib
İndirdiğiniz sıkıştırılmış dosyayı açmanız gerek adreste şöyle;
C:\Program Files\Arduino\libraries
Sketchi hazırladınız, kütüphaneyi kurdunuz, şimdi programımız menülerinden sensör imalatçısının örnek uygulamasını deneyebilirsiniz. Adresi şöyle;
File>Examples>DHT Sensor Library>DHTtester
Bağlantılarla ilgili bir sorun yaşamadıysanız sorunsuz çalışıyor olması gerek. Çalıştığını “görmek” için uygulama üzerinde bulunan serial port’u açmanız gerekiyor.
Konu başlığındada belirttiğim gibi seriportla haberleşen bir uygulmaya odaklanmamız gerekiyor. Sensor imalatcısının uygulaması arduino çalışmaya başladıktan sonra seriporta düzenli olarak 2 saniye frekansla nem, sıcaklık ve hissedilen sıcaklık değerlerini yazıyordu.
Bizse C# uygulamamız içinden veri istendiğinde bize sıcaklık ve nem değerlerini vermesini istiyoruz. Buna göre kodu biraz devşirmek zorunda kaldım. Algoritmaya göre bağlanılan seriportta “deger” stringi girilip gönderirse geriye sıcaklık ve nem değerlerini döndüreceğiz.
Önce sonucu gösterip, sonra Arduino kodlarını paylaşayım;
Sorunsuz çalışıyor, kodları da paylaşayım;
#include "DHT.h" // Kütüphane #define DHTPIN 2 // Bağlı olduğumuz pin #define DHTTYPE DHT22 // DHT 22 (AM2302) Sensörümüzün tipi DHT dht(DHTPIN, DHTTYPE); String getValue = ""; // Seriport'ta gelen metini taşır void setup() { pinMode(13, OUTPUT); // Haberleşme sırasında görsel uyarı olsun Serial.begin(9600); // Seri haberleşme başlıyor dht.begin(); // Sensor başlatılıyor }//setup void loop() { digitalWrite(13, LOW); // LED : OFF float h = dht.readHumidity(); // Nem değeri float t = dht.readTemperature(); // Sıcaklık degeri while (Serial.available() > 0) { digitalWrite(13, HIGH); // LED : ON int inChar = Serial.read(); // Seriport oku if (inChar != '\n') { // Satırsonu gelene kadar oku getValue += (char)inChar; }//if else { // Satırsonu gelince gelen değere bak if (getValue == "deger"){ // Seriporta "deger" yazılmışsa sıcaklık ve nem gönder if (!(isnan(t) || isnan(h))){ Serial.print("Sicaklik: "); Serial.print(t); // Sıcaklık Serial.print(" C"); Serial.print(" \t"); Serial.print("Nem : % "); Serial.println(h); // Nem delay(1*3000); // Bekleyelim biraz } }//if getValue = ""; }//else }//while }//loop
Benim için asıl zor olan kısmı şimdi başlıyor (hep karşısında olduğum microsoft ürünleri ile geliştirmekte çok ama çok zorlanıyorum aslında!) . C#’dan seri porta sihirli kelimemizi gönderelim, ve gelen yanıtı karşılayalım. Tabi internette küçük bir aramayla yüzlercesine ulaşabilirsiniz, bende öyle yaptım.
Boş form üzerine serialport, 2 text yada combobox 2 buton koyarak rahatlıkla yapabilirsiniz. Ben statusbarları sevdiğim için alta statusStrip’de koydum. Son tasarım hali aşağıdaki gibi oldukça sade ve yalındır (üzerine tıklayarak büyütebilirsiniz)
Uygulamanın ekran görüntüleri şöyledir;
Açılış sırasında default port ve hız ile açılıyor. Siz uygulama içinden dilediğiniz gibi değiştirip bağlantı sağlayabiliyorsunuz. Bağlantı oluşunca kullanıcıya bir uyarı veriyor.
Seriport’a bağlandık ama hatırlarsanız veri çekmekden bahsetmiştik. Bunun için oluşturduğumuz Veri Çek butonu devreye giriyor. Bu butona tıkladığımızda ise seriporta deger kelimesini gönderip, sonucu çekiyoruz.
Kodlara gelirsek, try-catch gibi hata kontrolleri yok, sınıfsal bir çalışma yok hatta değişkenleride çok cimri kullanmadım. Eğer ciddi bir uygulama çalışacaksanız detayları atlamayın. Ben gereken noktaları kod içinde açıkladım.
Kodlarımız şöyle;
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.IO; using System.IO.Ports; namespace WindowsFormsApplication2 { public partial class Form1 : Form { String RxString = ""; // Seri porttan gelen veriler String RxStringLine = ""; // Seri porttan gelen veri cümlesi public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { //Seri haberleşme için Default değerlerimizi seçiyoruz comboBox1.SelectedIndex = comboBox1.Items.IndexOf("COM3"); comboBox2.SelectedIndex = comboBox2.Items.IndexOf("9600"); } //Seriporta Bağlan Butonu private void button1_Click_1(object sender, EventArgs e) { serialPort1.PortName = comboBox1.Items[comboBox1.SelectedIndex].ToString(); serialPort1.BaudRate = Convert.ToInt32(comboBox2.Items[comboBox2.SelectedIndex].ToString()); toolStripStatusLabel1.Text = "Port: " + serialPort1.PortName + " - Hız: " + serialPort1.BaudRate; if (!serialPort1.IsOpen == false) { serialPort1.Close(); } serialPort1.Open(); button3.Enabled = true; MessageBox.Show("Bağlantı Sağlandı", "Bilgilendirme", MessageBoxButtons.OK, MessageBoxIcon.Information); } //Seriportla bağlantı kes Butonu private void button2_Click(object sender, EventArgs e) { serialPort1.Close(); MessageBox.Show("Bağlantı Kesildi", "Bilgilendirme", MessageBoxButtons.OK, MessageBoxIcon.Information); } //Form kapanırken seriport açık kalmasın private void Form1_FormClosing(object sender, FormClosingEventArgs e) { if (serialPort1.IsOpen) serialPort1.Close(); } //Veri Çek butonu private void button3_Click(object sender, EventArgs e) { RxStringLine = ""; serialPort1.Write("deger\n"); } //Seriporttan veri gelirse... private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e) { RxString = serialPort1.ReadExisting(); this.Invoke(new EventHandler(DisplayText)); } //Metni göster private void DisplayText(object sender, EventArgs e) { foreach (var i in RxString) { RxStringLine = RxStringLine + i; } label3.Text = RxStringLine; } } }
Yaptığınız çalışmalarınızda umarım faydasını görürsünüz.
Hakan Müştak @2015
Bilgi : DHT11 içinde benzer yol izleyebilirsiniz
SHT15’in DHT22’den daha stabil ve doğru çalıştığı bilgisini öğrendim. Daha ciddi projeler için not olarak düşmekte fayda var.
Merhaba Hakan kardeşim,
Her zamanki formdasın. Arduino’ya doğru sürüklendiğimi hissediyorum 🙂
Öncelikle sizi, eksikliğinizi yakınen hissediyorum, çok özledik.
Geçmiş senelerde yazma isteğim çok olmadığı için, havada kalmış, uçmuş herşey. Bu sefer yazmak ve gerektiğinde dönüp okumak istiyorum. Sırf o yüzden yazıyorum aslında 🙂
Bu yapıcağımız,program ile Arduino programını kurmadan sadece Arduino Driver’ını yükleyerek çalıştırabilir miyiz?
Serial Manitör’den oluyordu ve bu iş arduino arayüzünden zahmetli bir işlemdi yani demek istediğim.Bu program ile daha kolay mı oluyor ?
Soruyu net anlamadım açıkcası ama; Arduino IDE’sini, Driver’ını, yada serial monitoru yüklemediğiniz bir bilgisayarda çalışan C# uygulamanızla donanımınızı bu şekilde haberleştirebilirsiniz.
Cevabınız için teşekkürler,sorum için kusura bakmayın vaktim olmadığı için biraz anlamsız yazmış olabilirim.
@hmustak
Kodlar Çalışmıyor.
Gerekli tabloyu vs. herşeyi oluşturdum fakat çalışmıyor yaklaşık 10 tane hata buldu program.
Kendimce düzelttim ama program çalışmıyor.
Merhaba, Denemediğim, çalıştığından emin olmadığım hiçbir kodu sitemde paylaşmam. Eminim atladığınız bir şeyler vardır.
Rica Etsem,Exe’li bir şekilde reklamsız olarak paylaşabilir misiniz?
Ödevim var,benim için çok gerekli.
Hakan bey aldığım hata şöyle ;
Error 1 Expected class, delegate, enum, interface, or struct C:\Users\LAB2\Desktop\Form1.cs 60 13 WindowsFormsApplication2
4 tane hatam var hepside böyle:
—- KOD —-
—- / KOD —-
Hakan Bey sorunumu çözdüm sadece DisplayText oluşturamadım DisplayText nereden oluşturabilirim?
Telefonla ezbere yaziyorum
serialPort1_DataReceived icinde eventhandleri cagirdiginizda bu fonksiyonu ide otomatik yazmali. Yazmuyorsa da copy/paste’le yazabilirsiniz.
Sanirim label yada textbox gibi bir nesne zannettiniz.
Teşekkürler,Hakan Bey çok yardımcı oldunuz.
hakan bey serialPort1.Write(“deger\n”); kısmını anlamadım ve sürekli buradan hata alıyorum. deger değişkeni formda tanımlı olmadığı için sürekli hata alıyorum. Yardımcı olursanız sevinirim 🙄
Günaydın, aslında yazıda ki örnekte de verdiğim gibi manuel yada program içinden seriport aracılığı ile sensorun bağlı olduğu işlemciye “deger” string’i geldiğinde sıcaklık ve nemi okuyup göndermesini sağlamak. Bunu işlemciye gömülen kodun 28. satırında görüyoruz. Kodun bir üzerindeki seriport bağlantısında da manuel, el ile “deger” yazıp gönderirken bir ekran görüntüsü de koymuşum konu anlaşılsın diye.
C# kodu içinde ise temelde, sıcaklık ve nemi alabilmek için uygulama içinden serialPort1.Write(“deger\n”) ile “deger” stringini gönderiyor (C# kodunun 67.satırı) ve sonrasında da işlemcinin sıcaklık nem değerlerini çekiyoruz.
Kendim hata alıyor olsaydım ilk bakacaklarım; Sayfama SerialPort1 nesnesi koyup koymadığım ve port ayarlarımın doğru olup olmadığı olurdu.
Selamlar 😉
Hallettim hocam çok sağolun. deger değişkenini tırnak içerisinde yazmazsak çalışmıyormuş görmüş oldum. 😛 😛
String değil değişken olarak yazmaya çalışmışsınız 🙂 Geçmiş olsun. uygulama sorunsuz çalışıyor değil mi? 😉
Port kısmı sıkıntı hocam. Port bilgisi combobox a gelmiyor. Doğal olarak hız bilgisi ile alakalı combobox ta çalışmıyor. O bilgileri el ile girince de tahmin edeceğiniz üzere serialPort1.PortName = comboBox1.Items[comboBox1.SelectedIndex].ToString(); kodunda hata veriyor. Çözecez inşallah 🙂