i
MONSTER ARDUINO Panduan Praktis Belajar Arduino untuk Pemula
Versi 2
|
HARI SANTOSO www.elangsakti.com
i
KOBARKAN SEMANGAT INDONESIA!
ii
MONSTER ARDUINO 2 Ebook ini merupakan lanjutan dari ebook sebelumnya yang berjudul “Panduan Praktis Belajar Arduino untuk Pemula” yang kita bagikan secara gratis. Dengan terbitnya ebook terbaru ini, maka ebook tersebut akan kita rapikan kembali dan akan kita beri nama MONSTER ARDUINO 1. Ebook edisi pertama berisi tentang pengenalan Arduino, cara instalasi Arduino IDE, setting driver, bahasa yang yang dipakai, tipe-tipe data, dan semua hal yang sifatnya dasar terkait dasar-dasar untuk memulai pemrograman Arduino. Pada MONSTER ARDUINO 2, kita akan membahas sedikit lebih dalam terkait teknik dan tips dalam memprogram serta contoh pemrograman sensor, display, dan pengolah data di Arduino. Kedepan, serial ebook MONSTER ARDUINO akan kita kembangkan lagi dengan pembahasan yang lebih dalam dan lebih spesifik. Masih banyak yang harus dipelajari agar kita dapat berinovasi dengan Arduino. Masukan ide, kritik, dan saran yang membangun boleh dikirim ke
[email protected]. Kita tunggu email dari Anda. Salam hangat, Hari. iii
KOBARKAN SEMANGAT INDONESIA!
iv
CATATAN PENULIS Penulis sangat bersyukur, atas rahmat Allah, penulis masih diberi kemampuan untuk melanjutkan penulisan buku tentang Arduino versi 2 setelah beberapa bulan vakum. Semoga versi berikutnya bisa rilis lebih cepat. Terima kasih penulis ucapkan kepada istri tercinta, Aprillia Dewi Kreswanti, yang telah merelakan waktu keluarga demi terselesaikannya penulisan ebook ini. Terima kasih juga kepada kawan-kawan yang sudah request untuk join ke grup facebook MONSTER ARDUINO, berkat kalian penulis menjadi lebih bersemangat untuk berbagi pengalaman melalui media sosial. Selanjutnya, semoga ebook ini bermanfaat bagi penggiat Arduino, bagi yang ingin berinovasi di ranah teknologi, robotika, dan IoT. Salam hangat penuh semangat!
Malang, 11 September 2017,
Hari Elangsakti v
KOBARKAN SEMANGAT INDONESIA!
vi
DAFTAR ISI MONSTER ARDUINO 2 .............................................................................iii CATATAN PENULIS .................................................................................. v DAFTAR ISI............................................................................................ vii #00 SEBELUM MULAI ............................................................................... 1 #01 MEMINANG ARDUINO ....................................................................... 3 1.1 Jenis Arduino untuk Pemula ............................................................. 6 1.2 Project yang Butuh Banyak Pin I/O .................................................... 7 1.3 Program dengan Clock Tinggi .......................................................... 8 1.4 Project dengan Ukuran Program Besar .............................................. 9 1.5 Saatnya Memilih!.......................................................................... 11 #02 ARDUINO DAN BOOTLOADER ........................................................... 12 2.1 Sekilas tentang Bootloader ............................................................ 12 2.2 Cara Install Bootloader Arduino ...................................................... 16 2.2.1 Install Bootloader dengan USBAsp ............................................ 17 2.2.2 Arduino Sebagai ISP Programmer ............................................. 24 2.2.3 Install Bootloader dengan Arduino ............................................ 26 2.2.4 Pengecekan Hasil Instalasi Bootloader ....................................... 29 #03 HELLO BUZZER ............................................................................... 30 3.1 Project Hello Buzzer ..................................................................... 30 3.1.1 Rangkaian Hello Buzzer........................................................... 30 vii
3.1.2 Program Hello Buzzer............................................................. 31 3.2 Buzzer Aktif dan Buzzer Pasif ......................................................... 33 3.3 Project Dummy Logger ................................................................. 34 #04 TIPS MEMILIH TIPE DATA ................................................................. 38 4.1 Byte dan Boolean, 1 Byte ............................................................... 39 4.2 Char atau Unsigned Char, 1 Byte.................................................... 41 4.3 Integer dan Unsigned Integer, 2 Byte............................................... 41 4.4 Long dan Unsigned Long, 4 Byte ..................................................... 42 4.5 Float atau Double, 4 Byte............................................................... 42 4.6 Volatile & Interrupt ...................................................................... 42 4.7 PROGMEM .................................................................................. 44 4.8 String dengan F( ) ........................................................................ 45 #05 OPTIMALISASI DELAY ...................................................................... 47 5.1 Seberapa Cepatkah 16MHz itu? ...................................................... 47 5.2 Project Perbaikan Dummy Logger ................................................... 50 5.3 Program Simpel Delay yang Responsive ........................................... 56 #06 RESPONSIVE DENGAN TIMER INTERRUPT ........................................... 59 6.1 Seperti Apa Timer Interrupt? .......................................................... 59 6.2 Program Timer Interrupt Sederhana ................................................ 60 6.3 Dummy Logger dengan Timer Interrupt ........................................... 63 #07 WDT & PROGRAM ANTIMACET ......................................................... 68 7.1 Program WDT Sederhana .............................................................. 71 7.2 Program WDT Lanjutan ................................................................. 73 #08 MODUL RELAY................................................................................ 76 viii
8.1 Active Low atau Active High ........................................................... 79 8.2 Masalah yang Sering Muncul.......................................................... 80 8.3 Mengisolasi Power Supply ............................................................. 81 8.4 Sekilas tentang SSR (Solid State Relay) ............................................. 83 #09 EKSPLORASI TOMBOL PUSH BUTTON ................................................. 85 9.1 Internal Pullup Resistor ................................................................. 86 9.1.1 Rangkaian Testing Pullup Resistor ............................................ 87 9.1.2 Program Tombol tanpan Pullup Resistor .................................... 88 9.1.3 Program Tombol dengan Internal Pullup Resistor........................ 90 9.2 Membuat Tombol Multikondisi ....................................................... 91 9.2.1 Program Tombol yang Manusiawi ............................................. 92 9.2.2 Program Tombol dengan Lock Status......................................... 94 9.2.3 Program Tombol Modular ....................................................... 97 9.2.4 Program Satu Tombol Banyak Menu........................................ 100 9.3 Membuat Aksi Tombol yang Ditekan Lama ..................................... 104 9.3.1 Program Aksi Tombol Berdasarkan Lama Ditekan ...................... 105 9.4 Mengelola Banyak Tombol dengan Satu Pin.................................... 110 9.4.1 Rangkaian Program untuk Membaca 5 Tombol ......................... 112 9.4.2 Program Analisis Output Tombol ............................................ 113 9.4.3 Program Menu 5 Tombol....................................................... 115 9.4.4 Rangkain 5 Tombol 5 LED ...................................................... 119 9.4.5 Program 5 Tombol 5 LED....................................................... 121 #10 EEPROM SEBAGAI BLACKBOX.......................................................... 126 ix
10.1 Program Simulasi EEPROM .........................................................128 10.2 Program EEPROM 5 Tombol 5 LED ...............................................131 #11 PIN OUTPUT YANG MELIMPAH ........................................................137 11.1 Rangkaian Dasar IC 74HC595.......................................................140 11.2 Project LED Berjalan ..................................................................141 11.2.1 Rangkaian LED Berjalan........................................................141 11.2.2 Program LED Berjalan ..........................................................142 11.2.3 Rangkaian Shift Register dengan SPI.......................................145 11.2.4 Program Shift Register dengan SPI .........................................146 #12 SERBA-SERBI DISPLAY 7 SEGMENT....................................................149 12.1 Seven Segment 1 Digit................................................................151 12.1.1 Rangkaian Seven Segment 1 Digit ..........................................152 12.1.2 Program Seven Segment 1 Digit.............................................153 12.2 Seven Segment 4 Digit................................................................160 12.2.1 Rangkaian Seven Segment 4 Digit ..........................................160 12.2.2 Program Seven Segment 4 Digit.............................................162 12.2.3 Program Seven Segment Rata Kanan ......................................169 12.3 Seven Segment dengan Library SevSeg..........................................170 12.3.1 Program Seven Segment dengan Sevseg .................................170 12.4 Seven Segment dengan Shift Register ...........................................172 12.4.1 Rangkaian 7 Segment 1 Digit dengan Shift Register ..................172 12.4.2 Program 7 Segment 1 Digit dengan Shift Register ....................173 12.4.3 Rangkaian Seven Segment 2 Digit dengan Shift Register ............176 12.4.4 Program Seven Segment 2 Digit dengan Shift Register ..............177 x
12.4.5 Rangkaian Seven Segment 4 Digit dengan Shift Register ........... 180 12.4.6 Program Seven Segment 4 Digit dengan Shift Register ............. 182 #13 LEBIH CANTIK DENGAN LCD1602 .................................................... 187 13.1 Sekilas Modul I2C LCD ............................................................... 187 13.2 Rangkaian Dasar Modul I2C LCD ................................................. 189 13.3 Program Mencari Alamat Modul I2C ............................................ 191 13.4 Program Mengontrol Lampu Backlight LCD.................................. 194 13.5 Program Format Teks LCD.......................................................... 197 13.6 Program Efek Teks NgeBlink....................................................... 200 13.7 Program Format Teks dan NgeBlink............................................. 202 13.8 Program Teks Bergerak ............................................................. 205 13.9 Program Membuat Custom Karakter LCD ..................................... 210 #14 ALARM SENSOR PIR....................................................................... 214 14.1 Sensor PIR HC-SR501 ................................................................ 216 14.2 Rangkaian Sensor HC-SR501....................................................... 219 14.3 Program Alarm Sensor PIR ......................................................... 220 14.4 Program Identifikasi Delay Sensor PIR.......................................... 221 14.5 Program Custom Delay Alarm Sensor PIR ..................................... 224 #15 SENSOR DHT11 & KUMBUNG JAMUR ............................................... 228 15.1 Sensor DHT11 .......................................................................... 228 15.2 Akuisi Data Sensor DHT11 .......................................................... 230 15.2.1 Rangkaian Dasar Sensor DHT11 ............................................ 230 15.2.2 Program Akuisisi Data Sensor DHT11 ..................................... 231 xi
15.3 Menampilkan Data pada LCD ......................................................234 15.3.1 Program Sensor Suhu dan Kelembaban Digital .........................235 15.4 Project Kumbung Jamur Sederhana ..............................................238 15.4.1 Rangkaian Project Kumbung Jamur ........................................239 15.4.2 Program Kumbung Jamur Sederhana......................................240 #16 APLKASI REALTIME DENGAN RTC .....................................................247 16.1 Rangkaian Dasar RTC DS1307 ......................................................249 16.2 Menampilkan Waktu di Serial Monitor ..........................................250 16.3 Menampilkan Jam di Seven Segment ............................................253 16.3.1 Rangkaian Menampilkan Jam di Seven Segment .......................253 16.3.2 Program Menampilkan Jam di Seven Segment .........................255 16.4 Menampilkan Waktu di LCD ........................................................261 16.4.1 Rangkan Menampilkan Waktu di LCD......................................261 16.4.2 Program Menampilkan Waktu di LCD .....................................262 16.5 Menampilkan Nama Hari dan Bulan .............................................265 16.5.1 Program Menampilkan Nama Hari dan Bulan...........................266 16.6 Menampilkan Tanggal Bergerak ...................................................271 16.6.1 Program Menampilkan Tanggal Bergerak ................................271 16.7 Project Timer Pagi Sore ..............................................................278 16.7.1 Rangkaian Timer Pagi Sore ...................................................280 16.7.2 Program Timer Pagi Sore......................................................281 #17 KENDALI DENGAN REMOTE INFRARED..............................................291 17.1 Mengidentifikasi Tombol Remote .................................................292 17.1.1 Rangkaian Modul Receiver Infrared ........................................292 xii
17.1.2 Program Identifikasi Tombol Remote ..................................... 293 17.2 Project Remote Kontrol Karakter LCD........................................... 296 17.2.1 Rangkaian Remote Kontrol Karakter LCD ................................ 297 17.2.2 Program Remote Kontrol Karakter LCD .................................. 298 #18 PENGENALAN SERVO .................................................................... 306 18.1 Motor Servo Dasar .................................................................... 307 18.1.1 Rangkain Servo dan Arduino................................................. 307 18.1.2 Program Servo Sederhana.................................................... 308 18.2 Kendali Servo dengan Potensiometer ........................................... 310 18.2.1 Rangkaian Kendali Servo...................................................... 310 18.2.2 Program Kendali Servo ........................................................ 311 18.3 Kendali Servo dengan Remote .................................................... 312 18.3.1 Rangkaian Kendali Servo dan IR Receiver................................ 313 18.3.2 Program Kendali Servo dengan Remote IR .............................. 314 Tentang Penulis .................................................................................. 320
xiii
Bagian #00
SEBELUM MULAI Untuk mendapatkan hasil maksimal dalam belajar, maka Anda harus praktek. Jika kesulitan dalam memahami program yang ada dalam ebook ini, Anda bisa tanya di grup facebook MONSTER ARDUINO. Silakan cari postingan yang berkaitan dengan program yang ingin ditanyakan. Selain itu, silakan hubungi penulis jika berkenan miliki paket belajar pendukung khusus ebook ini. Daftar peralatan yang digunakan dalam ebook ini yaitu : 1.
Arduino Uno R3 – DIP x 1
2.
Kabel Data Arduino x 1
3.
Paket Belajar Burning Bootloader, terdiri dari : - IC ATMega328P x 1 - Capasitor 22pf x 2 - XTAL 16MHz x 1
4.
Project Board besar MB102 x 1
5.
Timer Tiny RTC x 1
6.
Sensor PIR x 1
7.
Sensor DHT11 x 1
8.
Motor Servo SG90 x 1
9.
Remote IR 1 paket x 1 1
10. IC Shift Register 74HC595 x 2 11. LCD 1602 x 1 12. Modul LCD I2C x 1 13. 7 segment 1 Digit x 1 14. 7 segment 4 Digit x 1 15. Relay 2 Channel x 1 16. Buzzer aktif x 1 17. Tombol Push Button DIP x 1 18. Potensiometer x 1 19. Resistor 220 x 10 20. Resistor 1k x 10 21. Resistor 4k7 x 10 22. LED merah x 10 23. LED kuning x 10 24. LED hijau x 10 25. Kabel Jumper 20cm (30mm + 10 mf) x 1 ElangSakti.com TIDAK bekerja sama dengan toko manapun dalam penyusunan ebook ini. Oleh sebab itu, jika ada yang mengatasnamakan ElangSakti.com dalam menjual paket belajar sesuai isi ebook ini, kami pastikan bahwa itu bukan dari kami. Sebab, support dari kami hanya diinfokan di website project.elangsakti.com, fanpage ElangSakti.com, atau grup facebook MONSTER ARDUINO. Kami tidak bertanggungjawab apabila ada pihak yang dirugikan yang mengatasnamakan ElangSakti.com. 2
Bagian #01
MEMINANG ARDUINO Saat kita mulai bangga dan merasa bisa, itulah tanda bahwa keilmuan kita akan segera kadaluarsa.
___
Kekurangan dari produk open source adalah varian yang kadang terlalu banyak dan membingungkan. Belum khatam mempelajari varian A, sudah muncul varian B. Baru dapet produk varian B, sudah muncul varian C dan D. Arrgggh… mau nggak mau, kita harus menjadi fast learner, mampu belajar lebih cepat dari kebanyakan orang. Ada banyak varian dari board Arduino, baik yang hanya minimum board atau yang sudah dilengkapi dengan sensor. Sebut saja Arduino Uno, Nano, Pro Mini, Mega, Intel, Due, Wemos, Lilypad, Zero, atau yang lainnya. Dari deretan varian tersebut, mana yang lebih cocok untuk Anda? Mana yang lebih cocok untuk pemula? ***
3
Belajar pemrograman Arduino, berarti Anda akan belajar tentang logika, algoritma, sintaks bahasa C/C++, konsep elektronika,
dan
sedikit
banyak
tentang
karakteristik
hardware Arduino yang Anda pakai. Sedikit banyak Anda perlu tahu kapasitas memori, penggunaan
register,
ADC,
DAC,
serta
jumlah
dan
karakteristik kaki input/output yang tersedia. Merasa berat dengan semua yang harus Anda pelajari? Santai saja, sebab semua orang yang levelnya sudah expert, pasti berawal dari level pemula. Level tersebut akan Anda dapat tanpa terasa seiring berjalannya waktu.
Yang Anda butuhkan adalah fokus belajar dan bersabar, bersabar lebih lama dari biasanya!
Kalau dalam belajar Anda merasa pusing, berbahagialah, itu artinya otak Anda sedang bertumbuh. Itu agak mirip ketika ada gigi yang mau tumbuh, sehingga gusi kadang bengkak dan sakit. Begitu juga dengan otak kita. Jika jaringan di otak kita berusaha membuat simpul-simpul keilmuan dan pengalaman baru, kadang kita akan merasa pusing. Percayalah…
4
Untuk belajar Arduino, Anda hanya butuh membuat programnya, upload, jika ada yang error atau aneh, segera tanya teman, atau cari solusinya di internet. Begitu juga ketika Anda mencoba sensor : cari contoh program, sesuaikan variabel dan pin-pinya, upload, jika ada yang error atau aneh, coba betulkan, jika tetap error, cari solusinya dari teman atau internet. Banyak sekali pemula yang belajar Arduino di Indonesia, jadi Anda tidak perlu takut untuk mulai belajar Arduino. Anda juga bisa gabung di grup Facebook MONSTER ARDUINO. Jika belum join, Anda boleh join di https://goo.gl/1PcSEq. Tabel 1.1 Perbandingan Spesifikasi Beberapa Jenis Arduino Jenis 101 Gemma LilyPad Mega 2560 Mega ADK Pro Mini Uno Zero Due Nano Yun
Proc. Intel® Curie Attiny85 ATmega168V ATmega328P ATmega2560 ATmega2560 ATmega328P ATmega328P ATSAMD21G18 ATSAM3X8E ATmega168 ATmega328P ATmega32U4 AR9331 Linux
Speed
SRAM
32MHz 8MHz 8MHz
0.5kB 0.5kB
24kB 0.5kB 1kB
196kB 8kB 16kB
6/14/4 1/3/2 6/14/6
16MHz 16MHz 8/16MHz 16MHz 48MHz 84MHz 16MHz
4kB 4kB 1kB 1kB 0.5kB 1kB 1
8kB 8kB 2kB 2kB 32kB 96kB 1kB 2kB 2.5kB 16MB
256kB 256kB 32kB 32kB 256kB 512kB 16kB 32kB 32kB 64MB
16/54/15 16/54/15 16/14/6 6/14/6 6/14/10 12/54/12 8/14/6
16MHz 400MHz
Flash
Pin
EEPROM
A/D/PWM
12/20/7
Tabel 1.1 menunjukkan spesifikasi beberapa jenis Arduino berdasarkan jenis processor atau IC mikrokontroller 5
yang dipakai, kecepatan, kapasitas EEPROM, SRAM, memory flash,
serta
jumlah
pin
Analog,
Digital,
dan
PWM.
Berdasarkan tabel tersebut, kita bisa memilih Arduino sesuai kebutuhan project kita.
1.1 Jenis Arduino untuk Pemula Ini murni pendapat pribadi, berdasarkan pengalaman ketika mulai belajar Arduino. Awalnya, Anda bisa mulai dengan Arduino Uno atau Nano. Kenapa? Sebab harganya relatif terjangkau dan referensi yang berkaitan dengan kedua jenis Arduino ini lebih banyak daripada jenis lainnya. Dulu, penulis belajar dengan Arduino Uno. Selanjutnya, ketika mengerjakan project, penulis biasanya menggunakan Arduino nano karena harganya lebih murah, setidaknya dua kali lebih murah daripada Arduino Uno. Ada sekitar 7 buah Arduino Nano yang siap digunakan untuk mengerjakan pesanan program dari customer. Kan nggak asik kalau mau nyoba program harus lepas-pasang arduino. Kalaupun Anda ingin langsung mulai belajar dengan Arduino Nano, penulis sarankan sekalian beli mini project board sehingga lebih mudah kalau mau pasang kabel jumper. Untuk project yang jumlahnya banyak dan hanya butuh sedikit program, penulis lebih menyarankan untuk 6
menggunakan Arduino Nano. Kenapa tidak menggunakan Arduino Pro Mini?
Gambar 1.1 Arduino Nano dengan mini project board
Arduino Pro Mini tidak memiliki jack USB yang bisa langsung dipasang ke komputer. Jadi misal mau update program, lebih simpel jika pakai Arduino Nano. Hanya saja, jika power supply yang ingin Anda gunakan adalah 3.3v, Anda bisa memilih Arduino Pro Mini yang 3.3v.
1.2 Project yang Butuh Banyak Pin I/O Jika pin I/O yang Anda butuhkan hanya sebagai OUTPUT, maka Anda bisa menambahkan shift register. Dengan IC shift register, Anda hanya membutuhkan 3 buah pin Arduino untuk dikonversi menjadi 8, 16, atau 24 pin output. Asik kan? Pembahasan tentang IC shift register ini juga kita bahas pada buku ini.
7
Namun jika yang dibutuhkan adalah jumlah input yang banyak, Anda bisa menggunakan Arduino Mega, entah Mega 2560 atau Mega ADK. Terdapat 54 pin I/O yang bisa dipakai pada Arduino Mega.
Gambar 1.2 Arduino Mega 2560 dan Mega ADK
1.3 Program dengan Clock Tinggi Varian Arduino memiliki kecepatan dari 8Mhz – 400Mhz. Arduino Uno, Nano, dan Mega beroperasi pada kecepatan 16Mhz. Arduino Pro Mini bisa pilih yang 8Mhz atau yang 16Mhz. Jika butuh kecepatan sekitar 32Mhz, Anda bisa gunakan Arduino 101. Jika butuh kecepatan 48Mhz, Anda bisa pilih Arduino Zero. Selanjutnya ada Arduino Due dengan kecepatan 84Mhz, dan Arduino Yun dengan kecepatan 400Mhz. Silakan gunakan sesuai kebutuhan. 8
Gambar 1.3 Arduino Due dan Yun
1.4 Project dengan Ukuran Program Besar Jika program yang dibuat < 32 kB, Anda bisa menggunakan Arduino Uno, Nano, atau Pro Mini. Kalau butuh yang lebih besar, Anda bisa gunakan Arduino Mega, Due, atau Yun. Oiya, selain
memori
untuk
menyimpan
program.
Arduino juga memiliki 2 buah memori lainnya yaitu EEPROM dan SRAM. Apa bedanya? Semoga penjelasan tentang memori ini bisa diterima dengan baik: 1. Memori Flash, memori untuk menyimpan program. Program yang yang kita buat, setelah dikompilasi akan disimpan dalam memori ini. Data yang disimpan pada 9
memori flash tidak akan hilang, kecuali ditimpa dengan program yang lain. 2. EEPROM, memori untuk menyimpan data program. Data yang disimpan pada memori ini tidak akan hilang meski arduino dimatikan. 3. SRAM, memori yang digunakan untuk manipulasi data variabel-variabel yang kita gunakan dalam program. Data yang tersimpan pada memori ini akan hilang ketika Arduino direset atau dimatikan. Kalau boleh diibaratkan, memori flash dan EEPROM mirip seperti hardisk pada komputer, dimana program dan data bisa disimpan di sana. Sedangkan SRAM mirip seperti RAM (DDR, DDR2, dst) sebab data akan hilang apabila komputer dimatikan. Untuk Arduino Uno, memori flash berkapasitas 32kB, EEPROM 1kB, dan SRAM kapasitasnya 2kB. Apakah cukup? Cukup… tergantung kompleksitas program kita.
Gambar 1.4 Informasi penggunaan memory saat program dicompile
Informasi tentang penggunaan memori flash dan SRAM bisa diketahui saat kita compile program. Pada Gambar 1.4, besar program hanya 1892 bytes, sekitar 5% dan total 10
kapasitas yang tersedia. Sedangkan data yang diolah selama program running (penggunaan variabel) menghabiskan 208 bytes, sekitar 10% dari kapasitas yang tersedia. Silakan pilih Arduino sesuai kebutuhan ukuran program Anda.
1.5 Saatnya Memilih! Anda jadi memilih yang mana? Apapun pilihan Anda, silakan gabung di grup facebook MONSTER ARDUINO. Sebagai pengingat, harapan dibuatnya group tersebut adalah untuk belajar lebih dalam tentang materi yang ada di buku ini. Target kita tidak hanya jadi Master Arduino, tapi, jadilah MONSTER ARDUINO!
Monster yang siap mengubah Indonesia lebih baik dengan adanya teknologi, penggagas ide-ide kreatif yang dimulai dan dirancang dengan Arduino. Orang-orang Indonesia itu kreatif, jika kita arahkan untuk merancang dengan serius, kita bisa mendahului negara-negara maju lainnya. Hehehe… Mimpi bangng…?! IYA!!! Kalau kita mimpinya rame-rame, semoga bisa jadi kenyataan!
11
Bagian #02
ARDUINO DAN BOOTLOADER Untuk Indonesia, jadilah Legenda! (Superman Is Dead)
___
2.1 Sekilas tentang Bootloader Beberapa pertanyaan tentang bootloader di bawah ini sering muncul tidak hanya dari programmer pemula seperti penulis, bahkan kadang programmer veteran pun pernah mempertanyakannya. Mungkin dalam pikiran Anda juga pernah tersirat salah satu atau beberapa pertanyaan di bawah ini: 1. Apa sih fungsi bootloader pada arduino? 2. Bisa nggak, misal bikin arduino tanpa bootloader? 3. Kalau nggak pakai bootloader, Arduino tetep bisa jalan nggak? 4. Apa kita bisa bikin bootloader sendiri untuk arduino? Anda bisa menjawab sendiri pertanyaan di atas setelah memahami cara kerja arduino berdasarkan ilustrasi berikut. 12
Jika kita mau memprogram IC mikrokontroller, sebut saja keluarga AT89Sxx, ATMega, atau PIC, maka kita butuh alat tambahan (hardware) yang biasa dikenal dengan istilah programmer atau downloader. Contoh downloader untuk AVR dan PIC seperti gambar di bawah ini.
Gambar 2.1 USBAsp untuk AVR dan PIC Programmer
Jika Anda menggunakan Arduino, Anda sudah tidak memerlukan
downloader
lagi.
Anda
bisa
langsung
memasang program pada IC melalui software Arduino IDE di komputer. Fungsi downloader sudah ditangani oleh bootloader dalam IC. Program yang dikirim komputer ke Arduino akan “ditangkap” dan disimpankan oleh bootloader dalam memori program yang masih kosong. Program mikrokontroller akan disimpan dalam memori flash atau flash memory. Setiap mikrokontroller dijalankan, biasanya alamat program yang pertama dieksekusi adalah alamat 0x0000 di flash memory.
13
Program bootloader biasanya dipasang pada alamat memori
0x0000
program
yang
sehingga pertama
program kali
tersebut
dieksekusi.
menjadi
Anda
bisa
memperhatikan perbedaan antara proses memprogram mikrokontroller biasa dengan mikrokontroller yang telah dipasangi bootloader Arduino pada Gambar di bawah ini.
Gambar 2.2 Perbedaan cara kerja mikrokontroller konvensional dan cara kerja Arduino
Pada mikrokontroller biasa, yang bertugas menyimpan program adalah programmer yang berupa hardware. Sedangkan pada Arduino, proses penyimpanan program ke memori flash dikerjakan oleh bootloader. Lebih detailnya, bootloader memiliki cara kerja seperti berikut: 1. Bootloader
hanya
dieksekusi
saat
Arduino
dinyalakan. Oleh sebab itu, proses penyimpanan program oleh bootloader hanya bisa dilakukan sesaat setelah Arduino direset. 14
2. Saat awal start, jika Arduino menerima kiriman program dari komputer. Maka tugas bootloader adalah menyimpan kiriman program tersebut pada memory flash yang tidak dipakai bootloader, misal alamat memory 0x00AB. 3. Jika tidak ada kiriman program dari komputer, maka
eksekusi program akan langsung lompat ke alamat 0x00AB untuk menjalankan program utama. ***
Selain berfungsi untuk mengatur program yang akan diinstal dalam IC, bootloader juga berperan sebagai pengatur konfigurasi awal arduino seperti clock yang akan digunakan, mode komunikasi dengan serial komputer, timer,
dan
konfigurasi
lainnya.
Meskipun
demikian,
konfigurasi-konfgurasi tersebut tetap bisa kita ubah melalui program yang kita upload. Misal kita punya board arduino, tapi IC yang dipasang tidak
ada
bootloadernya.
Kita
tidak
bisa
langsung
memprogramnya dengan Arduino IDE, sebab perantara (bootloader) yang bisa menyimpankan program tidak ada. Kita juga bisa membuat bootloader Arduino versi kita. Sebagai informasi tambahan, bootloader arduino yang terbaru berukuran setengah kB dan dikenal juga dengan istilah optiboot. Anda bisa lihat beberapa versinya di folder 15
instalasi arduino, yaitu pada /hardware/avr/bootloaders atau bisa cek di https://goo.gl/sjrHYo. Sebelum Anda lanjut praktek pada bab-bab selanjutnya, Anda boleh simak pesan-pesan ini. Mari belajar dengan lebih serius, sebab negeri kita butuh banyak programmer dan inovator teknologi. Ada banyak pedangan, petani, nelayan, peternak, dan UKM yang butuh sentuhan teknologi agar menghasilkan produk yang lebih berkualitas, lebih cepat, lebih murah, dan lebih banyak, demi kesejahteraan negeri. Semoga pesan ini bisa diterima dan diingat-ingat. Sekali lagi, kita butuh para Monster untuk menggoyang negeri ini dengan inovasi teknologi.
2.2 Cara Install Bootloader Arduino Setidaknya ada dua cara untuk menginstall bootloader Arduino, atau istilah lainnya burning bootloader. Yang pertama, kita bisa menggunakan downloader AVR, di buku ini kita akan menggunakan USBAsp. Sedangkan cara yang kedua yaitu menggunakan board Arduino yang sudah ada. Menggunakan AVR downloader atau Arduino, inti rangkaian keduanya sama, yaitu menggunakan pin SCK, MOSI, MISO, dan RST. Detail rangkaian dapat dilihat pada masing-masing sub pembahasan berikutnya. 16
2.2.1 Install Bootloader dengan USBAsp Dalam hal ini, kita menganggap Anda sudah bisa install driver USBAsp. Proses instalasi bootloader akan dilakukan dengan mode grafis menggunakan aplikasi PROGISP dan command line dengan avrdude. Jika Anda belum familiar dengan kedua program tersebut, Anda boleh googling dan mempelajari secukupnya.
2.2.1.1 Rangkaian IC ATMega8 /168/328 Siapkan peralatan dan rangkaian seperti di bawah ini: 1. AVR Programmer x 1 2. IC ATMega8/168/328 x 1 3. Project board x 1 4. XTAL 16MHz x 1 5. Kapasitor 22pf x 2 6. Resistor (ukurannya 220, 330, 1k, 4k7, atau 10k) x 1 7. Kabel jumper secukupnya Sambungan pin antara Programmer dan ATMega: AVR Programmer
IC ATMega8/168/328
Pin MOSI Pin MISO Pin SCK/CLOCK Pin SS / RST VCC GND
Pin 17 (MOSI) Pin 18 (MISO) Pin 19 (SCK/CLOCK) Pin 1 (RST) VCC GND
17
Gambar 2.3 Rangkaian untuk install bootloader IC ATMega8/168/328
2.2.1.2 Rangkaian untuk Board Arduino Instalasi bootloader Arduino seperti ini biasanya ketika IC rusak, atau program dalam IC mengalami bootloop. Bootloop adalah istilah dimana arduino restart terusmenerus karena kesalahan program, seperti akibat karena kesalahan konfigurasi register. Yang perlu disiapkan adalah: 1. Board Arduino x 1 2. Downloader USBAsp x 1 3. Kabel secukupnya x 1 Sambungan pin antara Programmer dan Arduino: AVR Programmer
Arduino Uno/Nano
MOSI MISO SCK/CLOCK SS / RST VCC GND
Pin 11 (MOSI) Pin 12 (MISO) Pin 13 (SCK/CLOCK) Pin RESET (RST) VCC GND
18
Gambar 2.4 Rangkaian untuk install bootloader langsung ke board Arduino
2.2.1.3 Install Bootloader dengan Progisp Yang paling penting saat menginstall dengan Progisp adalah konfigurasi fuse bit. Informasi
fuse bit bisa
didapatkan dari file boards.txt dalam folder instalasi Arduino IDE, yaitu dalam sub folder /hardware/arduino/avr : Fuse
Data
Low High Extended
0xFF 0xDA 0xFD
19
Gambar 2.5 Penyesuaian fuse bit pada Progisp
Gambar 2.6 Isi folder /hardware/arduino/avr/bootloder/atmega
Setelah mengatur fuse bit, klik tombol Load Flash untuk memilih file .hex bootloader di folder program Arduino IDE, pada subfolder /hardware/arduino/avr/bootloder/atmega. Pilih file ATmegaBOOT_168_atmega328.hex. File tersebut adalah bootloader untuk Arduino Uno, Nano, dan Pro Mini yang 16MHz. 20
Gambar 2.7 Load file .hex bootloader
Gambar 2.8 Proses instalasi bootloader Arduino
21
Selanjutnya, install bootloader dengan menekan tombol Auto. Tunggu hingga proses instalasi selesai. Untuk mengecek hasil instalasi, silakan lihat sub bab berikutnya.
2.2.1.4 Install Bootloader dengan AVRDUDE Untuk menginstall dengan avrdude, Anda bisa pakai avrdude yang sudah ada di master Arduino IDE, atau Anda bisa download dari https://goo.gl/Np9MBH. Pastikan Anda download versi yang terbaru. Setelah berhasil download, silakan ekstrak di folder yang mudah dijangkau dengan aplikasi command prompt supaya Anda masuk ke foldernya tidak capek ngetik, hehe. Setelah diekstrak, copy file bootloader dari folder /hardware/arduino/avr/bootloder/atmega.
Untuk
Arduino
Uno, Nano, Pro Mini 16MHz kita bisa menggunakan file ATmegaBOOT_168_atmega328.hex. Copy file tersebut, kemudian paste di folder hasil ekstrakan dari avrdude tadi.
Gambar 2.9 Contoh isi folder avdude dan bootloader Arduino
Selanjutnya, buka command prompt dan ketik perintah berikut untuk melakukan instalasi bootloader. 22
avrdude -b19200 -c usbasp -p m328p -v -e -U flash:w:ATmegaBOOT_168_atmega328.hex -U lock:w:0x0F:m
Gambar 2.10 Isi folder avrdude dan perintah untuk menginstall bootloader
Gambar 2.11 Proses instalasi bootloader selesai
Setelah proses instalasi selesai, cek hasil instalasi dengan cara yang dijelaskan pada subbab selanjutnya. 23
2.2.2 Arduino Sebagai ISP Programmer Selain menggunakan hardware programmer seperti USBAsp, kita juga
bisa
menjadikan
Arduino sebagai
programmer. Cara yang bisa digunakan untuk mengubah Arduino menjadi programmer adalah dengan menginstall program ArduinoISP.
Gambar 2.12 File program ArduinoISP
Program ArduinoISP sudah ada di sampel program dalam aplikasi Arduino IDE. Pilih menu File > Examples > ArduinoISP. Setelah source codenya terbuka, upload dan tunggu hingga selesai. Setelah ArduinoISP berhasil diinstall, Arduino Anda sudah berubah menjadi programmer. 24
Selanjutnya, Arduino Anda
bisa
digunakan untuk
menginstall bootloader atau mengupload program ke Arduino lainnya langsung dari aplikasi Arduino IDE.
Gambar 2.13 Upload Sketch dengan Arduino sebagai ISP Programmer
Penting!!! Jika Anda mengupload Sketch ke IC yang terinstall bootloader dengan “Upload Using Programmer”, maka bootloadernya akan ditimpa oleh Sketch tadi!
Jika Anda ingin menupload Sketch dengan arduino sebagai programmer, maka settinglah programmer sebagai “Arduino as ISP”, siapkan sketch yang akan diupload, kemudian pilih menu Sketch > Upload using Programmer. 25
2.2.3 Install Bootloader dengan Arduino 2.2.3.1 Rangkaian untuk IC ATMega8 /168/328 Siapkan part dan peralatan di bawah ini: 1. Arduino Uno / Nano x 1 2. IC ATMega8/168/328 x 1 3. Project board x 1 4. XTAL 16MHz x 1 5. Kapasitor 22pf x 2 6. Resistor x 1 (ukurannya 220, 330, 1k, 4k7, atau 10k) 7. Kabel jumper secukupnya Sambungan pin antara Arduino dan ATMega : Arduino Uno/Nano
IC ATMega8/168/328
Pin 11 (MOSI) Pin 12 (MISO) Pin 13 (SCK/CLOCK) Pin RESET (RST) VCC GND
Pin 17 (MOSI) Pin 18 (MISO) Pin 19 (SCK/CLOCK) Pin 1 (RST) VCC GND
26
Gambar 2.14 Rangkaian untuk install bootloader dengan Arduino
2.2.3.2 Rangkaian untuk Board Arduino Ada banyak kombinasi yang bisa dilakukan, misalnya ingin menginstall bootloader Arduino Uno dengan Uno, Nano dengan Uno, Uno dengan Nano, Nano dengan Nano, bahkan Mega dengan Nano. Namun inti dari semua rangkaian ini adalah pin CLK/SCK dihubungkan ke CLK/SCK, MOSI ke MOSI, MISO ke MISO, dan pin 10 ke RESET. Sambungan pin antar Arduino : Arduino Programmer
Arduino Target
Pin 11 (MOSI) Pin 12 (MISO) Pin 13 (SCK/CLOCK) Pin 10 VCC
Pin 11 (MOSI) Pin 12 (MISO) Pin 13 (SCK/CLOCK) Pin RESET (RST) VCC
27
GND
GND
Gambar 2.15 Rangkaian install board arduino dengan arduino lainnya
2.2.3.3 Instalasi Bootloader dengan Arduino Proses instalasi bootloader dengan Arduino dilakukan dengan tahapan berikut melalui menu Tools: 1. Pastikan pilihan jenis board Arduino disesuaikan dengan Arduino Target. Jika targetnya Uno, pilih Uno. Jika Targetnya Nano, pilih Nano. 2. Pilih koneksi Port yang sesuai dengan port Arduino sebagai Programmer. Ingat, port harus disesuaikan dengan Port Arduino sebagai Programmer. 3. Ganti settingan Arduino menjadi “Arduino as ISP”. 4. Pilih “Burn Bootloader”, lalu tunggu hingga proses burning atau instalasi bootloader selesai. 28
5. Jika muncul error, Anda bisa langsung googling atau tanya di grup Facebook MONSTER ARDUINO.
Gambar 2.16 Proses konfigurasi dan instalasi bootloader
2.2.4 Pengecekan Hasil Instalasi Bootloader Instalasi berhasil ketika LED di pin 13 Arduino berkedip pelan. Cobalah upload program dari Arduino IDE, jika berhasil, berarti Anda telah sukses menginstall.
29
Bagian #03
HELLO BUZZER Tanpa cinta, kecerdasan itu berbahaya, dan tanpa kecerdasan, cinta itu berbahaya. (B.J Habibie)
___ Kalau dalam bahasa pemgoraman, program pertama yang dibuat adalah untuk menampilkan “Hello World!”. Untuk mikrokontroller umumnya adalah lampu
flip-flop.
Tapi kita bisa memulainya dengan cara yang berbeda, kita pakai Buzzer! Komponen utama dari program Hello Buzzer adalah Arduino dan buzzer, aktif buzzer. Apakah kita akan membahas teori tentang buzzer dahulu? Tidak, kita praktek dulu. :D
3.1 Project Hello Buzzer 3.1.1 Rangkaian Hello Buzzer Silakan buat rangkaian seperti berikut. Alat, bahannya dan skemanya sebagai berikut: 30
1. Arduino Uno x 1 2. Kabel Jumper Male to Female x 2 3. Buzzer Aktif x 1 Sambungan pin antara Arduino dan Buzzer : Arduino
Buzzer
Pin 2 VCC
GND VCC
Gambar 3.1 Rangkaian Project Hello Buzzer
3.1.2 Program Hello Buzzer Program 3.1 Program Hello Buzzer 1 2 3 4 5 6 7 8 9 10
/* * MONSTER ARDUINO V2 * Program Hello Buzzer * www.ElangSakti.com */ // buzzer disetting active low // BUZZER_OFF kebalikan dari BUZZER_ON #define BUZZER_ON LOW #define BUZZER_OFF !BUZZER_ON
31
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
// GND buzzer dihubungkan ke pin 2 const byte PIN_BUZZER = 2; void setup() { // pin buzzer sebagai output pinMode(PIN_BUZZER, OUTPUT); } void loop() { // Tit pertama digitalWrite(PIN_BUZZER, BUZZER_ON); delay(200); // mati sebentar digitalWrite(PIN_BUZZER, BUZZER_OFF); delay(100); // Tit kedua digitalWrite(PIN_BUZZER, BUZZER_ON); delay(200); // mati agak lama digitalWrite(PIN_BUZZER, BUZZER_OFF); delay(1000); }
Berdasarkan
rangkaian
pada
Gambar
3.1,
buzzer
disetting supaya aktif ketika pin 2 berlogika LOW. Sebab, kaki positif buzzer langsung dihubungkan pada VCC +5v. Rangkaian ini sengaja penulis balik supaya tidak sama dengan referensi pada umumnya. Supaya Anda bingung. =)) Jika Anda tidak bingung, Selamat… berarti pemahaman Anda tentang elektronika sudah baik. Tapi jika Anda merasa bingung, mari dicerna pelan-pelan. 32
3.2 Buzzer Aktif dan Buzzer Pasif Buzzer yang kita gunakan pada adalah buzzer aktif. Apa bedanya dengan buzzer pasif? Buzzer aktif adalah buzzer yang langsung bunyi ketika kita aliri arus listrik. Sedangkan buzzer pasif adalah buzzer yang akan berbunyi ketika kita tentukan frekuensi bunyinya. Maksudnya begini, jika buzzer pasif hanya dialiri arus listrik atau dihubungkan ke sumber tegangan, ia tidak akan bunyi. Buzzer pasif akan berbunyi ketika kita berikan nada atau frekuensi tertentu. Buzzer pasif sama dengan speaker yang biasanya kita pakai untuk membunyikan musik. Dulu, di Ebook Versi 1 telah kita bahas, yaitu tentang Tone.
Gambar 3.2 Buzzer aktif dan pasif tampak dari atas (kiri) dan dari bawah (kanan)
Buzzer aktif dan pasif bentuknya agak mirip, tapi kita bisa membedakannya dengan bagian bawahnya. Pada buzzer aktif, bagian biasanya terpasang label putih dan bagian bawahnya tertutup full. Pada buzzer pasif, bagian atasnya biasanya tanpa label, sedangkan bagian bawah 33
masih ada bagian yang terbuka sehingga papan PCB nya terlihat. Sebenarnya cara membedakan ini bisa saja tidak valid, hanya saja dari semua buzzer yang ada, ciri-cirinya biasanya seperti itu.
3.3 Project Dummy Logger Kali ini kita akan membuat program yang akan mengirim data setiap 3 detik. Setiap mengirim data, buzzer akan berbunyi tilit. Bisakah Anda pura-pura mendengar dan membayangkannya? Jika kita perhatikan, program Hello Buzzer dipenuhi dengan fungsi delay(). Padahal, fungsi delay harus kita hindari
selagi
bisa.
Sebab,
jika
kita
terlalu
menggunakan delay(), programnya jadi aneh. Program 3.2 Program Dummy Logger 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/* * MONSTER ARDUINO V2 * Program Dummy Logger * www.ElangSakti.com */ // buzzer disetting active low // BUZZER_OFF kebalikan dari BUZZER_ON #define BUZZER_ON LOW #define BUZZER_OFF !BUZZER_ON // GND buzzer dihubungkan ke pin 2 const byte PIN_BUZZER = 2; // variabel untuk cek waktu kirim
34
banyak
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
unsigned long waktu_kirim = 0; void setup() { // aktifkan komunikasi serial // pada baudrate 19200 Serial.begin(19200); // tunggu hinga Serial siap digunakan while(!Serial); // pin buzzer sebagai output pinMode(PIN_BUZZER, OUTPUT); // pastikan buzzer maat saat pertama kali start digitalWrite(PIN_BUZZER, BUZZER_OFF); // catat waktu kirim pertama kali waktu_kirim = millis(); } void loop() { // kirim data KirimData(); // bunyi tilit tilit TilitTilit(); } void TilitTilit(){ // Tit pertama digitalWrite(PIN_BUZZER, BUZZER_ON); delay(200); // mati sebentar digitalWrite(PIN_BUZZER, BUZZER_OFF); delay(100); // Tit kedua digitalWrite(PIN_BUZZER, BUZZER_ON); delay(200);
35
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
// mati agak lama digitalWrite(PIN_BUZZER, BUZZER_OFF); delay(1000); // tambahan delay supaya pas 3 detik :v delay(1500); } // fungsi untuk mengirim data void KirimData(){ // cetak selisih waktu kirim sebelumnya // dengan pengiriman saat ini Serial.print("Selisih Waktu : "); Serial.println( millis() - waktu_kirim ); // catat waktu kirim data waktu_kirim = millis(); }
Gambar 3.3 Hasil eksekusi program kirim data setiap 3 detik
Program Hello Buzzer bisa dimodifikasi seperti program di atas. Supaya bisa genap 3 detik, maka harus ditambah 36
delay sekitar 1.5 detik (lihat baris 64). Namun, tidak sesederhana itu! Program akan bermasalah ketika ada penambahan source code baru. Program
di
atas
tidaklah
relevan,
akan
sangat
bermasalah apabila logika program di atas digunakan untuk data logger. Teknik untuk menyelesaikan project ini kita bahas pada bab selanjutnya, yaitu tentang optimalisasi fungsi delay yang umumnya dikenal dengan istilah nonblocking delay.
37
Bagian #04
TIPS MEMILIH TIPE DATA Anda tidak bisa mengajari sesuatu kepada seseorang; Anda hanya dapat membantu orang itu menemukan sesuatu dalam dirinya. (Galileo Galilei)
___ Jika Anda hanya ingin membuat program sederhana dan merasa sudah paham cara memilih tipe data yang cocok, Anda boleh lompati bab ini. Pada bab ini, kita akan berbagi pengalaman bagaimana cara menggunakan tipe data dalam memprogram Arduino. Kenapa memilih tipe data yang cocok menjadi suatu keharusan? Arduino tidak sama dengan komputer biasa yang memiliki kapasitas memori dan media penyimpanan yang besar. Contoh, pada Arduino Uno, kita hanya diberi ruang memori sebanyak 1kB untuk menyimpan data, 2kB sebagai RAM, 32 kB untuk menyimpan program. Jika Anda membuat data array dengan tipe data long, maka kapasitas SRAM habis hanya dengan 512 data. Belum 38
lagi jika Anda banyak menggunakan teks atau String. Bagaimana jika Anda butuh ratusan atau ribuan data dummy untuk uji coba? Atau bagaimana jika kita perlu mencetak banyak teks data di serial monitor untuk keperluan debugging? Hal ini berbeda ketika kita membuat aplikasi web, android, atau aplikasi untuk komputer desktop. Dengan demikian, kita ditantang untuk bijak dalam memilih tipe data. Mari kita bahas satu-persatu, semoga Anda bisa bersabar mempelajari hal-hal remeh semacam ini. Ya, hal remeh tapi sangat penting untuk pengembangan keilmuan kita, agar tidak membuat program asal jadi. Mari kita bongkar secara blak-blakan apa yang penulis pahami tentang tipe data dan apa saja tips-tipsnya.
4.1 Byte dan Boolean, 1 Byte Banyak contoh
di internet, termasuk
di website
arduino.cc yang membuat variabel untuk pin seperti ini: int LedPin = 2; int SwitchPin = A0;
Penulis kurang setuju dengan penggunaan tipe data seperti itu. Kenapa? Karena mengunakan tipe integer untuk 39
diisi dengan pin Arduino itu kurang hemat. Jumlah kaki Arduino ada berapa? Tidak lebih dari 200. Sedangkan kapasistas untuk tipe data integer berapa? Kapasitas tipe integer adalah 65535 (jika mengabaikan tanda negatif). Sebenarnya, jika hanya untuk pin Arduino, penggunaan tipe data byte atau unsigned char sudah cukup. Lebih menghemat memori karena byte kapasitasnya 1 byte. Sedangkan integer adalah 2 byte. Jika kita memprogram Arduino Mega dengan tipe data integer untuk 50 pin, berarti kita menghabis 100 byte hanya untuk nama pinnya saja, dan itu sudah 5% dari total SRAM-nya Uno. Belum variabel yang lain. Penulis lebih senang menggunakan: const byte LedPin = 2;
Kenapa pakai const (konstanta) dan byte? Sebab LedPin tidak pernah diubah-ubah dan jumlah pin Arduino PASTI positif. Kita tidak butuh tipe data negatif. Apalagi tipe data byte sudah cukup untuk menampung 256 pin Arduino karena kapasitas untuk data byte adalah 0 – 255. Tipe data boolean, true, false, high, dan low sama-sama berkapasitas 1 byte. Jadi tidak ada masalah dengan tipe data ini.
40
4.2 Char atau Unsigned Char, 1 Byte Jika butuh data negatif tapi dibawah angka ratusan, bisa pakai char. Char adalah tipe data 1 byte yang bisa digunakan untuk mengolah angka dari -128 sampai 127. Selain itu, char juga bisa dipakai untuk sebuah karakter dalam ASCII. Sedangkan unsigned char sama dengan tipe data byte, angka yang bisa dimuat adalah 0 – 255. Tipe ini tidak terlalu banyak masalah bagi penulis.
4.3 Integer dan Unsigned Integer, 2 Byte Penulis hanya menggunakan tipe data ini jika angka yang akan diolah > 255 dan < 65535, jika datanya hanya positif. Jika data negatif, maka acuan untuk menggunakan data ini adalah > 127 dan < 32767, begitu juga untuk data negatifnya. Dulu
pernah
menemukan
contoh
program
yang
menggunakan tipe data int (bukan unsigned int) untuk menampung data millis(). Hasilnya ya tidak sesuai. Sebab, millis() pakai tipe data unsigned long yang kapasitasnya 4 byte yang mampu menampung data hingga 4000-an JUTA angka! Sementara integer maksimal 32 ribuan saja.
41
4.4 Long dan Unsigned Long, 4 Byte Sejujurnya, penulis lebih sering menggunakan unsigned long daripada long. Sebab, unsigned long sering penulis gunakan untuk menampun informasi waktu, entah itu dari millis() atau micros(). Kapasitas tipe data ini 4 byte. Artinya, jika tidak memperhatikan tanda negatif, jumlah angka yang dapat ditampung dengan tipe data ini adalah 4.294.967.295, empat ribu juta lebih.
4.5 Float atau Double, 4 Byte Penulis menggunakan tipe data ini hanya untuk data yang
berkoma.
membedakan
Lebarnya
keduanya
sama-sama adalah
4
byte.
Yang
kepresisiannya.
Ada
referensi yang menyebutkan bahwa jika ingin presisi, gunakan
double.
Tapi
sayang,
penulis
tidak
terlalu
memperhatikan kedua tipe data ini.
4.6 Volatile & Interrupt Sudah pernah pakai volatile? Jika belum, kemungkinan besar Anda belum pernah menggunakan interrupt. Volatile sebenarnya bukan tipe data. Volatile hanyalah kata kunci atau keyword, atau mungkin bisa penulis terjemahkan sebagai perintah pada compiler agar data dari 42
variabel yang kita buat tetap disimpan di RAM, bukan di register. Untuk apa? Interrupt adalah perintah dadakan yang harus segera dikerjakan. Contohnya begini, ketika Anda makan, pasti Anda menyediakan air di dekat Anda. Atau minimal, Anda sudah memastikan bahwa nanti ada air yang bisa diminum. Selama Anda menikmati makan, lalu tiba-tiba keselek! Nah, itu! Itu contoh interrupt! =)) Peristiwa keselek ini adalah peristiwa yang memaksa Anda untuk segera mencari air untuk minum. Apa yang akan terjadi jika di dekat Anda tidak ada air??? Boleh Anda bayangkan dan rasakan… :D *** Berikut penjelasan peristiwa makan, keselek, dan minum
yang jika dihubungkan konsep interrupt dan volatile dalam mikrokontroller: 1. Proses makan adalah program utama. 2. Keselek adalah pemicu interrupt (bisa dari external interrupt atau dari timer interrupt). 3. Kondisi harus minum adalah interrupt yang harus dikerjakan. 4. Air adalah data yang harus segera diproses. Jika airnya masih di dalam sumur, bisa-bisa Anda mati 43
sebelum minum. Begitu juga dengan data, jika datanya disimpan di register, terlalu lama untuk memprosesnya, bisa jadi datanya tidak dapat diolah dengan baik. Maka, data tersebut harus disimpan di RAM. Agar data disimpan di RAM, maka kita harus menandainya dengan keyword volatile. Contoh, volatile double sensor_data = 0;
Variabel
sensor_data
bertipe
double
dengan
keyword volatile menyebabkan 4 byte data untuk sensor_data disimpan di RAM, bukan memori register. Semoga Anda bisa memahami. Bisa Anda perhatikan pada contoh-contoh program selanjutnya, mungkin Anda akan bertemu dengan keyword volatile ini, khususnya yang memabahasa tentang interrupt.
4.7 PROGMEM Sebelumnya sudah penulis singgung tentang data dummy sensor, yaitu data buatan yang seolah-olah keluaran dari sebuah sensor. Jika kita butuh 1000 data dummy bertipe integer (2kB), maka SRAM Arduino Uno tidaklah 44
cukup. Solusinya, upgrade Arduino atau gunakan keyword PROGMEM. Dengan perintah PROGMEM, maka data akan disimpan di memori flash. Sekali lagi, data akan disimpan di memori flash! Memor
flash
adalah
memori
untuk
menyimpan
program. untuk Arduino Uno, kapasitasnya 32kB. Jika bootloader dan program menghabiskan 10 kB, berarti masih sisah 22 kB lagi yang bisa dipakai. Contoh program untuk PROGMEM akan dibahas pada buku serial selanjutnya. Pada kesempatan ini, Anda cukup tahu dulu dan bisa googling untuk mencari informasi tentang PROGMEM ini.
4.8 String dengan F( ) Cobalah membuat program yang menampilkan banyak tulisan di serial terminal. Penulis yakin, ketika jumlah huruf dalam satu string lebih dari 2000 huruf, pasti ada warning atau malah error. Kenapa demikian? Karena kapasitas SRAM hanya 2048 byte. Untuk mengatasi hal tersebut, Anda bisa menggunakan PROGMEM atau fungsi F(), eh bukan fungsi, tapi makro F(). 45
Makro F()
berguna
untuk
menyimpan
tipe data
(contohnya tipe String) ke memori flash. Fungsi makro F() sama dengan PROGMEM. Bedanya, makro F() bisa dipakai layaknya sebuah fungsi, sedangkan PROGMEM hanya untuk inisialisasi. Makro F() bisa dipanggil di bagian mana saja dalam program. Seperti itulah beberapa hal yang dapat penulis share tentang tipe data. untuk pertanyaan lebih lanjut atau mungkin
contoh-contoh
juga
akan
dibahas di
grup
Facebook MONSTER ARDUINO. Selanjutnya, mari kita bahas hal-hal yang menarik lainnya yang mungkin belum Anda ketahui.
46
Bagian #05
OPTIMALISASI DELAY Modal bisa memenjarakan manusia, membuat manusia bekerja tanpa henti dari jam 5 subuh sampai jam 8 malam untuk kekayaan orang lain. (Tan Malaka)
___
5.1 Seberapa Cepatkah 16MHz itu? Arduino
Uno
dengan
kecepatan
16MHz
mampu
mengeksekusi 16.000.000 instruksi dalam 1 detik. Jika Anda menggunakan delay 1 detik dengan perintah delay(1000), berarti dia nganggur dalam 1 detik tersebut. Sebagai gambaran, perintah digitalWrite(13,HIGH); membutuhkan waktu eksekusi sekitar 5-7 mikrodetik. Jika kita anggap rata-ratanya 6 mikrodetik yang setara dengan 0.000006 detik, maka kita bisa mengeksekusi sekitar 166.666 lebih perintah digitalWrite() dalam 1 detik. Banyak? Iya! Daripada Anda memerintahkan Arduino untuk diam dengan memberikan perintah delay(), lebih baik Anda 47
alihkan pekerjaan Arduino untuk melakukan hal lain seperti mengecek nilai sensor, ganti tampilan LCD, atau aktivitas lainnya. ***
Mungkin Anda ingin bertanya, bagaimana penulis bisa tahu perintah pada kode di atas butuh waktu eksekusi sekitar 6 mikrodetik? Berikut adalah sketch yang penulis buat untuk simulasi. Program 5.1 Program Waktu Eksekusi DigitalWrite 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
/* * MONSTER ARDUINO V2 * Program Waktu Eksekusi DigitalWrite * www.ElangSakti.com */ // pin 13 sebagai output const byte PIN_LED = 13; // jumlah sampel data int delay_count = 100; // pencatat waktu unsigned long delay_sum = 0; unsigned long delay_first = 0; unsigned long delay_last = 0; // logika untuk flip flop boolean flip = true; void setup() { // buka koneksi serial // lalu jadikan pin_led sebagai output Serial.begin(19200); while(!Serial); pinMode(PIN_LED,OUTPUT);
48
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
} void loop() { // ambil 100 sampel data // catat dalam variabel delay_sum delay_sum = 0; for(byte i=0; i
Output program ini dapat dilihat pada Gambar 5.1. Sebagai tambahan informasi, waktu 6 mikrodetik adalah waktu rata-rata total eksekusi program dan waktu untuk load program ke register. Jika program sudah ada dalam register, maka waktu eksekusi akan lebih cepat. Kesimpulan dari pembahasan tentang fungsi delay() adalah: Untuk mendapatkan sistem yang responsive, hindari 49
penggunaan fungsi delay dalam program, kecuali memang sangat dibutuhkan.
Gambar 5.1 Hasil eksekusi Program Waktu Eksekusi DigitalWrite
5.2 Project Perbaikan Dummy Logger Rangkain untuk program ini masih sama dengan rangkain Project Dummy Logger. Sedangkan untuk program perbaikannya seperti di bawah ini. Program perbaikannya sama sekali tidak menggunakan delay(). Untuk menentukan timer 3 detik dan timer untuk mengaktifkan buzzer menggunakan permainan waktu. Misalnya, pada waktu pengiriman data dalam 3 detik. Setiap mengirimkan data, maka waktu pengiriman dicatat 50
dalam kirim data_time_last (lihat baris 109). Selanjutnya, waktu terus dicek apakah sejak pengiriman terakhir tadi sudah lewat 3 detik atau tidak (lihat baris 98). Jika sudah lewat 3 detik, kirim data. Jika belum lewat 3 detik, abaikan. Program 5.2 Program Perbaikan Dummy Logger 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
/* * MONSTER ARDUINO V2 * Program Perbaikan Dummy Logger * www.ElangSakti.com */ // buzzer disetting active low // BUZZER_OFF kebalikan dari BUZZER_ON #define BUZZER_ON LOW #define BUZZER_OFF !BUZZER_ON // GND buzzer dihubungkan ke pin 2 const byte PIN_BUZZER = 2; // variabel untuk cek waktu kirim unsigned long waktu_kirim = 0; // logika buzzer const unsigned long buzzer_delay[] = {0,200,100,200}; const boolean buzzer_state[] = {BUZZER_ON, BUZZER_OFF, BUZZER_ON, BUZZER_OFF}; byte buzzer_state_counter = sizeof(buzzer_state); // pencatat waktu timer buzzer unsigned long buzzer_time = 0; unsigned long buzzer_time_last = 0; // pencatat waktu timer kirim data unsigned long kirimdata_time = 0; unsigned long kirimdata_time_last = 0; // delay kirim data 3 detik const long kirimdata_delay = 3000;
51
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
void setup() { // aktifkan komunikasi serial // pada baudrate 19200 Serial.begin(19200); // tunggu hinga Serial siap digunakan while(!Serial); // pin buzzer sebagai output pinMode(PIN_BUZZER, OUTPUT); digitalWrite(PIN_BUZZER, BUZZER_OFF); // catat waktu kirim pertama kali waktu_kirim = millis(); } void loop() { // kirim data KirimData(); // bunyi tilit tilit TilitTilit(); } void TilitTilit(){ // state ada 4 kondisi : 0 1 2 dan 3 // 0 adalah bip pertama 200ms // 1 adalah matinya bip pertama 100ms // 2 adalah bip kedua 200ms // 3 adalah matinya bip kedua // jika buzzer_state_counter >= 4, // maka blok program ini tdk dieksekusi. if( buzzer_state_counter < sizeof(buzzer_state) ){ // catat waktu saat ini buzzer_time = millis(); // cek apakah delay pada index state sudah terpenuhi if(buzzer_time - buzzer_time_last >=
52
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
buzzer_delay[buzzer_state_counter]){ // aktifkan atau matika buzzer sesuai // logika pada index state digitalWrite(PIN_BUZZER, buzzer_state[buzzer_state_counter]); // pindah state berikutnya buzzer_state_counter++; // catat waktu tadi sebagai waktu eksekusi terakhir buzzer_time_last = buzzer_time; } } } // fungsi untuk mengirim data void KirimData(){ // catat waktu sekarang kirimdata_time = millis(); // apabila waktu kirim terakhir dan waktu sekarang sudah 3 detik // eksekusi blok program berikut if( kirimdata_time - kirimdata_time_last >= kirimdata_delay ){ // cetak selisih waktu kirim sebelumnya // dengan pengiriman saat ini Serial.print("Selisih Waktu : "); Serial.println( millis() - waktu_kirim ); // catat waktu kirim data waktu_kirim = millis(); // catat waktu kirim data terakhir kirimdata_time_last = kirimdata_time; // setelah ngirim data // reset state buzzer menjadi 0 // sehingga blok program pada // baris 72 dieksekusi buzzer_state_counter = 0; } }
53
Bunyi buzzer Tilit Tilit juga demikian, pengecekannya berdasarkan waktu eksekusi terakhir. Hanya saja, terdapat 4 kondisi yang membedakan antara ON/OFF buzzer dan delay yang harus ditunggu (lihat baris 19-20). Jika
fungsi
TilitTilit()
divisualisasikan
dalam
time
diagram, maka bentuknya akan tampak seperti Gambar 5.2.
Gambar 5.2 Time diagram untuk kondisi State delay
Nilai State dan delay bisa dicocokan dengan inisialisasi program pada baris 19-20. Cara kerjanya adalah sebagai berikut: 1. Saat State direset menjadi 0, yaitu pada baris 115, maka periksa delay yang pada indeks 0 ms. 2. Jika delay pada State 0 habis (0 ms), buzzer masuk ke State 0 = kondisi ON. Sementara waktu tunggu masuk ke State 1, yaitu waktu tunggu 200 ms.
54
3. Setelah waktu tunggu State 1 habis, maka buzzer menyusul masuk ke State 1, sehingga logika berubah menjadi OFF. 4. Begitu seterusnya hingga masuk ke State 4. Gambar 5.3 adalah hasil dari program setelah perbaikan. Hasilnya, waktu pengiriman data lebih pas 3 detik. Kelebihannya, program ini hanya sedikit terpengaruh apabila ada penambahan blok program baru. Namun akan terpengaruh apabila ada bagian blok program yang menggunakan delay yang melebihi 3 detik. Lalu bagaimana solusinya?
Gambar 5.3 Hasil perbaikan program Dummy Logger
Salah satu solusinya adalah menggunakan Timer Interrupt yang akan kita bahas pada bab selanjutnya. 55
Namun sebelum kita membahas tentang timer interrupt, penulis akan berbagi tentang salah satu source code yang dapat digunakan sebagai pengganti delay. Source code tersebut bisa kita sebut delay yang resposive. Kita sebut delay yang responsive sebab delay ini tidak memblok dan menghentikan eksekusi bagian program lainnya sebagaimana fungsi delay().
5.3 Program Simpel Delay yang Responsive Program 5.3 Program Delay Responsive 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/* * MONSTER ARDUINO V2 * Program Delay Responsive * www.ElangSakti.com */ // buzzer disetting active low // BUZZER_OFF kebalikan dari BUZZER_ON #define BUZZER_ON LOW #define BUZZER_OFF !BUZZER_ON // GND buzzer dihubungkan ke pin 2 const byte PIN_BUZZER = 2; // logika buzzer boolean DATA_BUZZER = BUZZER_OFF; void setup() { // pin buzzer sebagai output pinMode(PIN_BUZZER, OUTPUT); // matikan buzzer digitalWrite(PIN_BUZZER, DATA_BUZZER); }
56
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
void loop() { // buzzer akan nyala setiap 1 detik if( nonblocking_delay(1000) ){ DATA_BUZZER = !DATA_BUZZER; digitalWrite(PIN_BUZZER, DATA_BUZZER); } // program di baris 30-33 memiliki fungsi yg sama // dengan program berikut: // digitalWrite(PIN_BUZZER, BUZZER_ON); // delay(1000); // digitalWrite(PIN_BUZZER, BUZZER_OFF); // delay(1000); } // tambahan untuk membuat delay non blocking unsigned long nonblocking_time = millis(); unsigned long nonblocking_last = millis(); boolean nonblocking_delay(long milidetik){ nonblocking_time = millis(); if(nonblocking_time - nonblocking_last >= milidetik){ nonblocking_last = nonblocking_time; return true; } return false; }
Cara kerja program : Buzzer akan menyala satu detik, mati satu detik, dan begitu seterusnya. Biasanya, dulu kalau membuat LED flip flop, banyak referensi yang menggunakan blok program seperti pada baris 37 – 40. Nah, karena kita harus terbiasa untuk menghindari fungsi delay, maka penulis membuat fungsi 57
yang bernama nonblocking_delay() yang fungsinya bisa menggantikan
delay.
Blok
program
29
–
32
akan
menghasilkan bunyi yang sama dengan baris 37 – 40. Bedanya, baris 29 – 32 sifatnya responsive, sedangkan baris 37 – 40 tidak responsive. Cara menggunakan fungsi ini cukup dimasukkan dalam fungsi if(), kemudian tentukan delay yang diinginkan. Dengan demikian, program akan dieksekusi secara simultan sesuai delay atau durasi yang diinputkan. Fungsi
nonblocking_delay()
memanfaatkan
catatan
waktu eksekusi, khususnya dalam satuan milidetik. Waktu eksekusi terakhir akan dibandingkan dengan waktu eksekusi saat ini (lihat baris 49). Jika selisihnya lebih besar atau sama dengan nilai delay yang telah ditentukan, maka output dari fungsi ini adalah true. Namun jika belum sampai pada selisih waktu yang ditentukan, fungsi ini akan menghasilkan output false. Blok program pada baris 45 – 54 akan sering kita gunakan pada program dan project selanjutnya. Jadi, pastikan Anda memahami cara kerja fungsi tersebut. Jika Anda menginginkan timer yang presisi, Anda bisa gunakan timer interrupt. Mari kita bahas timer interrupt, silakan lanjut ke bab berikutnya. 58
Bagian #06
RESPONSIVE DENGAN TIMER INTERRUPT Orang yang menginginkan impiannya menjadi kenyataan, harus menjaga diri agar tidak tertidur. (Richard Wheeler)
___
6.1 Seperti Apa Timer Interrupt? Simpelnya, timer interrupt adalah salah satu dari ISR (Interrupt Service Routine) yang merupakan interupsi yang dilakukan berdasarkan pewaktu atau timer. Bagian program yang dieksekusi sebagai interupsi akan dianggap lebih penting daripada program yang sedang berjalan. Oleh sebab itu, bagian program yang sedang berjalan akan dijeda sementara sehingga alur program dialihkan ke bagian program yang diinterupsikan. Setelah program interupsi selesai, maka bagian program yang tadinya dijeda, akan dilanjutkan lagi.
59
Gambar 6.1 Perbedaan program dengan interupsi dan tanpa interupsi
Berdasarkan ilustrasi tersebut, kita bisa menginterupsi setiap sekian milidetik atau bahkan setiap mikrodetik. Bahkan ketika kita mengeksekusi perintah delay() sekalipun, interupsi tetap dijalankan. Mau bukti? Mari kita langsung coba dengan Arduino.
6.2 Program Timer Interrupt Sederhana Program 6.1 Program Timer Interrupt Sederhana 1 2 3 4 5 6 7 8 9
/* * MONSTER ARDUINO V2 * Program Timer Interrupt Sederhana * www.ElangSakti.com */ // timer interrupt 1Hz int Data_Hz = 1; // per 1 S
60
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
// hitung register untuk dicocokkan long INT_REGISTER = (16000000L / (Data_Hz*1024L)) - 1; volatile int counter = 0; void setup() { Serial.begin(19200); while(!Serial); // setting interrupt cli(); //stop interrupts TCCR1A = 0; // set TCCR1A register = 0 TCCR1B = 0; // set TCCR1B register = 0 TCNT1 = 0; // inisialisasi counter = 0 OCR1A = INT_REGISTER; // untuk 10kHz TCCR1B |= (1 << WGM12); // aktifkan CTC mode TCCR1B |= (1 << CS12) | (1 << CS10); // Set CS12&CS10 bits=1024 prescaler TIMSK1 |= (1 << OCIE1A); // aktifkan timer compare interrupt sei(); //allow interrupts } void loop() { delay(100000); } // ====================================== // eksekusi sesuai timer interrupt // ====================================== ISR(TIMER1_COMPA_vect){ cli(); //stop interrupts Serial.print("Counter: "); Serial.println(counter); counter++; sei(); //allow interrupts }
61
Perhatikan Program 6.1, pada fungsi loop() tidak ada perintah untuk mengirim data serial monitor. Perintah untuk mengirim data dipicu dalam fungsi yang menangani timer interrupt (lihat baris 44).
Gambar 6.2 Hasil eksekusi program dengan timer Interrupt
Jika ingin menggunakan timer interrupt, maka yang harus dilakukan adalah: 1. Memilih waktu interrupt, interrupt akan dilakukan dalam durasi berapa lama? Pada contoh di program, interrupt dilakukan setiap 1 detik (lihat baris 8). 2. Setelah menentukan waktu interrupt, hitung alamat register yang akan dimasukkan untuk konfigurasi waktu yang telah kita pilih tadi (lihat baris 11).
62
3. Tentukan konfigurasi register yang berhubungan dengan timer interrupt (lihat baris 23 - 29). 4. Sebelum
register
dikonfigurasi,
interrupt
harus
dimatikan dulu dengan perintah cli() (lihat baris 21). 5. Setelah mengkonfigurasi register, interrupt harus diaktifkan dengan perintah sei() (lihat baris 31). 6. Setelah melakukan konfigurasi, siapkan fungsi ISR seperti pada baris 44. Penting!!! Setiap variabel yang akan dimodifikasi dalam fungsi ISR harus didefinisikan sebagai variabel volatile. Jika ingin menggunakan fungsi yang berkaitan dengan interrupt seperti Serial.print(), millis(), atau micros(), maka interrupt harus dimatikan dahulu. Jika tidak, program pasti error. Perhatikan baris 45 dan 49.
6.3 Dummy Logger dengan Timer Interrupt Program 6.2 Program Dummy Logger dengan Timer Interrupt 1 2 3 4 5 6 7 8 9 10 11
/* * MONSTER ARDUINO V2 * Program Dummy Logger dengan Timer Interrupt * www.ElangSakti.com */ // buzzer disetting active low // BUZZER_OFF kebalikan dari BUZZER_ON #define BUZZER_ON LOW #define BUZZER_OFF !BUZZER_ON
63
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
// GND buzzer dihubungkan ke pin 2 const byte PIN_BUZZER = 2; // variabel untuk cek waktu kirim unsigned long waktu_kirim = 0; // logika buzzer const unsigned long buzzer_delay[] = {0,200,100,200}; const boolean buzzer_state[] = {BUZZER_ON, BUZZER_OFF, BUZZER_ON, BUZZER_OFF}; byte buzzer_state_counter = sizeof(buzzer_state); // pencatat waktu timer buzzer unsigned long buzzer_time = 0; unsigned long buzzer_time_last = 0; // pencatat waktu timer kirim data unsigned long kirimdata_time = 0; unsigned long kirimdata_time_last = 0; // delay kirim data 3 detik const long kirimdata_delay = 3000;
// timer interrupt 10kHz int Data_Hz = 10000; // per 0.1 S // hitung register untuk dicocokkan long INT_REGISTER = (16000000L / (Data_Hz*1024L)) - 1;
void setup() { // aktifkan komunikasi serial // pada baudrate 19200 Serial.begin(19200); // tunggu hinga Serial siap digunakan while(!Serial); // pin buzzer sebagai output pinMode(PIN_BUZZER, OUTPUT); digitalWrite(PIN_BUZZER, BUZZER_OFF);
64
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
// catat waktu kirim pertama kali waktu_kirim = millis(); // setting interrupt cli(); //stop interrupts TCCR1A = 0; // set TCCR1A register = 0 TCCR1B = 0; // set TCCR1B register = 0 TCNT1 = 0; // inisialisasi counter = 0 OCR1A = INT_REGISTER; // untuk 10kHz TCCR1B |= (1 << WGM12); // aktifkan CTC mode TCCR1B |= (1 << CS12) | (1 << CS10); // Set CS12&CS10bits=1024 prescaler TIMSK1 |= (1 << OCIE1A); // aktifkan timer compare interrupt sei(); //allow interrupts
} void loop() { // program utama delay(30000); } // ====================================== // eksekusi sesuai timer interrupt // ====================================== ISR(TIMER1_COMPA_vect){ cli(); //stop interrupts // kirim data KirimData(); // bunyi tilit tilit TilitTilit(); sei(); //allow interrupts } void TilitTilit(){ // state ada 4 kondisi : 0 1 2 dan 3 // 0 adalah bip pertama 200ms
65
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
// 1 adalah matinya bip pertama 100ms // 2 adalah bip kedua 200ms // 3 adalah matinya bip kedua // jika buzzer_state_counter >= 4, // maka blok program ini tdk dieksekusi. if( buzzer_state_counter < sizeof(buzzer_state) ){ // catat waktu saat ini buzzer_time = millis(); // cek apakah delay pada index state sudah terpenuhi if(buzzer_time - buzzer_time_last >= buzzer_delay[buzzer_state_counter]){ // aktifkan atau matika buzzer sesuai // logika pada index state digitalWrite(PIN_BUZZER, buzzer_state[buzzer_state_counter]); // pindah state berikutnya buzzer_state_counter++; // catat waktu tadi sebagai waktu eksekusi terakhir buzzer_time_last = buzzer_time; } } } // fungsi untuk mengirim data void KirimData(){ // catat waktu sekarang kirimdata_time = millis(); // apabila waktu kirim terakhir dan waktu sekarang sudah 3 detik // eksekusi blok program berikut if( kirimdata_time - kirimdata_time_last >= kirimdata_delay ){ // cetak selisih waktu kirim sebelumnya // dengan pengiriman saat ini Serial.print("Selisih Waktu : "); Serial.println( millis() - waktu_kirim ); // catat waktu kirim data waktu_kirim = millis(); // catat waktu kirim data terakhir kirimdata_time_last = kirimdata_time;
66
141 142 143 144 145 146 147 148 149
// setelah ngirim data // reset state buzzer menjadi 0 // sehingga blok program pada // baris 72 dieksekusi buzzer_state_counter = 0; } }
Gambar 6.3 Hasil perbaikan program Dummy Logger dengan Timer Interrupt
67
Bagian #07
WDT & PROGRAM ANTIMACET Banyak hal yang bisa menjatuhkanmu. Tapi satu-satunya hal yang benar-benar dapat menjatuhkanmu adalah sikapmu sendiri. (Raden Ajeng Kartini)
___
Program antimacet. Ya, jika kita mampu menggunakan WDT pada program kita, kita bisa membuat program yang antimacet. WDT adalah singkatan dari watchdog timer atau timer watchdog. WDT akan otomatis mereset program apabila program macet atau hang. Jika kita membuat alat yang mudah dijangkau, mungkin WDT tidak terlalu
terasa
pentingnya. Jika
alat kita
bermasalah karena program error, kita bisa memantaunya dari
dekat
dan
tinggal pencet tombol reset
untuk
menormalkannya kembali. Namun, jika alat yang Anda buat diletakkan di atas loteng, di atas tower, atau di atas gunung, apakah Anda tidak keberatan jika harus bersusah-susah naik ke sana hanya untuk mencet tombol reset?! 68
Ilmu tentang WDT ini sepele, tapi efeknya bisa menghemat biaya dan waktu. Bisa dibayangkan jika Anda membuat alat untuk mengisi air bak mandi otomatis yang dapat dikontrol melalui internet. Eh, tiba-tiba tengah malam alatnya macet, padahal relay pompanya sedang aktif. Apa yang terjadi? Banjiiiiirrrr… :D ***
Konsep WDT bisa dijelaskan dengan perumpamaan seperti ini: Anggap saja Anda sedang ikut lomba makan 101 buah krupuk. Kemudian Mukidi yang bertugas menghitung dari 1 sampai 10. Aturannnya lombanya adalah : 1. Setiap 1 krupuk harus habis sebelum hitungan ke 10. Apabila Anda berhasil menghabiskan krupuk pada hitungan ke 6, Anda bisa lanjut makan krupuk nomer 2, dan hitungan Mukidi mulai dari angka 1 lagi. 2. Pada krupuk-krupuk selanjutnya, jika pada hitungan ke-5 Anda keselek hingga hitungan ke-10, maka Anda kena pinalti. Anda harus mulai dari awal lagi, makan krupuk dari nomer 1 lagi. Nah, kurang lebih seperti itu
cara
kerja WDT. Jika WDT gagal
mengihitung counter, program harus reset dari awal. Ilustrasi di atas dapat dijabarkan seperti ini : Anda adalah program Arduino yang sedang dieksekusi. Mukidi adalah WDT. WDT adalah timer yang bisa dipicu dari 69
internal mikrokontroller atau bisa juga dari eksternal mikrokontroller. Counter pada WDT tidak pernah berhenti meski program sedang error atau macet. Ketika WDT diaktifkan, ia bertugas merestart Arduino sesuai durasi yang telah ditentukan.
Jika kita mengaktifkan WDT dengan durasi 8 detik, maka Arduino akan restart setiap 8 detik. Akan aneh kalau alat kita restart setiap 8 detik kan? hehe. Dengan demikian, kita harus mereset hitungan timer WDT sebelum mencapai 8 detik. Seperti kasus Mukidi, kita harus segera menghabiskan krupuk sebelum hitungan Mukidi mencapai angka 10. Jadi, sebelum hitungan WDT yang 8 detik habis, kita harus mereset WDT menjadi 0 lagi. Proses reset timer WDT biasanya dilakukan di dalam fungsi loop(). Dengan demikian, kita harus memastikan bahwa program yang ada di dalam fungsi loop() tidak membutuhkan waktu lebih dari 8 detik. Kalau lebih dari 8 detik, entah karena program error atau delay terlalu lama, maka Arduino akan restart. Simpel kan? Selanjutnya, mari kita langsung praktek. Oiya, untuk penjelasan program pada bab 7 akan dijelaskan pada edisi revisi. Oleh sebab itu, untuk versi 70
ebook versi ini, silakan Anda baca keterangan di setiap barisnya untuk memahami.
7.1 Program WDT Sederhana Program 7.1 Program WDT Sederhana 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
/* * MONSTER ARDUINO V2 * Program WDT Sederhana * www.ElangSakti.com */ // include library wdt #include
// counter const byte jumlah_krupuk = 10; // lama delay makan krupuk dal ms int lama_makan_krupuk[jumlah_krupuk] = { 3000, 3500, 2000, 5500, 4000, 9000, // keselek, jadi lama 2000, 3000, 4000, 5000 }; byte giliran = 0; void setup() { // disable wdt // lalu tunggu hingga stabil wdt_disable(); delay(2000);
71
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
Serial.begin(19200); while(!Serial); // // kunfigurasi lainnya jika ada // Serial.println("==== Start Program!"); // aktifkan wdt dg waktu tunggu 8 detik wdt_enable(WDTO_8S); } void loop() { // lama makan krupuk sesuai giliran delay( lama_makan_krupuk[giliran] ); // giliran berikutnya giliran++; Serial.print("Krupuk No. "); Serial.print(giliran); Serial.println(", habis!"); // reset wdt, krupuk sudah habis wdt_reset(); }
72
Gambar 7.1 Output Program WDT dasar
7.2 Program WDT Lanjutan Program 7.2 Program WDT Lanjutan 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/* * MONSTER ARDUINO V2 * Program WDT Lanjutan * www.ElangSakti.com */ // include library wdt #include byte counter = 0; void setup() { // disable wdt // lalu tunggu hingga stabil wdt_disable(); delay(2000);
73
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
Serial.begin(19200); while(!Serial); // // kunfigurasi lainnya jika ada // Serial.println("==== Start Program!"); // aktifkan wdt dg waktu tunggu 4 detik wdt_enable(WDTO_4S); } void loop() { Serial.print("Counter: "); Serial.print(counter); Serial.print(" => "); if( counter == 0 ){ // blok program 2 detik Serial.println(" 2 detik."); delay(2000); } else if( counter == 1 ){ // blok program 6 detik Serial.println(" 6 detik."); delay(1000); delay(1000); delay(1000); wdt_reset(); delay(1000); delay(1000); delay(1000); wdt_reset(); } else if( counter == 2 ){ // blok program 11 detik Serial.println(" 11 detik."); for(byte i=0; i<11; i++){ delay(1000); wdt_reset(); } } else { // blok program 4.5 detik
74
61 62 63 64 65 66 67 68 69
Serial.println(" 4.5 detik."); delay(4500); } counter++; // reset wdt, krupuk sudah habis wdt_reset(); }
Gambar 7.2 Output Program WDT lanjutan
Penjelasan lebih banyak tentang WDT akan dilejaskan saat kita membahas tentang interrupt secara keseluruhan pada edisi selanjutnya. Untuk saat ini, Anda bisa mencobacoba program yang khusus WDT dahulu.
75
Bagian #08
MODUL RELAY Orang yang paling tidak bahagia ialah mereka yang yang paling takut pada perubahan. (Mignon McLaughlin)
___
Relay adalah komponen yang dapat digunakan sebagai saklar elektronik. Secara singkat, cara kerja relay adalah memanfaatkan magnet buatan untuk memicu kontaktor dari keadaan off menjadi on, atau sebaliknya.
Gambar 8.1 Skema Relay
Ibaratnya begini, jika ingin menghidupkan lampu, kita harus pencet saklar yang nempel di tembok. Tapi jika menggunakan
relay,
kita
bisa
menghidupkan
atau
mematikan lampu tanpa menyentuh saklar lagi. Relay
76
disebut juga sebagai saklar elektronik, yaitu saklar dapat dikontrol dengan alat elektronik lainnya seperti Arduino.
Gambar 8.2 Relay 2 Channel tampak depan
Gambar 8.3 Relay 2 Channel tampak belakang
Relay umumnya punya 5 pin atau kaki., yang terdiri dari: 1. Dua kaki untuk listrik + dan GND, jika arus dan tegangannya cukup, maka relay akan aktif yang ditandai dengan bunyi „tek‟. 77
2. Satu kaki sumber C (common), kaki ini yang akan dihubungkan ke kaki NC atau NO. Jika relay akan digunakan untuk mengontrol lampu rumah, maka kaki C disambung ke salah satu jalur listrik dari PLN. 3. Kaki NC (Normally Close), sebelum relay aktif, kaki NC nyambung ke kaki C (perhatikan gambar). Tapi kalai relaynya aktif, kaki NC terputus dari kaki C. 4. Kaki NO (Normally Open), sebelum relay aktif, kaki NO tidak nyambung ke mana-mana. Tapi ketika relay aktif, kaki NO terhubung ke kaki C. Sebelum mencoba relay yang sudah dirangkai dalam sebuah modul, istilah yang perlu kita pahami yaitu : Active Low dan Active High. Active Low artinya, relay akan aktif kalau input diberi logika LOW atau GND. Sedangkan Active High artinya, relay akan aktif apabila input diberi logika HIGH atau +5v.
78
8.1 Active Low atau Active High
Gambar 8.4 Skema untuk testing Relay
Relay Active Low atau Active High bisa dicek pada spesifikasi yang telah ditentukan oleh pabriknya. Jika Anda ragu, Anda bisa cek langsung modul relaynya dengan beberapa komponen dan power supply yang cocok. Perhatikan Gambar 8.4. Selain untuk menentukan Active Low atau Active High, cara ini biasa penulis gunakan untuk menentukan apakah relay berfungsi dengan baik atau tidak. Untuk relay Active Low, relay akan aktif jika input dihubungkan ke GND. Jika relay Active High, relay aktif jika input dihubungkan ke VCC. Namun jika relay tidak merespon ketika diberi input GND atau VCC, pastikan kabel-kabelnya terhubung dengan benar. Kalau semua sudah benar, tapi tetap tidak ada respon. Kemungkinan besar ada komponen yang rusak. 79
8.2 Masalah yang Sering Muncul Kontaktor relay diaktifkan dengan elektromagnetik yang dihasilkan oleh kumparan pada relay. Setiap alat yang memiliki kumparan, sifat elektromagnetik pada kumparan akan dikembalikan menjadi listrik lagi apabila sumber tegangannya
diputus. Artinya, sesaat setelah
sumber
tegangan diputus, maka medan elektromagnetik yang menyelubungi kumparan akan diserap lagi oleh kumparan sehingga terbentuklah listrik yang polaritasnya berkebalikan dengan sumber tegangan. Listrik yang terbentuk dan berbalik arah ini disebut Back Electromotive Force, atau bisa disingkat Back EMF.
Gambar 8.5 Polaritas kaki kumparan saat aktif dan sesaat setelah diputus
Bukti adanya Back EMF bisa dilihat di video ini : https://youtu.be/EtJGgHNe7iY Apa masalahnya kalau ada Back EMF? Back EMF dapat mengganggu sistem kelistrikan Arduino, entah karena listrik yang dihasilkan atau munculnya EMI (Electromagnetic
80
Interference). Untuk hal ini, Anda bisa googling tentang EMI dan Latch-Up pada mikrokontroller. Untuk
mengatasi
adanya
Back
EMF
dan
EMI,
dipasanglah dioda pada kaki kumparan dan tambahan kapasitor untuk memfilter. Hanya saja, proteksi ini kadang gagal. Sehingga mengakibatkan sistem kelistrikan tetap terganggu. Efek nyatanya, Arduino akan RESTART sesaat setelah relay dimatikan. Jika Anda membuat sistem yang agak sensitif terhadap medan elektromagnet, Anda bisa mengisolasi power supply relay dari power supply Arduino. Selain itu, Anda juga bisa mengganti relay dengan SSR (Solid State Relay). Cara mengisolasi power supply pada relay yang akan dipakai akan kita jelaskan pada sub bab berikutnya.
8.3 Mengisolasi Power Supply Pada modul Relay, ada jumper JD-VCC, VCC, dan GND. Jangan pernah memasang jumper antara VCC dan GND, ya.. . Jika jumper dipasang antara JD-VCC dan VCC, berarti sumber tegangan untuk Relay adalah sesuai VCC di sebelah IN1 dan IN2. Tapi jika ingin menggunakan sumber tegangan dari luar, silakan lepas jumpernya. Kemudian dirangkai seperti gambar 8.6. 81
Gambar 8.6 Isolasi power supply Relay
JD-VCC dihubungkan ke kabel positif power supply, GND ke GND. Untuk bagian input, GND TIDAK dihubungkan ke GND Arduino. Kenapa? Jika GND dihubungkan ke GND Arduino, maka rangkaiannya tidak terisolasi lagi. Jika Anda masih masih bingung kenapa rangkaiannya seperti itu, coba pelajari skema pada Gambar 8.7.
Gambar 8.7 Skema internal optocoupler modul Relay
Skema rangkaian di atas menunjukkan bahwa sisi kiri (VCC dan IN2) dan sisi kanan (JD-VCC dan GND) dipisah 82
oleh optocoupler U3. Jadi rangkaian Relay benar-benar terisolasi dari rangkaian Arduino. Selanjutnya, mari kita ulas sedikit tentang SSR.
8.4 Sekilas tentang SSR (Solid State Relay) Kalau relay adalah saklar elektronik, maka SSR adalah relay elektronik. Bingung? Tidak kan ya… Relay bisa dibilang termasuk alat elektro mekanik, sebab ada bagian yang harus bergerak saat ia diaktifkan. Ketika relay aktif, logam menjadi magnet, lalu tuas tertarik magnet dan menyambungkan kaki NO dan C.
Gambar 8.8 Contoh Solid State Relay
Sedangkan pada SSR, tidak ada magnet, tidak ada kumparan, tidak ada tuas yang bergerak. Komponen yang digunakan sebagai saklar adalah semikonduktor seperti SCR, TRIAC, atau transistor seperti MOSFET.
83
Pada relay, gerakan tuas untuk ON-OFF dikendalikan oleh magnet. Sedangkan pada SSR, proses ON-OFF dikendalikan oleh cahaya. Bagian input akan memancarkan cahaya ketika diaktifkan, pada bagian output terdapat Optocoupler yang nantinya akan memicu kontaktor. Jika dibandingkan dengan Relay biasa, SSR lebih cepat responnya, kisaran 10us. Sedangkan Relay kisar 10ms. Jika Anda butuh sistem yang sangat cepat respon dan tanpa BACK EMF, gunakan SSR. SSR lebih tahan terhadap getaran dan goncangan. Hal ini disebabkan komponen SSR yang tidak memiliki tuas dan perangkat mekanik lainnya. Yang menjadi kelebihan lagi dari SSR adalah: harganya lebih tinggi dari Relay biasa.
Semakin tinggi harganya, semakin berkualitas barangnya.
Mungkin Anda setuju dengan pernyataan di atas, mungkin juga tidak. Relatif kan ya? Semua orang juga tahu bahwa harga berbanding lurus dengan kualitas. Selanjutnya, kita akan membahas bagaimana tips dan teknik memprogram tombol push button supaya fungsinya tidak monoton. Silakan langsung lompat ke bab selanjutnya. 84
Bagian #09
EKSPLORASI TOMBOL PUSH BUTTON Apabil dalam diri seseorang masih ada rasa malu dan takut untuk berbuat sesuatu kebaikan, maka jaminan bagi orang tersebut adalah tidak akan bertemunya ia dengan kemajuan selangkah pun. (Ir. Soekarno)
___
Pada buku versi pertama, kita telah belajar tentang push button atau tombol. Kita juga telah belajar tentang bagaimana sebuah tombol dijadikan sebagai INPUT dan merangkai tombol dengan pullup resistor. Pada buku ini kita akan membahas tentang: 1. Cara menggunakan internal Pullup Resistor 2. Membuat tombol multikondisi 3. Membuat aksi ketika tombol ditekan lama 4. Menangani banyak tombol dengan sebuah pin Analog Di bawah ini adalah gambar push button dengan kaki panjang, lebih enak jika kita menggunakan project board. Tidak sulit pas nancepin. 85
Gambar 9.1 DIP Push button, tombol berkaki panjang
9.1 Internal Pullup Resistor Dengan adanya internal pullup resistor, kita tidak perlu lagi menambahkan resistor pada tombol sebagai pullup. Cukup
mengaktifkan
internal
pullup
resistor
dengan
program. Mungkin ada bertanya, buat apa sih pullup resistor? Jika pin Arduino diset sebagai INPUT, maka logika yang terbaca oleh Arduino tergantung INPUT yang diberikan. Jika pin dihubungkan ke VCC, logika yang terbaca adalah HIGH. Jika pin dhibungkan ke GND, maka logika yang terbaca adalah LOW. Lalu bagaimana jika pin tidak dihubungkan ke VCC atau GND?
86
Nah, kondisi seperti itu disebut floating. Logika pada pin bisa dibilang kacau, HIGH dan LOW bergantian. Logika pada pin INPUT seakan digantung, nggak jelas. Sehingga kita butuh resistor untuk menentukan kondisi defaultnya, apakah akan dibuat default HIGH atau default LOW. Ngomong-ngomong, apakah perasaan Anda pernah digantung sama orang? =)) *abaikan
Untuk mengaktifkan internal pullup resistor, pin Arduino tidak didefinisikan dengan INPUT lagi, tapi INPUT_PULLUP. Langsung buat rangkaian seperti di bawah ini. Setelah itu, coba kedua program di bawah untuk melihat perbedaan antara penggunaan INPUT dan INPUT_PULLUP.
9.1.1 Rangkaian Testing Pullup Resistor Peralatan dan rangkaian yang perlu disiapkan adalah: 1. Arduino x 1 2. Push button x 1 3. Kabel jumper secukupnya Sambungan pin Antara Arduino dan push button : Arduino
Push Button
Pin 2 GND
Kaki 1 Kaki 2
87
Gambar 9.2 Rangkaian untuk testing Internal Pullup Resistor
9.1.2 Program Tombol tanpan Pullup Resistor Program 9.1 Program Tombol tanpa Pullup Resistor 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/* * MONSTER ARDUINO V2 * Program Tombol tanpa Pullup Resistor * www.ElangSakti.com */ // tombol pada pin 2 const byte PIN_TOMBOL = 2; // variabel penyimpan data dari tombol // dan data sebelumnya boolean data = HIGH; boolean data_last = data; void setup() { // buka koneksi ke serial Serial.begin(19200); while(!Serial); // tombol sebagai input pinMode(PIN_TOMBOL,INPUT); }
88
24 25 26 27 28 29 30 31 32 33 34 35
void loop() { // baca data tombol data = digitalRead(PIN_TOMBOL); // jika data berbeda dari data sebelumnya // cetak ke serial monitor if(data != data_last){ Serial.println( data ); // simpan data sebagai data sebelumnya data_last = data; } }
Setelah program diupload, Anda boleh cek di Serial Monitor dengan baud rate 19200. Nilai apa yang keluar, 0 atau 1? Atau tampilannya kacau? Saya sengaja tidak menampilkan hasilnya di sini supaya Anda mencobanya sendiri. Ketika pin Arduino dalam kondisi floating (tidak jelas apakah defaultnya 0 atau 1), maka dia akan kebingungan. Sehingga yang muncul di Serial Monitor adalah 0 dan1 bergantian, meski tombol tidak diapa-apakan. Selanjutnya edit baris 21 hingga menjadi program selanjutnya, dan bandingkan hasilnya.
89
9.1.3 Program Tombol dengan Internal Pullup Resistor Program 9.2 Program Tombol dengan Internal Pullup Resistor 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
/* * MONSTER ARDUINO V2 * Program Tombol dengan Internal Pullup Resistor * www.ElangSakti.com */ // tombol pada pin 2 const byte PIN_TOMBOL = 2; // variabel penyimpan data dari tombol // dan data sebelumnya boolean data = HIGH; boolean data_last = data; void setup() { // buka koneksi ke serial Serial.begin(19200); while(!Serial); // tombol sebagai input dengan pullup resistor pinMode(PIN_TOMBOL,INPUT_PULLUP); } void loop() { // baca data tombol data = digitalRead(PIN_TOMBOL); // jika data berbeda dari data sebelumnya // cetak ke serial monitor if(data != data_last){ Serial.println( data ); // simpan data sebagai data sebelumnya data_last = data; } }
Pada program yang kedua, data akan muncul jika tombol ditekan. Berdasarkan logika program, data dicetak 90
ke serial monir apabila data berubah (logika yang diterima berbeda dengan logika sebelumnya), lihat baris 29. Dengan tambahan pengetahuan ini, Anda telah belajar bagaimana menangani input berupa tombol dan mengerti tentang pullup resistor yang ada dalam internal Arduino.
9.2 Membuat Tombol Multikondisi Apa maksud dari tombol multikondisi? Normalnya, tombol push button hanya punya dua logika, ON dan OFF, namun
kondisi
ON
tidak
dapat
terkunci.
Jika
kita
menggukan switch ON/OFF seperi saklar, kondisi ON akan terkunci dengan mudah karena proses pengunciannya secara fisik. Jika kita pakai tombol push button, akan susah kalau kita ingin mengunci kondisi ON. Sebab logika tombol akan langsung berubah menjadi OFF ketika tombol kita lepas. Untuk mengawali belajar tentang tombol multikondisi, pertama kita akan membuat program yang lebih manusiawi. Program yang lebih manusiawi maksudnya adalah informasi yang muncul di serial monitor bukan angka 0 atau 1, tapi tulisan yang lebih bisa dipahami.
91
9.2.1 Program Tombol yang Manusiawi Mungkin penamaannya aneh. Tapi nggak masalah, yang penting kita bisa membedakan berbagai program dalam buku ini berdasarkan nama programnya. Program 9.3 Program Tombol yang Manusiawi 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
/* * MONSTER ARDUINO V2 * Program Tombol yang Manusiawi * www.ElangSakti.com */ // kita set supaya tombol active low #define ON LOW #define OFF !ON // tombol pada pin 2 const byte PIN_TOMBOL = 2; // data awal ada OFF // dan data sebelumnya juga OFF boolean data = OFF; boolean data_last = data; void setup() { // buka koneksi ke serial Serial.begin(19200); while(!Serial); // tombol sebagai input dengan pullup resistor pinMode(PIN_TOMBOL,INPUT_PULLUP); } void loop() { // baca data tombol data = digitalRead(PIN_TOMBOL); // jika data berbeda dari data sebelumnya // cetak ke serial monitor if(data != data_last){
92
35 36 37 38 39 40 41 42 43 44 45 46 47
// jika ON, cetak ON // jika OFF, cetak OFF if(data == ON){ Serial.println("ON"); } else { Serial.println("OFF"); } // simpan data sebagai data sebelumnya data_last = data; } }
Gambar 9.3 Hasil Program Multikondisi yang Manusiawi
Pada output Program 9.3, muncul tulisan ON ketika tombol ditekan. Lalu akan muncul tulisan OFF ketika penekanan tombol dilepas. Mungkin sesekali akan muncul tulisan ON dan OFF dua kali. Hal tersebut bisa menjadi masalah, sebab memang perubahaan data memang terjadi 93
2 kali yaitu perubahan dari OFF ke ON ketika tombol mulai ditekan dan perubahan dari ON ke OFF saat tombol dilepas. Kita bisa memodifikasi karakteristik tombol di atas supaya mirip dengan switch ON/OFF. Jadi, ketika tombol ditekan, maka kondisi akan ON. Jika tombol ditekan lagi, kondisi berubah menjadi OFF. Jika tombol ditekan lagi, kondisi menjadi ON lagi, dan seterusnya. Jadi status ON dan OFF-nya seakan bisa dikunci seperti switch
atau
saklar.
Silakan
langsung
coba
selanjunya.
9.2.2 Program Tombol dengan Lock Status Program 9.4 Program Tombol dengan Lock Status 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/* * MONSTER ARDUINO V2 * Program Tombol dengan Lock Status * www.ElangSakti.com */ // kita set supaya tombol active low #define ON LOW // active low #define OFF !ON // tombol pada pin 2 const byte PIN_TOMBOL = 2; // data awal ada OFF // dan data sebelumnya juga OFF boolean data = OFF; boolean data_last = data; // variabel untuk lock status
94
program
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
boolean logika = data; // delay untuk penekanan tombol. // setelah tombol ditekan, maka selama 150 ms // tidak bisa ditekan. // delay ini berguna untuk menghindari 2 kali eksekusi unsigned long delay_press = 150; // dalam ms unsigned long delay_press_last = 0; void setup() { // buka koneksi ke serial Serial.begin(19200); while(!Serial); // tombol sebagai input dengan pullup resistor pinMode(PIN_TOMBOL,INPUT_PULLUP); } void loop() { // jika selisih waktu penekanan tombol // lebih besar dari waktu delay tombol // baca tombol lagi, jika tidak tombol tdk dibaca if( millis() - delay_press_last > delay_press ){ // baca data tombol data = digitalRead(PIN_TOMBOL); // jika data berbeda dari data sebelumnya // cetak ke serial monitor if(data != data_last){ // jika data = ON if(data == ON){ // balik status logika tolbol logika = !logika; // jika ON, cetak ON // jika OFF, cetak OFF if( logika == ON ){ Serial.println("ON"); } else {
95
63 64 65 66 67 68 69 70 71 72 73
Serial.println("OFF"); } } // simpan data sebagai data sebelumnya data_last = data; // catat waktu penekanan tombol terakhir delay_press_last = millis(); } } }
Pada Program 9.4, status ON atau OFF tombol tidak didasarkan pada data yang dibaca oleh digitalRead(). Akan tetapi, status ON atau OFF ditentukan dengan variabel logika (lihat baris 20). Cara kerjanya seperti ini : 1. Pertama kali, variabel logika berstatus OFF. 2. Jika tombol ditekan, data variabel logika dibalik menjadi OFF. 3. Jika tombol ditekan lagi, data variabel logika dibalik lagi menjadi ON. Begitu seterusnya. 4. Proses pembalikan logika dilakukan pada baris 56. 5. Untuk
membalik
logika,
kita
hanya
butuh
mendeteksi penekanan tombol, yaitu ketika kondisi tombol = ON. Lihat baris 53. Program 9.4 sudah tidak lagi menampilkan dua kali eksekusi untuk sekali penekanan tombol. Pencegahan dua kali eksekusi dilakukan dengan menambahkan pemeriksaan apakah logika tombol berubah atau tidak (lihat baris 50). Terakhir kali menekan tombol dicatat pada baris 70. 96
Jadi, selama logika tombol tidak berubah, maka Arduino akan mengunci status dan tombol tidak akan pernah terbaca berkali-kali. Kecuali tombol dilepas, baru status akan kembali berubah. ***
Selanjutnya, mari kita pisah fungsi untuk membaca tombol dan fungsi yang mengeksekusi aksi dari penekanan tombol. Kenapa harus dipisah? Bukannya kalau bersatu kita bisa teguh??? Dengan pemisahan menjadi beberapa fungsi, akan lebih mudah ketika kita ingin modifikasi dan pengembangan program. Lalu, akan lebih mudah juga jika kita menemukan error, sebab bagian-bagian program sudah terlokalisasi sesuai fungsinya. Setiap fungsi dijadikan modul-modul, atau bisa juga disebut sabagai modular.
9.2.3 Program Tombol Modular Program 9.5 Program Tombol Modular 1 2 3 4 5 6 7 8 9
/* * MONSTER ARDUINO V2 * Program Tombol Modular * www.ElangSakti.com */ // kita set supaya tombol active low #define ON LOW // active low #define OFF !ON
97
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
// tombol pada pin 2 const byte PIN_TOMBOL = 2; // data awal ada OFF // dan data sebelumnya juga OFF boolean data = OFF; boolean data_last = data; // variabel untuk lock status boolean logika = data; // delay untuk penekanan tombol. // setelah tombol ditekan, maka selama 150 ms // tidak bisa ditekan. // delay ini berguna untuk menghindari 2 kali eksekusi unsigned long delay_press = 150; // dalam ms unsigned long delay_press_last = 0; void setup() { // buka koneksi ke serial Serial.begin(19200); while(!Serial); // tombol sebagai input dengan pullup resistor pinMode(PIN_TOMBOL,INPUT_PULLUP); } void loop() { // baca logika tombol TombolListener(); } // fungsi TombolListener void TombolListener(){ // jika selisih waktu penekanan tombol // lebih besar dari waktu delay tombol // baca tombol lagi, jika tidak tombol tdk dibaca if( millis() - delay_press_last > delay_press ){ // baca data tombol
98
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
data = digitalRead(PIN_TOMBOL); // jika data berbeda dari data sebelumnya // cetak ke serial monitor if(data != data_last){ // jika data = ON if(data == ON){ // balik status logika tolbol logika = !logika; // eksekusi aksi tombol sesuai logika AksiTombol(logika); } // simpan data sebagai data sebelumnya data_last = data; // catat waktu penekanan tombol terakhir delay_press_last = millis(); } } } // Fungsi AksiTombol // INPUT : boolean tombol void AksiTombol(boolean tombol){ // jika ON, cetak ON // jika OFF, cetak OFF if( tombol == ON ){ Serial.println("ON"); } else { Serial.println("OFF"); } }
Program multikondisi kita pecah menjadi dua buah fungsi. Fungsi pertama untuk membaca logika tombol. Sedangkan fungsi satunya lagi untuk menangani aksi 99
penekanan tombol. Misal kita ingin mendisable aksi penekanan tombol cukup dengan mendisable baris 67 dengan menambahkan dua garis miring didepannya. Jika ingin mendisable fungsi pembacaan tombol, kita tinggal mendisable baris 41. Lebih simpel daripada menghapus atau mendisable banyak baris program. Selanjutnya, kita akan membuat program yang memiliki banyak menu, tapi dipilih dengan sebuah tombol. Apakah bisa? Bisa dong…
9.2.4 Program Satu Tombol Banyak Menu Program 9.6 Program Satu Tombol Banyak Menu 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/* * MONSTER ARDUINO V2 * Program Satu Tombol Banyak Menu * www.ElangSakti.com */ // kita set supaya tombol active low #define ON LOW // active low #define OFF !ON // definisikan 4 buah menu // menu 0 - 3 #define MENU_0 0 #define MENU_1 1 #define MENU_2 2 #define MENU_3 3 // tombol pada pin 2 const byte PIN_TOMBOL = 2; // data awal ada OFF
100
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
// dan data sebelumnya juga OFF boolean data = OFF; boolean data_last = data; // variabel untuk lock status boolean logika = data; // jadikan menu sebagai array supaya lebih mudah const byte MENU[] = {MENU_0,MENU_1,MENU_2,MENU_3}; // siapkan teks nama-nama menu const String TEKS_MENU[] = { "Menu Utama", "Menu 1 Setting", "Menu 2 Inpu Data", "Menu 3 Exit" }; // cata menu yang aktif saat ini // saat start, menu yg aktif adalah menu_3 byte MENU_COUNTER = MENU_3; // delay untuk penekanan tombol. // setelah tombol ditekan, maka selama 150 ms // tidak bisa ditekan. // delay ini berguna untuk menghindari 2 kali eksekusi unsigned long delay_press = 150; // dalam ms unsigned long delay_press_last = 0; void setup() { // buka koneksi ke serial Serial.begin(19200); while(!Serial); // tombol sebagai input dengan pullup resistor pinMode(PIN_TOMBOL,INPUT_PULLUP); } void loop() { // baca logika tombol TombolListener(); }
101
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
// fungsi TombolListener void TombolListener(){ // jika selisih waktu penekanan tombol // lebih besar dari waktu delay tombol // baca tombol lagi, jika tidak tombol tdk dibaca if( millis() - delay_press_last > delay_press ){ // baca data tombol data = digitalRead(PIN_TOMBOL); // jika data berbeda dari data sebelumnya // cetak ke serial monitor if(data != data_last){ // jika data = ON if(data == ON){ // pilih menu selanjutnya MENU_COUNTER++; // jika menu melebihi jumlah menu yg ada // pilih menu awal if( MENU_COUNTER >= sizeof(MENU) ){ MENU_COUNTER = 0; } // eksekusi aksi tombol sesuai logika AksiTombol(MENU_COUNTER); } // simpan data sebagai data sebelumnya data_last = data; // catat waktu penekanan tombol terakhir delay_press_last = millis(); } } } // Fungsi AksiTombol // INPUT : byte tombol void AksiTombol(byte tombol){
102
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
// print sesuai menu yang dipilih switch(tombol){ case MENU_0: // proses sesuatu Serial.println(TEKS_MENU[MENU_0]); break; case MENU_1: // proses sesuatu Serial.println(TEKS_MENU[MENU_1]); break; case MENU_2: // proses sesuatu Serial.println(TEKS_MENU[MENU_2]); break; case MENU_3: // proses sesuatu Serial.println(TEKS_MENU[MENU_3]); break; } }
Gambar 9.4 Hasil Program Satu Tombol Banyak Menu
103
Program
9.6
akan
menampilkan
menu
secara
bergantian. Boleh diperhatikan input data pada fungsi AksiTombol() adalah byte tombol (baris 107), bukan lagi boolean tombol sebagaimana pada program 9.5 baris 81. Dengan demikian, variasi jumlah logika atau kondisi bisa lebih lebih banyak lagi, mau 200 menu pun bisa. Inti dari perubahan menu ini ada pada perubahan variabel MENU_COUNTER pada baris 85 – 90. Setiap tombol ditekan, angka MENU_COUNTER terus bertambah, jika melebihi jumlah menu yang ada, maka akan direset menjadi 0. Selain itu, penyesuaian dilakukan pada fungsi AksiTombol(). Menu akan dicetak sesuai data yang diterima oleh tombol (lihat baris 110 – 130). Jika Anda sudah mulai paham dengan logika program 9.6, mari kita lanjut untuk membuat aksi jika tombol lama ditekan. Aksi ini seperti kita mau matiin ponsel, setelah kita tekan tombol power sekian detik, ponsel baru mati. Mari lanjut ke Program selanjutnya.
9.3 Membuat Aksi Tombol yang Ditekan Lama Untuk membuat tombol yang bisa melakukan sesuai ketika terjadi penekanan yang lama ada banyak cara sesuai kondisi. Namun, inti dari program ini adalah penyisipan 104
timer. Setiap penekanan tombol tidak boleh langsung diputuskan untuk melakukan aksi. Namun, setiap penekanan tombol akan ditunggu hingga tombol dilepas. Jadi, kondisi tombol ditentukan saat tombol dilepas. Dalam banyak pemrograman komputer ada aksi yang disebut onKeyUp, artinya aksi yang dikerjakan apabila tombol dilepas. Dengan begitu, kita bisa menghitung berapa lama tombol ditekan.
Selanjutnya kita akan
membuat program tombol dengan karakteristik berikut: 1. Jika tombol ditekan sebentar, muncul menu utama 2. Jika tombol ditekan > 3 detik, akan muncul menu 1 3. Jika tombol ditekan > 5 detik , akan muncul menu 2 4. Jika tombol ditekan > 10 detik atau lebih, akan muncul menu 3
9.3.1 Program Aksi Tombol Berdasarkan Lama Ditekan Program 9.7 Program Aksi Tombol Berdasarkan Lama Ditekan 1 2 3 4 5 6 7 8 9 10 11 12
/* * MONSTER ARDUINO V2 * Program Aksi Tombol Berdasarkan Lama Ditekan * www.ElangSakti.com */ // kita set supaya tombol active low #define ON LOW // active low #define OFF !ON // definisikan 4 buah menu // menu 0 - 3
105
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
#define MENU_0 0 #define MENU_1 1 #define MENU_2 2 #define MENU_3 3 // tombol pada pin 2 const byte PIN_TOMBOL = 2; // data awal ada OFF // dan data sebelumnya juga OFF boolean data = OFF; boolean data_last = data; // variabel untuk lock status boolean logika = data; // pemetaan delay terhadap aksi menu // delay 0 - 3000 => muncul menu_0 // delay 3000 - 5000 => muncul menu_1 // delay 5000 - 10000=> muncul menu_2 // delay > 10000 => muncul menu_3 const unsigned int TOMBOL_DELAY[] = {0, 3000, 5000, 10000}; // dalam ms // jadikan menu sebagai array supaya lebih mudah const byte MENU[] = {MENU_0,MENU_1,MENU_2,MENU_3}; // siapkan teks nama-nama menu const String TEKS_MENU[] = { "Menu Utama", "Menu 1 Setting", "Menu 2 Input Data", "Menu 3 Exit" }; // cata menu yang aktif saat ini // saat start, menu yg aktif adalah menu_3 byte MENU_COUNTER = MENU_3; // delay untuk penekanan tombol. // setelah tombol ditekan, maka selama 150 ms // tidak bisa ditekan. // delay ini berguna untuk menghindari 2 kali eksekusi unsigned long delay_press = 150; // dalam ms unsigned long delay_press_last = 0;
106
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
// variabel untuk mencatat awal tombol ditekan unsigned long start_press = 0; void setup() { // buka koneksi ke serial Serial.begin(19200); while(!Serial); // tombol sebagai input dengan pullup resistor pinMode(PIN_TOMBOL,INPUT_PULLUP); } void loop() { // baca logika tombol TombolListener(); } // fungsi TombolListener void TombolListener(){ // jika selisih waktu penekanan tombol // lebih besar dari waktu delay tombol // baca tombol lagi, jika tidak tombol tdk dibaca if( millis() - delay_press_last > delay_press ){ // baca data tombol data = digitalRead(PIN_TOMBOL); // jika data berbeda dari data sebelumnya // cetak ke serial monitor if(data != data_last){ // ketika OFF / onKeyUp if(data == OFF){ // catat selisih antara // awal tombol ditekan hingga dilepas unsigned long selisih = millis() - start_press; if( selisih >= TOMBOL_DELAY[MENU_3] ){
107
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
// jika lama ditekan >= 10 detik MENU_COUNTER = MENU_3; } else if( selisih >= TOMBOL_DELAY[MENU_2] ){ // jika lama ditekan >= 5 detik MENU_COUNTER = MENU_2; } else if( selisih >= TOMBOL_DELAY[MENU_1] ){ // jika lama ditekan >= 3 detik MENU_COUNTER = MENU_1; } else { // jika antara 0 - 3 detik MENU_COUNTER = MENU_0; } // eksekusi aksi tombol sesuai logika AksiTombol(MENU_COUNTER); } else { // reset waktu yang tercatat start_press = millis(); } // simpan data sebagai data sebelumnya data_last = data; // catat waktu penekanan tombol terakhir delay_press_last = millis(); } } } // Fungsi AksiTombol // INPUT : byte tombol void AksiTombol(byte tombol){ // print sesuai menu yang dipilih switch(tombol){ case MENU_0: // proses sesuatu Serial.println(TEKS_MENU[MENU_0]); break;
108
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
case MENU_1: // proses sesuatu Serial.println(TEKS_MENU[MENU_1]); break; case MENU_2: // proses sesuatu Serial.println(TEKS_MENU[MENU_2]); break; case MENU_3: // proses sesuatu Serial.println(TEKS_MENU[MENU_3]); break; } }
Cara kerja program 9.7 yaitu : 1. Pertama kali tombol ditekan, waktu penekanan dicatat oleh start_press (lihat baris 122). 2. Selama tombol ditekan, kondisi pada baris 89 bernilai false. Sehingga blok program di dalam if() tersebut tidak pernah dieksekusi. 3. Ketika tombol dilepas, kondis if() pada baris 89 bernilai true, karena logika tombol berubah dari true menjadi false. 4. Karena logika tombol adalah false, maka blok program pada baris 96 – 117 akan dieksekusi. Selisih waktu dihitung, lalu menu dipilih sesuai index tombol yang telah didefinisikan pada baris 34. 5. Setelah tombol terpilih, eksekusi aksi berdasarkan tombol yang terpilih tersebut. 109
Program 9.7 relatif simpel, kalaupun belum terbiasa, sekaranglah
waktunya
untuk
membiasakan
berpikir
kerasss!!! Selanjutnya, mari kita membuat banyak tombol, tapi dengan sebuah pin INPUT. Bisa kah? Bisa….. asalkan PIN input yang digunakan adalah Analog. Mari lanjut ke pembahasan berikutnya.
9.4 Mengelola Banyak Tombol dengan Satu Pin
Gambar 9.5 Rangkaian dasar banyak tombol dengan satu pin
Syarat untuk mengelola tombol dengan sebuah pin Input adalah pin tersebut harus Analog. Di Arduino Uno, kita bisa menggunakan pin A0 – A5. Kenapa harus analog? Sebab, kita akan mengimplementasikan konsep pembagi tegangan dan data diterima dengan pin analog. Anda boleh memperhatikan gambar 9.5, sebab konsep yang akan kita pakai akan seperti gambar tersebut. 110
Pada Gambar 9.5, ketika tombol S1 – S5 ditekan, maka output akan menghasilkan voltase yang berbeda-beda yang dapat dihitung berdasarkan konsep pembagi tegangan. Perbedaan voltase inilah yang diterima oleh pin Analog. Jika semua resistor memiliki nilai resistansi yang sama, maka secara teori data output bisa dihitung seperti Tabel 9.1. Berapapun nilai resistornya, yang penting nilainya seragam, maka hasilnya akan seperti tabel ini. Tabel 9.1 Tabel Perhitungan Ouput Tombol berdasarkan Konsep Pembagi Tegangan
Tombol Ditekan S1 S2 S3 S4 S5
Resistor Aktif R1, R2, R3, R4, R5 R1, R3, R4, R5 R1, R4, R5 R1, R5 R1
Output Volt 5V/5 = 1V 5V/4 = 1.25V 5V/3 = 1.67V 5V/2 = 2.5V 5V/1 = 5V
Data (analogRead()) 1*(1023/5) = 204.6 1.25*(1023/5) = 255.75 1.67*(1023/5) = 341.68 2.5*(1023/5) = 511.5 5*(1023/5) = 1023
Berdasarkan tabel di atas, jika data dari analogRead() adalah sekitar 204, berarti tombol S1 ditekan. Jika data dari analogRead() adalah sekitar 511, berarti tombol S4 ditekan. Saya sebut kira-kira karena bisa jadi nilai resistansi resistor agak berbeda, jadi bisa kurang bisa lebih. Untuk mengatasi kurang lebih nilai tersebut, kita bisa ambil nilai toleransi 10 – 20. Misal untuk tombol S1, berarti nilai untuk mengidentifikasi tombolnya adalah antara 194 – 214. Selanjutnya, mari kita buktikan dengan program. 111
9.4.1 Rangkaian Program untuk Membaca 5 Tombol Peralatan dan rangkaian yang perlu disiapkan adalah: 1. Arduino x 1 2. Push button x 5 3. Resistor dengan nilai seragam x 5 4. Project board x 1 5. Kabel jumper secukupnya Sambungan pin antara Arduino dan push button : Arduino
Rangkaian Push Button
Pin A0
Output push button (sisi lain dari sisi tombol yang terhubung ke resistor pembagi tegangan) Resistor pembagi tegangan Resistor pembagi tegangan sekaligus sebagai pullup resistor untuk pin A0
VCC GND
Gambar 9.6 Rangkaian program 1 input banyak tombol
112
9.4.2 Program Analisis Output Tombol Program 9.8 Program Analisis Output Tombol 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
/* * MONSTER ARDUINO V2 * Program Analisis Output Tombol * www.ElangSakti.com */ // output tombol di pin A0 const byte PIN_TOMBOL = A0; // data saat ini dan data sebelumnya int data = 0; int data_last = 0; // delay untuk penekanan tombol. // setelah tombol ditekan, maka selama 150 ms // tidak bisa ditekan. // delay ini berguna untuk menghindari 2 kali eksekusi unsigned long delay_press = 150; // dalam ms unsigned long delay_press_last = 0; void setup() { // buka koneksi ke serial Serial.begin(19200); while(!Serial); // tombol sebagai input pinMode(PIN_TOMBOL,INPUT); } void loop() { // panggil fungsi utk membaca tombol TombolListener(); } void TombolListener(){ // jika selisih waktu penekanan tombol
113
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
// lebih besar dari waktu delay tombol // baca tombol lagi, jika tidak tombol tdk dibaca if( millis() - delay_press_last > delay_press ){ // baca data tombol data = analogRead(PIN_TOMBOL); // jika data lebih kecil dari 10 abaikan if( data < 10 ) return; // jika data berbeda dari data sebelumnya // cetak ke serial monitor if(data != data_last){ Serial.println(data); data_last = data; delay_press_last = millis(); } } }
Gambar 9.7 Output program analisis output tombol
Output pada serial monitor masing-masing muncul dua kali. Data pertama ketika ditekan, data kedua muncul ketika dilepas. Berdasarkan data tersebut, kita bisa menggunakan toleransi 20. Sebab jika menggunakan toleransi 10, nilai 114
untuk SW2 mungkin tidak akan terdeteksi. Berdasarkan perhitungan, nilai output untuk SW2 adalah 255, sementara yang muncul di serial monitor adalah 246 atau 243. Jika menggunakan selisih 10, tentu angka 243 tidak terdeteksi sebagai SW2. Kurang lebih seperti itu cara kerja dan perhitungannya. Selanjutnya, mari kita lanjut ke program untuk menampilkan menu sesuai tombol yang ditekan.
9.4.3 Program Menu 5 Tombol Program 9.9 Program Menu 5 Tombol 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/* * MONSTER ARDUINO V2 * Program Menu 5 Tombol * www.ElangSakti.com */ // definisikan 5 tombol #define TOMBOL_NONE 0 #define TOMBOL1 1 #define TOMBOL2 2 #define TOMBOL3 3 #define TOMBOL4 4 #define TOMBOL5 5 // output tombol di pin A0 const byte PIN_TOMBOL = A0; // nilai data tombol sesuai tabel const int TOMBOL_VAL[] = {204,255,341,511,1023}; // nilai koreksi const byte KOREKSI = 15;
115
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
// tombol dalam array const byte TOMBOL[] = { TOMBOL1, TOMBOL2, TOMBOL3, TOMBOL4, TOMBOL5 }; // tombol saat ini dan tombol sebelumnya byte tombol = 0; byte tombol_last = 0; // data saat ini dan data sebelumnya int data = 0; int data_last = 0; // delay untuk penekanan tombol unsigned long delay_press = 400; // dalam ms unsigned long delay_press_last = 0; void setup() { // buka koneksi ke serial Serial.begin(19200); while(!Serial); // tombol sebagai input pinMode(PIN_TOMBOL,INPUT); } void loop() { // panggil fungsi utk membaca tombol TombolListener(); } void TombolListener(){ // jika selisih waktu penekanan tombol // lebih besar dari waktu delay tombol // baca tombol lagi, jika tidak tombol tdk dibaca if( millis() - delay_press_last > delay_press ){ // baca data analog tombol data = analogRead(PIN_TOMBOL); // reset tombol sebelumnya tombol = TOMBOL_NONE; // cocokkan data dengan ke-5 data tombol
116
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
for(byte i=0; i
117
111 112 113 114 115 116 117 118 119 120 121 122
case TOMBOL4: // proses sesuatu Serial.println("Menu 4"); break; case TOMBOL5: // proses sesuatu Serial.println("Menu 5"); break; } }
Cara kerja program 9.9 yaitu: 1. Referensi data untuk 5 buah tombol ada di baris 19. Sedangkan nilai toleransi yang dipilih adalah angka 15 (lihat baris 22). 2. Ketika tombol ditekan, maka data dari tombol diterima dengan analogRead() pada baris 64. 3. Sebelum mendeteksi tombol, tombol direset untuk menghindari salah baca (lihat baris 66). 4. Berikutnya data yang terbaca akan dicocokkan dengan SEMUA referensi nilai tombol (lihat fungsi loop di baris 68). 5. Data akan dicocokkan dengan setiap referensi data. Jika selisihnya lebih kecil dari nilai toleransi (lihat baris 73), maka pilih tombol, lalu stop looping dengan perintah break pada baris 75. 6. Setelah tombol terpilih, pilih AksiTombol() yang sesuai denga tombol yang terpilih (lihat baris 85). 118
Gambar 9.8 Output program Menu 5 Tombol
Setelah program 5 tombol dengan satu pin ini bekerja dengan
baik,
mari
kita
lanjut
dengan
aksi
untuk
menghidupkan led untuk setiap tombol. Program tombol dan LED ini adalah kombinasi dari program
membaca
banyak tombol dan program tombol dengan lock status. Program tombol dan LED ini akan kita gunakan sebagai dasar untuk mempelajari EEPROM pada bab berikutnya. Jadi, pastikan Anda mencoba program terakhir pada Bab ini.
9.4.4 Rangkain 5 Tombol 5 LED Part yang harus disiapkan dan rangkaiannya adalah: 1. Arduino Uno x 1 119
2. Push button x 5 3. Resistor x 10 (bebas) 4. LED x 10 5. Project Board x 1 6. Jumper secukupnya Sambungan pin Arduino, LED, dan push button : Arduino
Rangkaian
Pin A0
Output push button (sisi lain dari sisi tombol yang terhubung ke resistor pembagi tegangan) Kaki positif LED 1, 2, 3, 4, dan 5 Resistor pada tombol pembagi tegangan - Resistor pada tombol pembagi tegangan - Resistor pada kaki negatif LED
Pin 2, 3, 4, 5, dan 6 VCC GND
Gambar 9.9 Rangkaian untuk program 5 tombol 5 LED
Nilai resistor di gambar adalah 220 ohm, tapi Anda bisa menggunakan nilai lainnya.
120
9.4.5 Program 5 Tombol 5 LED Program 9.10 Program 5 Tombol 5 LED 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
/* * MONSTER ARDUINO V2 * Program 5 Tombol 5 LED * www.ElangSakti.com */ // led setting active high #define LED_ON HIGH #define LED_OFF !LED_ON // definisikan 5 tombol #define TOMBOL_NONE 0 #define TOMBOL1 1 #define TOMBOL2 2 #define TOMBOL3 3 #define TOMBOL4 4 #define TOMBOL5 5 // output tombol di pin A0 // pin led di pin 2 - 6 const byte PIN_TOMBOL = A0; const byte PIN_LED[] = {2,3,4,5,6}; // nilai data tombol sesuai tabel // dan nilai toleransi 15 const int TOMBOL_VAL[] = {204,255,341,511,1023}; const byte TOLERANSI = 15; // status led untuk lock status byte STATUS_LED[] = {LED_OFF,LED_OFF,LED_OFF,LED_OFF,LED_OFF}; // tombol dalam array const byte TOMBOL[] = { TOMBOL1, TOMBOL2, TOMBOL3, TOMBOL4, TOMBOL5 }; // tombol saat ini dan tombol sebelumnya byte tombol = 0; byte tombol_last = 0;
121
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
// data saat ini dan data sebelumnya int data = 0; int data_last = 0; // delay untuk penekanan tombol unsigned long delay_press = 400; // dalam ms unsigned long delay_press_last = 0; void setup() { // buka koneksi ke serial Serial.begin(19200); while(!Serial); // tombol sebagai input pinMode(PIN_TOMBOL,INPUT); // pin sebagai output, defaultnya OFF for(byte i=0; i delay_press ){ // baca data analog tombol data = analogRead(PIN_TOMBOL); // reset tombol sebelumnya tombol = TOMBOL_NONE; // cocokkan data dengan ke-5 data tombol for(byte i=0; i
122
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
// jika ada yang cocok, // catat tombol yang sesuai, lalu // hentikan looping. if( abs(data - TOMBOL_VAL[i]) < TOLERANSI ){ tombol = TOMBOL[i]; break; } } // jika ada tombol yang cocok // cetak tombol, panggil aksi tombol // lalu catat waktu pembacaan tombol if(tombol != TOMBOL_NONE){ Serial.println(tombol); AksiTombol(tombol); tombol_last = tombol; delay_press_last = millis(); } } } // fungsi AksiTombol // INPUT : byte tombol void AksiTombol(byte tombol){ // konversi dari nomer tombol menjadi index tombol byte index_led = tombol-1; // balik status LED sesuai index/led yang cocok // jika HIGH, ubah jadi LOW, dan sebaliknya STATUS_LED[index_led] = !STATUS_LED[index_led]; // cetak sesuai tombol yang terpilih switch(tombol){ case TOMBOL1: // proses sesuatu if( STATUS_LED[index_led] == LED_ON ){ Serial.println("Nyalakan LED 1"); } else { Serial.println("Matikan LED 1"); }
123
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
break; case TOMBOL2: // proses sesuatu if( STATUS_LED[index_led] == LED_ON ){ Serial.println("Nyalakan LED 2"); } else { Serial.println("Matikan LED 2"); } break; case TOMBOL3: // proses sesuatu if( STATUS_LED[index_led] == LED_ON ){ Serial.println("Nyalakan LED 3"); } else { Serial.println("Matikan LED 3"); } break; case TOMBOL4: // proses sesuatu if( STATUS_LED[index_led] == LED_ON ){ Serial.println("Nyalakan LED 4"); } else { Serial.println("Matikan LED 4"); } break; case TOMBOL5: // proses sesuatu if( STATUS_LED[index_led] == LED_ON ){ Serial.println("Nyalakan LED 5"); } else { Serial.println("Matikan LED 5"); } break; } // hidup matikan led, sesuai status led digitalWrite(PIN_LED[index_led],STATUS_LED[index_led]); }
124
Cara kerja Program 9.10 adalah: Anda boleh membaca source code di atas sendiri ya. Penjelasan lengkap bisa ditunggu pada edisi revisi. Btw, semakin sering Anda membaca
source
code,
Anda
akan
semakin
mahir
memahami cara kerjanya. Silakan pahami maksud dari setiap baris programnya. :D Setelah Anda memahami cara kerja Program 9.10, mari lanjut mempelajari EEPROM. EEPROM bisa kita gunakan untuk menyimpan data-data aplikasi yang sifatnya tidak boleh berubah ketika Arduino mati atau restart.
125
Bagian #10
EEPROM SEBAGAI BLACKBOX Hidupmu ada batasnya,jadi jangan sia-siakan hidupmu untuk terus hidup dari orang lain. (Steve Jobs)
___
Secara singkat EEPROM bisa diibaratkan sebagai hardisk internal pada Arduino. Data yang disimpan dalam EEPROM tidak akan hilang meski Arduino dimatikan. Mungkin Anda pernah menghadapi masalah tentang konfigurasi atau settingan Arduino yang hilang setelah Arduino restart atau mati. Kita ambil contoh Program 5 Tombol 5 Led pada bab sebelumnya. Pada program 5 Tombol 5 Led, ketika beberapa LED kita hidupkan, lalu Arduino kita reset, maka led yang tadinya hidup akan kembali ke kondisi awal, yaitu semua LED tidak menyala. Untuk menyimpan LED status LED nyala atau tidak, kita bisa menyimpan informasi tersebut pada EEPROM. Apabila terjadi kegagalan sistem, maka Arduino tidak akan kehilangan data meskipun Arduino restart berulang-ulang. Itulah kenapa judul pada bab ini kita namakan BlackBox. 126
Beberapa hal yang harus dipahami tentang EEPROM: 1. Ketahui kapasitas EEPROM, beda Arduino bisa jadi beda kapasitasnya. Anda boleh cek di pengenalan jenis-jenis Arduino. 2. Jika data pada alamat EEPROM belum pernah digunakan untuk menyimpan data, data defaultnya adalah 255. 3. Setiap alamat EEPROM hanya bisa menyimpan tipe data byte, yaitu dari 0 – 255. Jika ingin menyimpan data lebih dari 255, Anda harus memecahnya ke dalam beberapa alamat. 4. Library yang harus di-include adalah EEPROM.h yang sudah ada di Arduino IDE 5. Cara menyimpan ke EEPROM menggunakan perintah EEPROM.write(alamat,data); 6. Cata membaca data dari EEPROM menggunakan perintah EEPROM.read(alamat); Mari kita membuat program counter sederhana. Jika arduino baru start atau restart, maka counter tidak mengulang dari depan lagi, tapi melanjutkan counter sebelumnya. Membuat sistem yang seperti ini dapat dilakukan dengan bantuan EEPROM. Mari kita praktek…
127
10.1 Program Simulasi EEPROM Program ini tidak membutuhkan rangkaian khusus karena kita hanya simulasi dengan counter dan EEPROM yang sudah ada di internal Arduino. Jika Anda baru saja mencoba rangkaian lain, biarkan saja rangkaian tersebut karena tidak akan mempengaruhi program. Program 10.1 Program Simulasi EEPROM 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
/* * MONSTER ARDUINO V2 * Program Simulasi EEPROM * www.ElangSakti.com */ // import library EEPROM #include // pilih adrress 0 untuk menyimpan data const byte ADDR_COUNTER = 0; // nilai maksimum counter const byte counter_max = 100; void setup() { // buka koneksi ke serial Serial.begin(19200); while(!Serial); // print tulisan Starting saat mulai start Serial.println("Starting..."); } void loop() { // gunakan nonblocking_delay // untuk delay responsive if ( nonblocking_delay(1000) ){
128
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
// eksekusi fungsi untuk membaca // dan menyimpan data dalam EEPROM byte data = ReadSaveCounter(); // cetak counter di serial monitor Serial.print("Counter : "); Serial.println(data); } } // fungsi untuk baca-tulis data ke EEPROM // INPUT : // OUTPUT : byte data counter byte ReadSaveCounter(){ // baca alamat 0 pada EEPROM byte counter = EEPROM.read( ADDR_COUNTER ); // data yang diperoleh dari EEPROM tambah 1 // jika hasil counter > nilai maksimum counter // reset counter ke 0 counter++; if (counter > counter_max) counter = 0; // simpan lagi data yang telah dimodifikasi EEPROM.write(ADDR_COUNTER, counter); // return data return counter; } // tambahan untuk membuat delay non blocking unsigned long nonblocking_time = millis(); unsigned long nonblocking_last = millis(); boolean nonblocking_delay(long milidetik){ nonblocking_time = millis(); if(nonblocking_time - nonblocking_last >= milidetik){ nonblocking_last = nonblocking_time; return true; } return false; }
129
Gambar 10.1 Ouput program simulasi EEPROM
Cara kerja program Simulasi EEPROM adalah: 1. Untuk menggunaan EEPROM, kita harus import library EEPROM.h pada baris 8. 2. Alamat EEPROM untuk menyimpan data counter adalah di alamat 0 (lihat baris 11). 3. Setiap arduino mulai start atau restart, kan muncul tulisan “Starting…” di serial monitor (lihat baris 22). 4. Proses baca tulis EEPROM dilakukan setiap 1 detik (1000
ms),
nilai
ini
dimasukkan
ke
fungsi
nonblockin_delay() (lihat baris 29). 5. Setiap 1 detik, arduino akan menjalankan fungsi ReadSaveCounter() (lihat baris 33).
130
6. Arduino membaca data sebelumnya pada alamat 0 (lihat baris 48), apabila data nilainya lebih besar dari nilai maksimum counter, reset counter menjadi 0. Jika tidak, data tersebut adalah data yang terakhir disimpan. Ouput program menunjukkan bahwa setiap program restart, data counter langsung dilanjut berdasarkan data yang disimpan pada EEPROM. Selanjutnya mari kita membuat program 5 Tombol 5 LED dapat menyimpan status LED. Sehingga ketika Arduino aktif, status LED akan disesuaikan dengan kondisi status LED sebelumnya.
10.2 Program EEPROM 5 Tombol 5 LED Rangkaian untuk program ini sesuai dengan rangkaian Rangkaian 5 Tombol 5 LED pada bab sebelumnya. Program 10.2 Program EEPROM 5 Tombol 5 LED 1 2 3 4 5 6 7 8 9 10 11 12 13
/* * MONSTER ARDUINO V2 * Program EEPROM 5 Tombol 5 LED * www.ElangSakti.com */ // import library EEPROM # // led diset active high #define LED_ON HIGH #define LED_OFF !LED_ON
131
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
// definisikan 5 tombol #define TOMBOL_NONE 0 #define TOMBOL1 1 #define TOMBOL2 2 #define TOMBOL3 3 #define TOMBOL4 4 #define TOMBOL5 5 // output tombol di pin A0 // pin led di pin 2 - 6 const byte PIN_TOMBOL = A0; const byte PIN_LED[] = {2,3,4,5,6}; // alamat EEPROM untuk data LED const byte ADDR_LED[] = {0,1,2,3,4}; // nilai data tombol sesuai tabel // dan nilai toleransi 15 const int TOMBOL_VAL[] = {200,250,338,507,1014}; const byte TOLERANSI = 15; // status led untuk lock status byte STATUS_LED[] = {LED_OFF,LED_OFF,LED_OFF,LED_OFF,LED_OFF}; // tombol dalam array const byte TOMBOL[] = { TOMBOL1, TOMBOL2, TOMBOL3, TOMBOL4, TOMBOL5 }; // tombol saat ini dan tombol sebelumnya byte tombol = 0; byte tombol_last = 0; // data saat ini dan data sebelumnya int data = 0; int data_last = 0; // delay untuk penekanan tombol unsigned long delay_press = 400; // dalam ms unsigned long delay_press_last = 0; void setup() { // buka koneksi ke serial Serial.begin(19200);
132
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
while(!Serial); // tombol sebagai input pinMode(PIN_TOMBOL,INPUT); // pin sebagai output, defaultnya OFF for(byte i=0; i delay_press ){ // baca data analog tombol data = analogRead(PIN_TOMBOL); // reset tombol sebelumnya tombol = TOMBOL_NONE; // cocokkan data dengan ke-5 data tombol for(byte i=0; i
133
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
} } // jika ada tombol yang cocok // cetak tombol, panggil aksi tombol // lalu catat waktu pembacaan tombol if(tombol != TOMBOL_NONE){ Serial.println(tombol); AksiTombol(tombol); tombol_last = tombol; delay_press_last = millis(); } } } // fungsi AksiTombol // INPUT : byte tombol void AksiTombol(byte tombol){ // konversi dari nomer tombol menjadi index tombol byte index_led = tombol-1; // balik status LED sesuai index/led yang cocok // jika HIGH, ubah jadi LOW, dan sebaliknya STATUS_LED[index_led] = !STATUS_LED[index_led]; // cetak sesuai tombol yang terpilih switch(tombol){ case TOMBOL1: // proses sesuatu if( STATUS_LED[index_led] == LED_ON ){ Serial.println("Nyalakan LED 1"); } else { Serial.println("Matikan LED 1"); } break; case TOMBOL2: // proses sesuatu if( STATUS_LED[index_led] == LED_ON ){ Serial.println("Nyalakan LED 2"); } else {
134
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
Serial.println("Matikan LED 2"); } break; case TOMBOL3: // proses sesuatu if( STATUS_LED[index_led] == LED_ON ){ Serial.println("Nyalakan LED 3"); } else { Serial.println("Matikan LED 3"); } break; case TOMBOL4: // proses sesuatu if( STATUS_LED[index_led] == LED_ON ){ Serial.println("Nyalakan LED 4"); } else { Serial.println("Matikan LED 4"); } break; case TOMBOL5: // proses sesuatu if( STATUS_LED[index_led] == LED_ON ){ Serial.println("Nyalakan LED 5"); } else { Serial.println("Matikan LED 5"); } break; } // hidup matikan led, sesuai status led digitalWrite(PIN_LED[index_led],STATUS_LED[index_led]); // simpan status led pada EEPROM sesuai alamat EEPROM.write(ADDR_LED[index_led],STATUS_LED[index_led]); } // fungsi PrepareLED // untuk membaca data EEPROM saat awal start void PrepareLED(){ for(byte i=0; i
135
188 189 190 191 192 193 194 195
STATUS_LED[i] = EEPROM.read(ADDR_LED[i]); // status led adalah boolean 0 atau 1 // jika data yg tersimpan > 1, reset ke 0 if(STATUS_LED[i] > 1) STATUS_LED[i] = 0; // kondisikan LED sesuai data yg tersimpan digitalWrite(PIN_LED[i],STATUS_LED[i]); } }
Cara kerja program ini seperti Program 5 Tombol 5 LED, yang membedakannya adalah proses penyimpanan status LED di EEPROM (lihat baris 180). Selain itu, ketika program mulai start, maka program akan membaca status LED sebelumnya di memori dengan fungsi PrepareLED (lihat baris 71). Fungsi PrepareLED() ada di baris 185 – 195, sedangkan baris untuk membaca data di EEPROM ada di baris 188. Pada bab sebelumnya, kita telah belajar bagaimana caranya memperbanyak jumlah tombol (INPUT) dengan pin Analog dan konsep pembagi tegangan. Selanjutnya, kita akan memperbanyak jumlah ouput Arduino dengan Shift Register.
Bagiamana
caranya?
berikutnya…
136
Mari
lanjut
ke
bab
Bagian #11
PIN OUTPUT YANG MELIMPAH Jangan takut gagal, karena yang tidak pernah gagal hanyalah orang-orang yang tidak pernah melangkah. (Buya Hamka)
___ Pernahkah Anda merasa kalau pin Arduino kurang ketika
membuat
sebuah
project?
Misal
ketika
menghubungkan Arduino dengan LCD 1602, atau ketika Arduino harus mengontrol banyak relay? Nah, solusi untuk masalah tersebut akan kita bahas pada bab ini. Untuk memperbanyak pin ouput Arduino, kita bisa menggunan shift register. Shift register yang akan kita pakai berupa IC yang berkode 74HC595. Kita tidak akan berteori terlalu banyak tentang Shift Register ini. Namun kita usahakan tetap ada informasi tentang Shift Register agar Anda dapat memahami
dengan mudah bagaimana cara
kerjanya. Tentu pengetahuan ini sebagai bekal untuk berbagai project yang mungkin akan Anda kerjakan nanti.
137
Shift Register (register geser) adalah teknik pergeseran bit data yang berfungsi untuk mengonversi data serial ke paralel atau dari paralel ke serial. Pengertian di atas adalah pendapat pribadi yang didasarkan pada cara kerja shift register, khususnya untuk konversi data. Semoga pengertian tersebut bisa dipahami. Jadi, pengertian tersebut bukanlah pengertian secara tekstual seperti yang dimuat di buku-buku pada umumnya. Pada dasarnya ada 4 jenis shift register: 1. Serial In Serial Out (SISO), shift register ini untuk mengolah atau memodifikasi data serial. 2. Paralel In Paralel Out (PIPO), shift register jenis ini juga mungkin akan jarang ditemui, gunanya adalah untuk mengubah data paralel. 3. Serial In Paralel Out (SIPO), shift register ini digunakan untuk mengonversi data serial ke data paralel. Jadi input data bisa hanya satu atau dua jalur, tapi outputnya bisa banyak jalur. Pada bab ini, kita akan membahas salah satu IC untuk shift register jenis ini, yaitu menggunakan IC 74HC595. 4. Paralel In Serial Out (PISO), shift register ini untuk konversi data paralel menjadi data serial. Bingung dengan istilah data serial dan data paralel? Perhatikan gambar di bawah ini. 138
Gambar 11.1 Perbedaan transmisi data dengan serial dan paralel
Data serial hanya membutuhkan satu jalur data. Bit data akan dikirim satu-satu sehingga data harus antri pada jalur yang sama. Sedangkan data yang ditransfer secara paralel menggunakan banyak jalur data sehingga data yang dikirim sesuai jumlah jalur yang tersedia. Proses konversi dari serial ke paralel atau dari paralel ke serial diilustrasikan dengan gambar berikut:
Gambar 11.2 Konversi data serial ke paralel (kiri) dan dari paralel ke serial (kanan)
Pada gambar 11.2 kiri adalah konversi dari serial ke paralel, input data satu jalur, sedangkan ouputnya menjadi 4 jalur. Pada konversi serial ke paralel, output bisa tak terbatas tergantung kemampuan IC yang digunakan. Sedangkan
139
konversi dari paralel ke serial (lihat gambar 11.2 kanan), input data dari 4 jalur, sedangkan outputnya jadi satu jalur. Seperti itulah penjelasan sangat singkat terkait shift register. Konsep ini diterapkan pada IC shift register 74HC595 yang akan kita gunakan untuk “memperbanyak” kaki Arduino pada bab ini.
11.1 Rangkaian Dasar IC 74HC595
Gambar 11.3 Gambar dan Skema kaki IC 74HC595
IC 74HC595 memiliki jumlah kaki 16. Sebuah IC 74HC595 dapat mengkonversi dari serial data menjadi 8 bit output. Jika membutuhkan lebih banyak output, kita bisa menggunakan beberapa IC sekaligus yang dihubungkan secara seri. Jika butuh 20 output, Anda bisa menggunakan 3 buah IC 74HC595. Informasi kegunaan pin IC bisa dilihat pada Tabel 11.1. Setelah Anda memahami cara kerja dan fungsi pin-pinnya, 140
mari kita membuat program lampu “berjalan”, maksudnya lampu LED yang nyala satu-satu bergantian. Tabel 11.1 Fungsi Pin IC 74HC595
Pin
Simbol
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Q1 Q2 Q3 Q4 Q5 Q6 Q7 GND Q7’ MR SH_CP ST_CP OE DS Q0 VCC
Keterangan Output bit ke 2 Output bit ke 3 Output bit ke 4 Output bit ke 5 Output bit ke 6 Output bit ke 7 Output bit ke 8 Ground Output data serial ke pin input (DS) IC berikutnya Master Reset (active low) Clock untuk Shift Register Latch, Clock untuk Storage Register Output Enable (active low) Data Serial (DS) input Ouput bit ke 1 VCC
11.2 Project LED Berjalan 11.2.1 Rangkaian LED Berjalan Peralatan yang disiapkan dan rangkaiannya adalah: 1. Arduino x 1 2. IC Shift Register 74HC595 x 1 3. LED x 8 4. Resistor dengan nilai seragam x 8 5. Project board x 1 141
6. Kabel jumper secukupnya Sambungan pin Arduino, IC 74HC595, dan lainnya yaitu : Arduino
IC 74HC595
Komponen Lain
Pin 2 Pin 3 Pin 4 VCC GND -
Pin 14, Data Pin 12, Latch Pin 11, Clock Pin 10 dan 16 Pin 8 dan 13 Pin 15,1,2,3,4,5,6,7 (Q0-Q) Pin 9
Resistor ke kaki negatif LED Kaki positif LED 1,2,3,4,5,6,7,8 -
Gambar 11.4 Rangkain LED berjalan dengan shift register
11.2.2 Program LED Berjalan Program 11.1 Program LED Berjalan dengan Shift Register 1 2 3 4 5 6 7
/* * MONSTER ARDUINO V2 * Program LED Berjalan dengan Shift Register * www.ElangSakti.com */ // konfigurasi pin Arduino
142
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
const byte DataPin = 2; // DS data serial const byte LatchPin = 3; // ST_CP const byte ClockPin = 4; // SH_CP // menampung data byte data = 0; void setup() { // konfigurasi pin sebagai ouput pinMode(LatchPin, OUTPUT); pinMode(ClockPin, OUTPUT); pinMode(DataPin, OUTPUT); } void loop() { // delay 200ms if ( nonblocking_delay(200) ){ // geser kiri data <<= 1; // jika data == 0 (gesernya sudah habis) // ulangi dari awal if( data == 0 ) data = 1; // mulai transfer digitalWrite(LatchPin, LOW); // kirim data shiftOut(DataPin, ClockPin, MSBFIRST, data); // stop transfer digitalWrite(LatchPin, HIGH); } } // tambahan untuk membuat delay non blocking unsigned long nonblocking_time = millis(); unsigned long nonblocking_last = millis(); boolean nonblocking_delay(long milidetik){ nonblocking_time = millis(); if(nonblocking_time - nonblocking_last >= milidetik){ nonblocking_last = nonblocking_time; return true;
143
51 52 53
} return false; }
Cara kerja program di atas adalah : 1. Untuk mengontrol IC 74HC595, kita membutuhkan 3 buah pin Arduino yang akan digunakan sebagai jalur data, latch, dan clock (lihat baris 8 - 10). 2. Karena jumlah LED hanya 8 buah, maka kita minimal harus menggunakan data dengan lebar 8 bit. Data yang memiliki lebar 8 bit adalah tipe data byte. Jadi penggunaan tipe data byte sudah cukup untuk membuat LED berjalan ini. 3. Untuk LED berjalan, kita bisa menggunakan perintah untuk menggeser bit dari kiri ke kanan atau dari kanan ke kiri. Pada contoh kali ini kita akan menggeser
bit
dari
kanan
ke
kiri.
Ilustrasi
pergeserannya adalah seperti berikut:
Gambar 11.5 Ilustrasi pergeseran bit data
Dari angka 1 digeser ke kiri sebanyak 1 bit (lihat baris 29). Jika sudah sampai pada bit 7, ketika 144
digeser ke kiri satu kali lagi, maka angka akan berubah jadi 0. Sebab tipe data byte maksimal hanya hingga bit ke 7. Jika digeser ke bit 8, maka bit 0 – 7 akan menjadi 0 semua. 4. Untuk mengirim data, maka antara Arduino dan IC 74HC595 harus diaktifkan dan disinkronisasi dahulu dengan mengaktifkan pin Latch (lihat baris 35). 5. Data
dikirim
dengan
perintah
ShiftOut()
dan
disesuaikan berdasarkan clock yang disinkronisasi (lihat baris 37). 6. Setelah pengiriman data selesai, akhiri transfer data dengan menonaktifkan pin latch (lihat baris 39). Selain menggunakan perintah ShiftOut, komunikasi ke IC 74HC595 bisa dilakukan dengan SPI. Apa bedanya? Jika menggunakan ShiftOut, kita bisa menggunakan kaki mana saja untuk dijadikan pin Clock dan Data. Jika menggunakan SPI, maka pin Clock dan Data harus dihubungkan ke pin digital 13 dan 11.
11.2.3 Rangkaian Shift Register dengan SPI Peralatan pada rangkaian ini sama dengan rangkain pada Program 11.1. Yang berbeda adalah kaki untuk pin
145
latch, data, dan clock yang menghubungkan antara Arduino dan IC 74HC595.
Gambar 11.6 Rangkain LED berjalan dengan shift register SPI
Perbedaan dengan rangkaian sebelumnya adalah jalur data
dan
clocknya.
Seperti
yang
telah
disebutkan
sebelumnya, jalur data pada pin 11 dan clock pada pin 13. Jalur untuk pin Latch penulis ganti ke pin 12 supaya gambarnya cukup rapi.
11.2.4 Program Shift Register dengan SPI Program 11.2 Program Shift Register dengan SPI 1 2 3 4 5 6 7 8
/* * MONSTER ARDUINO V2 * Program Shift Register dengan SPI * www.ElangSakti.com */ // include libary komunikasi SPI #include
146
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
// konfigurasi pin Arduino // SH_CP | default SPI di pin 13 // data | defatul SPI di pin 11 const byte LatchPin = 12; // ST_CP // menampung data byte data = 0; void setup() { // konfigurasi pin sebagai ouput pinMode(LatchPin, OUTPUT); // konfigurasi SPI SPI.setBitOrder(MSBFIRST); SPI.setDataMode(SPI_MODE0); SPI.setClockDivider(SPI_CLOCK_DIV2); SPI.begin(); } void loop() { // delay 200ms if ( nonblocking_delay(200) ){ // geser kiri data <<= 1; // jika data == 0 (gesernya sudah habis) // ulangi dari awal if( data == 0 ) data = 1; // mulai transfer digitalWrite(LatchPin, LOW); // kirim data SPI.transfer(data); // stop transfer digitalWrite(LatchPin, HIGH); } } // tambahan untuk membuat delay non blocking unsigned long nonblocking_time = millis();
147
52 53 54 55 56 57 58 59 60
unsigned long nonblocking_last = millis(); boolean nonblocking_delay(long milidetik){ nonblocking_time = millis(); if(nonblocking_time - nonblocking_last >= milidetik){ nonblocking_last = nonblocking_time; return true; } return false; }
Cara
kerja
program
ini
sama
dengan
program
sebelumnya, yang berbeda hanya mengirim data (lihat baris 44) dan inisialisasi komunikasinya (lihat baris 24-27). Oiya, untuk komunikasi SPI, juga harus include library SPI.h (lihat baris 8) dan hanya butuh konfigurasi pin latch (lihat baris 13). Library SPI.h sudah ada di aplikasi Arduino IDE. Selain kedua cara di atas, kita juga bisa menggunakan library
Shift
Register
yang
telah
dibuat
oleh
para
pengembang. Ada beberapa library yang bisa Anda gunakan, ada Shifter, ShiftRegister74HC595, atau library lainnya. Library tersebut akan kita bahas pada edisi revisi. Oiya satu lagi, IC Shift Register ini bisa Anda gunakan untuk mengontrol banyak relay, display 7 segment, bahkan LCD. Pada buku edisi ini hanya akan membahas tengan cara mengontrol display 7 segment.
148
Bagian #12
SERBA-SERBI DISPLAY 7 SEGMENT Tuhan sering mengunjungi kita, tetapi kebanyakan kita sedang tidak ada di rumah. (Joseph Roux)
___ Anda pasti pernah lihat display seven segment, entah di pom bensin, kalkulator generasi lama, atau perangkat elektronika yang menampilkan angka dalam bentuk kotak.
Gambar 12.1 Display seven segment menampilkan harga BBM
Display seven segment terdiri dari 7 buah lampu LED yang bisa menampilkan angka, dan kadang ada tambahan 1 LED sebagai titik di pojok bawah. Ah, sepertinya basabasinya gak penting-penting amat, hehe. Sebab seven segmen bisa kita ketahui dengan mudah. Mungkin yang 149
tidak begitu mudah adalah memahami skema dan posisi kaki tiap segmentnya, iya kan? Sebelum kita lanjut membuat rangkaian dan program, ada baiknya kita pahami dulu tentang tipe seven segmen yang biasa kita temui. Jangan sampai salah pilih. Tipe seven segment yang penulis maksud adalah tipe Common Cathode dan Common Anode. Cathode atau Katoda, adalah istilah lain dari GND (ground). Sedangkan Anode atau Anoda, adalah istilah lain dari VCC (positif). Jika Anda belum menghafalnya, Anda
bisa mengingatnya
dengan sebutan : Aples Kamin. Apa Aples Kamin? Aples = Anoda Ples (Plus, kutub + ) Kamin = Katoda Min (minus, kutub - )
Jika Anda lupa Anoda atau Katoda itu apa, ingatlah baik-baik mantra Aples Kamin.
Secara umum, LED pada seven segment diberi label A, B, C, D, E, F, G, dan DP. Semua segment LED terhubung menjadi satu pada salah satu sisinya. Jika yang terhubung jadi satu adalah kaki positif, maka disebut dengan Common Anode (CA). Jika yang terhubung jadi satu adalah kaki 150
negatifnya, maka disebut dengan Common Cathode (CC). Anda boleh memperhatikan dengan seksama gabar di bawah ini.
Gambar 12.2 Skema seven segment CC dan CA
Di pasaran ada yang jual seven segment, ada yang 1 digit, ada yang 3 digit, ada juga yang 4 digit. Prinsip kerja semua seven segment tersebut sama saja, hanya saja cara menampilkan angka dan rangkaiannya sudah pasti beda.
12.1 Seven Segment 1 Digit
Gambar 12.3 Seven segment tunggal tampak depan dan belakang
Kita langsung rangkai dan buat programnya! 151
12.1.1 Rangkaian Seven Segment 1 Digit Peralatan dan rangkaian yang harus disiapkan adalah: 1. Arduino x 1 2. Display 7 Segment 1 Digit CC x 1 3. Resistor 1k x 1 4. Project Board x 1 5. Kabel jumper secukupnya Sambungan pin Arduino dan display 7 segment yaitu : Arduino
Display 7 Segment 1 Digit
Pin 2 Pin 3 Pin 4 Pin 5 Pin 6 Pin 7 Pin 8 Pin 9 GND
Kaki LED A Kaki LED B Kaki LED C Kaki LED D Kaki LED E Kaki LED F Kaki LED G Kaki LED DP Resistor di kaki common CC
Gambar 12.4 Rangkaian seven segment tunggal
152
Rangkaian di atas menunjukkan bahwa seven segment yang penulis pakai adalah Common Cathode (CC), sebab kaki tengah dihubungkan ke GND. Masihkah Anda ingat Cathode itu istilah lain dari apa? Ingat, Aples Kamin! Pada rangkaian di atas, penulis menggunakan resistor di pin common-nya. Sebenarnya penggunaan resistor yang seperti itu akan berpengaruh pada tingkat kecerahan LEDnya. Pengaruhnya adalah ketika menampilkan angka 1 akan lebih cerah daripada ketika menampilkan angka 8. Kenapa? Sebab arus pada masing-masing LED dipakai bersama. Akan berbeda hasilnya apabila kita menggunakan resistornya di masing-masing segment A, B, C, D, E, F, G, dan DP. Tujuan penulis menggunakan satu buah resistor supaya lebih simpel dan menghemat penggunaan resistor saja. Untuk performa terbaik, gunakan resistor di masing-masing segment, ya.
12.1.2 Program Seven Segment 1 Digit Program 12.1 Program Seven Segment 1 Digit 1 2 3 4 5 6 7 8
/* * MONSTER ARDUINO V2 * Program Seven Segment 1 Digit * www.ElangSakti.com */ // definisikan CC, CA, ON, dan Brightness #define COMMON_ANODE HIGH
153
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
#define COMMON_CATHODE LOW #define ON HIGH #define BRIGHTNESS 100 // konfigurasi seven segment CC // CC : active low boolean COMMON = COMMON_CATHODE; boolean SEGMENT_ON = LOW; boolean SEGMENT_OFF = !SEGMENT_ON; // pin 2-9 untuk segmen A – DP const byte SegA = 2; // A const byte SegB = 3; // B const byte SegC = 4; // C const byte SegD = 5; // D const byte SegE = 6; // E const byte SegF = 7; // F const byte SegG = 8; // G const byte SegDp = 9; // DP // jadikan array biar mudah const byte SEGMENT[] = {SegA, SegB, SegC, SegD, SegE, SegF, SegG, SegDp}; // pengaturan untuk brightness unsigned long brightness_now = 0; unsigned long brightness_last = 0; unsigned long brightness_limit = 0; // data counter untuk ditampilkan byte counter = 0; void setup() { // sesuaikan active low/high // dengan tipe Common Anode atau Common Cathode if( COMMON == COMMON_ANODE ){ SEGMENT_ON = !ON; } else { SEGMENT_ON = ON; } SEGMENT_OFF = !SEGMENT_ON; // set segment sebagai output for(byte i=0; i
154
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
pinMode(SEGMENT[i],OUTPUT); } } void loop() { // counter data setiap 1 detik // jika lebih besar dr 9, reset ke 0 if( nonblocking_delay(1000) ){ counter++; if(counter > 9) counter = 0; } // tampilkan angka di seven segment Digit(counter, SEGMENT_OFF, BRIGHTNESS); } // fungsi Digit // untuk menampilkan angka pada seven segment void Digit(byte data, boolean dp, int brightness){ // delay nyala segment, efeknya pada brigthness brightness_limit = constrain(brightness,1,100); brightness_limit = map(brightness_limit,1,100,1,5000); brightness_now = micros(); if(brightness_now – brightness_last < brightness_limit){ // nyalakan 7 segmen sesuai angka switch(data){ case 0: digitalWrite(SegA, SEGMENT_ON); digitalWrite(SegB, SEGMENT_ON); digitalWrite(SegC, SEGMENT_ON); digitalWrite(SegD, SEGMENT_ON); digitalWrite(SegE, SEGMENT_ON); digitalWrite(SegF, SEGMENT_ON); digitalWrite(SegG, SEGMENT_OFF); digitalWrite(SegDp, dp); break; case 1: digitalWrite(SegA, SEGMENT_OFF);
155
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
digitalWrite(SegB, SEGMENT_ON); digitalWrite(SegC, SEGMENT_ON); digitalWrite(SegD, SEGMENT_OFF); digitalWrite(SegE, SEGMENT_OFF); digitalWrite(SegF, SEGMENT_OFF); digitalWrite(SegG, SEGMENT_OFF); digitalWrite(SegDp, dp); break; case 2: digitalWrite(SegA, SEGMENT_ON); digitalWrite(SegB, SEGMENT_ON); digitalWrite(SegC, SEGMENT_OFF); digitalWrite(SegD, SEGMENT_ON); digitalWrite(SegE, SEGMENT_ON); digitalWrite(SegF, SEGMENT_OFF); digitalWrite(SegG, SEGMENT_ON); digitalWrite(SegDp, dp); break; case 3: digitalWrite(SegA, SEGMENT_ON); digitalWrite(SegB, SEGMENT_ON); digitalWrite(SegC, SEGMENT_ON); digitalWrite(SegD, SEGMENT_ON); digitalWrite(SegE, SEGMENT_OFF); digitalWrite(SegF, SEGMENT_OFF); digitalWrite(SegG, SEGMENT_ON); digitalWrite(SegDp, dp); break; case 4: digitalWrite(SegA, SEGMENT_OFF); digitalWrite(SegB, SEGMENT_ON); digitalWrite(SegC, SEGMENT_ON); digitalWrite(SegD, SEGMENT_OFF); digitalWrite(SegE, SEGMENT_OFF); digitalWrite(SegF, SEGMENT_ON); digitalWrite(SegG, SEGMENT_ON); digitalWrite(SegDp, dp); break; case 5: digitalWrite(SegA, SEGMENT_ON);
156
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
digitalWrite(SegB, SEGMENT_OFF); digitalWrite(SegC, SEGMENT_ON); digitalWrite(SegD, SEGMENT_ON); digitalWrite(SegE, SEGMENT_OFF); digitalWrite(SegF, SEGMENT_ON); digitalWrite(SegG, SEGMENT_ON); digitalWrite(SegDp, dp); break; case 6: digitalWrite(SegA, SEGMENT_ON); digitalWrite(SegB, SEGMENT_OFF); digitalWrite(SegC, SEGMENT_ON); digitalWrite(SegD, SEGMENT_ON); digitalWrite(SegE, SEGMENT_ON); digitalWrite(SegF, SEGMENT_ON); digitalWrite(SegG, SEGMENT_ON); digitalWrite(SegDp, dp); break; case 7: digitalWrite(SegA, SEGMENT_ON); digitalWrite(SegB, SEGMENT_ON); digitalWrite(SegC, SEGMENT_ON); digitalWrite(SegD, SEGMENT_OFF); digitalWrite(SegE, SEGMENT_OFF); digitalWrite(SegF, SEGMENT_OFF); digitalWrite(SegG, SEGMENT_OFF); digitalWrite(SegDp, dp); break; case 8: digitalWrite(SegA, SEGMENT_ON); digitalWrite(SegB, SEGMENT_ON); digitalWrite(SegC, SEGMENT_ON); digitalWrite(SegD, SEGMENT_ON); digitalWrite(SegE, SEGMENT_ON); digitalWrite(SegF, SEGMENT_ON); digitalWrite(SegG, SEGMENT_ON); digitalWrite(SegDp, dp); break; case 9:
157
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
digitalWrite(SegA, SEGMENT_ON); digitalWrite(SegB, SEGMENT_ON); digitalWrite(SegC, SEGMENT_ON); digitalWrite(SegD, SEGMENT_ON); digitalWrite(SegE, SEGMENT_OFF); digitalWrite(SegF, SEGMENT_ON); digitalWrite(SegG, SEGMENT_ON); digitalWrite(SegDp, dp); break; } }else{ // matikan semua 7 segment for(byte d=0; d= milidetik){ nonblocking_last = nonblocking_time; return true; } return false; }
Cara kerja program di atas adalah : 1. Pilih jenis seven segment, apakah CC atau CA (lihat baris 15 – 16). Beda tipe beda cara mengaktifkan seven segment (lihat baris 44 – 49). 2. Set semua segment sebagai output (lihat baris 53) 3. Data pada variabel counter akan berubah setiap detik dengan delay responsive (lihat baris 61) 158
4. Angka yang akan ditampilkan dari 0 – 9, jika data counter > 9, maka reset ke 0 lagi (lihat baris 63). 5. Menampilkan
angka
Digit(angka,dp,kecerahan).
dengan Angka
fungsi
adalah
angka
yang ditampilkan, dp adalah logika untuk titik (segment DP), dan kecerahan adalah angka untuk tingkat kecerahan LED (lihat baris 67). 6. Dalam fungsi Digit(), masing-masing angka punya cara tersendiri untuk menampilkannya. Contohnya begini, jika kita ingin menampilkan angka 1, maka segmen yang harus nyala adalah segment B dan C.
Gambar 12.5 Angka 1 ditampilkan dengan menyalakan segment B dan C
Dengan demikian, hanya segmen B dan C yang dinyalakan (lihat baris 95 – 102). Untuk menampilkan angka
yang
lain,
maka
segment
yang
harus
dinyalakan juga berbeda. 7. Brightness terkait dengan berapa lama waktu LED
segment nyala dan mati. Anda bisa mengamati baris 80 untuk pengecekan lama segment nyala dan baris 159
195 – 197 untuk segment OFF seluruhnya. Silakan coba ubah-ubah angkanya supaya Anda bisa bisa memahaminya lebih baik…
12.2 Seven Segment 4 Digit Seven segment 4 digit memiliki 12 kaki. 8 kaki untuk segment, dan 4 untuk digit D1, D2, D3, dan D4. Cara kerjanya sama dengan seven segment 1 digit. Hanya saja, untuk menampilkan angka di semua digit, kita harus melakukan scanning untuk setiap digit. Jadi ke-4 digit harus gantian nyala.
Gambar 12.6 Seven segment 4 digit tampak depan dan belakang dan skemanya
12.2.1 Rangkaian Seven Segment 4 Digit Peralatan dan rangkaian yang perlu disiapkan : 160
1. Arduino x 1 2. Display 7 Segment 4 Digit CC x 1 3. Project board x 1 4. Resistor dengan nilai yang seragam x 4 5. Kabel jumper secukupnya Rangkaian pin Arduino dan 7 segment 4 digit : Arduino
Display 7 Segment 4 Digit
Pin 2 Pin 3 Pin 4 Pin 5 Pin 6 Pin 7 Pin 8 Pin 9 Pin A0, A1, A2, dan A3
Kaki LED A Kaki LED B Kaki LED C Kaki LED D Kaki LED E Kaki LED F Kaki LED G Kaki LED DP Resistor pada kaki digit D1, D2, D2, dan D4
Gambar 12.7 Rangkaian segment 4 Digit
161
12.2.2 Program Seven Segment 4 Digit Program 12.2 Program Seven Segment 4 Digit 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
/* * MONSTER ARDUINO V2 * Program Seven Segment 4 Digit * www.ElangSakti.com */ // definisikan CC, CA, ON, dan Brightness #define COMMON_ANODE HIGH #define COMMON_CATHODE LOW #define ON HIGH #define BRIGHTNESS 100 // konfigurasi seven segment CC // CC : active low boolean COMMON = COMMON_CATHODE; boolean SEGMENT_ON = LOW; boolean SEGMENT_OFF = !SEGMENT_ON; boolean DIGIT_ON = HIGH; boolean DIGIT_OFF = !DIGIT_ON; // pin 2-9 untuk segmen A - DP const byte SegA = 2; // A const byte SegB = 3; // B const byte SegC = 4; // C const byte SegD = 5; // D const byte SegE = 6; // E const byte SegF = 7; // F const byte SegG = 8; // G const byte SegDp = 9; // DP // pin A0-A3 untuk digit 1-4 const byte Digit1 = A0; const byte Digit2 = A1; const byte Digit3 = A2; const byte Digit4 = A3; // jadikan array biar mudah const byte SEGMENT[] = {SegA, SegB, SegC, SegD, SegE, SegF, SegG, SegDp}; const byte DIGIT[] = {Digit1, Digit2, Digit3, Digit4};
162
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
// digit terpilih - 0 dari digit satuan (kanan) byte DIGIT_SELECT = 0; // pengaturan untuk brightness unsigned long brightness_now = 0; unsigned long brightness_last = 0; unsigned long brightness_limit = 0; // counter dari -50 int counter = -50; // string angka String str_data_last = "";
void setup() { // sesuaikan active low/high // dengan tipe Common Anode atau Common Cathode if( COMMON == COMMON_ANODE ){ SEGMENT_ON = !ON; DIGIT_ON = ON; } else { SEGMENT_ON = ON; DIGIT_ON = !ON; } SEGMENT_OFF = !SEGMENT_ON; DIGIT_OFF = !DIGIT_ON; // set pin segment sebagai output for(byte i=0; i
163
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
// jika lebih besar dr 200, reset ke -50 if( nonblocking_delay(100) ){ counter++; if(counter > 200) counter = -50; } // tampilkan angka di seven segment Digit(counter, SEGMENT_OFF, BRIGHTNESS); } void Digit(int data, boolean dp, int brightness){ // delay nyala segment, efeknya pada brigthness brightness_limit = constrain(brightness,1,100); brightness_limit = map(brightness_limit,1,100,1,5000); // konversi angka menjadi string // lalu cek lebar angkannya String str_data = String(data); byte len_data = str_data.length(); brightness_now = micros(); if(brightness_now - brightness_last < brightness_limit){ // replace data sesuai digit yang terpilih if( DIGIT_SELECT < len_data ){ // jika data < 0, berarti ada tanda - di depan if( data < 0 && DIGIT_SELECT == 0){ data = '-'; } else { // ambil data sesuai index digitnya data = (str_data.substring(DIGIT_SELECT,DIGIT_SELECT+1)).toInt(); } // nyalakan digit yang terpilih digitalWrite(DIGIT[DIGIT_SELECT],DIGIT_ON); } // nyalakan 7 segmen sesuai angka switch(data){ case 0: digitalWrite(SegA, SEGMENT_ON);
164
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
digitalWrite(SegB, SEGMENT_ON); digitalWrite(SegC, SEGMENT_ON); digitalWrite(SegD, SEGMENT_ON); digitalWrite(SegE, SEGMENT_ON); digitalWrite(SegF, SEGMENT_ON); digitalWrite(SegG, SEGMENT_OFF); digitalWrite(SegDp, dp); break; case 1: digitalWrite(SegA, SEGMENT_OFF); digitalWrite(SegB, SEGMENT_ON); digitalWrite(SegC, SEGMENT_ON); digitalWrite(SegD, SEGMENT_OFF); digitalWrite(SegE, SEGMENT_OFF); digitalWrite(SegF, SEGMENT_OFF); digitalWrite(SegG, SEGMENT_OFF); digitalWrite(SegDp, dp); break; case 2: digitalWrite(SegA, SEGMENT_ON); digitalWrite(SegB, SEGMENT_ON); digitalWrite(SegC, SEGMENT_OFF); digitalWrite(SegD, SEGMENT_ON); digitalWrite(SegE, SEGMENT_ON); digitalWrite(SegF, SEGMENT_OFF); digitalWrite(SegG, SEGMENT_ON); digitalWrite(SegDp, dp); break; case 3: digitalWrite(SegA, SEGMENT_ON); digitalWrite(SegB, SEGMENT_ON); digitalWrite(SegC, SEGMENT_ON); digitalWrite(SegD, SEGMENT_ON); digitalWrite(SegE, SEGMENT_OFF); digitalWrite(SegF, SEGMENT_OFF); digitalWrite(SegG, SEGMENT_ON); digitalWrite(SegDp, dp); break; case 4:
165
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
digitalWrite(SegA, SEGMENT_OFF); digitalWrite(SegB, SEGMENT_ON); digitalWrite(SegC, SEGMENT_ON); digitalWrite(SegD, SEGMENT_OFF); digitalWrite(SegE, SEGMENT_OFF); digitalWrite(SegF, SEGMENT_ON); digitalWrite(SegG, SEGMENT_ON); digitalWrite(SegDp, dp); break; case 5: digitalWrite(SegA, SEGMENT_ON); digitalWrite(SegB, SEGMENT_OFF); digitalWrite(SegC, SEGMENT_ON); digitalWrite(SegD, SEGMENT_ON); digitalWrite(SegE, SEGMENT_OFF); digitalWrite(SegF, SEGMENT_ON); digitalWrite(SegG, SEGMENT_ON); digitalWrite(SegDp, dp); break; case 6: digitalWrite(SegA, SEGMENT_ON); digitalWrite(SegB, SEGMENT_OFF); digitalWrite(SegC, SEGMENT_ON); digitalWrite(SegD, SEGMENT_ON); digitalWrite(SegE, SEGMENT_ON); digitalWrite(SegF, SEGMENT_ON); digitalWrite(SegG, SEGMENT_ON); digitalWrite(SegDp, dp); break; case 7: digitalWrite(SegA, SEGMENT_ON); digitalWrite(SegB, SEGMENT_ON); digitalWrite(SegC, SEGMENT_ON); digitalWrite(SegD, SEGMENT_OFF); digitalWrite(SegE, SEGMENT_OFF); digitalWrite(SegF, SEGMENT_OFF); digitalWrite(SegG, SEGMENT_OFF); digitalWrite(SegDp, dp); break; case 8:
166
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
digitalWrite(SegA, SEGMENT_ON); digitalWrite(SegB, SEGMENT_ON); digitalWrite(SegC, SEGMENT_ON); digitalWrite(SegD, SEGMENT_ON); digitalWrite(SegE, SEGMENT_ON); digitalWrite(SegF, SEGMENT_ON); digitalWrite(SegG, SEGMENT_ON); digitalWrite(SegDp, dp); break; case 9: digitalWrite(SegA, SEGMENT_ON); digitalWrite(SegB, SEGMENT_ON); digitalWrite(SegC, SEGMENT_ON); digitalWrite(SegD, SEGMENT_ON); digitalWrite(SegE, SEGMENT_OFF); digitalWrite(SegF, SEGMENT_ON); digitalWrite(SegG, SEGMENT_ON); digitalWrite(SegDp, dp); break; case '-': digitalWrite(SegA, SEGMENT_OFF); digitalWrite(SegB, SEGMENT_OFF); digitalWrite(SegC, SEGMENT_OFF); digitalWrite(SegD, SEGMENT_OFF); digitalWrite(SegE, SEGMENT_OFF); digitalWrite(SegF, SEGMENT_OFF); digitalWrite(SegG, SEGMENT_ON); digitalWrite(SegDp, dp); break; } }else{ // matikan semua digit for(byte d=0; d
167
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
// lanjut ke digit berikutnya DIGIT_SELECT++; // jika semua digit sudah ditampilkan, reset ke 0 if( DIGIT_SELECT >= len_data) DIGIT_SELECT = 0; brightness_last = brightness_now; } }
// tambahan untuk membuat delay non blocking unsigned long nonblocking_time = millis(); unsigned long nonblocking_last = millis(); boolean nonblocking_delay(long milidetik){ nonblocking_time = millis(); if(nonblocking_time - nonblocking_last >= milidetik){ nonblocking_last = nonblocking_time; return true; } return false; }
Program ini masih menggunakan contoh counter, namun counternya dari -50 hingga 200. Cara kerja program di atas mirip dengan program seven segment 1 Digit. Yang berbeda adalah : 1. Ada pin digit yang harus diinisialisasi (lihat baris 32 – 35, 39, dan 76 – 78) 2. Untuk menampilkan angka, proses menampilkan angka harus satu-persatu untuk setiap digit yang terpilih pada variabel DIGIT_SELECT. 3. Karena angka yang ditampilkan lebih dari 1 digit, maka angka akan dikonversi menjadi string (lihat baris 103), lalu pilih satu-persatu berdasarkan posisi indeksnya dengan cara memecah string angka 168
tersebut (lihat baris 117). Angka yang terpilih akan dikonversi menjadi angka dan ditampilkan sesuai angka yang cocok (lihat baris 125 – 245). 4. Untuk menampilkan angka minus, maka data harus dicek apakah < 0 atau tidak (lihat baris 113). 5. Proses pergeseran digit dipilih saat semua segment dimatikan (lihat baris 259). Tampilan counter pada program ini muncul rata kiri (muncul di sebela kiri seven segment). Untuk memunculkan di sebelah kanan, Anda bisa coba program Seven Segment Rata Kanan.
12.2.3 Program Seven Segment Rata Kanan Rangkaian untuk program ini sama dengan rangkai program 12.2. Untuk menampilkan angka rata kanan, kita hanya perlu mengganti baris 121 menjadi : Program 12.3 Program Seven Segment 4 Digit Rata Kanan 120 121
// nyalakan digit yang terpilih, geser ke kanan digitalWrite(DIGIT[ sizeof(DIGIT) - (len_data-DIGIT_SELECT) ],DIGIT_ON);
Udah, gitu aja.
169
12.3 Seven Segment dengan Library SevSeg Libray SevSeg adalah library untuk mempermudah penggunaan seven segment, terserah kita mau punya berapa digit. Library ini dibuat oleh Dean Reading. Link downloadnya tidak penulis sertakan di sini karena info pembuatnya sudah penulis informasikan. Silakan googling!
12.3.1 Program Seven Segment dengan Sevseg Program 12.4 Program Seven Segment dengan SevSeg 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
/* * MONSTER ARDUINO V2 * Program Seven Segment dengan SevSeg * www.ElangSakti.com */ // include library sevseg #include // buat object dari class sevseg SevSeg SevSegment; // pin digit 1-4 const byte Digit[] = {A0, A1, A2, A3}; // pin segment A,B,C - DP const byte Segments[] = {2,3,4,5,6,7,8,9}; // penggunaan R internal const bool R_Segments = false; // tipe seven segment const byte HW_Config = COMMON_CATHODE; // atau COMMON_ANODE // counter dari -50 int counter = -50; void setup() {
170
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
// konfigurasi sevseg SevSegment.begin(HW_Config, R_Segments);
sizeof(Digit),
Digit,
Segments,
} void loop() { // counter data setiap 200ms if( nonblocking_delay(200) ){ counter++; if(counter > 200) counter = -50; // ganti angka yang akan ditampilkan SevSegment.setNumber(counter); } // refresh tampilan angka SevSegment.refreshDisplay(); } // tambahan untuk membuat delay non blocking unsigned long nonblocking_time = millis(); unsigned long nonblocking_last = millis(); boolean nonblocking_delay(long milidetik){ nonblocking_time = millis(); if(nonblocking_time - nonblocking_last >= milidetik){ nonblocking_last = nonblocking_time; return true; } return false; }
Dengan menggunakan library, kita bisa menghemat banyak waktu dan tentu baris source codenya jadi lebih sedikit. Tapi, belum tentu ukuran programnya lebih sedikit juga.
171
12.4 Seven Segment dengan Shift Register Sebelumnya kita telah mengontrol seven segment dengan kaki arduino langsung sehingga jumlah kaki arduino yang tersisa semakin sedikit. Sebagaimana telah kita pelajari sebelumnya, solusi untuk menghemat kaki Arduino adalah dengan shift register. Mari kita gunakan shift register untuk mengatur tampilan seven segment!
12.4.1 Rangkaian 7 Segment 1 Digit dengan Shift Register Peralatan dan rangkaian yang perlu disiapkan adalah: 1. Arduino x 1 2. IC Shift Register 74HC595 x 1 3. Display 7 Segment 1 Digit CC x 1 4. Project board x 1 5. Resistor 1k x 1 6. Kabel jumper secukupnya Sambungan pin Arduino, 74HC595, dan 4 segment : Arduino IC 74HC595
Display 7 Segment 1D
Pin 2 Pin 3 Pin 4 VCC GND
Resistor di kaki Common Pin Segment A,B,C,D,E,F,G,DP
Pin 14, Data Pin 12, Latch Pin 11, Clock Pin 10 dan 16 Pin 8 dan 13 Pin 13,1,2,3,4,5,6,7 (Q0–Q7)
172
Gambar 12.8 Rangkain seven segment dengan shift register
12.4.2 Program 7 Segment 1 Digit dengan Shift Register Program 12.5 Program Seven Segment dengan Shift Register 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/* * MONSTER ARDUINO V2 * Program Seven Segmen 1D dg Shift Register * www.ElangSakti.com */ // untuk common cathode #define OFF ~255 // konversi angka // 8 bit data : A B C D E F G DP const byte angka[] = { B11111100, // 0 B01100000, // 1 B11011010, // 2 B11110010, // 3 B01100110, // 4 B10110110, // 5 B10111110, // 6
173
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
B11100000, B11111110, B11110110, B00000010
// 7 // 8 // 9 // -
};
// konfigurasi pin Arduino const byte DataPin = 2; // data const byte LatchPin = 3; // ST_CP const byte ClockPin = 4; // SH_CP // data counter byte counter = 0; void setup() { // konfigurasi pin sebagai ouput pinMode(LatchPin, OUTPUT); pinMode(ClockPin, OUTPUT); pinMode(DataPin, OUTPUT); // pastikan seven segment mati // mulai transfer digitalWrite(LatchPin, LOW); // kirim data shiftOut(DataPin, ClockPin, LSBFIRST, OFF); // stop transfer digitalWrite(LatchPin, HIGH); } void loop() { // delay 1 detik if ( nonblocking_delay(1000) ){ counter++; if(counter >= sizeof(angka)) counter = 0; // mulai transfer digitalWrite(LatchPin, LOW); // kirim data shiftOut(DataPin, ClockPin, LSBFIRST, angka[counter]); // stop transfer digitalWrite(LatchPin, HIGH); } }
174
64 65 66 67 68 69 70 71 72 73 74 75
// tambahan untuk membuat delay non blocking unsigned long nonblocking_time = millis(); unsigned long nonblocking_last = millis(); boolean nonblocking_delay(long milidetik){ nonblocking_time = millis(); if(nonblocking_time - nonblocking_last >= milidetik){ nonblocking_last = nonblocking_time; return true; } return false; }
Pada rangkaian seven segment biasa, mode komunikasi antara Arduino dan Seven segment bisa disebut komunikasi serial. Sebab, ada 8 jalur data untuk mengirim data secara bersamaan. Dengan shift register, kita hanya butuh 1 jalur data. Sehingga 8 bit data yang awalnya dikirim secara paralel, harus kita kumpulkan jadi satu dulu. Ke-8 bit data tersebut kita urutkan seri, lalu kita kirim berurutan. Proses pengurutan data menjadi seri (serial), dapat dilihat pada baris 13 – 23. Baris 13, data 0B11111100 adalah data serial untuk angka 0 di seven segment. Begitu juga dengan angka 1, 2, dan seterusnya. Data-data angka kita konversi menjadi data yang berurutan (serial). Proses counter dilakukan seperti biasa, selebihnya keterangan bisa dibaca pada bagian-bagian programnya. Penulis percaya Anda sedang bersemangat belajar. Jadi, silakan coba pahami setiap baris code yang ada di program. 175
Jika sudah paham, mari lanjut dengan 2 digit seven segment.
12.4.3 Rangkaian Seven Segment 2 Digit dengan Shift Register Peralatan dan rangkaian yang harus disiapkan adalah: 1. Arduino x 1 2. IC Shift Register 74HC595 x 2 3. Display Seven Segment 1 Digit x 2 4. Resistor 1k x 2 5. Kabel jumper secukupnya Sambungan pin Arduino, 74HC595, dan 7 Segment : Arduino IC 74HC595 1
IC 74HC595 2
Pin 2 Pin 3 Pin 4 VCC GND -
Pin 12, Latch Pin 11, Clock Pin 10 dan 16 Pin 8 dan 13 Pin 14, Data
Pin 14, Data Pin 12, Latch Pin 11, Clock Pin 10 dan 16 Pin 8 dan 13 Pin 9 (Q7’)
IC 74HC595 1 atau 2
Display 7 Segment 1 atau 2
Pin 15,1,2,3,4,5,6,7 (Q0-Q7) GND
Pin Segment A,B,C,D,E,F,G,DP Pin Common
176
Gambar 12.9 Rangkain seven segment 2 digit dengan shift register
Jika menggunakan shift register, berapun output yang kita inginkan, cukup dikontrol dengan 3 buah pin Arduino. Yang perlu diperhatikan dalam merangkan 2 buah IC Shift register adalah: 1. Kaki Clock IC pertam diparalel dengan IC kedua 2. Kaki Latch IC pertama diparalel dengan IC kedua 3. Input DS IC kedua dari Output Q7‟ IC pertama Jadi, silakan perhatikan sambungannya baik-baik.
12.4.4 Program Seven Segment 2 Digit dengan Shift Register Program 12.6 Program Seven Segment 2D dengan Shift Register 1 2
/* * MONSTER ARDUINO V2
177
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
* Program Seven Segmen 2D dg Shift Register * www.ElangSakti.com */ // common cathode #define OFF ~255 // konversi angka // 8 bit data : A B C D E F G DP const byte Angka[] = { B11111100, // 0 B01100000, // 1 B11011010, // 2 B11110010, // 3 B01100110, // 4 B10110110, // 5 B10111110, // 6 B11100000, // 7 B11111110, // 8 B11110110, // 9 B00000010 // }; // konfigurasi pin Arduino const byte DataPin = 2; // data const byte LatchPin = 3; // ST_CP const byte ClockPin = 4; // SH_CP // jumlah digit single seven segment const byte jumlah_digit = 2; // data counter int counter = 0; void setup() { // konfigurasi pin sebagai ouput pinMode(LatchPin, OUTPUT); pinMode(ClockPin, OUTPUT); pinMode(DataPin, OUTPUT); // pastikan seven segment mati // mulai transfer digitalWrite(LatchPin, LOW); // kirim data
178
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
shiftOut(DataPin, ClockPin, LSBFIRST, OFF); // stop transfer digitalWrite(LatchPin, HIGH); } void loop() { // delay 200ms if ( nonblocking_delay(200) ){ counter++; if( counter >= 100 ) counter = 0; // cetak angka PrintDigit(counter, jumlah_digit); } } // fungsi untuk mencetak angka // INPUT : angka dan jumlah_digit void PrintDigit(int angka, byte jumlah_digit){ // konversi angka jadi string String numstr = String(angka); byte lenstr = numstr.length(); // mulai transfer digitalWrite(LatchPin, LOW); // kirim data sesuai index angka for(byte i=0; i
179
90 91 92 93 94 95 96 97 98 99
unsigned long nonblocking_time = millis(); unsigned long nonblocking_last = millis(); boolean nonblocking_delay(long milidetik){ nonblocking_time = millis(); if(nonblocking_time - nonblocking_last >= milidetik){ nonblocking_last = nonblocking_time; return true; } return false; }
Untuk mempermudah cetak digit yang lebih dari satu, blok program yang berfungsi untuk menampilkan angka pada seven segment dipisah ke dalam fungsi tersendiri, yaitu fungsi PrintDigit(). Fungsi tersebut tidak hanya untuk menampilkan 1 digit saja, tapi bisa banyak digit, sesuai dengan jumlah digit yang telah ditentukan (lihat baris 32). Bagian yang cukup rumit mikirnya adalah pada baris 73 – 83. Tapi karena programnya sudah jadi, maka Anda tinggal mencoba dan mempelajarinya, enak kan? Selanjutnya kita akan kembali menggunakan seven segment 4 digit, tapi tetap menggunakan shift register.
12.4.5 Rangkaian Seven Segment 4 Digit dengan Shift Register Peralatan dan rangkaian yang harus disiapkan adalah sebagai berikut : 1. Arduino x 1 2. IC Shift Register 74HC595 x 1 180
3. Display Seven Segment 4 Digit CC x 1 4. Resistor dengan nilai seragam x 4 5. Project board 6. Kabel jumper secukupnya Sambungan pin Arduino, 74HC595, dan 7 Segment : Arduino IC 74HC595
Display 7 Segment 1D
Pin 2 Pin 3 Pin 4 Pin A0 Pin A1 Pin A2 Pin A3 VCC GND
D1 D2 D3 D4 Resistor di kaki Common Pin Segment A,B,C,D,E,F,G,DP
Pin 14, Data Pin 12, Latch Pin 11, Clock Pin 10 dan 16 Pin 8 dan 13 Pin 13,1,2,3,4,5,6,7 (Q0–Q7)
Gambar 12.10 Rangkain seven segment 4 digit dengan shift register
Lagi-lagi, Anda harus lebih teliti merangkainya. 181
12.4.6 Program Seven Segment 4 Digit dengan Shift Register Program 12.7 Program Seven Segment 4D dengan Shift Register 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
/* * MONSTER ARDUINO V2 * Program Seven Segmen 4D dg Shift Register * www.ElangSakti.com */ // common cathode #define OFF ~255 // untuk brightness #define BRIGHTNESS 100 // konversi angka // 8 bit data : A B C D E F G DP const byte Angka[] = { B11111100, // 0 B01100000, // 1 B11011010, // 2 B11110010, // 3 B01100110, // 4 B10110110, // 5 B10111110, // 6 B11100000, // 7 B11111110, // 8 B11110110, // 9 B00000010 // }; // konfigurasi pin Arduino const byte DataPin = 2; // data const byte LatchPin = 3; // ST_CP const byte ClockPin = 4; // SH_CP // untuk mengontrol digit, // kita masih pakai pin arduino // untuk lebih menghemat, bisa tambah // IC shift register lagi const byte Digit1 = A0; const byte Digit2 = A1; const byte Digit3 = A2;
182
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
const byte Digit4 = A3; const byte DIGIT[] = {Digit1, Digit2, Digit3, Digit4}; // jumlah digit seven segment const byte jumlah_digit = sizeof(DIGIT); // digit terpilih untuk diaktifkan byte DIGIT_SELECT = 0; // pengaturan untuk brightness unsigned long brightness_now = 0; unsigned long brightness_last = 0; unsigned long brightness_limit = 0; int counter = 0; void setup() { // konfigurasi pin sebagai ouput pinMode(LatchPin, OUTPUT); pinMode(ClockPin, OUTPUT); pinMode(DataPin, OUTPUT); // pastikan bahwa display mati for(byte i=0; i
183
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
counter++; if( counter >= 10000 ) counter = 0; } // cetak angka PrintDigit(counter, jumlah_digit); } // fungsi untuk mencetak angka // INPUT : angka dan jumlah_digit void PrintDigit(int angka, byte jumlah_digit){ // delay nyala segment, efeknya pada brigthness brightness_limit = constrain(BRIGHTNESS,1,100); brightness_limit = map(brightness_limit,1,100,1,5000); // konversi angka jadi string String numstr = String(angka); byte lenstr = numstr.length(); // mulai transfer digitalWrite(LatchPin, LOW); brightness_now = micros(); if(brightness_now - brightness_last < brightness_limit){ // nyalakan digit yang terpilih digitalWrite(DIGIT[DIGIT_SELECT],LOW); if( DIGIT_SELECT < lenstr ){ // jika digit yang terpilih < jumlah angka // cetak angka pada digit tersebut byte angka = ( numstr.substring( DIGIT_SELECT, DIGIT_SELECT + 1)).toInt(); shiftOut(DataPin, ClockPin, LSBFIRST, Angka[ angka ]); } else { // jika tidak, matikan semua segment shiftOut(DataPin, ClockPin, LSBFIRST, OFF); } }else{ // matikan semua digit for(byte d=0; d
184
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
digitalWrite(DIGIT[d], HIGH); } // matikan semua segment shiftOut(DataPin, ClockPin, LSBFIRST, OFF); DIGIT_SELECT++; if( DIGIT_SELECT >= lenstr) DIGIT_SELECT = 0; brightness_last = brightness_now; } // stop transfer digitalWrite(LatchPin, HIGH); } // tambahan untuk membuat delay non blocking unsigned long nonblocking_time = millis(); unsigned long nonblocking_last = millis(); boolean nonblocking_delay(long milidetik){ nonblocking_time = millis(); if(nonblocking_time - nonblocking_last >= milidetik){ nonblocking_last = nonblocking_time; return true; } return false; }
Secara prinsip, antara seven segment yang single digit dan multi digit memiliki cara yang berbeda saat akan menampilkan data. Untuk seven segment yang single digit, kita tidak perlu melakukan scan digit, sebab kan memang hanya 1 digit. Sedangkan untuk seven segment yan multiple digit dalam satu modul, proses untuk menampilkan data harus bergantian dengan cara scan satu-satu.
185
Perbedaan tersebut tampak pada pemanggilan fungsi PrintDigit(). Perhatikan pada Program seven segment 2 Digit dengan Shift register dan program seven segment 4 digit dengan shift register. 1. Pada Program 12.4, PrintDigit() ada di baris 59. Posisinya
bisa
diletakkan
di
dalam
fungsi
nonblocking_delay(). 2. Sedangkan pada Program 12.6, PrintDigit() di baris 90.
Posisinya
harus
nonblocking_delay().
Kenapa
diluar demikian?
fungsi Sebab,
pada seven segment 4 digit harus ada proses scanning. Itulah yang mempengaruhi peletakannya. Baik, pembahasan seven segment bisa kita akhiri di sini. Selanjutkan, akan
ada
project yang displaynya
juga
membutuhkan seven segment. Anda boleh ingat-ingat cara kerja seven segment 1 digit dan 4 digit. Bab selanjutnya yaitu tentang memaksimalkan tampilan pada LCD1602. Semoga pembahasan berikutnya lebih menarik.
186
Bagian #13
LEBIH CANTIK DENGAN LCD1602 Jika seseorang belum menemukan sesuatu untuk diperjuangkan hingga akhir hayatnya, maka kehidupannya tidak berharga. (Anonim)
___
Pembahasan tentang LCD sudah pernah kita uraikan di buku yang pertama. Pada buku kali ini, kita akan mengoptimalkan fungsi LCD, baik dari sisi rangkaian dan coding. Jika Anda butuh pengetahuan dasar tentang LCD, Anda boleh download buku panduan yang pertama dengan mengklik link ini → https://goo.gl/JCEDmh.
13.1 Sekilas Modul I2C LCD Jika menggunakan rangkaian standar, kita butuh 6 – 8 pin
untuk
mendapatkan
fungsi
maksimal
seperti
menghidupmatikan backlight dan membaca data dari LCD. Kali ini kita merekomendasikan penggunaan modul I2C LCD untuk menghemat penggunaan pin tersebut. Dengan 187
modul ini, kita hanya butuh 2 pin untuk menampilkan data di LCD. Lebih hemat kan? :D
Gambar 13.1 Modul I2C LCD tampak depan dan belakang
Gambar 13.2 Modul belum dipasang pada LCD dan belum disolder
Ada beberapa bagian penting yang perlu diperhatikan untuk menggunakan modul ini: 1. Bagian Power Supply, adalah pin VCC dan GND, penulis pikir Anda sudah paham ya.. :D 2. Bagian
Komunikasi,
Modul
ini
berkomunikasi
dengan protokol komunikasi I2C (Inter-Integrated Circuit). Komunikasi ini membutuhkan 2 jalur data, satu untuk mengirim data, satunya lagi clock untuk sinkronisasi. Pada modul, ditandai dengan nama SDA (Synchronous Data) dan SCL (Synchronous Clock). Komunikasi I2C juga dikenal dengan komunikasi 188
Two-Write Serial Interface (TWI). Pada Arduino Uno dan Nano, SDA dan SCA ada pada pin A4 dan A5. 3. Jumper Backlight (lihat no. 1), Jika jumper dilepas, maka lampu backlight LCD tidak bisa dinyalahidupkan dengan program. 4. Pengatur Kontras LCD, (lihat no. 2), Jika tampilan tulisannya kurang jelas atau malah berbentuk kotak, silakan putar-putar VR ini. Modul I2C LCD sebenarnya adalah I2C IO extender / expansion yang menggunakan IC PCF8574x dengan huruf x yang bisa berbeda. Jika Anda penasaran dengan IC ini, Anda boleh mencari skemanya di internet. Mari kita langsung praktek!
13.2 Rangkaian Dasar Modul I2C LCD Semua program akan menggunakan rangkaian seperti ini. Jadi, selama mencoba program-program pada bab ini, Anda bisa menggunakan rangkaian seperti Gambar 13.3 dan peralatan yang dibutuhkan adalah: 1. Arduino x 1 2. Modul LCD yang sudah terpasang modul I2C x 1 3. Kabel jumper secukupnya
189
Sambungan pin Arduino dan LCD 1602 adalah : Arduino LCD 1602 Pin A4 Pin A5 VCC GND
SDA SCL VCC GND
Gambar 13.3 Rangkaian dasar I2C LCD
Kelebihan dari komunikasi I2C adalah: banyak device, modul, atau sensor yang bisa dipasang secara paralel dan tetap dapat berkomunikasi. Anda bisa perhatikan gambar di bawah ini.
Gambar 13.4 Arduino dengan sensor dan modul I2C
190
Mungkin yang akan jadi pertanyaan, apakah data dari semua modul tersebut tidak akan tertukar atau saling bertabrakan, sementara jalur komunikasi hanya satu? Tidak, sebab setiap modul I2C punya alamat sendiri-sendiri, termasuk modul I2C untuk LCD. Darimana kita bisa tahu alamat modul I2C LCD? Ada library I2C LCD yang sudah otomatis mencari alamat LCD, ada juga yang tidak. Nah, sebelum kita lanjut untuk membuat variasi pada tampilan LCD, kita berikan contoh program untuk mencari alamat I2C.
13.3 Program Mencari Alamat Modul I2C Program 13.1 Program Mencari Alamat I2C 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/* * MONSTER ARDUINO V2 * Program Mencari Alamat I2C * www.ElangSakti.com */ // include library wire #include void setup() { // komunikasi serial dg baud 19200 Serial.begin(19200); while(!Serial); Serial.println("#============o0o=============#"); Serial.println("# I2C Scanner #"); Serial.println("# Explored by Elangsakti.com #"); Serial.println("#============================#");
191
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
// panggil fungsi untuk mencari alamat I2C Cari_Alamat(); } void loop() { } void Cari_Alamat() { // buka komunikasi Wire.begin(); byte respon, alamat, modul = 0; Serial.println("Scanning..."); Serial.println(); // tes alamat dari 0 - 127 for(alamat=0; alamat<127; alamat++){ Wire.beginTransmission(alamat); respon = Wire.endTransmission(); switch(respon){ case 0: Serial.print(" "); Serial.print(modul+1); Serial.print(". Alamat = 0x"); if( alamat < 16 ) Serial.print("0"); Serial.println(alamat, HEX); modul++; break; case 4: Serial.print(" - Error "); if( alamat < 16 ) Serial.print("0"); Serial.println(alamat, HEX); } } Serial.println(); if(modul > 0){ Serial.print("Ditemukan "); Serial.print(modul); Serial.println(" modul I2C."); }else{
192
64 65 66 67 68
Serial.println("Tidak ada modul I2C."); } delay(2000); }
Cara kerja program diatas adalah mencoba satu-persatu alamat yang mungkin dipakai oleh modul I2C. Rentang alamat yang mungkin dipakai adalah dari 0 hingga 127 (lihat baris 37). Teknik yang dilakukan oleh program di atas adalah dengan mengetahui respon yang diterima. Jika responnya adalah 0, berarti ada device I2C di alamat tersebut (lihat baris 40). Jika tidak ada respon, berarti tidak terpakai. Berikut contoh hasil alamat LCD yang kita jadikan ujicoba, kita mendapatkan alamat 0x27.
Gambar 13.5 Output program mencari alamat I2C
Alamat tersebut nantinya kita masukkan ke konfigurasi LCD. Jika alat I2C tidak ditemukan, kemungkinannya adalah 193
karena kabelnya kendor, alatnya rusak, atau kabel SDA dan SCL-nya terbalik. Setelah Anda menemukan alamat I2C yang benar, mari lanjut ke program berikutnya.
13.4 Program Mengontrol Lampu Backlight LCD Program ini akan membuat lampu backlight LCD hidup mati. rangkaian pada program ini sama dengan program 13.1. Program 13.2 Program Pengontrol Lampu Backlight LCD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/* * MONSTER ARDUINO V2 * Program Mengontrol Lampu Backlight LCD * www.ElangSakti.com */ // library LCD dengan modul I2C #include #define BACKLIGHT_ON HIGH #define BACKLIGHT_OFF !BACKLIGHT_ON // jumlah kolom dan baris LCD (16x2) #define LCD_COL 16 #define LCD_ROW 2 // ===== Konfigurasi LCD =========== // LCD1602 dengan Modul I2C // Alamat I2C di 0x27 // lcd_Addr, EN, RW, RS, D4, D5, D6, D7, PIN_BACKLIGHT, Pol LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
194
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
// status backlight lcd boolean status_backlight = BACKLIGHT_ON; void setup() { // Settingan LCD lcd.begin(LCD_COL,LCD_ROW); // Nyalakan Backlight lcd.setBacklight(BACKLIGHT_ON); // letakkan kursor pada baris 0 kolom 0 // lalu kirim tulisan ELANGSAKTI.COM (14 karakter) lcd.setCursor(0,0); lcd.print("ELANGSAKTI.COM"); // arahkan kursor pada baris 1 kolom 0 // lalu kirim tulisan BACKLIGHT: (10 karakter) lcd.setCursor(0,1); lcd.print("BACKLIGHT:"); } void loop() { if( nonblocking_delay(2000) ) { // balik logika status_backlight = !status_backlight; // letakkan kursor pada baris 1 kolom 10 // (setelah tulisan BACKLIGHT:) lcd.setCursor(10,1); // jika status ON, tulis ON, nyalakan backlight // jika status OFF, tulis OFF, matikan backlight if( status_backlight == BACKLIGHT_ON ){ // spasi " " setelah tulisan "ON " // berguna untuk menutupi // huruf "F" paling akhir pada tulisan "OFF" lcd.print("ON "); lcd.setBacklight(BACKLIGHT_ON); } else {
195
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
lcd.print("OFF"); lcd.setBacklight(BACKLIGHT_OFF); } } } // tambahan untuk membuat delay non blocking unsigned long nonblocking_time = millis(); unsigned long nonblocking_last = millis(); boolean nonblocking_delay(long milidetik){ nonblocking_time = millis(); if(nonblocking_time - nonblocking_last >= milidetik){ nonblocking_last = nonblocking_time; return true; } return false; }
Program di atas akan membuat lampu backlight LCD berkedip setiap detik. Jadi, pastikan jumper LCD dipasang. Status backlight akan tertulis di LCD. Cara kerja program di atas adalah : 1. Jika menggunakan modul I2C, maka kita harus import dulu library LCD yang khusus I2C (lihat baris 8) 2. Jangan lupa jumlah baris dan kolom LCD juga ditentukan (lihat baris 14 dan 15) 3. Alamat
LCD
yang
sudah
kita
temukan
tadi
dimasukkan ke konfigurasi pada baris 22. Ada beberapa cara penulisan konfigurasi ini, namun yang lebih simpel adalah seperti pada baris tersebut. Semoga penjelasan lebih detail bisa disertakan saat edisi revisi. 196
4. Perlu diperhatikan, angka 2, 1, 0, 4, 5, 6, 7, dan 3 bukanlah kaki pin Arduino, tapi pin di IC modul I2C. 5. Selanjutnya, bisa Anda pelajari di masing-masing baris code di atas.
13.5 Program Format Teks LCD Program ini akan menampilkan tulisan rata kiri, rata tengah, atau rata kanan. Program 13.3 Program Format Teks LCD1602 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
/* * MONSTER ARDUINO V2 * Program Format Teks LCD1602 * www.ElangSakti.com */ // library LCD dengan modul I2C #include #define BACKLIGHT_ON HIGH #define BACKLIGHT_OFF !BACKLIGHT_ON // jumlah kolom dan baris LCD (16x2) #define LCD_COL 16 #define LCD_ROW 2 #define ALIGN_LEFT 1 // teks rata kiri #define ALIGN_CENTER 2 // teks center #define ALIGN_RIGHT 3 // teks rata kanan #define CLEAR true // clear screen // ===== Konfigurasi LCD =========== // LCD1602 dengan Modul I2C // Alamat I2C di 0x27 // lcd_Addr, EN, RW, RS, D4, D5, D6, D7, PIN_BACKLIGHT, Pol
197
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // pilihat format penulisan teks byte tipe_format[] = {ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT}; byte format = ALIGN_LEFT; void setup() { // Settingan LCD lcd.begin(LCD_COL,LCD_ROW); // Nyalakan Backlight lcd.setBacklight(BACKLIGHT_ON); } void loop() { if( nonblocking_delay(2000) ) { SetDisplay("ELANGSAKTI.COM", 0, tipe_format[format], CLEAR); switch( tipe_format[format] ){ case ALIGN_LEFT: SetDisplay("LEFT", 1, ALIGN_LEFT, !CLEAR); break; case ALIGN_CENTER: SetDisplay("CENTER", 1, ALIGN_CENTER, !CLEAR); break; case ALIGN_RIGHT: SetDisplay("RIGHT", 1, ALIGN_RIGHT, !CLEAR); break; } format++; if( format >= sizeof(tipe_format) ){ format = 0; } } } // fungsi untuk menampilkan teks pada lcd sesuai format
198
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
void SetDisplay(String data, byte baris, byte format, boolean hapus){ if(hapus) lcd.clear(); int cols = data.length(); if( cols > LCD_COL) format = ALIGN_LEFT; if(format == ALIGN_CENTER){ if(cols%2 == 1) cols++; cols = (LCD_COL/2) - (cols/2); }else if(format == ALIGN_RIGHT){ cols = LCD_COL - cols; }else{ cols = 0; } lcd.setCursor(cols,baris); lcd.print(data); } // tambahan untuk membuat delay non blocking unsigned long nonblocking_time = millis(); unsigned long nonblocking_last = millis(); boolean nonblocking_delay(long milidetik){ nonblocking_time = millis(); if(nonblocking_time - nonblocking_last >= milidetik){ nonblocking_last = nonblocking_time; return true; } return false; }
Program ini akan menampilkan teks rata kiri, rata tengah, atau rata kanan. Bagian penting dari program ini yaitu fungsi SetDisplay(). Fungsi SetDisplay() terdiri dari 4 parameter: 1. data, String data yang akan dicetak ke LCD 2. baris, baris LCD. Untuk LCD 1602, pilihannya 0 atau 1 3. format, pilihannya ALIGN_LEFT, ALIGN_CENTER, dan ALIGN_RIGHT 199
4. hapus, jika bernilai true, maka tampilan LCD akan dibersihkan (clear) sebelum menulis teks. Silakan analisa bagaimana cara kerja program ini, khususnya yang ada dalam fungsi SetDisplay().
13.6 Program Efek Teks NgeBlink Program ini merupakan
salah
satu teknik untuk
menampilkan teks ngeblink di LCD. Program 13.4 Program Efek Teks NgeBlink 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/* * MONSTER ARDUINO V2 * Program Efek Teks NgeBlink * www.ElangSakti.com */ // library LCD dengan modul I2C #include #define BACKLIGHT_ON HIGH #define BACKLIGHT_OFF !BACKLIGHT_ON // jumlah kolom dan baris LCD (16x2) #define LCD_COL 16 #define LCD_ROW 2 // ===== Konfigurasi LCD =========== // LCD1602 dengan Modul I2C // Alamat I2C di 0x27 // lcd_Addr, EN, RW, RS, D4, D5, D6, D7, PIN_BACKLIGHT, Pol LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); boolean blink_state = true; unsigned long blink_timer = 0;
200
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
void setup() { // Settingan LCD lcd.begin(LCD_COL,LCD_ROW); // Nyalakan Backlight lcd.setBacklight(BACKLIGHT_ON); } void loop() { // string steks, kolom 0, baris 0, waktu on 500 (ms), waktu off 500 (ms) BlinkDisplay("ELANGSAKTI.COM",0,0,500,500); } // fungsi untuk menampilkan teks blink di lcd // input : teks, baris, kolom, waktu on, waktu off void BlinkDisplay(String data, byte baris, byte kolom, unsigned long on_time, unsigned long off_time){ byte len = data.length(); if( blink_state == true ){ if( millis() - blink_timer < on_time ) return; data = ""; for(byte i=0; i
201
68 69 70 71 72 73 74 75 76 77 78 79 80 81
} // tambahan untuk membuat delay non blocking unsigned long nonblocking_time = millis(); unsigned long nonblocking_last = millis(); boolean nonblocking_delay(long milidetik){ nonblocking_time = millis(); if(nonblocking_time - nonblocking_last >= milidetik){ nonblocking_last = nonblocking_time; return true; } return false; }
Program ini akan membuat efek ngeblink pada teks. Kunci dari efek ini ada pada baris 55. Jika status blink_state adalah true, maka teks akan digantikan dengan spasi. Jika tidak, tampilkan teks aslinya. Silakan coba-coba dengan delay yang berbeda-beda.
13.7 Program Format Teks dan NgeBlink Program ini menampilan format teks rata kiri, rata tengah, dan rata kanan dengan efek ngeblink. Program 13.5 Program Kombinasi Format Teks dan Ngeblink 1 2 3 4 5 6 7 8 9
/* * MONSTER ARDUINO V2 * Program Kombinasi Format Teks dan NgeBlink * www.ElangSakti.com */ // library LCD dengan modul I2C #include
202
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
#define BACKLIGHT_ON HIGH #define BACKLIGHT_OFF !BACKLIGHT_ON // jumlah kolom dan baris LCD (16x2) #define LCD_COL 16 #define LCD_ROW 2 #define ALIGN_LEFT 1 // teks rata kiri #define ALIGN_CENTER 2 // teks center #define ALIGN_RIGHT 3 // teks rata kanan #define CLEAR true // clear screen // ===== Konfigurasi LCD =========== // LCD1602 dengan Modul I2C // Alamat I2C di 0x27 // lcd_Addr, EN, RW, RS, D4, D5, D6, D7, PIN_BACKLIGHT, Pol LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // pilihat format penulisan teks byte tipe_format[] = {ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT}; byte format = ALIGN_LEFT; boolean blink_state = true; unsigned long blink_timer = 0; void setup() { // Settingan LCD lcd.begin(LCD_COL,LCD_ROW); // Nyalakan Backlight lcd.setBacklight(BACKLIGHT_ON); } void loop() { SetDisplay( BlinkDisplay("ELANGSAKTI.COM",500,1000) , 0, ALIGN_CENTER, !CLEAR); }
203
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
// fungsi untuk menampilkan teks blink di lcd // input : teks, baris, kolom, waktu on, waktu off String BlinkDisplay(String data, unsigned long on_time, unsigned long off_time){ byte len = data.length(); if( blink_state == true ){ data = ""; for(byte i=0; i LCD_COL) format = ALIGN_LEFT; if(format == ALIGN_CENTER){ if(cols%2 == 1) cols++; cols = (LCD_COL/2) - (cols/2); }else if(format == ALIGN_RIGHT){ cols = LCD_COL - cols; }else{ cols = 0; } lcd.setCursor(cols,baris); lcd.print(data); } // tambahan untuk membuat delay non blocking
204
95 96 97 98 99 100 101 102 103 104 105
unsigned long nonblocking_time = millis(); unsigned long nonblocking_last = millis(); boolean nonblocking_delay(long milidetik){ nonblocking_time = millis(); if(nonblocking_time - nonblocking_last >= milidetik){ nonblocking_last = nonblocking_time; return true; } return false; }
Pengganbungan kedua efek teks cukup simpel, kita hanya perlu memodifikasi teks yang akan dicetak dengan fungsi SetDisplay (lihat baris 48). Pada baris tersebut, setelah teks diberi efek ngeblink, teks diberi format rata kiri, rata tengah, atau rata kanan.
13.8 Program Teks Bergerak Program ini menampilkan cara membuat teks bergerak dari kiri ke kanan, dari kanan ke kiri, dari atas ke bawah, atau dari bawah ke atas. Program 13.6 Program Teks Bergerak 1 2 3 4 5 6 7 8 9 10
/* * MONSTER ARDUINO V2 * Program Teks Bergerak * www.ElangSakti.com */ // library LCD dengan modul I2C #include #define BACKLIGHT_ON HIGH
205
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
#define BACKLIGHT_OFF !BACKLIGHT_ON // jumlah kolom dan baris LCD (16x2) #define LCD_COL 16 #define LCD_ROW 2 #define ALIGN_LEFT 1 // teks rata kiri #define ALIGN_CENTER 2 // teks center #define ALIGN_RIGHT 3 // teks rata kanan #define CLEAR true // clear screen #define MOVE_NONE 0 #define MOVE_UP 1 // teks rata kiri #define MOVE_DOWN 2 // teks center #define MOVE_LEFT 3 // teks rata kanan #define MOVE_RIGHT 4 #define CLEAR true // clear screen // ===== Konfigurasi LCD =========== // LCD1602 dengan Modul I2C // Alamat I2C di 0x27 // lcd_Addr, EN, RW, RS, D4, D5, D6, D7, PIN_BACKLIGHT, Pol LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // pilihat format penulisan teks byte pilihan_move[] = {MOVE_UP, MOVE_DOWN, MOVE_LEFT, MOVE_RIGHT}; byte moving = MOVE_NONE; boolean moving_state = true; unsigned long moving_timer = 0; // temporary untuk move_up dan move_down String tmp_teks = ""; // temporarty untuk move_left dan move_right int posisi_kolom = 0; int counter = 0; void setup() { // Settingan LCD lcd.begin(LCD_COL,LCD_ROW);
206
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
// Nyalakan Backlight lcd.setBacklight(BACKLIGHT_ON); } void loop() { String tulisan = "Counter : "; tulisan.concat( counter ); MoveText(tulisan, 1, MOVE_UP, 0); delay(1000); counter++; }
void MoveText(String data, byte baris, byte pilih_moving, unsigned long moving_delay){ if( millis() - moving_timer < moving_delay ) return; int cols = 0; int real_cols = 0; switch(pilih_moving){ case MOVE_UP: SetDisplay(tmp_teks, 0, ALIGN_LEFT, CLEAR); SetDisplay(data, 1, ALIGN_LEFT, !CLEAR); tmp_teks = data; break; case MOVE_DOWN: SetDisplay(tmp_teks, 1, ALIGN_LEFT, CLEAR); SetDisplay(data, 0, ALIGN_LEFT, !CLEAR); tmp_teks = data; break; case MOVE_LEFT: lcd.setCursor(0,baris); for(byte i=0; i
207
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
lcd.setCursor(0,baris); real_cols = data.length(); if( posisi_kolom < 0 ){ data = data.substring( abs(posisi_kolom) ); } cols = data.length(); for(byte i=0; i
208
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
lcd.print(data); i = cols; }else{ lcd.print(' '); } } else { if( i == posisi_kolom ){ lcd.print(data); i += cols; } else { lcd.print(' '); } } } posisi_kolom++; if( posisi_kolom > LCD_COL ) posisi_kolom = -real_cols+1; break; } moving_timer = millis(); }
// fungsi untuk menampilkan teks pada lcd sesuai format void SetDisplay(String data, byte baris, byte format, boolean hapus){ if(hapus) lcd.clear(); int cols = data.length(); if( cols > LCD_COL) format = ALIGN_LEFT; if(format == ALIGN_CENTER){ if(cols%2 == 1) cols++; cols = (LCD_COL/2) - (cols/2); }else if(format == ALIGN_RIGHT){ cols = LCD_COL - cols; }else{ cols = 0; } lcd.setCursor(cols,baris); lcd.print(data); } // tambahan untuk membuat delay non blocking unsigned long nonblocking_time = millis();
209
183 184 185 186 187 188 189 190 191
unsigned long nonblocking_last = millis(); boolean nonblocking_delay(long milidetik){ nonblocking_time = millis(); if(nonblocking_time - nonblocking_last >= milidetik){ nonblocking_last = nonblocking_time; return true; } return false; }
Program teks bergerak ini juga dikombinasikan dengan format teks rata kiri, rata tengah, atau rata kanan. Fungsi utama dari program ini adalah MoveText. Ada pilihan MOVE_UP, MOVE_DOWN, MODE_LEFT, dan MOVE_RIGHT. Anda bisa mencobanya dengan mengedit baris 62.
13.9 Program Membuat Custom Karakter LCD Contoh program ini menampilkan cara membuat karakter sendiri pada LCD sesuai kenginan. Program 13.7 Program Membuat Custom Karakter LCD 1 2 3 4 5 6 7 8 9 10 11 12 13 14
/* * MONSTER ARDUINO V2 * Program Membuat Custom Karakter LCD * www.ElangSakti.com */ // library LCD dengan modul I2C #include #define BACKLIGHT_ON HIGH #define BACKLIGHT_OFF !BACKLIGHT_ON // jumlah kolom dan baris LCD (16x2) #define LCD_COL 16
210
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
#define LCD_ROW 2 // ===== Konfigurasi LCD =========== // LCD1602 dengan Modul I2C // Alamat I2C di 0x27 // lcd_Addr, EN, RW, RS, D4, D5, D6, D7, PIN_BACKLIGHT, Pol LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); byte mangap_arr[] = { B00000, B01110, B01011, B11111, B00011, B10011, B01110, B00000 }; byte mingkem_arr[] = { B00000, B01110, B01011, B11111, B11111, B01111, B00000, B00000 }; byte counter = 0; byte char_mangap = 0; byte char_mingkem = 0; boolean char_state = 0; int posisi_kolom = LCD_COL; void setup() { // Settingan LCD lcd.begin(LCD_COL,LCD_ROW); // Nyalakan Backlight
211
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
lcd.setBacklight(BACKLIGHT_ON); lcd.createChar(0, mingkem_arr); lcd.createChar(1, mangap_arr); } void loop() { if( nonblocking_delay(200) ){ char_state = !char_state; lcd.clear(); lcd.setCursor(posisi_kolom,0); if( char_state == true ){ lcd.write( byte(0) ); } else { lcd.write( byte(1) ); } counter++; if( counter == 3 ){ posisi_kolom--; if( posisi_kolom < 0 ){ posisi_kolom = LCD_COL; } counter = 0; } } } // tambahan untuk membuat delay non blocking unsigned long nonblocking_time = millis(); unsigned long nonblocking_last = millis(); boolean nonblocking_delay(long milidetik){ nonblocking_time = millis(); if(nonblocking_time - nonblocking_last >= milidetik){ nonblocking_last = nonblocking_time; return true; } return false; }
212
Bagian penting membuat karakter sendiri adalah : 1. Anda harus mendefinisikan bit-bit pixel untuk setiap karakter pada LCD. Setiap karakter LCD memiliki 5x8 pixel (lihat baris 24 – 44). 2. Untuk mempermudah pembuatan bit-bit pixelnya, anda
bisa
gunakan
aplikasi
eksternal
seperti
https://goo.gl/dYVzAx atau yang lainnya. 3. Setelah memiliki bit karakternya, selanjutnya proses pembuatan karakter seperti pada baris 60 dan 61. 4. Jika karakter sudah dibuat, selanjutnya tinggal cetak ke LCD (lihat baris 73 dan 75). Sepertinya sudah cukup banyak contoh dan tips memaksimalkan
tampilan
LCD.
Semoga
setelah
ini
kemampuan kita makin meningkat. Selanjutnya, mari kita membuat progra muntuk sensor PIR.
213
Bagian #14
ALARM SENSOR PIR Saya tidak pernah takut pada orang yang menguasai 10.000 jurus tapi saya takut pada orang yang menguasai 1 jurus tapi melatihnya 10.000 kali. (Bruce Lee)
___ Sensor PIR (Passive Infra Red) adalah sensor inframerah yang didesain hanya untuk mendeteksi
sinar inframerah
yang terpancar dari tubuh manusia. Sensor PIR tidak didesain untuk mendeteksi semua benda yang bergerak. Kenapa? Anda bisa menemukan alasannya pada penjelasan selanjutnya. Sensor PIR disebut pasif sebab sensor tersebut tidak memancarkan sinar inframerah untuk dideteksi pantulannya. Sensor
PIR
hanya
menerima
sinar
inframerah
dari
lingkungan sekitar, baik dari lampu, tubuh manusia, dan semua benda yang memancarkan sinar inframerah. Bagaimana Sensor PIR dapat mendeteksi manusia?
214
Pada
sensor
PIR
terdapat
filter
frekuensi
yang
dicocokkan dengan karakteristik pancaran sinar inframerah dari tubuh manusia, yaitu 9 – 10 mikrometer. Filter pada sensor PIR didesain untuk mendeteksi sinar inframerah dengan panjang gelombang 8 – 14 mikrometer. Jika ada benda, hewan, atau makhluk yang memancarkan sinar inframerah dalam rentang tersebut, maka sensor PIR aktif.
Gambar 14.1 Blok diagram sensor PIR
Untuk memahami lebih dalam tentang tentang cara kerja sensor PIR, Anda boleh memperhatikan gambar bagian-bagian sensor PIR pada Gambar 14.1. Berikut penjelasan dari gambar tersebut: 1. Energi (sinar infrared) dari lingkungan sekitar akan melewati lensa Fresnel yang berfungsi memfokuskan sinar infrared menuju sensor Pyroelectric. 2. Lensa Fresnel adalah pengembangan dari lensa cembung. Kelebihan dari lensa Fresnel yaitu bentuk yang jauh lebih tipis dari pada lensa cembung biasa. 215
3. Sinar infrared yang difokuskan oleh lensa Fresnel akan menimpa sensor Pyroelectric. Sensor ini mirip dengan solar cell. Jika terkena sinar infrared, partikel pada sensor bereaksi dan menghasilkan arus listrik. 4. Arus yang dihasilkan Pyroelectric masih lemah, sehingga diperkuat dengan Amplifier. 5. Output dari Amplifier akan dicocokkan polanya dengan
Komparator.
Pencocokan
pola
ini
dissesuaikan dengan karakteristik sinar infrared yang dipancarkan oleh tubuh manusia sesuai gelombang yang telah disebutkan sebelumnya.
14.1 Sensor PIR HC-SR501 Setelah mengetahui bagian-bagian penting dari sensor PIR, silakan perhatikan modul sensor PIR yang akan kita pakai untuk belajar, yaitu modul HC-SR501. Simak gambar 14.2 dan 14.3 berikut penjelasannya.
Gambar 14.2 Sensor PIR HC-SR501 tampak luar dan dalam
216
Gambar 14.3 Sensor HC-SR501 tampak belakang
Bagian-bagian yang perlu kita ketahui tentang sensor PIR HC-SR501: 1. Lensa Fresnel, dapat memfokuskan sinar inframerah dengan jangkauan sudut 120 o 2. Sensor Pyroelectric mendeteksi sinar inframerah 3. Pengatur delay sensor aktif setelah mendeteksi gerakan. Jika sensor mendeteksi gerakan, maka lama sensor akan aktif sesuai dengan kondisi VR. Putar kiri untuk mengurangi, putar kanan untuk menambah delay (makin lama). Delay dari 3 – 300 detik. 4. Pengatur
sensitifitas
sensor.
Semakin
sensitif
semakin jauh jangkauan (3 – 7 meter). Putar kiri untuk mengurangi sensitifitas, putar kanan untuk meningkatkan sensitifitas. 5. Pengaturan Trigger. Jumper terpasang pada L, No Repeat. Jumper terpasang pada H, Repeat. Status jumper pada gambar, kondisi trigger adalah Repeat. 217
Pengaturan Trigger sangat terkait dengan lama delay. Jika kondisi Repeat, setiap ada gerakan, maka delay akan reset ke awal. Jika kondisi No Repeat, maka sensor tidak akan mendeteksi gerakan lagi sebelum delay habis. Contohnya seperti ini, misal delay adalah 5 detik : -
Ketika
kondisi
No
Repeat,
misal
sensor
mendeteksi gerakan lagi pada detik ke 3, sensor tidak akan merespon sebelum hitungan 5 detik berakhir. -
Ketika kondisi Repeat, misal sensor mendeteksi gerakan lagi pada detik ke 3, maka hitungan detik akan
kembali
ke
0
lagi,
lalu
delay
akan
menghitung dari awal hingga 5 detik berakhir. 6. IC pengolah data sensor 7. VCC, GND, dan OUTPUT dalam bentuk sinyal digital. VCC dapat diberi tegangan 5v – 20v. Untuk OUTPUT, HIGH berarti ada gerakan, LOW berarti tidak ada gerakan. Penting!!! Kelemahan sensor HC-SR501 adalah ada jeda sekitar 5 detik sebelum sensor bisa mendeteksi gerakan berikutnya. 218
14.2 Rangkaian Sensor HC-SR501 Pada rangkaian ini, kita akan mengaktifkan buzzer sesuai dengan logika pada Output. Apabila ada gerakan, maka buzzer akan berbunyi sesuai konfigurasi delay pada sensor PIR. Perhatikan rangkaian pada Gambar Pin 2 dijadikan output ke buzzer, kaki positif buzzer. Sedangkan pin 3 dijadikan sebagai input dari sensor PIR. Silakan atur supaya sensitifitas sensor maksimal dengan memutar VR di nomer 4 full ke kanan. Kemudian atur supaya time delay sangat cepat dengan cara mengatur VR di nomer 3 full ke kiri. Setelah itu, upload program berikut untuk memberikan nyawa pada arduino sesuai fungsinya. Alat dan rangkaian yang perlu disiapkan adalah: 1. Arduino x 1 2. Sensor PIR x 1 3. Buzzer x 1 4. Project board x 1 5. Kabel jumper secukupnya Sambungan pin Arduino, sensor PIR, dan buzzer : Arduino Sensor PIR
Buzzer
Pin 2 Pin 3 VCC GND
Kaki positif Kani GND
Ouput VCC GND
219
Gambar 14.4 Rangkaian Sensor PIR dan Buzzer
14.3 Program Alarm Sensor PIR Program 14.1 Program Alarm Sensor PIR 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/* * MONSTER ARDUINO V2 * Program Alarm Sensor PIR * www.ElangSakti.com */ // pin buzzer di pin 2 dan sensor pir di pin 3 const byte PIN_BUZZER = 2; const byte PIN_PIR = 3; void setup() { // buzzer sebagai output // sensor pir sebagai input pinMode(PIN_BUZZER,OUTPUT); pinMode(PIN_PIR,INPUT); } void loop() { // logika buzzer == logika sensor pir digitalWrite( PIN_BUZZER, digitalRead(PIN_PIR) ); }
220
Setelah program diupload, buzzer akan berbunyi ketika sensor mendeteksi gerakan. Buzzer akan diam setelah time delay habis. Silakan bermain-main dengan kombinasi pengaturan time delay dan sensitifitas untuk memperoleh respon yang diinginkan.
14.4 Program Identifikasi Delay Sensor PIR Program 14.2 Program Identifikasi Delay Sensor PIR 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
/* * MONSTER ARDUINO V2 * Program Identifikasi Delay Sensor PIR * www.ElangSakti.com */ // pin + buzzer di pin 2 // output sensor pir di pin 3 const byte PIN_BUZZER = 2; const byte PIN_PIR = 3; // variabel untuk history logika sensor pir boolean logika_pir = LOW; boolean logika_pir_last = logika_pir; // variabel untuk mencatat timer unsigned long timer_pir = 0; void setup() { // aktifkan komunikasi serial di baud 19200 Serial.begin(19200); // buzzer sebagai output // sensor pir sebagai input pinMode(PIN_BUZZER,OUTPUT); pinMode(PIN_PIR,INPUT);
221
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
} void loop() { // baca sensor pir logika_pir = digitalRead(PIN_PIR); // kondisikan buzzer sesuai logika sensor pir digitalWrite(PIN_BUZZER,logika_pir); // jika output sensor berubah // dari HIGH ke LOW, atau dari LOW ke HIGH if( logika_pir_last != logika_pir){ if ( logika_pir == HIGH ){ // sensor baru saja aktif Serial.println("Sensor ON"); timer_pir = millis(); } else { // sensor baru saja tidak aktif Serial.println("Sensor OFF"); Serial.print("Delay : "); Serial.print( millis() - timer_pir); Serial.print(" ms"); Serial.println(); } } // catat kondisi sensor sebelumnya logika_pir_last = logika_pir; }
Rangkaian untuk program ini akan tetap menggunakan rangkaian sebelumnya. Kita hanya menambahkan program untuk mengetahui lama delay pada pengaturan VR di no. 3.
222
Untuk hasil yang lebih valid tentang delay minimal dan maksimal sensor PIR yang kita punya, maka kita harus mengubah mode Trigger menjadi No Repeat Trigger. Caranya, ubah jumper pada no. 5 ke posisi L. Jika ingin mengetahui delay tercepat pada sensor PIR, lakukan langkah-langkah berikut: 1. Putar VR (no. 3) full ke kiri 2. Upload program 3. Buka Serial Monitor, ubah baud rate menjadi 19200 4. Cek dengan menggerakkan bagian tubuh di depan sensor PIR Jika ingin mengetahui delay terlama, putar VR (no. 3) full ke kanan. Silakan coba-coba sendiri.
223
Gambar 14.5 Output program identifikasi delay sensor PIR
Berdasarkan hasil percobaan, delay tercepat adalah sekitar 2.5 detik (2587 ms). Sedangkan delay terlama adalah sekitar 8 menit (530345 ms) sebagaimana tampak pada gambar di bawah. Jika Anda mencoba dan hasilnya jauh berbeda, itu wajar-wajar saja. Sebab setiap komponen tidak sama persis yang mempengaruhi pada nilai delay.
14.5 Program Custom Delay Alarm Sensor PIR Pada kondisi real, delay yang ditentukan oleh VR kadang tidak sesuai dengan yang kita butuhkan. Contoh, misal kita ingin mengaktifkan buzzer selama 5 detik setelah mendeteksi gerakan. Maka akan merepotkan kalau kita harus memutar-mutar VR hanya untuk mendapatkan delay 5 224
detik. Akan sangat merepotkan juga apabila delaynya ingin kita ubah-ubah. Solusinya, kita tidak tidak mengaktifkan buzzer sesuai dengan delay sensor. Kita akan mengaktifkan buzzer sesuai delay yang kita tentukan sendiri, kita buat variabel sendiri, kita buat delay sendiri. Program di bawah ini akan mengaktifka buzzer selama 5 detik ketika sensor mendeteksi gerakan. Silakan asah logika Anda dengan membaca dan menganalisa program ini. Program 14.3 Program Custom Delay Alarm Sensor PIR 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/* * MONSTER ARDUINO V2 * Program Custom Delay Alarm Sensor PIR * www.ElangSakti.com */ // pin + buzzer di pin 2 // output sensor pir di pin 3 const byte PIN_BUZZER = 2; const byte PIN_PIR = 3; // variabel untuk history logika sensor pir boolean logika_pir = LOW; boolean logika_pir_last = logika_pir; // variabel untuk mencatat timer unsigned long timer_pir = 0;
// output buzzer boolean output_buzzer = LOW; boolean buzzer_aktif = false;
225
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
// delay bunyi buzzer yang diinginkan dalam ms unsigned long DELAY_BUZZER = 5000; // variabel untuk mencatat waktu buzzer unsigned long timer_buzzer = 0; void setup() { // aktifkan komunikasi serial di baud 19200 Serial.begin(19200); // buzzer sebagai output // sensor pir sebagai input pinMode(PIN_BUZZER,OUTPUT); pinMode(PIN_PIR,INPUT); } void loop() { // baca sensor pir logika_pir = digitalRead(PIN_PIR); // jika output sensor berubah // dari HIGH ke LOW, atau dari LOW ke HIGH if( logika_pir_last != logika_pir){ if ( logika_pir == HIGH ){ // sensor baru saja aktif Serial.println("Buzzer ON"); timer_pir = millis(); timer_buzzer = millis(); buzzer_aktif = true; } } // jika buzzer aktif, periksa delay if( buzzer_aktif ){ // buzzer nyala sesuai delay yang ditentukan if( millis() - timer_buzzer >= DELAY_BUZZER){
226
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
// matikan buzzer buzzer_aktif = false; Serial.println("Buzzer OFF"); Serial.print("Delay : "); Serial.print( millis() - timer_pir); Serial.print(" ms"); Serial.println(); } } // aktifkan buzzer sesuai logika buzzer_aktif digitalWrite(PIN_BUZZER, buzzer_aktif); // catat kondisi sensor sebelumnya logika_pir_last = logika_pir; }
Hasil dari program di atas tampak pada Gambar 14.6. Boleh Anda perhatikan, delay untuk nyala alarm bisa kita tentukan sesuai kebutuhan. Teknik ini bisa Anda terapkan untuk sensor lainnya.
Gambar 14.6 Output program custom delay 5 detik
227
Bagian #15
SENSOR DHT11 & KUMBUNG JAMUR Jangan ragu dan jangan malu, tunjukkan pada dunia bahwa sebenarnya kita mampu. (Iwan Fals)
___ Pada ebook pertama, kita menggunakan sensor LM35 untuk mengetahui suhu sekitar. Kali ini kita tidak hanya mengeksplorasi project yang berkaitan dengan suhu saja, tetapi juga yang berkaitan dengan kelembaban udara. Kira-kira, ide apa saja yang terbersit di benak Anda ketika diminta untuk membuat project yang terkait dengan suhu dan kelembaban? Kita abaikan dulu apa yang Anda pikirkan. Kita mulai kenalan dulu dengan sensor DHT11.
15.1 Sensor DHT11 Sensor DHT11 adalah modul yang berisi sensor suhu dan sensor kelembaban dalam satu device. Sensor DHT11 relative simpel, terjangkau, dan mudah digunakan untuk pemula. Akurasinya cukup baik dan tidak kalah dengan sensor suhu LM35. 228
DHT11
dibundel dengan NTC (Negative Temperature
Coefficient) sebagai sensor suhu yang mampu mengukur suhu dari 0 – 50 menggunakan
o
tipe
C. Sedangkan sensor kelembabannya resistif
yang
mampu
mengukur
kelembaban dari 20 – 90 %.
Gambar 15.1 Sensor DHT11
Sensor ini memiliki respon perubahan suhu sekitar 6 30 detik. Jadi jika perubahan suhu yang dideteksi masih di dalam rentang angka tersebut, masih wajar. Jika Anda butuh sensor yang memiliki responsifitas yang lebih cepat, bisa gunakan tipe yang lain.
229
15.2 Akuisi Data Sensor DHT11 Sensor DHT11 terdiri dari dua buah sensor, yaitu sensor suhu dan sensor kelembaban. Namun, pin data hanya satu (lihat Gambar 15.1), bagaimana cara Arduino memperoleh data dari sensor tersebut? Begini, data suhu dan kelembaban diolah oleh IC, kemudian dikirim dengan komunikasi one-wire protocol. One-wire protocol adalah protokol komunikasi yang hanya membutuhkan
satu
jalur
data
untuk
mengirim
dan
menerima data. Saat ini kita tidak akan membahas terlalu detail tentang one-wire, sebab protokol tersebut sudah ada dalam library DHT yang akan kita pakai. Selanjutnya, mari kita langsung ke praktek!
15.2.1 Rangkaian Dasar Sensor DHT11 Perhatikan rangkaian sensor DHT11, kaki dari kiri adalah VCC, DATA, NC, dan GND. NC artinya Not Connected. Rangkaian simpel seperti di gambar. Peralatan yang dibutuhkan adalah: 1. Arduino x 1 2. Sensor DHT11 x 1 3. Resistor 10k x 1 230
4. Project board x 1 5. Kabel Jumper secukupnya Sambungan pin Arduino dan DHT11 yaitu : Arduino Sensor DHT11 Pin 2 VCC GND
Ke Pin Output dengan pullup resistor VCC GND
Gambar 15.2 Skema dasar rangkaian DHT11
15.2.2 Program Akuisisi Data Sensor DHT11 Program ini akan menampilkan suhu dan kelembaban di serial monitor. Komunikasi antara komputer dan Arduino menggunakan baud rate 19200.
Program 15.1 Program Akuisisi Data Sensor DHT11 1 2 3 4
/* * MONSTER ARDUINO V2 * Program Akuisisi Data Sensor DHT11 * www.ElangSakti.com
231
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
*/ // include library dht #include // buat instan dari class DHT dht DHT; // pin output DHT11 const byte DHT_PIN = 2; // variabel untuk sensor suhu dan kelembaban int suhu = 0; int kelembaban = 0; void setup() { // Aktifkan komunikasi serial di baud 19200 Serial.begin(19200); } void loop() { // jika sensor normal if( DHT.read11(DHT_PIN) == DHTLIB_OK ){ // print suhu dan kelembaban // setiap delay 2000 ms (2 detik) if( nonblocking_delay(2000) ){ // akses data suhu dan kelembaban suhu = DHT.temperature; kelembaban = DHT.humidity; // cetak di serial terminal Serial.print("Suhu:"); Serial.print(suhu); Serial.print(" Kelembaban:"); Serial.print(kelembaban); Serial.println(); } } }
232
49 50 51 52 53 54 55 56 57 58 59 60
// tambahan untuk membuat delay non blocking unsigned long nonblocking_time = millis(); unsigned long nonblocking_last = millis(); boolean nonblocking_delay(long milidetik){ nonblocking_time = millis(); if(nonblocking_time - nonblocking_last >= milidetik){ nonblocking_last = nonblocking_time; return true; } return false; }
Gambar 15.3 Output program akuisisi data sensor DHT11
Untuk bisa mengakses data dari sensor DHT11, maka library yan harus diinclude adalah dht.h. Anda bisa download librarynya di internet. Proses pengambilan data suhu dan kelembaban relatif mudah. Jika proses pembacaan sensor berhasil (lihat baris 30), maka data dapat dicetak ke serial monitor.
233
Selanjutnya, data suhu dan kelembaban akan kita tampilkan pada display LCD 1602. Jika Anda sudah memahami program-program sebelumnya, mungkin Anda sudah terbiasa menampilkan data pada LCD.
15.3 Menampilkan Data pada LCD Kita sudah bisa menampilkan suhu dan kelembaban di Serial Terminal. Selanjutnya, kita akan menampilkan suhu dan kelembaban di LCD 1602. Silakan rangkai alat-alat seperti gambar di bawah. Posisi kaki sensor tetap seperti pada
program
sebelumnya.
Yang
ditambah
adalah
rangkaian LCD dan modul LCD I2C. 1. Arduino x 1 2. Sensor DHT11 x 1 3. LCD1602 dengan Modul I2C LCD x 1 4. Project board x 1 5. Kabel jumper secukupnya Sambungan pin Arduino, LCD, dan sensor DHT11 : Arduino LCD 1602 dg I2C
Sensor DHT11
Pin 2 Pin A4 Pin A5 VCC GND
Ke pin Ouput dengan pullup resistor VCC GND
Pin SDA Pin SCL VCC GND
234
Gambar 15.4 Rangkaian untuk menampilkan data sensor di LCD1602
15.3.1 Program Sensor Suhu dan Kelembaban Digital Program 15.2 Program Sensor Suhu dan Kelembaban Digital 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/* * MONSTER ARDUINO V2 * Program Sensor Suhu dan Kelembaban Digital * www.ElangSakti.com */ // include library dht #include // library LCD dengan modul I2C #include // jika true, maka munculkan data di serial terminal #define DEBUG true
// ===== Sensor DHT11 =========== // buat instan dari class DHT
235
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
dht DHT; // pin output DHT11 const byte DHT_PIN = 2; // variabel untuk sensor suhu dan kelembaban int suhu = 0; int kelembaban = 0;
// ===== Konfigurasi LCD =========== // LCD1602 dengan Modul I2C // Alamat I2C di 0x27 : lcd_Addr, EN, RW, RS, D4, D5, D6, D7, PIN_BACKLIGHT, Pol LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // jumlah kolom dan baris LCD (16x2) const byte LCD_COL = 16; const byte LCD_ROW = 2; void setup() { // jika DEBUG = true // Aktifkan komunikasi serial di baud 19200 if( DEBUG ) Serial.begin(19200); // Settingan LCD lcd.begin(LCD_COL,LCD_ROW); // Nyalakan Backlight lcd.setBacklight(BACKLIGHT_ON); // letakkan kursor pada baris 0 kolom 0 lcd.setCursor(0,0); lcd.print("SENSOR SUHU"); // letakkan kursor pada baris 1 kolom 0 lcd.setCursor(0,1); lcd.print("& KELEMBABAN"); delay(3000); }
236
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
void loop() { // jika sensor normal if( DHT.read11(DHT_PIN) == DHTLIB_OK ){ // ambil data suhu dan kelembaban // setiap delay 2000 ms (2 detik) if( nonblocking_delay(2000) ){ // akses data suhu dan kelembaban suhu = DHT.temperature; kelembaban = DHT.humidity; // hapus tulisan di LCD lcd.clear(); // pindah kursor ke baris 0, kolom 0 // tulis suhu lcd.setCursor(0,0); lcd.print("Suhu: "); lcd.print(suhu); // pindah kursor ke baris 1, kolom 0 // tulis kelembaban lcd.setCursor(0,1); lcd.print("Kelembaban: "); lcd.print(kelembaban); // jika DEBUG = true if ( DEBUG ) { // cetak di serial terminal Serial.print("Suhu:"); Serial.print(suhu); Serial.print(" Kelembaban:"); Serial.print(kelembaban); Serial.println(); } } } } // tambahan untuk membuat delay non blocking unsigned long nonblocking_time = millis();
237
106
unsigned long nonblocking_last = millis(); boolean nonblocking_delay(long milidetik){ nonblocking_time = millis(); if(nonblocking_time - nonblocking_last >= milidetik){ nonblocking_last = nonblocking_time; return true; } return false; }
Penjelasan untuk program ini bisa dibaca di tiap-tiap baris kode, sebab untuk program yang menampilkan data ke LCD penulis sudah pada paham dan simpel.
15.4 Project Kumbung Jamur Sederhana Project kali ini adalah membuat alat untuk mengontrol suhu dan kelembaban di kumbung jamur. Alat yang akan kita buat memiliki karakteristik kerja seperti berikut. 1. Informasi suhu dan kelembaban ditampilkan di LCD 2. Jika suhu atau kelembaban melebihi batas tertentu, maka alat akan mengaktifkan pompa selama 5 menit. 3. Pompa dimatikan setelah akttif 5 menit, lalu sistem harus istirahat
(menunggu)
10
menit
sebelum
pengecekan ulang suhu dan kelembaban. 4. Selama istirahat, lampu LCD dimatikan. 5. Setelah waktu istirahat selesai, aktifkan pompa apabila suhu dan kelembaban masih belum sesuai dengan batas yang ditentukan. 238
6. Selama pompa aktif, alarm atau buzzer akan berbunyi dengan nada putus-putus.
15.4.1 Rangkaian Project Kumbung Jamur Rangkaian alat sama persis seperti pada rangkaian sebelumnya, namun ada penambahan buzzer di pin 3 seperti di Gambar 15.5. peralatan dan rangkaian yang harus disiapkan adlah: 1. Arduino x 1 2. Sensor DHT11 x 1 3. Modul relay 2 channel atau 1 channel x 1 4. Buzzer aktif x 1 5. LCD1602 dengan modul I2C x1 6. Jumper secukupnya Sambungan antara Arduino, LCD, DHT11, Buzzer, dan relay adalah sebagai berikut : Arduino
LCD 1602
DHT11
Buzzer
Relay
Pin 2 Pin 3 Pin 4 Pin A4 Pin A5 VCC GND
Pin SDA Pin SCL VCC GND
Pin Ouput VCC GND
Pin Positif Pin GND
Pin Input VCC GND
239
Gambar 15.5 Rangkain project kumbung jamur sederhana
15.4.2 Program Kumbung Jamur Sederhana Program 15.3 Program Kumbung Jamur Sederhana 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/* * MONSTER ARDUINO V2 * Program Kumbung Jamur Sederhana * www.ElangSakti.com */ // include library dht #include // library LCD dengan modul I2C #include // jika true, maka munculkan data di serial terminal #define DEBUG true #define RELAY_ON LOW #define RELAY_OFF !RELAY_ON
240
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
#define BUZZER_ON HIGH #define BUZZER_OFF !BUZZER_ON #define RUNNING true #define NOT_RUNNING !RUNNING #define YES true #define NO !YES #define BACKLIGH_ON HIGH #define BACKLIGH_OFF !BACKLIGH_ON
// pin output DHT11, buzzer, dan relay const byte PIN_DHT = 2; const byte PIN_BUZZER = 3; const byte PIN_RELAY = 4;
// ===== Sensor DHT11 =========== // buat instan dari class DHT dht DHT; // variabel untuk sensor suhu dan kelembaban int suhu = 0; int kelembaban = 0;
// ===== Konfigurasi LCD =========== // LCD1602 dengan Modul I2C // Alamat I2C di 0x27 LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7); // jumlah kolom dan baris LCD (16x2) const byte LCD_COL = 16; const byte LCD_ROW = 2;
// Setpoint Suhu dan Kelembaban // jika suhu >= 28 atau kelembaban <= 70 // aktifkan pompa const int MAX_SUHU = 28; const int MIN_KELEMBABAN = 70;
241
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
// status logika relay dan buzzer boolean status_relay = BUZZER_OFF; boolean status_buzzer = RELAY_OFF; // status pompa boolean pompa_running = NOT_RUNNING; boolean pompa_running_last = pompa_running; boolean wait_after_pompa_running = NO;
// delay pompa on dan waktu tunggu setelah off dalam ms unsigned long pompa_running_time = 5 * 60000L; unsigned long pompa_wait_time = 10 * 60000L; // pencatat timer lama pompa on dan setelah off unsigned long pompa_running_start = 0; unsigned long pompa_running_stop = 0; // delay buzzer on dan off unsigned int buzzer_on_delay = 300; unsigned int buzzer_off_delay = 2000; unsigned long buzzer_timer = 0; boolean sensor_ready = NO;
void setup() { // jika DEBUG = true // Aktifkan komunikasi serial di baud 19200 if( DEBUG ) Serial.begin(19200); // buzzer dan relay sebagai output pinMode(PIN_BUZZER,OUTPUT); pinMode(PIN_RELAY,OUTPUT); // matikan buzzer dan relay saat pertama start digitalWrite(PIN_BUZZER,BUZZER_OFF); digitalWrite(PIN_RELAY,RELAY_OFF); // Settingan LCD lcd.begin(LCD_COL,LCD_ROW); // backlight active high
242
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
lcd.setBacklightPin(3, POSITIVE); // Nyalakan Backlight lcd.setBacklight(BACKLIGH_ON); } void loop() { // jika sensor normal if( DHT.read11(PIN_DHT) == DHTLIB_OK ){ // ambil data suhu dan kelembaban // setiap delay 1000 ms (1 detik) if( nonblocking_delay(1000) ){ // akses data suhu dan kelembaban suhu = DHT.temperature; kelembaban = DHT.humidity; // hapus tulisan di LCD lcd.clear(); // pindah kursor ke baris 0, kolom 0 // tulis suhu lcd.setCursor(0,0); lcd.print("Suhu: "); lcd.print(suhu); // pindah kursor ke baris 1, kolom 0 // tulis kelembaban lcd.setCursor(0,1); lcd.print("Kelembaban: "); lcd.print(kelembaban); // jika DEBUG = true if ( DEBUG ) { // cetak di serial terminal Serial.print("Suhu:"); Serial.print(suhu); Serial.print(" Kelembaban:"); Serial.print(kelembaban); Serial.println(); }
243
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
sensor_ready = YES; } } // jika sensor belum stabil // abaikan pengecekan suhu dan kelembaban if( sensor_ready == NO ) return; // jika pompa sedang tidak running if ( pompa_running == NO ){ // buzzer dan relay di-off kan status_buzzer = BUZZER_OFF; status_relay = RELAY_OFF; // jika pompa dalam status menunggu setelah running if ( wait_after_pompa_running == YES ) { // jika waktu tunggu setelah running selesai if ( millis() - pompa_running_stop >= pompa_wait_time ){ wait_after_pompa_running = false; } // matikan lcd selama waktu tunggu lcd.setBacklight(BACKLIGH_OFF); } else { // jika sudah tidak dalam waktu tunggu // periksa apakah suhu dan kelembaban di bawah batas maksimal if( suhu >= MAX_SUHU || kelembaban <= MIN_KELEMBABAN ){ // jika diatas/sama dengan batas maksimal // nyalakan pompa pompa_running = YES; pompa_running_start = millis(); } // hidupkan lampu lcd lcd.setBacklight(BACKLIGH_ON);
244
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
} } else { // pompa dalam kondisi running // hidupkan buzzer buzzer_sound(); // aktifkan relay status_relay = RELAY_ON; // cek lama waktu pompa running if ( millis() - pompa_running_start >= pompa_running_time ){ // jika lama pompa running sudah sesuai // matikan pompa, catat waktu, dan aktifkan waktu tunggu pompa_running = NO; pompa_running_stop = millis(); wait_after_pompa_running = YES; } } // sesuaikan status relay dan buzzer digitalWrite(PIN_RELAY, status_relay); digitalWrite(PIN_BUZZER, status_buzzer); }
// bunyi buzzer sesuai waktu void buzzer_sound(){ if( status_buzzer == BUZZER_ON ){ if( millis() - buzzer_timer >= buzzer_on_delay ){ status_buzzer = BUZZER_OFF; buzzer_timer = millis(); } } else { if( millis() - buzzer_timer >= buzzer_off_delay ){ status_buzzer = BUZZER_ON; buzzer_timer = millis(); } }
245
234 235 236 237 238 239 240 241 242 243 244 245 246
} // tambahan untuk membuat delay non blocking unsigned long nonblocking_time = millis(); unsigned long nonblocking_last = millis(); boolean nonblocking_delay(long milidetik){ nonblocking_time = millis(); if(nonblocking_time - nonblocking_last >= milidetik){ nonblocking_last = nonblocking_time; return true; } return false; }
Program
untuk
kumbung
jamur
sederhana
akan
dijelaskan secara detail pada edisi revisi. Untuk sementara Anda boleh baca keterangan yang ada pada source code.
246
Bagian #16
APLKASI REALTIME DENGAN RTC Keberhasilan adalah kemampuan untuk melewati dan mengatasi satu kegagalan ke kegagalan berikutnya tanpa kehilangan semangat. (Winston Chuchill)
___
Jika komputer atau laptop tidak menggunakan RTC, maka setiap menyalakan komputer, kita akan diminta untuk memasukkan tanggal dan jam. Namun tidak demikian, setiap kita menyalakan komputer, tanggal dan jam selalu sama dengan tanggal dan jam sebenarnya. Itulah kegunaan dari Real Time Clock (RTC). Mungkin juga kita pernah menemukan jam digital di rumah-rumah ibadah, pom bensin, atau fasilitas umum lainnya. Komponen yang dipakai agar tanggal dan jamnya selalu update pada peralatan tersebut adalah RTC. Ada banyak jenis RTC, dari yang biasa hingga yang akurasinya tinggi. Mungkin Anda sudah pernah dengar atau lihat RTC DS1302, DS1307, DS3231, PCF8563, atau yang 247
lainnya. IC-IC tersebut memiliki fungsi utama yang sama, yaitu mencacah dan mencatat waktu. Namun setiap IC punya kelebihan dan kekurangan masing-masing. Sebagai dasar pengenalan dan pembelajaran, kita menggunakan yang Tiny RTC 1307 karena akurasinya cukup memadai dan harganya pun relatif terjangkau.
Gambar 16.1 RTC Tiny DS1307 tampak dari depan dan belakang
Seperti modul I2C LCD, data dari RTC DS1307 ini dapat diakses dengan komunikasi I2C. Bagian-bagian modul yang perlu minimal dipahami yaitu: 1. VCC, sumber tegangan +5V 2. GND, sumber tegangan Ground 3. SDA, serial data. Pin ini menjadi jalur komunikasi data antara Arduino dan Modul RTC 4. SCL, serial clock untuk melakukan sinkronisasi komunikasi data antara Arduino dan RTC 5. Selain ke-4 pin tersebut, pin yang lain mungkin akan jarang dipakai. Jika Anda penasaran dengan fungsifungsinya, silakan googling. 248
Sebagai informasi tambahan, jantung utama RTC adalah komponen Crystal dan baterai. Crystal digunakan untuk mencacah waktu dengan akurat. Detik, menit, jam, dan tanggal
yang
disimpan
dalam
memori
ditentukan
berdasarkan hasil cacahan ini. Baterai
berfungsi
untuk
memastikan
RTC
terus
mencacah. Jika baterai mati atau dilepas, maka RTC tidak dapat mencacah. Hal ini menyebabkan informasi waktu yang tersimpan di memori menjadi tidak valid, alias tanggal atau jamnya kadaluarsa. Jika Anda pernah punya laptop atau komputer yang tanggalnya selalu kadaluarsa ketika dihidupkan, berarti baterai RTC-nya sudah kehabisan energi.
16.1 Rangkaian Dasar RTC DS1307 Peralatan dan rangkaian yang perlu disiapkan adalah : 1. Arduino x 1 2. TinyRTC D1307 x 1 3. Kabel jumper secukupnya Sambungan Arduino dan RTC yaitu: Arduino
TinyRTC DS1307
VCC 5V GND A4 A5
VCC GND SDA SCL
249
Gambar 16.2 Rangkaian dasar RTC DS1307 dan Arduino
16.2 Menampilkan Waktu di Serial Monitor Program 16.1 Program Menampilkan Waktu di Serial Monitor 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/* * MONSTER ARDUINO V2 * Program Menampilkan Waktu di Serial Monitor * www.ElangSakti.com */ // include library Wire dan RTCLib #include #include // buat object RTC RTC_DS1307 RTC; void setup() { // buka koneksi ke serial monitor Serial.begin(19200); while(!Serial); // buka koneksi ke RTC Wire.begin(); RTC.begin(); delay(1000); // jika RTC belum disetting & running
250
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
if (! RTC.isrunning()) { // set waktu RTC sesuai waktu di komputer RTC.adjust(DateTime(__DATE__, __TIME__)); Serial.println("RTC is NOT Running"); } else { // RTC normal Serial.println("RTC OK!"); } } void loop() { // cetak waktu setiap detik if( nonblocking_delay(1000) ){ PrintTime(); } } // fungsi untuk mencetak waktu // di serial monitor void PrintTime(){ // ambil data jam dan tanggal DateTime now = RTC.now(); // jika tanggal < 9, tambahkan // angka 0 didepan angka. if( now.day() < 10 ) Serial.print(0); Serial.print(now.day(), DEC); Serial.print('/'); // tampilkan bulan if( now.month() < 10 ) Serial.print(0); Serial.print(now.month(), DEC); Serial.print('/'); // tampilkan tahun Serial.print(now.year(), DEC); Serial.print(' '); // tampilkan jam if( now.hour() < 10 ) Serial.print(0); Serial.print(now.hour(), DEC); Serial.print(':');
251
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
// tampilkan menit if( now.minute() < 10 ) Serial.print(0); Serial.print(now.minute(), DEC); Serial.print(':'); // tampilkan detik if( now.second() < 10 ) Serial.print(0); Serial.print(now.second(), DEC); Serial.println(); } // tambahan untuk membuat delay non blocking unsigned long nonblocking_time = millis(); unsigned long nonblocking_last = millis(); boolean nonblocking_delay(long milidetik){ nonblocking_time = millis(); if(nonblocking_time - nonblocking_last >= milidetik){ nonblocking_last = nonblocking_time; return true; } return false; }
Cara kerja program di atas yaitu : 1. Import library yang dibutuhkan modul RTC, yaitu Wire.h dan RTCLib.h (lihat baris 8 dan 9) 2. Setelah membuat koneksi ke modul RTC, cek apakah RTC sudah running atau belum (lihat baris 25). Jika belum running, waktu yang tersimpan di RTC tidak update. Oleh sebab itu, update waktu RTC sesuai dengan waktu compile komputer (lihat baris 27). 3. Untuk mencetak waktu, ambil data dari RTC seperti pada baris 48. Setelah itu ambil data tanggal, tahun, bulan, jam, menit, dan detik. Pastikan format yang dicetak pada serial monitor adalah desimal (DEC). 252
4. Untuk merapikan tampilan, apabila angka lebih kecil dari angka 10, tampilkan angka 0 di depannya. Hal ini sangat berguna ketika menggunakan display LCD. Yang perlu diperhatikan adalah jangan menempatkan perintah update waktu seperti baris ke 27 di sembarang tempat. Sebab, jika salah penempatan, waktu yang ada di RTC akan diupdate seperti waktu saat program dicompile dan waktu akan reset ke awal ketika Arduino direset.
16.3 Menampilkan Jam di Seven Segment Dengan program ini, kita akan membuat jam digital seperti yang dipakai oleh instansi atau rumah-rumah ibadah. Oleh sebab itu, silakan pelajari dengan baik.
16.3.1 Rangkaian Menampilkan Jam di Seven Segment Peralatan dan rangkaian yang harus disiapkan adalah: 1. Arduino x 1 2. TinyRTC DS1307 x 1 3. IC Shift Register 74HC595 x 1 4. Display Seven Segment 4 Digit CC x 1 5. Project board x 1 6. Kabel jumper secukupnya 253
Sambungan pin Arduino, TinyRTC, 74HC595, dan 7 segement yaitu : Arduino
TinyRTC
74HC595
7 Segment
Pin 2 Pin 3 Pin 4 Pin A0 Pin A1 Pin A2 Pin A3 Pin A4 Pin A5 VCC GND
SDA SCL VCC GND
Pin 14, Data Pin 12, Latch Pin 11, Clock Pin 10 dan 16 Pin 8 dan 13
D1 D2 D3 D4 -
Gambar 16.3 Rangkaian untuk menampilkan jam di seven segment
254
16.3.2 Program Menampilkan Jam di Seven Segment Program 16.2 Program Menampilkan Jam di Seven Segment 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
/* * MONSTER ARDUINO V2 * Program Menampilkan Jam di Seven Segment * www.ElangSakti.com */ // include library Wire dan RTCLib #include #include // common cathode #define OFF 0B00000000 // kecerahan led segmen #define BRIGHTNESS 100 // konversi angka // 8 bit data : A B C D E F G DP const byte Angka[] = { B11111100, B01100000, B11011010, B11110010, B01100110, B10110110, B10111110, B11100000, B11111110, B11110110, B00000010 }; // konfigurasi pin Arduino const byte DataPin = 2; // data const byte LatchPin = 3; // ST_CP const byte ClockPin = 4; // SH_CP // untuk mengontrol digit, // kita masih pakai pin arduino
255
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
// untuk lebih menghemat, bisa tambah // IC shift register lagi const byte Digit1 = A0; const byte Digit2 = A1; const byte Digit3 = A2; const byte Digit4 = A3; const byte DIGIT[] = {Digit1, Digit2, Digit3, Digit4}; // jumlah digit seven segment const byte jumlah_digit = sizeof(DIGIT); // digit terpilih untuk diaktifkan byte DIGIT_SELECT = 0; // pengaturan untuk brightness unsigned long brightness_now = 0; unsigned long brightness_last = 0; unsigned long brightness_limit = 0; // onject untuk RTC RTC_DS1307 RTC; // teks jam String teks_jam = ""; // titik dua ngeblink utk detik boolean blink_detik = false; void setup() { // buka koneksi ke serial monitor // untuk debug Serial.begin(19200); while(!Serial); // buka koneksi ke RTC Wire.begin(); RTC.begin(); delay(1000); // jika RTC belum disetting & running if (! RTC.isrunning()) { // set waktu RTC sesuai waktu di komputer RTC.adjust(DateTime(__DATE__, __TIME__)); Serial.println("RTC is NOT Running");
256
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
} else { // RTC normal Serial.println("RTC OK!"); } // konfigurasi pin sebagai ouput pinMode(LatchPin, OUTPUT); pinMode(ClockPin, OUTPUT); pinMode(DataPin, OUTPUT); // pastikan bahwa display mati for(byte i=0; i
257
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
// mengkonversinya jadi string String JamMenit(){ DateTime now = RTC.now(); teks_jam = ""; if( now.hour() < 10 ) teks_jam.concat(0); teks_jam.concat(now.hour()); if( now.minute() < 10 ) teks_jam.concat(0); teks_jam.concat(now.minute()); return teks_jam; } // fungsi PrintDigit // fungsi untuk mencetak banyak angka ke // seven segment void PrintDigit(String numstr, byte jumlah_digit){ // delay nyala segment, efeknya pada brigthness brightness_limit = constrain(BRIGHTNESS,1,100); brightness_limit = map(brightness_limit,1,100,1,5000); // hitung lebar string byte lenstr = numstr.length(); // mulai transfer digitalWrite(LatchPin, LOW); brightness_now = micros(); if(brightness_now - brightness_last < brightness_limit){ digitalWrite(DIGIT[DIGIT_SELECT],LOW); if( DIGIT_SELECT < lenstr ){ // jika digit yang terpilih < jumlah angka // cetak angka pada digit tersebut byte angka = ( numstr.substring( DIGIT_SELECT, DIGIT_SELECT + 1 ) ).toInt(); // ambil logika segment sesuai indeks angka byte number = Angka[ angka ]; // jika waktunya ngeblink if ( blink_detik == true ){ // jika digit yg terpilih adalah // digit nomer 2 (digit yg ada titik duanya) // maka tambahkan angkanya dengan 1, // untuk mengubah logika DP menjadi 1
258
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
if(DIGIT_SELECT == 2) number += 1; } // cetak angka di digit shiftOut(DataPin, ClockPin, LSBFIRST, number); } else { // matika digit shiftOut(DataPin, ClockPin, LSBFIRST, OFF); } }else{ // matikan semua digit for(byte d=0; d= lenstr) DIGIT_SELECT = 0; brightness_last = brightness_now; } // stop transfer digitalWrite(LatchPin, HIGH); } // tambahan untuk membuat delay non blocking unsigned long nonblocking_time = millis(); unsigned long nonblocking_last = millis(); boolean nonblocking_delay(long milidetik){ nonblocking_time = millis(); if(nonblocking_time - nonblocking_last >= milidetik){ nonblocking_last = nonblocking_time; return true; } return false; }
Cara kerja program di atas yaitu : 259
1. Mengambil informasi jam dan menit di RTC (lihat baris 116), lalu mengonversinya menjadi String. Contoh, misal jam 3 sore lewat 2 menit, maka hasil konversi ke stringnya adalah “1502”. Proses ini dilakukan oleh fungsi JamMenit pada baris 128. 2. Untuk menampilkan titik dua yang berkedip yaitu dengan memanfaatkan perubahan logika blink_detik yang setiap detik statusnya bergantian dari true ke false (lihat baris 114). 3. Pada seven segment 4 digit, titik 2 (DP) ada di digit nomer 2 dari kiri atau indeks nomer 2 dari kanan. 4. Ketika kondisi blink_detik = true (lihat baris 165), maka harus dicek, posisi scan digit saat ini ada di digit yang mana. 5. Jika posisi digit ada di nomer 2 (lihat baris 170), maka hidupkan segment DP. 6. Kalau diperhatikan bit-bit segment pada baris 20 – 30, bit DP ada di bit yang paling kanan. Logika bitnya semuanya 0. Berdasarkan konsep konversi bilangan dari desimal ke biner, bit yang paling kanan adalah LSB, nilainya adalah 1. Oleh sebab itu untuk mengaktifkan logika DP, angka yang akan dikirim ke shift register harus ditambahkan dengan 1 (lihat baris 170). 7. Untuk melihat nilai angka pada masing-masing bit, Anda bisa tengok kembali Gambar 11.5. 260
16.4 Menampilkan Waktu di LCD 16.4.1 Rangkan Menampilkan Waktu di LCD Peralatan dan rangkaian yang harus disiapkan adalah: 1. Arduino x 1 2. TinyRTC DS1307 x 1 3. LCD1602 dengan Modul I2C x 1 4. Project board x 1 5. Kabel jumper secukupnya Sambungan pin Arduino, TinyRTC, dan LCD 1602 : Arduino
TinyRTC
LCD1602
Pin A4 Pin A5 VCC GND
SDA SCL VCC GND
SDA SCL VCC GND
Gambar 16.4 Rangkaian untuk menampilkan waktu di LCD
261
Perhatikan rangkan kaki SDA dan SCL pada modul I2C LCD dan modul RTC. Kedua modul tersebut dihubungkan secara paralel. Rangkaian paralel ini telah kita bahas pada Gambar 13.4.
16.4.2 Program Menampilkan Waktu di LCD Program 16.3 Program Menampilkan Waktu di LCD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
/* * MONSTER ARDUINO V2 * Program Menampilkan Waktu di LCD * www.ElangSakti.com */ // include library Wire dan RTCLib #include #include // library LCD dengan modul I2C #include #define BACKLIGHT_ON HIGH #define BACKLIGHT_OFF !BACKLIGHT_ON // jumlah kolom dan baris LCD (16x2) #define LCD_COL 16 #define LCD_ROW 2 #define ALIGN_LEFT 1 // teks rata kiri #define ALIGN_CENTER 2 // teks center #define ALIGN_RIGHT 3 // teks rata kanan #define CLEAR true // clear screen // ===== Konfigurasi LCD =========== // LCD1602 dengan Modul I2C // Alamat I2C di 0x27 // lcd_Addr, EN, RW, RS, D4, D5, D6, D7, PIN_BACKLIGHT, Pol LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
262
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
// pilihat format penulisan teks byte tipe_format[] = {ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT}; byte format = ALIGN_LEFT; // instance objek RTC RTC_DS1307 RTC; // jam dalam format teks String teks_jam = ""; void setup() { // buka koneksi ke serial monitor Serial.begin(19200); while(!Serial); // buka koneksi ke RTC Wire.begin(); RTC.begin(); delay(1000); // jika RTC belum disetting & running if (! RTC.isrunning()) { // set waktu RTC sesuai waktu di komputer RTC.adjust(DateTime(__DATE__, __TIME__)); Serial.println("RTC is NOT Running"); } else { // RTC normal Serial.println("RTC OK!"); } // Settingan LCD lcd.begin(LCD_COL,LCD_ROW); // Nyalakan Backlight lcd.setBacklight(BACKLIGHT_ON); } void loop() { // tampilkan data setiap detik if( nonblocking_delay(1000) ){ // Clear sebelum menampilkan tanggal di baris 1
263
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
// rata tengah SetDisplay(Tanggal(), 0, ALIGN_CENTER, CLEAR); // tanpa clear, langsung cetak jam di baris 2 SetDisplay(Jam(), 1, ALIGN_CENTER, !CLEAR); } } // fung Jam, mengonversi jam ke string String Jam(){ DateTime now = RTC.now(); teks_jam = ""; if( now.hour() < 10 ) teks_jam.concat(0); teks_jam.concat(now.hour()); teks_jam.concat(":"); if( now.minute() < 10 ) teks_jam.concat(0); teks_jam.concat(now.minute()); teks_jam.concat(":"); if( now.second() < 10 ) teks_jam.concat(0); teks_jam.concat(now.second()); return teks_jam; } // fungsi tanggal // mengonversi tanggal ke String String Tanggal(){ DateTime now = RTC.now(); String teks_tanggal = ""; if( now.day() < 10 ) teks_tanggal.concat(0); teks_tanggal.concat(now.day()); teks_tanggal.concat("/"); if( now.month() < 10 ) teks_tanggal.concat(0); teks_tanggal.concat(now.month()); teks_tanggal.concat("/"); if( now.year() < 10 ) teks_tanggal.concat(0); teks_tanggal.concat(now.year()); return teks_tanggal; } // fungsi untuk menampilkan teks pada lcd sesuai format void SetDisplay(String data, byte baris, byte format, boolean hapus){ if(hapus) lcd.clear(); int cols = data.length(); if( cols > LCD_COL) format = ALIGN_LEFT; if(format == ALIGN_CENTER){
264
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
if(cols%2 == 1) cols++; cols = (LCD_COL/2) - (cols/2); }else if(format == ALIGN_RIGHT){ cols = LCD_COL - cols; }else{ cols = 0; } lcd.setCursor(cols,baris); lcd.print(data); } // tambahan untuk membuat delay non blocking unsigned long nonblocking_time = millis(); unsigned long nonblocking_last = millis(); boolean nonblocking_delay(long milidetik){ nonblocking_time = millis(); if(nonblocking_time - nonblocking_last >= milidetik){ nonblocking_last = nonblocking_time; return true; } return false; }
Program
ini
cukup
simpel
karena
hanya
mengombinasikan antara dasar-dasar untuk mengambil data tanggal dan jam serta dasar-dasar membuat format teks di tampilan LCD. Jika Anda bingung, boleh cek di babbab sebelumnya. Atau, silakan tanya di group sesuai materi yang dibahas.
16.5 Menampilkan Nama Hari dan Bulan Program ini akan menampilkan nama hari dan nama bulan di LCD. Rangkaian untuk program ini sama dengan rangkaian untuk menampilkan waktu di LCD. 265
16.5.1 Program Menampilkan Nama Hari dan Bulan Program 16.4 Program Menampilkan Nama Hari dan Bulan 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
/* * MONSTER ARDUINO V2 * Program Menampilkan Nama Hari dan Bulan * www.ElangSakti.com */ // include library Wire dan RTCLib #include #include // library LCD dengan modul I2C #include #define BACKLIGHT_ON HIGH #define BACKLIGHT_OFF !BACKLIGHT_ON // jumlah kolom dan baris LCD (16x2) #define LCD_COL 16 #define LCD_ROW 2 #define ALIGN_LEFT 1 // teks rata kiri #define ALIGN_CENTER 2 // teks center #define ALIGN_RIGHT 3 // teks rata kanan #define CLEAR true // clear screen // ===== Konfigurasi LCD =========== // LCD1602 dengan Modul I2C // Alamat I2C di 0x27 // lcd_Addr, EN, RW, RS, D4, D5, D6, D7, PIN_BACKLIGHT, Pol LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // pilihat format penulisan teks byte tipe_format[] = {ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT}; byte format = ALIGN_LEFT; // membuat instance class RTC RTC_DS1307 RTC; // nama-nama hari
266
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
const String NAMA_HARI[] = { "Min", "Sen", "Sel", "Rab", "Kam", "Jum", "Sab" }; // nama-nama bulan // indeks 0 kita anggap tidak ada // sebab bulan dimulai dari 1, bukan 0 const String NAMA_BULAN[] = { "", "Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Agu", "Sep", "Okt", "Nop", "Des" }; // variabel waktu DateTime WAKTU; // detik byte DETIK = 0; String teks_jam = "";
void setup() { // buka koneksi ke serial monitor Serial.begin(19200); while(!Serial); // buka koneksi ke RTC
267
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
Wire.begin(); RTC.begin(); delay(1000); // jika RTC belum disetting & running if (! RTC.isrunning()) { // set waktu RTC sesuai waktu di komputer RTC.adjust(DateTime(__DATE__, __TIME__)); Serial.println("RTC is NOT Running"); } else { // RTC normal Serial.println("RTC OK!"); } // Settingan LCD lcd.begin(LCD_COL,LCD_ROW); // Nyalakan Backlight lcd.setBacklight(BACKLIGHT_ON); } void loop() { // catat waktu WAKTU = RTC.now(); // jika detik berubah if( WAKTU.second() != DETIK ){ // tampilkan tanggal berdsarkan waktu saat ini SetDisplay(Tanggal(WAKTU), 0, ALIGN_CENTER, !CLEAR); // tampilkan jam berdasarkan waktu saat ini SetDisplay(Jam(WAKTU), 1, ALIGN_CENTER, !CLEAR); // catat detik terakhir DETIK = WAKTU.second(); } } // fung Jam, mengonversi jam ke string String Jam(DateTime waktu){ teks_jam = ""; if( waktu.hour() < 10 ) teks_jam.concat(0); teks_jam.concat(waktu.hour()); teks_jam.concat(":"); if( waktu.minute() < 10 ) teks_jam.concat(0);
268
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
teks_jam.concat(waktu.minute()); teks_jam.concat(":"); if( waktu.second() < 10 ) teks_jam.concat(0); teks_jam.concat(waktu.second()); return teks_jam; } // fungsi tanggal // mengonversi tanggal ke String // termasuk nama hari dan bulan String Tanggal(DateTime waktu){ String teks_tanggal = ""; teks_tanggal.concat( NAMA_HARI[waktu.dayOfTheWeek()] ); teks_tanggal.concat(", "); if( waktu.day() < 10 ) teks_tanggal.concat(0); teks_tanggal.concat(waktu.day()); teks_tanggal.concat(" "); teks_tanggal.concat( NAMA_BULAN[waktu.month()] ); teks_tanggal.concat(" "); if( waktu.year() < 10 ) teks_tanggal.concat(0); teks_tanggal.concat(waktu.year()); return teks_tanggal; } // fungsi untuk menampilkan teks pada lcd sesuai format void SetDisplay(String data, byte baris, byte format, boolean hapus){ if(hapus) lcd.clear(); int cols = data.length(); if( cols > LCD_COL) format = ALIGN_LEFT; if(format == ALIGN_CENTER){ if(cols%2 == 1) cols++; cols = (LCD_COL/2) - (cols/2); }else if(format == ALIGN_RIGHT){ cols = LCD_COL - cols; }else{ cols = 0; } lcd.setCursor(cols,baris); lcd.print(data); } // tambahan untuk membuat delay non blocking unsigned long nonblocking_time = millis();
269
171 172 173 174 175 176 177 178 179
unsigned long nonblocking_last = millis(); boolean nonblocking_delay(long milidetik){ nonblocking_time = millis(); if(nonblocking_time - nonblocking_last >= milidetik){ nonblocking_last = nonblocking_time; return true; } return false; }
Cara kerja program ini yaitu: 1. Buat daftar nama hari dan bulan. Karena jumlah karakter lcd hanya 16, maka penamaannya dibatasi 3 huruf saja (lihat baris 41 – 68). Untuk menampilkan nama hari dan bulan secara lengkap dalam satu baris, maka teks tanggal harus bergerak. Untuk teks bergerak akan dicontohkan di program selanjutnya. 2. Teknik mengubah tampilan pada berbeda
dengan
program
program ini
sebelumnya.
Pada
program sebelumnya, tampilan LCD akan diubah setiap 1 detik. Sedangkan pada program ini, tampilan akan diubah setiap angka detik berubah (lihat baris 111). Beda logikanya kan ya? Perubahan teknik ini mungkin tidak akan berefek secara signifikan pada sistem. Tapi, perubahan teknik ini akan berpengaruh pada variasi logika berpikir kita sebagai programmer. Tujuannya satu, tapi bisa dilakukan dengan cara yang berbeda.
270
3. Untuk menampilkan nama hari dan nama bulan dilakukan saat mengon versi tanggal ke string, yaitu pada baris 140 dan 145.
16.6 Menampilkan Tanggal Bergerak Sebelumnya
kita
telah
membuat
program
untuk
menampilkan nama hari dan nama bulan di LCD, akan tetapi namanya harus kita singkat karena jumlah karakter di LCD tidak mencukupi. Salah satu solusinya adalah membuat teks tanggal bergerak ke kiri atau ke kanan. Dengan demikian informasi nama hari dan bulan dapat ditulis secara lengkap. Rangkaian untuk program ini sama dengan rangkaian untuk program sebelumnya.
16.6.1 Program Menampilkan Tanggal Bergerak Program 16.5 Program Menampilkan Tanggal Bergerak 1 2 3 4 5 6 7 8 9 10 11 12
/* * MONSTER ARDUINO V2 * Program Menampilkan Tanggal Bergerak * www.ElangSakti.com */ // include library Wire dan RTCLib #include #include // library LCD dengan modul I2C #include
271
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
#define BACKLIGHT_ON HIGH #define BACKLIGHT_OFF !BACKLIGHT_ON // jumlah kolom dan baris LCD (16x2) #define LCD_COL 16 #define LCD_ROW 2 #define ALIGN_LEFT 1 // teks rata kiri #define ALIGN_CENTER 2 // teks center #define ALIGN_RIGHT 3 // teks rata kanan #define CLEAR true // clear screen #define MOVE_NONE 0 // tidak bergerak #define MOVE_UP 1 // bergerak ke atas #define MOVE_DOWN 2 // bergrak ke bawah #define MOVE_LEFT 3 // bergerak ke kiri #define MOVE_RIGHT 4 // bergerak ke kanan // ===== Konfigurasi LCD =========== // LCD1602 dengan Modul I2C // Alamat I2C di 0x27 // lcd_Addr, EN, RW, RS, D4, D5, D6, D7, PIN_BACKLIGHT, Pol LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // pilihat format penulisan teks byte tipe_format[] = {ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT}; byte format = ALIGN_LEFT; // pilihat format penulisan teks byte pilihan_move[] = {MOVE_UP, MOVE_DOWN, MOVE_LEFT, MOVE_RIGHT}; byte moving = MOVE_NONE; boolean moving_state = true; unsigned long moving_timer = 0; // temporary untuk move_up dan move_down String tmp_teks = ""; // temporary untuk move_left dan move_right int posisi_kolom = 0;
272
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
// instance RTC RTC_DS1307 RTC; // nama hari lengkap const String NAMA_HARI[] = { "Minggu", "Senin", "Selasa", "Rabu", "Kamis", "Jumat", "Sabtu" }; // nama bulan lengkap const String NAMA_BULAN[] = { "", "Januari", "Februari", "Maret", "April", "Mei", "Juni", "Juli", "Agustus", "September", "Oktober", "Nopember", "Desember" }; // pencatat waktu DateTime WAKTU; byte DETIK = 0; // teks jam String teks_jam = ""; void setup() { // buka koneksi ke serial monitor Serial.begin(19200); while(!Serial);
273
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
// buka koneksi ke RTC Wire.begin(); RTC.begin(); delay(1000); // jika RTC belum disetting & running if (! RTC.isrunning()) { // set waktu RTC sesuai waktu di komputer RTC.adjust(DateTime(__DATE__, __TIME__)); Serial.println("RTC is NOT Running"); } else { // RTC normal Serial.println("RTC OK!"); } // Settingan LCD lcd.begin(LCD_COL,LCD_ROW); // Nyalakan Backlight lcd.setBacklight(BACKLIGHT_ON); } void loop() { // catat waktu WAKTU = RTC.now(); // baris pertama teks tanggal bergerak ke kiri MoveText(Tanggal(WAKTU), 0, MOVE_LEFT, 250); if( WAKTU.second() != DETIK ){ // baris kedua jam SetDisplay(Jam(WAKTU), 1, ALIGN_CENTER, !CLEAR); // catat detik terakhir DETIK = WAKTU.second(); } } // fung Jam, mengonversi jam ke string String Jam(DateTime waktu){ teks_jam = ""; if( waktu.hour() < 10 ) teks_jam.concat(0); teks_jam.concat(waktu.hour()); teks_jam.concat(":");
274
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
if( waktu.minute() < 10 ) teks_jam.concat(0); teks_jam.concat(waktu.minute()); teks_jam.concat(":"); if( waktu.second() < 10 ) teks_jam.concat(0); teks_jam.concat(waktu.second()); return teks_jam; } // fungsi tanggal // mengonversi tanggal ke String // termasuk nama hari dan bulan String Tanggal(DateTime waktu){ String teks_tanggal = ""; teks_tanggal.concat( NAMA_HARI[waktu.dayOfTheWeek()] ); teks_tanggal.concat(", "); if( waktu.day() < 10 ) teks_tanggal.concat(0); teks_tanggal.concat(waktu.day()); teks_tanggal.concat(" "); teks_tanggal.concat( NAMA_BULAN[waktu.month()] ); teks_tanggal.concat(" "); if( waktu.year() < 10 ) teks_tanggal.concat(0); teks_tanggal.concat(waktu.year()); return teks_tanggal; } // fungsi untuk menampilkan teks pada lcd sesuai format void SetDisplay(String data, byte baris, byte format, boolean hapus){ if(hapus) lcd.clear(); int cols = data.length(); if( cols > LCD_COL) format = ALIGN_LEFT; if(format == ALIGN_CENTER){ if(cols%2 == 1) cols++; cols = (LCD_COL/2) - (cols/2); }else if(format == ALIGN_RIGHT){ cols = LCD_COL - cols; }else{ cols = 0; } lcd.setCursor(cols,baris); lcd.print(data); } void MoveText(String data, byte baris, byte pilih_moving, unsigned long
275
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
moving_delay){ if( millis() - moving_timer < moving_delay ) return; int cols = 0; int real_cols = 0; switch(pilih_moving){ case MOVE_UP: SetDisplay(tmp_teks, 0, ALIGN_LEFT, CLEAR); SetDisplay(data, 1, ALIGN_LEFT, !CLEAR); tmp_teks = data; break; case MOVE_DOWN: SetDisplay(tmp_teks, 1, ALIGN_LEFT, CLEAR); SetDisplay(data, 0, ALIGN_LEFT, !CLEAR); tmp_teks = data; break; case MOVE_LEFT: lcd.setCursor(0,baris); for(byte i=0; i
276
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
} else { if( i == posisi_kolom ){ lcd.print(data); i += cols-1; } else { lcd.print(' '); } } } posisi_kolom--; if( (real_cols + posisi_kolom) == 0) posisi_kolom = LCD_COL-1; break; case MOVE_RIGHT: lcd.setCursor(0,baris); for(byte i=0; i
277
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
posisi_kolom++; if( posisi_kolom > LCD_COL ) posisi_kolom = -real_cols+1; break; } moving_timer = millis(); } // tambahan untuk membuat delay non blocking unsigned long nonblocking_time = millis(); unsigned long nonblocking_last = millis(); boolean nonblocking_delay(long milidetik){ nonblocking_time = millis(); if(nonblocking_time - nonblocking_last >= milidetik){ nonblocking_last = nonblocking_time; return true; } return false; }
Program ini merupakan kombinasi dari programprogram sebelumnya. Oleh sebab itu, kita tidak akan menjelaskan satu persatu. Akan tetapi, inti dari program ini ada di baris 127. Setelah mengkonversi tanggal menjadi string, langsung diberi efek bergerak ke kiri dengan fungsi MoveText(). Selanjutnya,
mari
kita
membuat project
sederhana dengan timer RTC. Kita buat timer pagi sore untuk mengontrol nyala lampu.
16.7 Project Timer Pagi Sore Project ini bertujuan untuk membuat timer pagi sore. Timer akan digunakan untuk menghidupkan lampu saat 278
sore, dan mematikan lampu ketika sudah pagi. Untuk mengontrol lampu, kita butuh relay sebagai pengendali listrik AC dari PLN. Cara kerja alat ini adalah : 1. Lampu akan menyala mulai jam 5 sore 2. Lampu akan mati ketika sudah jam 5 pagi 3. Jika ada kegagalan sistem seperti arduino error atau ada yang rusak, listrik akan otomatis menyala. 4. Muncul informasi tanggal dan jam di LCD 5. Muncul kondisi relay saat ON atau OFF di LCD 6. Saat dinyalakan, muncul nama pembuat program 7. Proses konfigurasi dimunculkan saat sistem startup Yang menjadi catatan penting adalah requirement nomer 3. Untuk mendapatkan respon sistem yang seperti itu, maka kita harus menyambung kabel lampu di posisi NC (Normally Close). Jika Anda belum memahami karakteristik ini, mungkin akan bingung. Sebab, status relay dan status lampu akan berkebalikan. Jika RELAY OFF, maka LAMPU ON Jika RELAY ON, maka LAMPU OFF
Boleh Anda ingat-ingat, jika kepala Anda mulai pusing. Berarti otak Anda mulai bertumbuh dan koneksi sel-sel sarafnya sedang membentuk struktur logika dan keilmuan baru. Percayalah. 279
16.7.1 Rangkaian Timer Pagi Sore Peralatan dan rangkaian yang perlu kita siapkan yaitu: 1. Arduino x 1 2. TinyRTC DS1307 x 1 3. LCD1602 dengan modul I2C x 1 4. Modul relay 2 channel atau 1 channel x 1 5. Project board 6. Kabel jumper secukupnya Sambungan pin Arduino, TinyRTC, LCD, dan relay : Arduino
TinyRTC
LCD1602
Modul Relay
Pin A0 Pin A4 Pin A5 VCC GND
SDA SCL VCC GND
SDA SCL VCC GND
Input1 VCC GND
Gambar 16.5 Rangkaian timer pagi sore
280
16.7.2 Program Timer Pagi Sore Program 16.6 Program Timer Pagi Sore 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
/* * MONSTER ARDUINO V2 * Program Timer Pagi Sore * www.ElangSakti.com */ // include library Wire dan RTCLib #include #include // input RELAY di pin 2 const byte PIN_RELAY = 2; // logika untuk relay #define RELAY_ON HIGH #define RELAY_OFF !RELAY_ON // library LCD dengan modul I2C #include // backlight lcd #define BACKLIGHT_ON HIGH #define BACKLIGHT_OFF !BACKLIGHT_ON // jumlah kolom dan baris LCD (16x2) #define LCD_COL 16 #define LCD_ROW 2 #define ALIGN_LEFT 1 // teks rata kiri #define ALIGN_CENTER 2 // teks center #define ALIGN_RIGHT 3 // teks rata kanan #define CLEAR true // clear screen // ===== Konfigurasi LCD =========== // LCD1602 dengan Modul I2C // Alamat I2C di 0x27 // lcd_Addr, EN, RW, RS, D4, D5, D6, D7, PIN_BACKLIGHT, Pol LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
281
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
// pilihat format penulisan teks byte tipe_format[] = {ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT}; byte format = ALIGN_LEFT; // instance RTC RTC_DS1307 RTC; // Teks jam dan teks informasi relay di lcd String teks_jam = ""; String teks_relay = ""; // status relay boolean status_relay = RELAY_OFF; boolean status_relay_last = status_relay; // jam sore lampu nyala const int SORE = 1700; // jam 17:00 // jam pagi lampu mati const int PAGI = 500; // jam 5:00 // hasil konversi jam ke angka jam:menit int angka_jam = 0; // pencatat waktu DateTime WAKTU; byte DETIK = 0; // teks bergerak #define MOVE_NONE 0 // tidak bergerak #define MOVE_UP 1 // bergerak ke atas #define MOVE_DOWN 2 // bergrak ke bawah #define MOVE_LEFT 3 // bergerak ke kiri #define MOVE_RIGHT 4 // bergerak ke kanan // pilihat format penulisan teks byte pilihan_move[] = {MOVE_UP, MOVE_DOWN, MOVE_LEFT, MOVE_RIGHT}; byte moving = MOVE_NONE; boolean moving_state = true; unsigned long moving_timer = 0; // temporary untuk move_up dan move_down
282
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
String tmp_teks = ""; // temporary untuk move_left dan move_right int posisi_kolom = 0; void setup() { // buka koneksi ke serial monitor Serial.begin(19200); while(!Serial); // buka koneksi ke RTC Wire.begin(); RTC.begin(); delay(1000); // jika RTC belum disetting & running if (! RTC.isrunning()) { // set waktu RTC sesuai waktu di komputer RTC.adjust(DateTime(__DATE__, __TIME__)); Serial.println("RTC is NOT Running"); } else { // RTC normal Serial.println("RTC OK!"); } // Settingan LCD lcd.begin(LCD_COL,LCD_ROW); // Nyalakan Backlight lcd.setBacklight(BACKLIGHT_ON); // tampilkan info startup di display // serta status sistem ketika mengkonfigurasi StartUp(); } void loop() { // catat waktu WAKTU = RTC.now(); if( WAKTU.second() != DETIK ){ // informasi tanggal di baris 1 rata tengah
283
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
SetDisplay(Tanggal(WAKTU), 0, ALIGN_CENTER, !CLEAR); // informasi jam di baris 2 rata kiri SetDisplay(Jam(WAKTU), 1, ALIGN_LEFT, !CLEAR); DETIK = WAKTU.second(); } // aksi untuk perubahan relay berdasarkan waktu RelayAction(WAKTU); } // fung Jam, mengonversi jam ke string String Jam(DateTime waktu){ teks_jam = ""; if( waktu.hour() < 10 ) teks_jam.concat(0); teks_jam.concat(waktu.hour()); teks_jam.concat(":"); if( waktu.minute() < 10 ) teks_jam.concat(0); teks_jam.concat(waktu.minute()); teks_jam.concat(":"); if( waktu.second() < 10 ) teks_jam.concat(0); teks_jam.concat(waktu.second()); return teks_jam; } // fungsi tanggal // mengonversi tanggal ke String String Tanggal(DateTime waktu){ String teks_tanggal = ""; if( waktu.day() < 10 ) teks_tanggal.concat(0); teks_tanggal.concat(waktu.day()); teks_tanggal.concat("/"); if( waktu.month() < 10 ) teks_tanggal.concat(0); teks_tanggal.concat(waktu.month()); teks_tanggal.concat("/"); if( waktu.year() < 10 ) teks_tanggal.concat(0); teks_tanggal.concat(waktu.year()); return teks_tanggal; } // fungsi get_angka // untuk mengkonversi jam dan menit menjadi sebuah angka // contoh jam 3:06 sore akan dikonversi menjadi angka 1506 // 15 mewakili jam 15, 06 untuk menit int get_angka(DateTime waktu){ // konversi jam dalam ratusan, menit dalam puluhan dan satuan
284
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
return (waktu.hour() * 100) + waktu.minute(); } // aksi untuk relay // sekaligus menampilkan informasi relay di LCD void RelayAction(DateTime waktu){ // L = Lampu teks_relay = " L:"; angka_jam = get_angka(waktu); // relay disetting normally close // relay ON => lampu mati // relay OFF => lampu nyala // ----// PAGI - SORE => relay ON // SORE - PAGI => relay OFF if(angka_jam >= PAGI && angka_jam <= SORE){ digitalWrite(PIN_RELAY, RELAY_ON); teks_relay.concat("OFF"); // RELAY ON, LAMPU OFF } else { digitalWrite(PIN_RELAY, RELAY_OFF); teks_relay.concat("ON"); // RELAY OFF, LAMPU ON } // tampilkan informasi relay di baris 2 rata kanan SetDisplay(teks_relay, 1, ALIGN_RIGHT, !CLEAR); } // fungsi untuk menampilkan teks pada lcd sesuai format void SetDisplay(String data, byte baris, byte format, boolean hapus){ if(hapus) lcd.clear(); int cols = data.length(); if( cols > LCD_COL) format = ALIGN_LEFT; if(format == ALIGN_CENTER){ if(cols%2 == 1) cols++; cols = (LCD_COL/2) - (cols/2); }else if(format == ALIGN_RIGHT){ cols = LCD_COL - cols; }else{ cols = 0; } lcd.setCursor(cols,baris);
285
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
lcd.print(data); } // fungsi untuk informasi startup // hanya dummy... bisa diganti dengan informasi lainnya void StartUp(){ // konfigurasi.... // tampilkan nama project dan nama pembuatnya SetDisplay(F("NAMA PROJECT"), 0, ALIGN_CENTER, CLEAR); SetDisplay(F("PEMBUAT"), 1, ALIGN_CENTER, !CLEAR); delay(5000); // teks bergerak bergantian... MoveText(F("Starting..."), 1, MOVE_UP, 0); delay(2000); MoveText(F("System Started..."), 1, MOVE_UP, 0); delay(2000); MoveText(F("Configuring..."), 1, MOVE_UP, 0); delay(2000); MoveText(F("Checking System..."), 1, MOVE_UP, 0); delay(2000); MoveText(F("Testing..."), 1, MOVE_UP, 0); delay(3000); MoveText(F("Please wait..."), 1, MOVE_UP, 0); delay(5000); // clear lcd lcd.clear(); } void MoveText(String data, byte baris, byte pilih_moving, unsigned long moving_delay){ if( millis() - moving_timer < moving_delay ) return; int cols = 0; int real_cols = 0; switch(pilih_moving){ case MOVE_UP: SetDisplay(tmp_teks, 0, ALIGN_LEFT, CLEAR); SetDisplay(data, 1, ALIGN_LEFT, !CLEAR); tmp_teks = data;
286
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
break; case MOVE_DOWN: SetDisplay(tmp_teks, 1, ALIGN_LEFT, CLEAR); SetDisplay(data, 0, ALIGN_LEFT, !CLEAR); tmp_teks = data; break; case MOVE_LEFT: lcd.setCursor(0,baris); for(byte i=0; i
287
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
break; case MOVE_RIGHT: lcd.setCursor(0,baris); for(byte i=0; i LCD_COL ) posisi_kolom = -real_cols+1; break; } moving_timer = millis(); }
Penjelasan requirement yang diinginkan dalam program adalah sebagai berikut: 288
1. Inisialisasi jam pagi ada di baris 59. 2. Jam sore ditentukan pada baris 57. 3. Kondisi lampu ON pada kondisi sistem mati, ditentukan
berdasarkan
sambungan
fisik, tidak
hanya berdasarkan program. Boleh Anda cek koneksi lampu di Gambar 16.5 yang dihubungkan ke pin NC. Jika siang (jam 5 pagi hingga jam 5 sore) lampu MATI, maka siang RELAY HARUS ON, pengecekan kondisi ini pada baris 187 – 189. Sedangkan kondisi malam (jam 5 sore hingga jam 5 pagi) lampu HIDUP, maka RELAY HARUS OFF (lihat baris 191 – 192). 4. Untuk menampilkan informasi tanggal dan jam ada di baris 126 dan 128. 5. Informasi ON/OFF lampu ada di dalam fungsi RelayAction(), khususnya pada baris 196. 6. Untuk
menampilkan
informasi
awal,
harus
dimasukkan dalam fungsi void setup(). Dalam hal ini dilakukan dengan mengeksekusi fungsi StartUp() pada baris 116. Fungsi StartUp() sendiri ada pada baris 218. Data-data yang muncul di LCD saat startup adalah data dummy. Hal ini termasuk requirement nomer 7.
289
Ada yang
menarik degan project ini? Mari kita
diskusikan di grup.
290
Bagian #17
KENDALI DENGAN REMOTE INFRARED Manusia tidak memiliki talenta yang sama, tapi kita memiliki kesempatan yang sama untuk mengembangkan talenta kita. (John Fitzgerald Kennedy)
___ Remote infrared yang akan dipakai bukanlah remote bekas
sebagaimana
pernah
kita
posting
di
https://goo.gl/uEc5Ys. Remote yang ini adalah remote yang memang ditujukan untuk edukasi. Remote ini kompatibel dengan library IRremote yang biasa dipakai pengembang.
Gambar 17.1 Modul IR remotedan IR receiver
291
Gambar 17.2 Modul receiver infrared KY-022
Modul infrared terdiri dari 3 pin. Pin yang ditandai dengan S adalah output Signal. Pin yang ditandai dengan ( – ) adalah pin GND. Pin yang tengah adalah VCC +5V. Pastikan masangnya tidak terbalik. Kalau terbalik, mungkin bisa hangus. Untuk memprogram remote, hal yang pertama harus kita lakukan adalah memetakan setiap tombol. Dengan adanya library IRremote, kita bisa langsung memetakan tombol dengan mudah. Mari langsung praktek!
17.1 Mengidentifikasi Tombol Remote 17.1.1 Rangkaian Modul Receiver Infrared Peralatan dan rangkaian yang perlu disiapkan adalah: 1. Arduino x 1 2. Modul receiver infrared (model KY-022) x 1 3. Kabel jumper secukupnya 292
Sambungan pin Arduino dan modul IR receiver adalah : Arduino
IR Receiver
Pin 2 VCC GND
Pin S (signal) VCC GND
Gambar 17.3 Rangkaian Arduino dan IR Receiver
17.1.2 Program Identifikasi Tombol Remote Program 17.1 Program Identifikasi Tombol Remote 1 2 3 4 5 6 7 8 9 10 11 12 13 14
/* * MONSTER ARDUINO V2 * Program Identifikasi Tombol Remote * www.ElangSakti.com */ // include library IRremote #include // pin Signal ke pin 2 const byte PIN_RECV = 2; // konfigurasi class irremote IRrecv irrecv(PIN_RECV);
293
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
// penampung hasil identifikasi remote decode_results results; void setup() { // buka koneksi ke serial monitor Serial.begin(19200); // aktifkan IR penerima irrecv.enableIRIn(); } void loop() { // jika menerima data dan berhasil mendecode data if (irrecv.decode(&results)) { // cetak ke serial monitor dg format Hex Serial.println(results.value, HEX); // hapus history hasil sebelumnya irrecv.resume(); } }
Cara kerja program di atas adalah: 1. Include libraray IRremote 2. Konfiugurasi pin dan variabel penampung data hasil identifikasi (lihat baris 14 dan 16) 3. Aktifkan modul untuk menerima sinyal infrared dengan enableIRIn() di baris 22. 4. Terima sinyal infrared, jika hasil decode berhasil (lihat baris 27), maka cetak hasilnya ke serial monitor. 5. Setelah mendeteksi tombol, reset data tombol (lihat baris 31). Jika tidak direset, maka proses decode akan mendeteksi tombol data lama sebagai data baru dan mencetak tombol yang sama pada serial monitor.
294
Gambar 17.4 Output tombol 0 – 9
Gambar 17.4 adalah output dari penekanan tombol 0 – 9. Data FFFFFFFF berarti data yang diterima sama dengan data sebelumnya karena penekanan tombol terlalu lama. Selengkapnya, hasil dari proses identifikasi tombol ini tampak seperti Tabel 17.1. Tabel 17.1 Kode tombol remote yang teridentifikasi
Tombol
Kode Hex
Tombol
Kode Hex
1 2 3 4 5 6 7 8 9
0xFFA25D 0xFF629D 0xFFE21D 0xFF22DD 0xFF02FD 0xFFC23D 0xFFE01F 0xFFA857 0xFF906F
0 * # Panah Atas Panah Bawah OK Panah Kiri Panah Kanan
0xFF9867 0xFF6897 0xFFB04F 0xFF18E7 0xFF4AB5 0xFF38C7 0xFF10EF 0xFF5AA5
295
Yap, masing-masing tombol sudah diketahui kodenya. Selanjutnya
apa?
Selanjutnya
buat
program
untuk
menangani perintah berdasarkan tombol yang dipilih. Untuk program
selanjutnya,
kita
bisa
saja
membuat
alat
pengontrol lampu (entah pakai LED atau relay), tapi itu terlalu mainstream. Kita coba buat project yang lain. Kita akan membuat remote kontrol karakter di dalam LCD. Anggap saja kita akan membuat game Pacman. Mari kita eksekusi project tersebut…
17.2 Project Remote Kontrol Karakter LCD Project ini bertujuan untuk membuat remote kontrol untuk sebuah karakter yang ada di LCD. Karakter akan bergerak ke atas, bawah, kiri, kanan, atau diam di tempat. Jika tombol kiri ditekan, karakter akan bergerak ke kiri. Jika tombol kanan ditekan, karakter akan bergerak ke kanan. Begitu juga jika tombol ke atas dan ke bawah ditekan. Apabila tombol OK ditekan, maka karakter akan diam. Selain
untuk mengontrol gerakan
karakter, nyala
backlight LCD juga dapat dikontrol dengan sebuah tombol di remote. Jika tombol bintang „*‟ ditekan, maka kondisi backlight LCD akan berubah. Jika backlight menyala, backligh akan mati, dan sebaliknya. 296
Informasi status backlight dan arah gerakan karakter harus tersimpan di sistem. Sehingga ketika sistem diaktifkan, karakter akan sebelumnya
bergerak sesuai
dan backlight akan
arah
yang tersimpan
mengeksekusi status
sebelumnya juga. Siap dengan program ini? Mari langsung merangkai dan membuat programnya!
17.2.1 Rangkaian Remote Kontrol Karakter LCD Peralatan dan rangkaian yang perlu disiapkan adalah: 1. 2. 3. 4. 5. 6.
Arduino x 1 Modul IR Receiver (model KY-022) x 1 Remote IR x 1 LCD 1602 dengan modul I2C LCd x 1 Project board Kabel jumper secukupnya
Sambungan pin Arduino, IR Receiver, dan LCD yaitu : Arduino
IR Receiver
LCD1602 I2C
Pin 2 Pin A4 Pin A5 VCC GND
Pin S (signal) VCC GND
SDA SCL VCC GND
297
Gambar 17.5 Rangkain pengontrol karakter LCD
17.2.2 Program Remote Kontrol Karakter LCD Program 17.2 Program Remote Kontrol Karakter LCD 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/* * MONSTER ARDUINO V2 * Program Remote Kontrol Karakter LCD * www.ElangSakti.com */ // include library IRremote #include #include // pin Signal ke pin 2 const byte PIN_RECV = 2; // konfigurasi class irremote IRrecv irrecv(PIN_RECV); // penampung hasil identifikasi remote decode_results results; // data tombol #define TOMBOL_1 0xFFA25D #define TOMBOL_2 0xFF629D
298
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
#define TOMBOL_3 0xFFE21D #define TOMBOL_4 0xFF22DD #define TOMBOL_5 0xFF02FD #define TOMBOL_6 0xFFC23D #define TOMBOL_7 0xFFE01F #define TOMBOL_8 0xFFA857 #define TOMBOL_9 0xFF906F #define TOMBOL_0 0xFF9867 #define TOMBOL_STAR 0xFF6897 // * #define TOMBOL_HASH 0xFFB04F // # #define TOMBOL_ATAS 0xFF18E7 // panah ke atas #define TOMBOL_BAWAH 0xFF4AB5 // panah ke bawah #define TOMBOL_OK 0xFF38C7 // ok #define TOMBOL_KIRI 0xFF10EF // panah ke kiri #define TOMBOL_KANAN 0xFF5AA5 // panah ke kanan // alamat untuk menyimpan status backlight #define ADDR_BACKLIGHT 0 #define ADDR_ARAH 1 // library LCD dengan modul I2C #include #define BACKLIGHT_ON HIGH #define BACKLIGHT_OFF !BACKLIGHT_ON // jumlah kolom dan baris LCD (16x2) #define LCD_COL 16 #define LCD_ROW 2 // LCD1602 dengan Modul I2C // Alamat I2C di 0x27 // lcd_Addr, EN, RW, RS, D4, D5, D6, D7, PIN_BACKLIGHT, Pol LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // status backlight LCD boolean backlight = BACKLIGHT_ON;
// karakter di LCD byte mangap_arr[] = { B00000, B01110,
299
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
B01011, B11111, B00011, B10011, B01110, B00000 }; byte mingkem_arr[] = { B00000, B01110, B01011, B11111, B11111, B01111, B00000, B00000 }; #define ARAH_DIAM 0 #define ARAH_KIRI 1 #define ARAH_KANAN 2 #define ARAH_ATAS 3 #define ARAH_BAWAH 4 byte arah = ARAH_DIAM; boolean Nganga = false; byte Nganga_counter = 0; const byte Nganga_pindah = 2; int posisi_baris = 0; int posisi_kolom = 0; void setup() { // buka koneksi ke serial monitor Serial.begin(19200); // Settingan LCD lcd.begin(LCD_COL,LCD_ROW); // baca informasi status backlight terakhir backlight = EEPROM.read(ADDR_BACKLIGHT); // jika backlight > 1 reset ke 1
300
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
if( backlight > 1) backlight = 1; // baca informasi arah gerakan arah = EEPROM.read(ADDR_ARAH); // jika arah > 4, maka diam if( arah > ARAH_BAWAH) arah = ARAH_DIAM; // buat karakter baru lcd.createChar(0, mingkem_arr); lcd.createChar(1, mangap_arr); // Nyalakan Backlight lcd.setBacklight(backlight); // aktifkan penerima infrared irrecv.enableIRIn(); } void loop() { // jika menerima data dan berhasil mendecode data if(irrecv.decode(&results)) { // cetak ke serial monitor dg format Hex Serial.println(results.value, HEX); // eksekusi aksi sesuai tombol yang dipilih IRAction(results.value); // hapus history hasil sebelumnya irrecv.resume(); } // gerakkan karakter lcd MoveChar(); } // fungsi aksi penekanan tombol void IRAction(unsigned long tombol){ // ketika anti arah atau ganti mode backlight // simpan data ke EEPROM switch(tombol){ // setting backlight case TOMBOL_STAR:
301
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
// balik logika backlight backlight = !backlight; lcd.setBacklight(backlight); // simpan konfigurasi backlight EEPROM.write(ADDR_BACKLIGHT,backlight); break; case TOMBOL_ATAS: arah = ARAH_ATAS; EEPROM.write(ADDR_ARAH,arah); break; case TOMBOL_BAWAH: arah = ARAH_BAWAH; EEPROM.write(ADDR_ARAH,arah); break; case TOMBOL_OK: arah = ARAH_DIAM; EEPROM.write(ADDR_ARAH,arah); break; case TOMBOL_KIRI: arah = ARAH_KIRI; EEPROM.write(ADDR_ARAH,arah); break; case TOMBOL_KANAN: arah = ARAH_KANAN; EEPROM.write(ADDR_ARAH,arah); break; } } // fungsi untuk menggerakkan karakter di lcd void MoveChar(){ // animasi menanga setiap 150ms if( nonblocking_delay(150) ){ // balik logika kondisi nganga Nganga = !Nganga; // bersihkan lcd, kemudian set posisi kursor
302
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
lcd.clear(); lcd.setCursor(posisi_kolom, posisi_baris); // jika ngaga = true // tampilkan karakter menganga // jika false, tampilkan karakter biasa if( Nganga == true ){ lcd.write(byte(0)); } else { lcd.write(byte(1)); } // setiap jumlah nganga = nganga_pindah // maka mindah posisi karakter if ( Nganga_counter == Nganga_pindah ){ // pindah posisi karakter sesuai // dengan arah yang dipilih tombol remote PilihArah(arah); Nganga_counter = 0; } else { Nganga_counter++; } } } // fungsi untuk memilih arah gerakan void PilihArah(byte arah){ switch(arah){ case ARAH_KANAN: // jika arah kanan, tambah posisi kolom // jika posisi melebihi jumlah kolom, // kembali ke 0 posisi_kolom++; if(posisi_kolom >= LCD_COL){ posisi_kolom = 0; } break; case ARAH_KIRI: // jika arah kiri, kurangi posisi kolom // jika posisi < posisi 0
303
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
// kembali ke kanan (posisi LCD_COL-1) posisi_kolom--; if(posisi_kolom < 0){ posisi_kolom = LCD_COL-1; } break; case ARAH_ATAS: // jika arah atas, kurangi posisi baris // ingat, 0 ada di atas // jika posisi lebih kecil 0, // kembali ke index row (LCD_ROW-1) posisi_baris--; if(posisi_baris < 0){ posisi_baris = LCD_ROW-1; } break; case ARAH_BAWAH: // jika arah bawah, tambah posisi baris // jika posisi melebihi jumlah baris, // kembali ke 0 posisi_baris++; if(posisi_baris >= LCD_ROW){ posisi_baris = 0; } break; } } // tambahan untuk membuat delay non blocking unsigned long nonblocking_time = millis(); unsigned long nonblocking_last = millis(); boolean nonblocking_delay(long milidetik){ nonblocking_time = millis(); if(nonblocking_time - nonblocking_last >= milidetik){ nonblocking_last = nonblocking_time; return true; } return false; }
304
Cara kerja program diatas jika disesuaikan dengan kebutuhan sistem yaitu : 1. Aksi untuk penekanan tombol atas, bawah, kanan, kiri, OK, dan tombol bintang ada di fungsi IRAction, khususnya pada baris 149 – 182. Fungsi IRAction dieksekusi ketika arduino mendeteksi penekanan tombol di baris 134. 2. Penekanan tombol bintang akan mengatur nyala backlight LCD pada baris 153 dan 154, proses penyimpanan data di EEPROM ada pada baris 155. 3. Penekanan tombol juga berpengaruh pada arah gerakan karakter melalui variabel arah dalam fungsi IRAction(), termasuk fungsi pilihArah() pada baris 214. 4. Untuk pemilihan arah kiri atau kanan, maka proses pemindahan
karakter
ditentukan
berdasarkan
variabel posisi_kolom (lihat baris 230 dan 240). Sedangkan untuk pemilihan arah atas atau bawah, maka perpindahan karakter ditentukan berdasarkan posisi_baris (lihat baris 251 dan 261).
305
Bagian #18
PENGENALAN SERVO M impi adalah kunci untuk kita menaklukkan dunia, berlarilah tanpa lelah sampai engkau meraihnya. (Nijdi)
___ Bab ini adalah bab bonus. Pembahasan lebih banyak tentang servo akan diulas pada buku berikutnya. Oleh sebab itu, kita akan membahas servo secukupnya saja. Secara prinsip, semua servo memiliki kaki dan fungsi yang sama. Namun ada dua jenis servo yang umum di pasaran, ada yang putarannya terbatas, ada yang berputar hingga 360o.
Gambar 18.1 Motor servo SG90
Kali ini kita hanya akan membahas motor servo yang dapat diputar 180o, salah satau contohnya adalah motor servo SG90. Ketika Anda bisa menggunakan servo ini, dapat 306
dipastikan Anda akan bisa menggunakan tipe servo sejenis lainnya. Yang penting Anda paham batasan sudut servo yang dipakai. Motor servo terdiri dari tiga buah kabel, kabel VCC (merah), GND (coklat), dan PWM (jingga). Fungsi kabel VCC dan GND sudah jelas sebagai jalur power supply. Sedangkan kabel PWM untuk mengatur arah putaran servo. Untuk memahami cara kerja PWM, silakan download buku Arduino Versi 1 di https://goo.gl/JCEDmh. Mari langsung praktek!
18.1 Motor Servo Dasar Pada praktek ini, servo akan dikendalikan berdasarkan sudut servo. Untuk mempermuda pemrograman, kita menggunakan library Servo.h, library ini sudah ada di aplikasi Arduino IDE. Karakteristik program pertama ini sederhana, Arduino bertugas untuk memutar servo dari sudut 0 – 180o dan sebaliknya.
18.1.1 Rangkain Servo dan Arduino Peralatan dan rangkaian yang perlu disiapkan adalah: 1. Arduino x 1 2. Servo SG90 x 1 3. Kabel jumper secukupnya 307
Sambungan pin Arduino dan Servo adalah : Arduino
Servo SG90
Pin 3 VCC GND
PWM (orange) VCC GND
Gambar 18.2 Rangkaian servo dan Arduino
18.1.2 Program Servo Sederhana Program 18.1 Program Motor Server Sederhana 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/* * MONSTER ARDUINO V2 * Program Motor Servo Sederhana * www.ElangSakti.com */ // include library servo #include // control PWM servo di pin 3 const byte PIN_SERVO = 3; // objeck untuk class servo Servo myservo;
308
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
// sudut servo dan sudut maksimum int posisi = 0; int SERVO_MAX = 180; void setup() { // siapkan servo myservo.attach(PIN_SERVO); } void loop() { // putar servo dari sudut 0 - 180 for(int i=0; i<=SERVO_MAX; i++){ myservo.write(i); delay(10); } delay(2000); // putar balik ke sudut 0 for(int i=SERVO_MAX; i>=0; i--){ myservo.write(i); delay(10); } delay(2000); }
Cara kerja program ini adalah: 1. Pin kontrol servo dihubungkan ke pin 3 Arduino 2. Tentukan sudut minimal / awal dan sudut maksimal (lihat baris 17 dan 18) 3. Setelah servo disiapkan (baris 22), putar servo dari sudut 0 – 180 (baris 27 – 30). Jeda 2 detik, lalu lanjut putar servo dari sudut 180 – 0 (baris 35 - 38).
309
4. Program
ini
simpel,
selanjutkan
kita
akan
mengendalikan servo dengan potensiomenter. Jadi gerakan servo bisa kita ubah dengan cepat.
18.2 Kendali Servo dengan Potensiometer Pada aplikasi ini, jika nilai potensio diputar ke arah maksimal, maka servo akan berpura ke sudut yang lebih tinggi. Begitu juga sebaliknya.
18.2.1 Rangkaian Kendali Servo Peralatan dan rangkain yang perlu kita siapkan adalah : 1. Arduino x 1 2. Servo SG90 x 1 3. Potensiometer x 1 4. Project board x 1 5. Kabel jumper secukupnya Sambungan pin Arduino, Servo SG90, dan Potensiometer adalah :
Arduino
Servo SG90
Potensiometer
Pin 3 Pin A0 VCC GND
PWM (orange) VCC GND
Kaki tengah Kaki kanan Kaki kiri
310
Gambar 18.3 Rangkain kendali servo dengan potensiometer
18.2.2 Program Kendali Servo Program 18.2 Program Kendali Servo dengan Potensiomenter 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/* * MONSTER ARDUINO V2 * Program Kendali Servo dengan Potensiometer * www.ElangSakti.com */ // include library servo #include // pwm servo di pin 3 // output potensi di pin A0 const byte PIN_SERVO = 3; const byte PIN_POTENSIO = A0; // objeck untuk class servo Servo myservo; // sudut servo dan sudut maksimum int posisi = 0; int SERVO_MAX = 180; void setup() { // siapkan servo
311
24 25 26 27 28 29 30 31 32 33 34
myservo.attach(PIN_SERVO); } void loop() { // posisikan servo sesuai data potensio int data = analogRead(PIN_POTENSIO); // normalisasi data potensio sesuai sudut servo posisi = map( data, 0, 1024, 0, 180 ); // kontrol servo myservo.write(posisi); }
Cara
kerja
program
ini
seperti
program
yang
sebelumnya. Yang berbeda adalah, kita bisa mengatur sudut servo
menggunakan
potensiomenter.
Data
dari
potensiometer diambil (lihat baris 29), lalu dinormalisasi sehingga nilainya sesuai dengan range 0 – 180 (lihat baris 31). Setelah data dinormalisasi menyerupai sudut dari 0 – 180, gerakkan servo sesuai data tersebut. Selanjutnya, kita akan mengendalikan servo dengan remote infrared.
18.3 Kendali Servo dengan Remote Aplikasi ini adalah implementasi dari program remote infrared, LCD, dan servo. Gerakan servo akan dikendalikan dengan tombol panah kanan dan panah kiri. Sedangkan jika kita menekan tombol panah ke atas, maka servo langsung bergerak ke sudut 180o, jika tombol panah ke bawah ditekan maka servo akan bergerak ke sudut 0 o .
312
18.3.1 Rangkaian Kendali Servo dan IR Receiver Peralatan dan rangkaian yang perlu kita siapkan adalah: 1. Arduino x 1 2. Servo SG90 x 1 3. LCD1602 dengan Modul I2C x 1 4. Modul receiver infrared x 1 5. Remote infrared x 1 6. Project board dan kabel jumper secukupnya Sambungan pin Arduino, Servo, LCD, dan IR Receiver : Arduino
Servo SG90
LCD1602 I2C
Receiver IR
Pin 2 Pin 3 Pin A4 Pin A5 VCC GND
PWM (orange) VCC GND
SDA SCL VCC GND
Pin S (signal) VCC GND
Gambar 18.4 Rangkaian kendali servo dengan remote IR dan LCD
313
18.3.2 Program Kendali Servo dengan Remote IR Program 18.3 Program Kendali Servo dengan Remote IR 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
/* * MONSTER ARDUINO V2 * Program Kendali Servo dengan Remote IR * www.ElangSakti.com */ // include library IRremote // dan servo #include #include // pin Signal IR receiver ke pin 2 // dan pin pwm servo di pin 3 const byte PIN_RECV = 2; const byte PIN_SERVO = 3; // konfigurasi class irremote IRrecv irrecv(PIN_RECV); // penampung hasil identifikasi remote decode_results results; // data tombol #define TOMBOL_1 0xFFA25D #define TOMBOL_2 0xFF629D #define TOMBOL_3 0xFFE21D #define TOMBOL_4 0xFF22DD #define TOMBOL_5 0xFF02FD #define TOMBOL_6 0xFFC23D #define TOMBOL_7 0xFFE01F #define TOMBOL_8 0xFFA857 #define TOMBOL_9 0xFF906F #define TOMBOL_0 0xFF9867 #define TOMBOL_STAR 0xFF6897 // * #define TOMBOL_HASH 0xFFB04F // # #define TOMBOL_ATAS 0xFF18E7 // panah ke atas #define TOMBOL_BAWAH 0xFF4AB5 // panah ke bawah #define TOMBOL_OK 0xFF38C7 // ok #define TOMBOL_KIRI 0xFF10EF // panah ke kiri #define TOMBOL_KANAN 0xFF5AA5 // panah ke kanan #define TOMBOL_REPEAT 0xFFFFFFFF // sama seperti sebelumnya
314
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
unsigned long tombol = TOMBOL_REPEAT; // instance class servo Servo myservo; int posisi = 0; int SERVO_MAX = 180; int posisi_last = -1; // library LCD dengan modul I2C #include #define BACKLIGHT_ON HIGH #define BACKLIGHT_OFF !BACKLIGHT_ON // jumlah kolom dan baris LCD (16x2) #define LCD_COL 16 #define LCD_ROW 2 #define ALIGN_LEFT 1 // teks rata kiri #define ALIGN_CENTER 2 // teks center #define ALIGN_RIGHT 3 // teks rata kanan #define CLEAR true // clear screen // ===== Konfigurasi LCD =========== // LCD1602 dengan Modul I2C // Alamat I2C di 0x27 // lcd_Addr, EN, RW, RS, D4, D5, D6, D7, PIN_BACKLIGHT, Pol LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // pilihat format penulisan teks byte tipe_format[] = {ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT}; byte format = ALIGN_LEFT; String teks_servo = ""; void setup() { Serial.begin(19200); // Settingan LCD
315
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
lcd.begin(LCD_COL,LCD_ROW); // Nyalakan Backlight lcd.setBacklight(BACKLIGHT_ON); // aktfikan servo myservo.attach(PIN_SERVO); // aktifkan penerima infrared irrecv.enableIRIn(); } void loop() { // jika menerima data dan berhasil mendecode data if(irrecv.decode(&results)) { // cetak ke serial monitor dg format Hex Serial.println(results.value, HEX); // eksekusi aksi sesuai tombol yang dipilih // jika tombol terdeteksi adalah 0xFFFFFFFF // berarti tombol yang ditekan sama dengan // tombol sebelumnya if( results.value != TOMBOL_REPEAT ){ tombol = results.value; } IRAction(tombol); // hapus history hasil sebelumnya irrecv.resume(); } // jika posisi berubah if( posisi_last != posisi ){ // putar servo sesuai sudut masing-masing myservo.write(posisi); // teks sudut servo dan simbol derajat teks_servo = "SUDUT:"; teks_servo.concat(posisi); teks_servo.concat((char)223); // jika lebar teks berubah, clear lcd sebelum cetak
316
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
if( String(posisi).length() != String(posisi_last).length() ){ SetDisplay( teks_servo, 0, ALIGN_LEFT, CLEAR); } else { SetDisplay( teks_servo, 0, ALIGN_LEFT, !CLEAR); } posisi_last = posisi; } } // fungsi aksi penekanan tombol void IRAction(unsigned long tombol){ // simpan data ke EEPROM switch(tombol){ case TOMBOL_ATAS: posisi = 180; break; case TOMBOL_BAWAH: posisi = 0; break; case TOMBOL_KIRI: if(posisi > 1) posisi--; break; case TOMBOL_KANAN: if(posisi < 180) posisi++; break; } } // fungsi untuk menampilkan teks pada lcd sesuai format void SetDisplay(String data, byte baris, byte format, boolean hapus){ if(hapus) lcd.clear(); int cols = data.length(); if( cols > LCD_COL) format = ALIGN_LEFT; if(format == ALIGN_CENTER){ if(cols%2 == 1) cols++; cols = (LCD_COL/2) - (cols/2); }else if(format == ALIGN_RIGHT){ cols = LCD_COL - cols;
317
171 172 173 174 175 176
}else{ cols = 0; } lcd.setCursor(cols,baris); lcd.print(data); }
Cara kerja program ini adalah : 1. Aksi tombol ketika dipencet panah ke kanan, kiri, atas, dan bawah ada di baris 141 – 157. Sedangkan proses identifikasi tombol ada di baris 99 – 109. 2. Jika tombol ditahan lama, maka kode tombol akan menjadi 0xFFFFFFFF, oleh sebab itu ada penyesuaian proses identifikasi tombol di baris 109 dan 108. Setiap ada tombol yang valid dan bukan 0xFFFFFFFF, maka
informasi
tombol tersebut dicatat
pada
variabel tombol. Apabila tombol yang teridentifikasi adalah 0xFFFFFFFF, maka tombol yang telah dicatan sebelumnya yang akan dikirim ke aksi tombol. 3. Untuk gerakan servo, jika terjadi perubahan sudut maka tampilan sudut di LCD diubah dan servo juga digerakkan sesuai sudut tersebut (lihat 120 – 131). Cukup demikian dengan penjelasan dan contoh motor servo. Teknik dan contoh yang lain akan dimuat dalam buku seri selanjutnya.
318
MONSTER ARDUINO 3 Semua ide Anda tentang usulan konten yang perlu dibahas pada ebook MONSTER ARDUINO 3 boleh dikirim ke [email protected], semua usulan kita tampung dan direalisasikan sesuai kondisi. Sekali lagi, kami ucapkan terima kasih pada member MONSTER ARDUINO karena telah meramaikan grup. Terima kasih juga karena telah tetap menjaga sopan santun dalam berdiskusi sesuai isi postingan.
319
Tentang Penulis Hari Santoso, Owner ElangSakti.com dan Penggagas ebook MONSTER ARDUINO. Ebook berseri tentang Arduino untuk pemula
dari
tingkat
dasar
hingga
menengah. Penulis adalah lulusan Teknik Informatika yang secara mandiri belajar mikrokontroller dan Arduino. Minat utama penulis dalam keilmuan komputer yaitu semua hal
yang
terkait
Programming,
Artificial
Network Security, dan Internet of Things (IoT).
320
Intelligence,