[TUTORIAL - LENGKAP] Membuat Monitor dan Pencatat Suhu Ruangan dengan Visual Studio C# & MS SQL
1. Dasar Teori
LM35 merupakan salah satu dari sekian banyak sensor analog untuk mengukur suhu. Perubahan suhu disekitar sensor menyebabkan terjadinya perubahan nilai tahanan pada sensor, sehingga turut menyebabkan perubahan nilai tegangan output dari sensor. Perubahan nilai tegangan inilah yang dimanfaatkan oleh komponen Analog to Digital Converter (ADC) pada mikrokontroler untuk menyediakan data digital berupa data suhu yang kemudian bisa dibaca oleh mikrokontroler.
Data digital yang telah diterima oleh mikrokontroler dalam hal ini masih berupa sampel data (data mentah) sehingga perlu dilakukan kalibrasi. Kalibrasi dilakukan dengan cara memasukan sampel data tersebut ke sebuah fungsi yang didapat dari hasil perhitungan dengan kondisi suhu pada pengukuran sebenarnya (perbandingan antara hasil terukur dan aktual). Setelah data suhu sebenarnya diketahui, data suhu tersebut dikirim ke komputer menggunakan komunikasi serial untuk ditampilkan pada interface.
Aplikasi interface pada komputer selanjutnya membaca port serial (COM) tempat dimana data suhu tersebut akan dikirim oleh mikrokontroler. Data serial yang telah diterima kemudian ditampilkan pada sebuah grafik sehingga bisa terlihat data suhu pada rentang waktunya, dan dalam interval waktu tertentu fungsi catat akan mencatat data suhu ke database.
2. Alat Dan Bahan
a. Perangkat Keras
- 1 Arduino Uno R3 x 1
- 2 Kabel USB A to B x 1
- 3 Kabel Jumper x 3
- 4 Sensor Suhu LM35 x 1
b. Perangkat Lunak
- 1 Arduino IDE Ver. 1.0.5 >
- 2 Microsoft Visual Studio Ver. 2008 >
- 3 ZedGraph class library Ver. 5.1.5 (Lihat cara setupnya disini)
- 4 Microsoft SQL Server 2008 R2 >
3. Ranah Kerja
Proses pengerjaannya akan dibagi menjadi tiga bagian, yaitu :
- Perakitan Perangkat Keras
- Pemrograman arduino
- Pemrograman Interface & Database
3.1 Perakitan Perangkat Keras
Perangkat keras dirakit berdasarkan gambar berikut :
3.2 Program Pada Arduino
/** Workshop Dasar Mikrokontroler 2014 RADE - Robotics AnD Embedded Systems STMIK STIKOM Bali **/ //Pin wiper pada sensor LM32 (terminal tengah) tersambung ke Analog //Pin 3 //Yang disamping tersambung ke 5V dan Ground int analogPin = 3; //Variabel untuk menyimpan data suhu float suhu; void setup() { //Setup serial dengan baud 9600 Serial.begin(9600); } void loop() { //Baca pin input suhu = analogRead(analogPin); //Lakukan kalibrasi suhu = suhu * 0.48828125; //Kirim ke komputer melalui serial Serial.println(suhu); //Delay sebelum melakukan pembacaan selanjutnya delay(50); }
3.3 Program Pada Interface dan Database
Pertama kita akan membuat database untuk menyimpan data suhu. Buka SQL Server Management Studio dan buat query baru dengan mengklik menu New Query. Masukan query berikut dan klik Execute !
/** Buat Database DB_SUHU **/ CREATE DATABASE DB_SUHU GO /** Gunakan Database DB_SUHU **/ USE DB_SUHU GO /** Buat Tabel tbl_suhu **/ CREATE TABLE tbl_suhu ( id int PRIMARY KEY IDENTITY(1,1), suhu float, waktu datetime ) GO /** Seting format waktu ke tanggal-bulan-tahun jam:menit:detik **/ SET DATEFORMAT dmy; GO
Setelah database terbentuk, dilanjutkan dengan membuat interface pada Visual Studio. Buka Visual Studio IDE, buat proyek baru dengan tipe Visual C# dan pilih Windows > Windows Forms Application. Ketik nama proyek Monitor Suhu kemudian OK.
Mulai membuat interface dengan mendrag-and-drop masing-masing kontrol ke form. Kemudian untuk kode pada form1 atau form utama gunakan kode berikut :
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; //namespace untuk zedGrpah using ZedGraph; //namespace untuk class serial using System.IO.Ports; //namespace untuk melihat setting global komputer using System.Globalization; //Namespace untuk databse MSSQL using System.Data.SqlClient; namespace Monitor_Suhu { public partial class Form_utama : Form { /**Inisialisaisi arduino * Setup port serial dengan nama port COM65, * dan baud rate sebesar 9600. * Baud rate disini dengan di arduino harus sama * **/ SerialPort arduino = new SerialPort("COM65",9600); /**Inisialisasi databse * setup string koneksi * **/ SqlConnection cs = new SqlConnection("Data Source=localhost;Initial Catalog=DB_SUHU;Integrated Security=True"); SqlDataAdapter da = new SqlDataAdapter(); //Array list untuk menyimpan data suhu dan waktu double[] bufferSuhu = new double[10]; double[] bufferWaktu = new double[10]; List<double> listSuhu = new List<double>(); List<double> listWaktu = new List<double>(); //waktu mulai dalam milidetik double waktuStart = 100; //interval simpan ke database (menit) int intervalSimpan = 1; //pencacah interval int counter = 0; //konstruktor public Form_utama() { InitializeComponent(); } //event ketuka tombol start diklik private void btn_kontrol_start_Click(object sender, EventArgs e) { //start detak untuk mulai mengaktifkan grapher try { //matikan tombol start btn_kontrol_start.Enabled = false; //nyalakan tombol stop btn_kontrol_stop.Enabled = true; //set batas waktu pembacaan serial sebelum dinyatakan gagal arduino.ReadTimeout = 1000; //set batas waktu penulisan serial arduino.WriteTimeout = 1000; //nyalakan detak Detak.Enabled = true; //mulai detak Detak.Start(); } catch (Exception gagal) { //Error handling //MessageBox.Show(gagal.ToString()); } } //event ketika detak dimulai private void Detak_Tick(object sender, EventArgs e) { try { //increment-kan pencacah counter++; //Mulai komunikasi dengan arduino arduino.Open(); //get item kurva pertama pada grafik LineItem kurvaSuhu = zedGraphSuhu.GraphPane.CurveList[0] as LineItem; //get PointPairList IPointListEdit listSuhu = kurvaSuhu.Points as IPointListEdit; //waktu yang terlewati double waktu = (Environment.TickCount - waktuStart) / 1000.0; //baca data suhu yang dikirim arduino, //konversi data tersebut (string) ke double, //dan tambahkan ke listSuhu float dataSuhu = float.Parse(arduino.ReadLine(), CultureInfo.InvariantCulture.NumberFormat); listSuhu.Add(waktu, Convert.ToDouble(dataSuhu)); //Tutup komunikasi dengan arduino arduino.Close(); //Buat scale X tetap rolling dalam interval 30 detik, dengan satu //langkah besar antara nilai X maksimal dan akhir dari axis Scale xScale = zedGraphSuhu.GraphPane.XAxis.Scale; if (waktu > xScale.Max - xScale.MajorStep) { xScale.Max = waktu + xScale.MajorStep; xScale.Min = xScale.Max - 30.0; } // Pastikan Y axis di scale ulang untuk mengakomodir data aktual zedGraphSuhu.AxisChange(); // Redraw paksa zedGraphSuhu.Invalidate(); /** * Mencatat suhu ke database * **/ //lakukan hanya pada interval yang telah ditentukan //intervalSimpan (menit) x 60 x 2, karena 1 detak = 500 milidetik / 1/2 detik if(counter == (intervalSimpan*60*2)) { //Buat query untuk insert catatan da.InsertCommand = new SqlCommand("INSERT INTO tbl_suhu (suhu, waktu) VALUES(@SUHU, @WAKTU)",cs); da.InsertCommand.Parameters.AddWithValue("@SUHU", SqlDbType.Float).Value = dataSuhu; da.InsertCommand.Parameters.AddWithValue("@WAKTU", SqlDbType.DateTime).Value = DateTime.Now; //buka koneksi ke database cs.Open(); //eksekusi query insert da.InsertCommand.ExecuteNonQuery(); //tutup koneksi ke database cs.Close(); //reset pencacah counter = 0; } } catch (Exception gagal) { //error handling //tutup komunikasi dengan arduino jika masih terhubung if (arduino.IsOpen) { arduino.Close(); } //MessageBox.Show(gagal.ToString()); } } //event ketika tombol stop diklik private void btn_kontrol_stop_Click(object sender, EventArgs e) { try { //nyalakan kembali tombol start btn_kontrol_start.Enabled = true; //matikan tombol stop btn_kontrol_stop.Enabled = false; //stop detak Detak.Stop(); //matikan detak Detak.Enabled = false; //jika komunikasi masih terbuka, tutup komunikasi if (arduino.IsOpen) { arduino.Close(); } } catch (Exception gagal) { //error handling //MessageBox.Show(gagal.ToString()); } } //event ketika form utama dibuka private void Form_utama_Load(object sender, EventArgs e) { try { //catat waktu pertama sebagai referensi waktuStart = Environment.TickCount; //Inisialisasi ZedGraph GraphPane grafikSuhu = zedGraphSuhu.GraphPane; grafikSuhu.Title.Text = "Grafik Suhu"; grafikSuhu.XAxis.Title.Text = "Waktu (Detik)"; grafikSuhu.YAxis.Title.Text = "Suhu (Celcius)"; //Simpan 120 point. Pada 500 ms sampel rate. //RollingPointPairList adalah class penyimpanan yang efisien //dengan tetap merolling kumpulan point data tanpa perlu //men-shift nilai data apapun RollingPointPairList listSuhu = new RollingPointPairList(120); //Inisialisasi kurva LineItem kurvaSuhu = grafikSuhu.AddCurve("Suhu", listSuhu, Color.Red, SymbolType.None); } catch (Exception gagal) { //error handling //MessageBox.Show(gagal.ToString()); } } //event ketika tombol lihat diklik private void btn_lihat_Click(object sender, EventArgs e) { try { //dari tanggal DateTime dari = Convert.ToDateTime(dtPicker_dari.Text); //hingga tanggal DateTime hingga = Convert.ToDateTime(dtPicker_hingga.Text); //string koneksi untuk mengambil data dari database da.SelectCommand = new SqlCommand("SELECT * FROM tbl_suhu WHERE waktu >= @DARI AND waktu <= @HINGGA ORDER BY id ASC", cs); da.SelectCommand.Parameters.AddWithValue("@DARI", SqlDbType.DateTime).Value = dari; da.SelectCommand.Parameters.AddWithValue("@HINGGA", SqlDbType.DateTime).Value = hingga; //buka koneksi ke database cs.Open(); //eksekusi query select da.SelectCommand.ExecuteNonQuery(); //tutup koneksi ke database cs.Close(); //buat datatable untuk menampung catatan suhu DataTable dt_suhu = new DataTable(); //kosongkan dt_suhu dt_suhu.Clear(); //isi dt_suhu dengan catatan dari database da.Fill(dt_suhu); //tampilkan pada datagrid dataGrid_suhu.DataSource = dt_suhu; } catch (Exception gagal) { //error handling //MessageBox.Show(gagal.ToString()); } } } }
Lakukan pengujian dengan menghubungkan Arduino ke komputer. Periksa nama port COM yang digunakan oleh Arduino dari Device Manager, kemudian pastikan tidak ada program lain yang menggunakan port tersebut termasuk Arduino IDE agar tidak bentrok. Kemudian cocokan nama port serialnya dengan yang tertulis di program. Run program untuk memulai debugging.
Jika terjadi kesalahan atau program tidak bekerja, uncomment syntax MessageBox pada block catch masing-masing kode untuk mentracing kesalahan yang menyebabkan program tidak bekerja.
Komentar
Cara mengirim dan menerima Serial Data dari Visual Studio C# ke
if(Serial.available()>0){ start = Serial.read(); if(start == "on"){ servoMotor.write(40); } }
code tersebut untuk memutar servo sebesar 40 derajat ketika arduino menerima data serial "on". Nah setelah code tersebut di eksekusi, maka arduino langsung menjalankan code analog read yang selanjutnya akan diambil oleh Visual C#. Yang saya bingung adalah, pada tutorial ini prinsip programnya adalah ketika tombol start diklik, maka method detak yang isinya open port arduino (untuk terima data serial) akan berjalan selama satu detik, lalu port arduino akan close. Kalau seperti ini, apakah bisa saya menambahkan codeif (arduino.IsOpen) { arduino.WriteLine("on"); //untuk kirim "on" ke Arduino }
di program Visual C# saya? kalau bisa, pada bagian mana? Kalau tidak bisa, apakah ada cara lain untuk mengirim dan menerima data serial secara simultan? Terima kasih sebelumnyaKirim data ke arduino melalui serial C#
Mohon maaf sebelumnya mas, saya sudah sempat replay komentarnya namun ternyata tidak masuk... baru setelah ada komentar baru diatas saya tahu kalau komentarnya tidak masuk
Kembali ke topik, siapa tahu ada orang lain yg mengalami hal serupa, mengenai bagaimana mengirim data ke Arduino sebelum dilakukan pembacaan, caranya mudah cukup tambah pada bagian event handler untuk tombol start (skrip tambahan saya tandai dengan //START TAMBAH & //END TAMBAH ):
Itu akan mengirim "on" ke Arduino sesaat sebelum pembacaan realtime dilakukan, semoga membantu...
HTSL://HIGH THINKING SIMPLE LIVING . ME
Cara menyimpan log Data kedalam database.
Logika simpan data arduino ke database
Halo mas,
pada tutorial diatas, saya melakukan penyimpanan pada method Detak_Tick yang dieksekusi sejalan dengan interval detak yaitu setiap 1/2 detik, nah... namun pada method Detak_Tick itu proses penyimpanannya tidak langsung saya lakukan pada setiap detak, tapi saya filter lagi dengan kondisi... alasannya karena saya tidak ingin membebani database dengan record data yang terlalu intens (setiap 1/5 detik atau dua kali dalam sedetik), saya pakai kondisi if untuk memfilter agar proses penyimpanan dilakukan setiap satu menit.
Caranya mudah, cukup buat variabel counter , lalu increment setiap detak, dan cek menggunakan if jika counternya sudah sampai 120 baru kemudian simpan data yang dikirim langsung oleh arduino ke database... bisa dilihat pada bagian kode ini:
semoga membantu, jika kurang jelas silahkan tanya lagi
HTSL://HIGH THINKING SIMPLE LIVING . ME
Database tidak tersimpan
Database tidak tersimpan
Cek koneksi Database
Halo, terimakasih sudah mampir ke blog saya...
Untuk masalah yg mas alami, mungkin ada masalah dengan koneksi ke databasenya. Coba lakukan troubleshooting dengan membuka block catch pada event handler Detak_Tick, dan btn_kontrol_start_Click.. caranya cukup uncomment bagian //MessageBox.Show(gagal.ToString());
Sebelumnya coba pastikan dulu kalau arduino sudah mengirim data melalui serial (bisa di print ke console variabelnya yg bernama dataSuhu), jika tidak ada masalah dengan arduino berarti masalah ada pada bagian koneksi dengan database...
HTSL://HIGH THINKING SIMPLE LIVING . ME
Database tidak tersimpan
Tipe data & filter kiriman arduino ke C# & SQL
Maaf late reply,
mengenai error "cannot convert variable float.... " itu berarti tipe data field databasenya tidak dibuat dengan benar, saya kurang jelas database yang mas pakai sekarang apa? Jika tidak pasti, coba ganti tipe data field di databasenya menjadi varchar
mengenai pertanyaannya:
1. Cara koneksi C# ke Microsoft SQL sangat mudah, cukup install MS SQL lalu eksekusi script yang saya tulis pada bagian program databasenya. Atau jika ingin buat manual silahkan merujuk ke halaman dokumentasi MS SQL dan C#.
2. Untuk grafiknya, jika keadaannya seperti itu berarti data yang dikirim oleh Arduino tidak stabil. Coba tambahkan filter dengan kondisi if, dan set batas wajar atas dan batas wajar bawah dari data yang dikirim oleh Arduino sebelum ditampilkan ke grafik/disimpan ke database. Jika datanya tidak wajar maka abikan dengan else.
Semoga membantu, jika masih kurang jelas silahkan diskusi lagi
HTSL://HIGH THINKING SIMPLE LIVING . ME
Gagal koneksi antara VB.net dan arduino uno
Menghubungkan Arduino dengan VB.net
Halo Kang,
maaf late reply, untuk menghubungkan Arduino dengan VB.net hampir sama dengan C#. Kuncinya adalah kita bermain dengan port Serial (karena Arduino terhubung ke komputer melalui komunikasi serial). Selebihnya akang bisa coba main ke halaman dokumentasi dari VB.net di sini https://msdn.microsoft.com/en-us/library/system.io.ports.serialport(v=vs.110).aspx dan di sini https://msdn.microsoft.com/en-us/library/7ya7y41k.aspx
Semoga membantu
HTSL://HIGH THINKING SIMPLE LIVING . ME