Categories
Mikrokontroler

Animasi LED mikrokontroler ATMega32 dengan Assembly dan C

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
;http://agfi.staff.ugm.ac.id
;------------------------------------------
.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 0x0000 (.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 0x0000, 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=0x80;” menjadi “unsigned char temp=0x01;“.

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.