Animasi LED mikrokontroler ATMega32 dengan Assembly dan C

Sabtu, Mei 22, 2010

Artikel ini sengaja saya tulis sebagai awal pembelajaran bagaimana membuat sebuah program aplikasi mikrokontroler AVR (khususnya ATMega32 dengan frekuensi kristal 7,3728MHz) untuk membuat animasi LED berjalan dari pin 0 hingga 7.

Rangkaian yang digunakan ditunjukkan pada Gambar 1, sengaja LED disusun secara CA atau common Anoda, sehingga untuk menyalakan LED harus dikirimkan logika ‘0′.

Untuk kompilasi digunakan AVR Studio versi 4.0 (silahkan unduh GRATIS dari http://www.atmel.com). Program kita awali dengan beberapa macam deklarasi, keterangan sengaja saya masukkan dalam listing program untuk memudahkan pembelajaran langsung dari listingnya, perhatikan instruksi yang diawali dengan ‘.’ merupakan directive dari AVR Studio, bukan instruksi assembly mikrokontroler AVR:

;------------------------------------------

;animasi LED berjalan dalam bahasa Assembly
;untuk mikrokontroler Atmel AVR ATMega32
;frekuensi kristal 7.3728MHz
;------------------------------------------
.nolist ;bagian ini
.include "m32def.inc" ;tidak perlu ditampilkan dalam
.list ;berkas list

Ingat berkas “m32def.inc” kita sertakan (directive .include) karena akan digunakan pustaka ATMega32 dalam program kita, tetapi tidak perlu disertakan dalam hasil berkas LIST-nya (hasil kompilasi program) menggunakan directive .nolist dan .list.

Selanjutnya dilakukan inisialisasi awal:

;----------inisialisasi konstanta dan register

.equ led=0b01111111 ;portb-7 ON
.def temp=r16 ;temp sebagai alias untuk R16
;====== program utama ====================
.cseg
.org 0000 ;awal kode program pada alamat 0x0000

Variabel LED digunakan untuk menyimpan data yang akan dikeluarkan melalui PORTA, awalnya diisi 0b01111111, artinya LED-0 akan dinyalakan terlebih dahulu. Variabel TEMP digunakan variabel alias untuk R16 (register-16), Anda boleh menggunakan nama alias apa saja, misalnya, tahu, brokoli, wortel dan lain sebagainya (emang buat sayur yach? he he he)…

Program diawali dengan mendeklarasikan segmen kode (.cseg) dan dimulai alamat 0×0000 (.org) - ini paling logis kita siapkan di alamat tersebut, silahkan saja kalo mo diganti dengan alamat lain asalkan tidak konflik dengan kepentingan lainnya dalam program. Ragu-ragu? Ya sudah ikuti saja pake alamat 0×0000, aman dech…!

Selanjutnya kita lakukan INISIALISASI STACK:

;menyiapkan alamat SP - Stack Pointer

;harus dituliskan sebagai inisialisasi SP pada RCALL
;jika tidak dilakukan program akan macet!
ldi temp,low(ramend)
out spl,temp
ldi temp,high(ramend)
out sph,temp

Jika Anda lupa atau tidak melakukan inisialisasi stack, ada kemungkinan besar akan terjadi kemacetan pada program, artinya program seakan-akan stuck. Jika Anda menggunakan simulator semacam Proteus (yang pernah saya coba menggunakan Proteus 7.6 SP4), program akan berjalan tanpa kesalahan, namun ketika dicobakan ke rangkaian sesungguhnya program akan berhenti (stuck). Saran saya, ada baiknya tidak terlalu mengandalkan simulator mikrokontroler semacam Proteus, usahakan untuk mencoba di dunia nyata, di rangkaian sesungguhnya. Berikut cuplikan program untuk menginisialisasi stack di akhir ruang RAM (RAMEND).

Karena STACK pada ATMega32 ukuran 16bit atau 2byte, maka pengisian SP dilakukan dua kali untuk SP Low atau SPL dan SP High atau SPH. Fungsi Low() dan High() masing-masing digunakan untuk mendapatka bagian LOW atau HIGH dari variabel RAMEND yang suda tersimpan dalam “m32def.inc”. Pengisian register pada AVR tidak bisa dilakukan langsung, dalam hal ini melalui variabel TEMP baru kemudian dipindahkan ke SPL dan SPH. Hal ini berlaku juga untuk penjelasan terkait berikut ini…

Berikutnya, karena kita menggunakan mikrokontroler AVR, sudah wajib kita menentukan sebuah PORT sebagai masukan atau luaran, jika masing-masing bit pada register DDRx diberi nilai ‘1′ artinya sebagai luaran (jika ‘0′ sebagai masukan). Karena digunakan PORTA maka digunakan register DDRA (penulisan ke DDRA (out ddra,temp) tidak bisa langsung, sehingga digunakan variabel TEMP (ldi temp,0b01111111)):

;----------- inisialisasi port---------------------

ldi temp,0b11111111 ;set semua bit register temp
out ddra,temp ;tuliskan ke register DDRA

Selanjutnya program utama dituliskan:

;--------portb telah di seting menjadi luaran ------

ldi temp,led ;isi register temp dengan led7
sec ;set carry flag (agar carry=1, LED mati)
putar:
out porta,temp ;kirim data ke porta (LED)
rcall tunda ;tunda sesaat 0.25 detik
ror temp ;putar satu bit ke kanan melalui carry
rjmp putar ;lompat ke label putar

Data disimpan terlebih dahulu di variabel TEMP (ldi temp,led), kemudian baru dikeluarkan ke PORTA (out porta,temp), tidak bisa langsung dikirim ke PORTA. Untuk menggeser dan memutar bit pada variabel TEMP digunakan instruksi ROR (Rotate Right Using Carry), karena melewati Carry sedangkan Carry biasanya isinya ‘0′, maka harus diberi ‘1′ dulu dengan instruksi SEC. Pengulangan dilakukan dengan melompat kembali ke label ‘putar’ menggunakan rjmp putar.

Bagian akhir dari program adalah subrutin penundaan sekitar 0.25detik (lihat pada listing program lengkap). Kok bisa ya? Ya pake saja program AVR Delay Loop Generator, sebagaimana screen shoot-nya ditunjukkan pada Gambar 2, silahkan unduh gratis di-sini.

Memang menggunakan pengulangan register, penundaan 0.25 detik tidak akan akurat, tetapi lumayan buat melakukan penundaan sesaat. Jika Anda ingin akurat, gunakan fasilitas Timer/Counter pada mikrokontroler AVR yang bersangkutan.

Program selengkapnya sebagai berikut (ingat akhiri program dengan .exit)…

;------------------------------------------

;animasi LED berjalan dalam bahasa Assembly
;untuk mikrokontroler Atmel AVR ATMega32
;frekuensi kristal 7.3728MHz
;http://agfi.staff.ugm.ac.id
;------------------------------------------
.nolist ;bagian ini
.include "m32def.inc" ;tidak perlu ditampilkan dalam
.list ;berkas list

;----------inisialisasi konstanta dan register
.equ led=0b01111111 ;portb-7 on
.def temp=r16 ;temp sebagai alias untuk R16

;====== program utama ====================
.cseg
.org 0000 ;awal kode program pada alamat 0x0000

;menyiapkan alamat SP - Stack Pointer
;harus dituliskan sebagai inisialisasi SP pada RCALL
;jika tidak dilakukan program akan macet!
ldi temp,low(ramend)
out spl,temp
ldi temp,high(ramend)
out sph,temp

;----------- inisialisasi port---------------------
ldi temp,0b11111111 ;set semua bit register temp
out ddra,temp ;tuliskan ke register DDRA

;--------portb telah di seting menjadi luara ------
ldi temp,led ;isi register temp dengan led7
sec ;set carry flag (agar carry=1, LED mati)
putar:
out porta,temp ;kirim data ke porta (LED)
rcall tunda ;tunda sesaat 0.25 detik
ror temp ;putar satu bit ke kanan melalui carry
rjmp putar ;lompat ke label putar

; =============================
; delay loop generator
; 1843200 cycles:
; untuk frek 7.3728MHz
; penundaan 0.25 detik
; -----------------------------
; delaying 1843182 cycles:
tunda:
ldi R17, $12
WGLOOP0: ldi R18, $A1
WGLOOP1: ldi R19, $D3
WGLOOP2: dec R19
brne WGLOOP2
dec R18
brne WGLOOP1
dec R17
brne WGLOOP0
; -----------------------------
; delaying 18 cycles:
ldi R17, $06
WGLOOP3: dec R17
brne WGLOOP3
; =============================
ret
; =============================
.exit ;akhir program

Sedangkan dalam Bahasa C Native (menggunakan AVR Studio 4 dan GCC) ditunjukkan lengkap sebagai berikut:

//========================================

// animasi LED di PORTA
//=========================================
#include
#include //pustaka DELAY untuk frek 1MHz
#define PORTLED PORTB //penentuan alias untuk PORTB
#define DDRLED DDRB //penentuan alias untuk DDRB

int main (void)
{
unsigned char temp=0x80; // data untuk LED
DDRLED=0xFF; // PORT sebagai luaran
while(1){
PORTLED=temp; //tulis ke port
_delay_ms(250); //lakukan penundaan sesaat
temp=(temp<<7)|(temp>>1);} //ROR dalam bahasa C
return(0);
}

Silahkan Anda cermati perbedaan penulisan menggunakan Assembly dan Native C (gcc), untuk urusan penundaah digunakan fungsi _delay_ms() yang sudah didefinisikan di berkas “delay.h” dan berlaku untuk frekuensi operasional 1MHz. Sedangkan inisialisasi PORT sama seperti pada Assembly. Yang mungkin Anda pertanyakan adalah pengganti perintah ROR yaitu menggunakan instruksi “temp=(temp<<7)|(temp>>1);“, untuk ROL tinggal Anda ganti dengan “temp=(temp<<1)|(temp>>7);” dan “unsigned char temp=0×80;” menjadi “unsigned char temp=0×01;“.

Demikian penjelasan singkat saya tentang aplikasi animasi LED berjalan menggunakan bahasa assembly dan C untuk mikrokontroler AVR ATMega32. Semoga bermanfaat dan sukses selalu untuk Anda! Ingin private dengan saya untuk Belajar Mikrokontroler AVR ATMega32 menggunakan bahasa BASIC? Silahkan cermati informasinya disini.



Sumber : http://agfi.staff.ugm.ac.id

Flowcode AVR 3.0: Aplikasi dengan LCD 2×16

belajar pemrograman aplikasi mikrokontroler AVR menggunakan Flowcode 3 for AVR sebagaimana sudah saya tulis artikel-nya sejak awal. Kali ini dicoba membuat aplikasi dengan tampilan LCD 2×16, hanya sekedar menampilkan dua kalimat, masing-masing di baris-1 dan baris-2, diagram atau flow-nya ditunjukkan pada Gambar 1 (termasuk hasil simulasinya).

Gambar 1

Hasil kompilasi kedalam Bahasa C saya tunjukkan satu persatu. Pada bagian pertama, sebagaimana ditunjukkan pada Gambar 2, merupakan deklarasi fungsi-fungsi makro untuk menangani LCD (baris 66 - 74). Terdapat 9 macam fungsi makro LCD dan hanya 3 yang akan digunakan dalam program, yaitu:

  • FCD_LCDDisplay0_Start(), digunakan untuk inisialisasi LCD;
  • FCD_LCDDisplay0_PrintString(char* String, char MSZ_String), digunakan untuk menuliskan string, dan
  • FCD_LCDDisplay0_Cursor(char x, char y), digunakan untuk menempatkan kursor dengan posisi kolom,baris).

Gambar 2

Untuk fungsi FCD_LCDDisplay0_Start() listing programnya ditunjukkan pada Gambar 3. Apa yang dilakukan oleh fungsi ini adalah melakukan inisialisasi tampilan LCD dengan antarmuka 4 bit data (Flowcode 3 AVR hanya menyediakan antarmuka 4-bit data LCD walaupun bisa juga digunakan rangkaian antarmuka 8-bit data LCD). Rangkaian yang digunakan menggunakan pemetaan PORT dan pin LCD sebagai berikut:

#define LCD_2360334_BIT0    2
#define LCD_2360334_BIT1 3
#define LCD_2360334_BIT2 4
#define LCD_2360334_BIT3 5
#define LCD_2360334_RS 0
#define LCD_2360334_E 1

Gambar 3

Untuk fungsi FCD_LCDDisplay0_PrintString() listingnya ditunjukkan pada Gambar 4. Fungsi ini digunakan untuk menampilkan string ke LCD pada posisi kursor saat itu. Fungsi ini membutuhkan dua parameter, string yang akan ditampilkan dan jumlah karakter pada string tersebut.

Gambar 4

Untuk fungsi FCD_LCDDisplay0_Cursor(char x, char y) listingnya ditunjukkan pada Gambar 5. Fungsi ini membutuhkan dua parameter yaitu x (untuk posisi kolom) dan y (untuk posisi baris), jika dituliskan FCD_LCDDisplay0_Cursor(0,1) artinya menempatkan kursor pada kolom pertama baris kedua, demikian seterusnya…

Gambar 5

Nah program utama ditunjukkan pada Gambar 6. Diawali dengan inisialisasi register MCUCSR dan WDTCR pada baris 373 dan 374 (baca artikel saya sebelumnya). Kemudian dilanjutkan dengan melakukan inisialisasi LCD (baris 381) menggunakan fungsi FCD_LCDDisplay0_Start(). Diikuti dengan menampilkan string “Halo Flowcode3″ (baris 386, angka 14 merupakan jumlah karakter pada string yang bersangkutan), menempatkan kursor pada baris kedua kolom pertama (baris 391), menampilkan string “by ATMega32″ (baris 396) dan diakhiri dengan infinite-loop atau kalang-takhingga (baris 399).

Gambar 6

Jika Anda perhatikan baik-baik pada ketiga fungsi tersebut, maka bisa Anda temukan pemanggilan fungsi lain yaitu LCD_2360334_RawSend(char nIn, char nMask), yang digunakan untuk mengirimkan satu karakter. Pendefinisian fungsi ini ada di dalam fungsi FCD_LCDDisplay0_GetDefines().

Program selengkapnya bisa diunduh disini.

Semoga bermanfaat.

Flowcode AVR 3.0: Aplikasi Masukan/Luaran (I/O) Sederhana

Kali ini Flowcode AVR kita gunakan untuk mencoba membuat sebuah aplikasi sederhana yang melakukan pembacaan masukan di PORT A kemudian menampilkan hasil pembacaan tersebut, yang sebelumnya melalui suatu variabel DATANYA, ke PORT B. Rancangan Flowcode AVR-nya ditunjukkan pada Gambar 1.

Gambar 1

Kemudian kita kompail dan disimulasikan hasilnya (juga) bisa dilihat pada Gambar 1 tersebut. Perhatikan bahwa tidak semua masukan PORT A kita buat berlogika 1, hanya A7, A5, A3 dan A1. Hasilnya juga tidak semua LED pada PORT B menyala, hanya sesuai dengan PORT A saja, yaitu B7, B5, B3 dan B1. Nah sekarang pertanyaannya:

Bagaimana dengan hasil kompilasi dalam bahasa C-nya (juga dalam bahasa ASM-nya)?

Berikut saya cuplik sebagian hasil kompilasi dalam bahasa C (baris 59-96), cukup yang utama dulu, selebihnya Anda bisa mencermati bahwa di awal program C-nya merupakan inisialisasi variabel, pemetaan mikrokontroler dan lain-lain. Perhatikan Gambar 2.

Gambar 2

Pada cuplikan listing tersebut saya sudah memberikan catatan. Bagaimana dengan Anda? Apa yang dilakukan pada bagian inisialisasi, baris 76 dan 77? Instruksi MCUCSR = 0×00; digunakan untuk mereset (memberikan logika 0) pada semua bit di register MCU Control and Register, perhatikan penjelasan pada gambar MCUCSR. Sedangkan WDTCR = 0×10; digunakan untuk mematikan watchdog, perhatikan penjelasan register WDTCR (Watchdog Control Register). Langkah ini dilakukan oleh Flowcode, menurut saya, untuk keamanan atau play safe saja. Karena kemungkinan kompailer C yang digunakan tidak mematikan watchdog secara otomatis (ada beberapa kompailer yang bisa melakukan-nya secara otomatis selama tidak secara eksplisit dinyatakan penggunaan watchdog).

MCUCSR

WDTCR

Listing program selebihnya adalah sesuai dengan yang diharapkan, baca masukan seperti pada baris 85, namun sebelumnya ada inisialisasi PORT A sebagai masukan, mengapa tidak langsung aja DDRA = 0×00? Kok harus di-AND-kan segala dengan 0, khan hasilnya sama saja logika-0 khan? Aneh? Kemudian dilanjutkan dengan mengirimkan isi variabel dari pembacaan PORT A ke PORTB, lihat baris 91, yang sebelumnya (juga) diawali dengan inisialisasi PORT B sebagai luaran (nah kalo ini caranya langsung).

Jika Anda berikan loop pada program, seperti pada Gambar 3, hasilnya juga sama saja, keunikan juga terjadi lagi seperti saya jelaskan pada artikel sebelumnya.

Gambar 3

Semoga bermanfaat, amin!

Flowcode AVR 3.0: Aplikasi Masukan/Luaran (I/O) Sederhana

Kali ini Flowcode AVR kita gunakan untuk mencoba membuat sebuah aplikasi sederhana yang melakukan pembacaan masukan di PORT A kemudian menampilkan hasil pembacaan tersebut, yang sebelumnya melalui suatu variabel DATANYA, ke PORT B. Rancangan Flowcode AVR-nya ditunjukkan pada Gambar 1.

Gambar 1

Kemudian kita kompail dan disimulasikan hasilnya (juga) bisa dilihat pada Gambar 1 tersebut. Perhatikan bahwa tidak semua masukan PORT A kita buat berlogika 1, hanya A7, A5, A3 dan A1. Hasilnya juga tidak semua LED pada PORT B menyala, hanya sesuai dengan PORT A saja, yaitu B7, B5, B3 dan B1. Nah sekarang pertanyaannya:

Bagaimana dengan hasil kompilasi dalam bahasa C-nya (juga dalam bahasa ASM-nya)?

Berikut saya cuplik sebagian hasil kompilasi dalam bahasa C (baris 59-96), cukup yang utama dulu, selebihnya Anda bisa mencermati bahwa di awal program C-nya merupakan inisialisasi variabel, pemetaan mikrokontroler dan lain-lain. Perhatikan Gambar 2.

Gambar 2

Pada cuplikan listing tersebut saya sudah memberikan catatan. Bagaimana dengan Anda? Apa yang dilakukan pada bagian inisialisasi, baris 76 dan 77? Instruksi MCUCSR = 0×00; digunakan untuk mereset (memberikan logika 0) pada semua bit di register MCU Control and Register, perhatikan penjelasan pada gambar MCUCSR. Sedangkan WDTCR = 0×10; digunakan untuk mematikan watchdog, perhatikan penjelasan register WDTCR (Watchdog Control Register). Langkah ini dilakukan oleh Flowcode, menurut saya, untuk keamanan atau play safe saja. Karena kemungkinan kompailer C yang digunakan tidak mematikan watchdog secara otomatis (ada beberapa kompailer yang bisa melakukan-nya secara otomatis selama tidak secara eksplisit dinyatakan penggunaan watchdog).

MCUCSR

WDTCR

Listing program selebihnya adalah sesuai dengan yang diharapkan, baca masukan seperti pada baris 85, namun sebelumnya ada inisialisasi PORT A sebagai masukan, mengapa tidak langsung aja DDRA = 0×00? Kok harus di-AND-kan segala dengan 0, khan hasilnya sama saja logika-0 khan? Aneh? Kemudian dilanjutkan dengan mengirimkan isi variabel dari pembacaan PORT A ke PORTB, lihat baris 91, yang sebelumnya (juga) diawali dengan inisialisasi PORT B sebagai luaran (nah kalo ini caranya langsung).

Jika Anda berikan loop pada program, seperti pada Gambar 3, hasilnya juga sama saja, keunikan juga terjadi lagi seperti saya jelaskan pada artikel sebelumnya.

Gambar 3

Semoga bermanfaat, amin!

 
Robotron-UNM © 2016 | Editor by Asis Robotron | Blogger Template by Blog Zone