Maswie BloG

Free Delphi, Visual Basic, Microcontrol, Mechatronic tutorial

DASAR-DASAR PEMROGRAMAN AVR

Posted by maswie2000 on November 5, 2007

Dalam bab ini, kita akan membahas bagaiman menuliskan program assembler untuk tahap pemrograman AVR berikutnya. Program assembler berisi mnemonic instruksi, label, dan pengarah assembler (directive). Mnemonic instruksi dan pengarah seringa kali memebutuhkan operan dalam penulisannya. Baris kode dalam penulisan program assembler dibatasi hingga 120 karakter.

Bahasa Asembler dan C untuk Mikrokontroler

Program sumber (source program) untuk mikrokontroler dapat dituliskan dalam berbagai bahasa, antara lain bahasa asembler dan C. Ada juga program yang dituliskan menggunakan bahasa basic untuk mikrokontroler, source program harus dikompilasi/diasembli menggunakan program yang sesuai. Penggunaan bahasa sangat tergantung pada kepentingan dan kemampuan suatu system aplikasi mikrokontroler.

Setiap bahasa memiliki kelebihan dan kekurangannya masing-masing. Bahasa assembler dituliskan dengan detail setiap langkah yang dijalankan, sehingga penulisanya relative lebih panjang. Pemrogram harus mengetahui benar proses yang terjadi dalam program tersebut. Namun demikian, program assembler sangat cocok dalam hal efisiensi penggunaan memori program. Di sini lain, bahasa C memiliki kemudahan dalam penulisan program, namun terkadang kode yang dihasilkan akan memakan memori program yang besar.

Program assembler berisi mnemonic instruksi, label, dan pengarah assembler (directive). Mnemonic instruksi, label, dan pengarah assembler (directive). Mnemonic instruksi dan pengarah sering kali membutuhkan operan dalam penulisannya. Baris kode dalam penulisan program assembler dibatasi hingga 120 karakter.

Label

Pada penulisan program, Anda akan banyak menggunakan label untuk menandai suatu rutin program. Pemberian label akan sangat berguna untuk menentukan tujuan instruksi lompatan (jump) dan percabangan (branch) serta sebagai nama variable dalam memori program dan RAM. Namun demikian, penggunaan label merupakan kenutuhan software assembler/compiler untuk mengenali suatu rutin program yang Anda buat. Anda dapat menambahkan komentar anda sendiri untuk memberi keterangan pada rutin atau instruksi yang Anda tulis sebagai suatu komentar. Komentar tidak akan mempengaruhi proses asembli dan akan diabaikan oleh software assembler/compiler. Untuk menuliskan komentar, Anda dapat memisahkannya dengan kode program menggunakan tanda titik koma (“;”) pada awal komentar anda.

Secara umum setiap baris dalam program assembler AVR memiliki bentuk sebagai berikut:

1. [label:] directive [operan] [komentar]

2. [label:] instruksi [operan] [komentar]

3. [komentar]

4. Baris kosong

Cara penulisan komentar adalah sebagai berikut:

[; teks komentar]

Pengarah Asembler

Dalam pennulisan program assembler, dikenal adanya sejumlah pengarah assembler (directive). Pengarah assembler tidak secara langsung diterjemahkan dalam opcode pada waktu asembli atau kompilasi. Pengarah digunakan untuk mengatur penempatan program ke dalam memori, mendefinisikan macro, inisialisasi memori, dan sebagainya. Pengarah assembler AVR dituliskan dengan didahului tanda titik(“.”), sehingga disebut juga perintah bertitik. Berikut ini pengarah assembler yang digunakan dalam pemrograman AVR.

Tabel 5.1 Daftar Pengarah Asembler

Pengarah

Deskripsi

BYTE

Byte untuk variable

CSEG

Segmen kode

DB

Mendefinisikanbyte konstanta

DEF

Mendefinisikan nama symbol dari register

DEVICE

Mendefinisikan tipe AVR

DSEG

Segmen dat

DW

Mendefinisikan word konstanta

ENDMACRO

Mengakhiri macro

EQU

Menentukan suatu symbol sama dengan ekspresi

ESEG

Segmen EEPROM

EXIT

Mengakhiri file

INCLUDE

Membaca source code dari file lain

LIST

Membangkitkan file list

LISTMAC

Ekspansi file list untuk macro

MACRO

Memulai macro

NOLIST

Tidak membangkitkan file list

ORG

Menentukan awal program

SET

Menentukan suatu symbol sebagai ekspresi

Penjelasan untuk masing-masing pengarah diberikan berikut ini.

1. BYTE

Pengarah BYTE merupakan pengarah yang digunakan untuk menjaga ketersediaan memori didalam SRAM. Agar dapat digunakan untuk menunjuk suatu lokasi memori, pengarah BYTE harus dituliskan melalui label. Pengarah BYTE akan mengambil sebuah parameter yaitu banyaknya byte yang akan dipertahankan. Pengarah ini hanya dapat digunakan dalam Data Segment.

Sintak:

Label: .BYTE ekspresi

Contoh:

. DSEG

varl: .BYTE 1

table: .BYTE tab_size

.CSEG

1di r30, low (var1)

1di r31, high (var1)

2. CSEG

Pengarah CSEG digunakan untuk mendefinisikan awal suatu Code Segment. Sebuah file assembler dapat terdiri dari beberapa Code Segment, yang semuanya terhubung dengan satu Code Segment. Pengarah BYTE tidak dapat digunakan di dalam sebuah Code Segment. Code Segment memiliki pencacah lokasinya sendiri, yaitu berupa pencacah kata. Pengarah ORG dapat digunakan untuk menempatkan kode dan konstanta pada suatu lokasi tertentu di dalam Memori Program. Dalam penulisannya, pengarah CSEG tidak memerlukan suatu operan apapun.

Sintak:

.CSEG

Contoh:

. DSEG ; Memulai data segment

vartab: .BYTE 4 ;

. CSEG ; Memulai code segment

const: .DW 2 ; Tulis 0x0002 dlm prog. Mem.

Mov r1,r0 ; Lakukan sesuatu

3. DB

Pengarah DB digunakan untuk menjaga sumber daya memori yang ada di dalam Memori Program atau memori EEPROM. Pengarah DB mengambil beberapa ekspresi sekaligus sebagai suatu daftar ekspresi. Dalam penulisannya, daftar ekspresi dituliskan sebagai runtun ekspresi yang masing-masing dipisahkan dengan tanda koma. Masing-masing ekspresi dapat berupa bilangan antara – 128 hingga 255. Untuk bilangan negative, bilangan komplemen dua 8 bit akan ditempatkan pada Memori Program atau Memori EEPROM.Pengarah DB harus ditempatkan pada Code Segment atau EEPROM Segment dan minimal harus mengandung sebuah ekspresi. Bila pengarah DB berada pada Code Segment dan daftar ekspresi berisi lebih dari satu ekspresi, maka ekspresi-ekspresi tersebut akan dikemas dalam dua byte kata pada Memori Program.

Sintaks:

Label : .DB daftar_ekspresi

Contoh:

.CSEG

konstanta: .DB 5, 255, 0b01000101, 0xaa

.ESEG

eeconstan: .DB 0xff

4. DEF

Pengarah DEF mengijinkan suatu register sehingga dapat ditunjuk menggunakan suatu symbol, suatu symbol yang didefinisikan disela-sela Memori Program dapat digunakan untuk menunjuk suatu register. Sebuah symbol dapat kembali didefinisikan pada bagian lain dalam program.

Sintaks:

.DEF Symbol=Register

Contoh:

.DEF temp=R16

.DEF ior=R0

.CSEG

1di temp, 0xf0 ; Load 0xf0 ke register temp

in ior, 0x3f ; Baca SREG ke dalam register oir

eor temp, ior ; exclusive OR temp dan ior

5. DEVICE

Pengarah DEVICE akan memberitahukan kepada software assembler mengenai jenis/tipe perangkat mikrokontroler apa yang akan digunakan untuk mengeksekusi kode program tersebut. Apabila pengarah ini anda gunakan, maka adanya suatu instruksi yang tidak mendukung tipe mikrokontroler akan ditampilkan sebagai peringatan (warning). Peringatan ini misalnya, apabila ukuran Code Segment atau EEPROM Segment melebihi kapasitas mikrokontroler yang dispesifikasikan. Bila pengarah ini tidak digunakan, maka anggap semua intruksi mendukung untuk digunakan pada perangkat mikrokontroler tersebut.

Sintak:

.DEVICE AT90S1200 | AT902313 | AT90S8515

Contoh:

.DEVICE AT90S2313 ; Menggunakan AT90S2313

6. DSEG

Pengarah DSEG digunakan untuk mengawali suatu Data Segment. Sebuah file assembler dapat berisi beberapa Data Segment, yang akan dinyatakan dalam sebuah Data Segment pada saat diasembli. Sebuah Data Segment lazimnya hanya berisi pengarah BYTE dan label saja.

Sintaks:

.DSEG

Contoh:

.DSEG

var1: .BYTE

table: .BYTE tab_size

.CSEG

1di r30, low(var1)

1di r30, high(var1)

1d r1, z

7. DW

Pengarah ini digunakan untuk mendefinisikan konstanta dalam Memori Program atau memori EEPROM. Pengarah DB akan membawa sebuah daftar ekspresi dan minimal harus mengandung sebuah ekspresi. Pengarah ini harus ditempatkan di dalam Code Segment atau EEPROM Segment. Daftar ekspresi merupakan runtun ekspresi, yang masing-masing dipisahkan dengan tanda koma dan merupakan bilangan antara – 23768 hingga 65535. Apabila ekspresi menyatakan bilangan negative, maka bilangan komplemen dua 16-bit akan ditempatkan pada Memori Program.

Sintaks:

LABEL: .DW daftar_ekspresi

Contoh:

.CSEG

varlist: .DW 64286, 0b0101011110100011,0xffff

.ESEG

eevar: .DW0xfafa

8. ENDMACRO

Penagarah ini digunakan untuk mendefinisikan akhir sebuah macro. Pengarah ini tidak membutuhkan parameter.

Sintaks:

.ENDMACRO

Contoh:

.MACRO SUBI16

subi r16, low(@0)

sbci r17, high (@0)

.ENDMACRO

9. EQU

Pengarah EQU digunakan untuk memberikan nilai terhadap suatu label. Label tersebut kemudian dapat digunakan pada papan ekspresi selanjutnya. Sebuah label yang telah diberi nilai menggunakan pengarah EQU merupakan sebuah konstanta dan tidak dapat diubah nilainya atau didefinisikan ulang.

Contoh:

.EQU oi_offset=0x23

.EQU porta = io_offset + 2

.CSEG

clr r2

out porta, r2

10. ESEG

Pengaran ini digunakan untuk mendefinisikan EEPROM Segments. Sebuah file assembler bisa saja terdiri dari beberapa EEPROM Segment, namun pada saat diasembli, semuanya akan dikumpulkan dalam satu EEPROM Segment. Pengarah ESEG tidak memerlukan parameter apapun dalam penulisannya.

Sintaks:

.ESEG

Contoh:

.DSEG

vartab: .BYTE 4

.ESEG

eevar: .DW 0x0ff0

.CSEG

const: .DW 2

mov r1, r0

1. EXIT

Pengarah EXIT akan memberitahu pada software Asembler untuk menghentikan proses asembli. Pada umumnya assembler akan berjalan hingga akhir file. Apabila pengarah EXIT ditemukan dalam suatu file include, maka Asembler akan melanjutkan prosesnya pada baris sesudah pengarah INCLUDE dalam file yang berisi pengarah INCLUDE tersebut.

Contoh:

.EXIT ; keluar dari file

12. INCLUDE

Pengarah INCLUDE akan memberitahukan pada software Asembler untuk mulai membaca pada sebuah file khusus yang ditunjuk. Setelah itu, Asembler akan membaca hingga akhir file tersebut atau hingga pengarah EXIT dijumpai.

Sintaks:

.INCLUDE “nama_file”

Contoh:

.EQU sreg=0x0f

.EQU sphigh=0x0e

.EQU splow=0x0d

.INCLUDE “iodefs.asm”

in r0, sreg

13. LIST

Pengarah LIST akan memberitahukan Asembler untuk membangkitkan file list. Asembler akan membangkitkan file list yang berisi gabungan kode assembler, alamat, dan opcode. File list akan dibangkitkan dalam mode defaut Asembler. Pengarah ini dapat pula digunakan bersama dengan mengarah NOLIST dengan maksud untuk hanya membangkitkan file list pada bagian tertentu saja.

Sintaks:

.LIST

Contoh:

.NOLIST

.INCLUDE “macro. inc”

.INCLUDE “consdef. inc”

.LIST ;mengaktifkan pembangkitan file LIST

14. LISTMAC

Pengarah LISTMAC akan mengatakan pada Asembler bahwa ketika sebuah macro dipanggil, maka penambahan macro akan ditampilkan pada file list yang dibangkitkan. Dalam mode default, hanya macro yang dipanggil dengan parameter yang akan ditempatkan dalam file list.

Sintaks:

.LISTMAC

Contoh:

.MACRO MACX

add r0, @0

eor r1, @1

.ENDMACRO

.LISTMAC

MACX r2, r1

15. MACRO

Pengarah MACRO digunakan untuk mengawali suatu macro. pengarah ini membutuhkan parameter berupa nama_macro.

Suatu macro diakhiri menggunakan pengarah ENDMACRO. Pada kondisi default, hanya pemanggilan macro yang ditampilkan pada file list yang dibangkitkan oleh software assembler. Untuk memasukkan macro yang ditunjuk ke dalam file list, maka pengarah LISTMAC harus digunakan. Suatu macro ditandai dengan tanda “+” pada opcode di dalam file list.

Sintaks:

.MACRO

Contoh:

.MACRO SUBI16

subi @1, low (@0)

sbci @2, high (@0)

.ENDMACRO

.CSEG

SUBI16 0X1234, r16, r17

16. NOLIST

Pengarah ini digunakan agar suatu runtuh instruksi tidak dimasukkan dalam file list yang dibangkitkan. Pada umumnya, software assembler akan membangkitkan file list yang berisi alamat, instruksi sumber, dan opcode dari file sumber. Pembangkitan file list akan dilakukan secara otomatis dalam mode default dan dapat dibuat tidak aktif menggunakan pengarah ini. Pengarah ini juga dapat digunakan bersama pengarah LIST yang digunakan untuk membangkitkan file list hanya untuk bagian tertentu dari program sumber.

Sintaks:

.NOLIST

Contoh:

.NOLIST ; Pembangkitan file list tidak diaktifkan

.INCLUDE “macro.inc”

.INCLUDE “cons.def”

.LIST ; Bangkitkan file list kembali

17. ORG

Pengarah ORG digunakan untuk menentukan pencacah lokasi pada suatu nilai mutlak tertentu. Nilai tersebut dituliskan sebagai parameter pengarah ini. ORG berarti nilai awal (origin). Apabila ORG digunakan pada Data Segment, makan nilai parameter akan menunjuk pada lokasi SRAM dan bila digunakan pada Code Segment, maka parameter tersebut akan menunjuk pada lokasi Memori Program. Sedangkan bila digunakan pada EEPROM Segment, maka parameter dari pengarah ini akan menunjuk lokasi EEPROM. Nilai default pencacah lokasi Code dan EEPROM adalah nol, sedangkan nilai default pencacah lokasi SRAM adalah 32 (karena register-register menempati alamat 0-31) pada saat proses asembli dimulai.

Sintaks:

.ORG ekspresi

Contoh:

.DSEG ; Mulai data segment

.ORG 0x37 ; Set alamat SRAM pada 37hex

variable: .BYTE 1 ;

.CSEG

.ORG 0x10 ; Set Program Counter dengan 10hex

mov r0, r1 ;

18. SET

Pengarah SET digunakan untuk memberikan suatu nilai tertentu pada suatu label. Label tersebut dapat digunakan pada ekspresi selanjutnya.

Sinteks:

.SET label=ekspresi

Contoh:

.SET io_ofset = 0x26

.SET porta = io_ofset +2

.CSEG

clr r2

out porta,r2

Ekspresi

Ekspresi dapat berupa operan, operator, maupun fungsi. Semua ekspresi akan diterjemahkan sebagai kode 32-bit oleh assembler/compiler.

Operan

operan yang dapat digunakan dalam program assembler antara lain :

̶ Label yang didefinisikan oleh user dan diberi nilai pencacah lokasi sesuai dengan tempat di mana label tersebut akan muncul.

̶ Variable yang didefinisikan oleh user menggunakan pengarah SET.

̶ Konstanta integer, dituliskan dalam beberapa format berikut:

  1. Desimal (default): 0, 23, 50
  2. Heksadesimal:0x0a, 0xff, $80
  3. Biner: 0b00101110

̶ PC: nilai pencacah Memori Program pada saat itu.

Fungsi

Fungsi yang digunakan pada assembler AVR didefinisikan dengan cara berikut:

̶ LOW (ekspresi) mengembalikan byte low dari sebuah ekspresi.

̶ HIGH (ekspresi) mengembalikan byte kedua dari sebuah ekspresi.

̶ BYTE2 (ekspresi) sama dengan HIGH.

̶ BYTE3 (ekspresi) mengembalikan byte ketiga dari sebuah ekspresi.

̶ BYTE4 (ekspresi) mengembalikan byte keempat dari sebuah ekspresi.

̶ LWRD (ekspresi) menunjuk pada bit 0-15 dari sebuah ekspresi.

̶ HWRD (ekspresi) menunjuk pada bit 16-31 dari sebuah ekspresi.

̶ PAGE (ekspresi) menunjuk pada bit 16-21 dari sebuah ekspresi.

̶ EXP2 (ekspresi) menunjuk 2 pangkat nilai ekspresi.

̶ LOG2 (ekspresi) menunjuk bagian integer dari log 2 dari ekspresi.

Operator

Operator yang digunakan dalam pemrograman assembler AVR diberikan pada Tabel 5.2.

Tabel 5.2 Daftar Operator

Tipe

Simbol

Deskripsi

Contoh

Kalkulasi

+

Penjumlahan

ldi r30, c1+c2

Pengurangan

ldi r17, c1-c2

*

Perkalian

ldi r30, label*2

/

Pembagian-Integer

ldi r30, label/2

Biner

&

Bitwise AND

ldi r18, High(c1&c2)

|

Bitwise OR

ldi r18, Low(c1|c2)

^

Bitwise Exclusive-OR

ldi r18, Low(c1^c2)

~

Bitwise NOT

ldi r16.~0xf0

<<

Geser kiri

ldi r17,1<<bitm

>>

Geser kanan

ldi r17,c1>>c2

Logika

<

Kurang dari

ori r18,bitmask*(c1<c2)+1

>

Lebih dari

ori r18,bitmask*(c1>c2)+1

= =

Sama dengan

andi r19,bitmask*(c1= =c2)+1

<=

Kurang dari atau sama dengan

ori r18,bitmask*(c1<=c2)+1

>=

Lebih dari atau sama dengan

ori r18,bitmask*(c1>=c2)+1

!=

Tidak sama dengan

.SET flag=(c1!=c2)

&&

AND

ldi r18, Low(c1&&c2)

‌‌‌| |

OR

ldi r18, Low(c1| |c2)

!

NOT

ldi r1, !0xf0

Dasar-dasar Pemrograman AVR

Struktur Program

Bentuk umum program yang biasa digunakan adalah sebagai berikut:

Deklarasi konstanta

Definisi variable

File include

Vektor Reset dan intrupsi

Program utama

Akhir program

Penggunaan Register

Penggunaan register dalam pemrograman AVR merupakan hal yang sangat esensial dan tidak dapat dipisahkan dalam penulisan program. Untuk itu anda perlu berhati-hati dalam menuliskan instruksi, memilih register, dan hal-hal lain yang berkaitan dengan penunggunan register. Mula-mula definisikan nama register menggunakan pengarah DEF dan pilihlah nama yang anda anggap mudah diingat dan mencerminkan fungsi dan kegunaannya, Jika anda perlu menggunakan akses pointer, gunakanlah register R26 sampai R31. Sedangkan bila anda ingin melakukan pencacahan menggunakan counter 16-bit, pilihlah pasangan register R24:R25. Apabila anda ingin membaca dari memori program, misal: nilai konstanta, anda dapat menggunakan Z (R31:R30) dan R0. Register R16 sampai R31, dapat anda gunakan untuk mengakses bit tunggal suatu register tertentu.

Dalam mikrokontroler AVR terdapat 32 buah register. Register tersebut memiliki nama asli R0 hingga R31, namun anda dapat memberi nama sesuai yang anda kehendaki dengan menggunakan pengarah assembler. Nama yang anda berikan hendaknya adalah nama yang mudah diingat dan mencerminkan kegunaan atau isi dari register tersebut.

.DEF reg_bilangan1 = R16

Dengan memberi nama reg_bilangan1 pada R16, maka anda dapat menggunakan reg_bilangan1 untuk menunjuk R16.

Misalkan anda ingin memberi nilai 150 pada register R16, anda dapat menggunakan perintah berikut:

LDI reg_bilangan1, 150

Penulisan bilangan pada assembler AVR memiliki default pada basis bilangan decimal. Bila anda ingin menuliskan bilangan dalam basis heksadesimal atau biner, maka anda harus menggunakan format penulisan yang lain, misalnya 0x6a atau $6a untuk heksadesimal, atau 0b01101010 untuk penulisan bilangan dalam format biner.

Dalam satu perintah, Anda mungkin ingin mengoperasikan dua buah register. Misalnya anda ingin memindahkan isi suatu register ke register yang lain, anda dapat menggunakan perintah MOV.

.DEF reg_bilangan1 = R16

.DEF reg_penampung = R17

LDI reg_bilangan1, 150

MOV reg_penampung, reg_bilangan1

Perintah diatas akan menulis nilai 150 pada register reg_bilangan1 dan kemudian menyalin isi register reg_bilangan1 ke reg_penampung. Perhatikan, bahwa register yang dituliskan terlebih dahulu pada instruksi MOV merupakan register target yang merupakan register di mana hasil operasi akan dituliskan.

Dua baris pertama yang berisi pengarah assembler di atas tidak akan menghasilkan kode apapundalam Memori Program AVR. Penggunaan pengarah assembler hanya untuk menberikan suatu informasi kepada software assembler dalam proses pelaksanaan asembli.

Untuk memuati reg_penampungan dengan suatu bilangan (missal 150), anda mingkin akan menuliskan perintah berikut:

.DEF reg_penampung = R15

LDI reg_penampung, 150

Maka anda akan kehilangan data. Perlu anda ketahui bahwa hanya register R16 hingga R31 yang dimuati dengan suatu konstanta menggunakan instruksi ldi. Keterbatasan ini sangat tidak menyenangkan, namun tidak dapat dihindari karena kontruksi instruksi set AVR. Sebagai pengecualian, terdapat satu instruksi yang berlaku untuk semua register yaitu clr, yang akan mengeset isi register dengan nilai nol. Perintah clr <nama_register>, berlaku untuk semua register.

Di samping instruksi LDI, terdapat instruksi-instruksi lain yang memiliki pembatasan dalam penggunaan dalam program assembler. Instruksi-instruksi tersebut adalah:

1. ANDI Rx, K ;bit-AND register Rx dengan konstanta K.

2. CBR Rx, M ;bersihkan semua bit dalam register Rx dan set ke “1” dengan mask value M.

3. CPI Rx, K ;bandingkan isi register Rx dengan konstanta bernilai K.

4. CBCI Rx, K ;kurangkan isi register Rx beserta nilai carry flag-nya dari nilai konstanta K.

5. SBR Rx, M ;set semua bit dalam register Rx dengan nilai “1”, dengan mask value M.

6. SER Rx ;set semua bit dalam register Rx (sama dengan perintah LDI Rx,255).

7. SUBI Rx, K ;kurangkan nilai konstanta K dari isi register Rx, dan simpan hasilnya ke register Rx.

Semua instruksi di atas hanya berlaku untuk register R16 sampai R31. Apabila anda ingin menggunakan instruksi-instruksi di atas, Anda perlu memilih salah satu register diatas. Hal itu akan memudahkan anda dalam pemrograman. Hal ini juga merupakan alasan tambahan digunakannya pengarah assembler untuk mendefinisikan lokasi register sehingga kita dapat lebih mudah mengubah lokasi register yang kita inginkan.

Sedikit mengulang apa yang telah anda pelajari di muka, dalam pemrograman assembler, terdapat aturan tambahan yang berlaku untuk pasangan register R26:R27, R28:R29, dan R30:R31. Seperti anda ketahui, ketiga pasangan register ini memiliki nama tambahan yaitu X, Y dan Z. Pasangan tersebut merupakan pointer register 16-bit yang dapat menunjuk alamat dengan maksimum 16-bit ke dalam lokasi memori SRAM (X, Y, Z) atau ke dalam lokasi Memori Program (Z). Byte bawah dari alamat 16-bit tersebut ditempatkan pada register yang lebih rendah, sedangkan byte atas ditempatkan pada register yang lebih tinggi. Kedua bagian ini memiliki nama yang sendiri-sendiri, misalkan, byte atas dari Z dinamakan ZH(=R31) dan byte bawah dari Z dinamakan ZL(= R30). Nama-nama tersebut didefinisikan dalam file header standar untuk masing-masing mikrokontroler. Pembagian nama pointer 16-bit tersebut dalam dua byte yang berbeda dilakukan seperti berikut:

.EQU Adress = RAMEND

1di YH, HIGH (Adress)

1di YL, LOW (Adress)

Pengaksesan melalui pointer dilakukan menggunakan instruksi yang dirancang khusus. Untuk membaca, digunakan instruksi LD (LoaD), sedangkan penulisan dilakukan dengan instruksi ST (Store).

Hanya terdapat satu instruksi akses baca untuk Memori Program yang didefinisikan pada pasangan register Z. Instruksi tersebut bernama LPM (Load Program Memory). Instruksi ini akan menyalin alamat byte Z dalam memori program ke register R0. Mengingat Program memori diatur dalam word-wise (satu instruksi pada satu alamat berisi 16-bit atau 2-byte atau 1-word) LSB menentukan byte bawah (jika LSB = “0”) atau byte atas (jika LSB = “1”). Hal ini mengakibatkan alamat asli harus dikalikan dua dan akses dibatasi untuk 15-bit atau 32kB memori program.

1di ZH, HIGH (2*Adress)

1di ZL, LOW (2*Adress)

LPM

Setelah perintah ini, alamat harus di-incremen untuk menunjuk byte berikutnya dalam memori program. Karena sering digunakan, increment pointer didefinisikan melalui perintah berikut:

ADIW Z, 1

LPM

ADIW berarti Add Immediate Word.

Komplemen instruksi ADIW adalah SBIW (SuBtract Immediate Word). ADIW dan SBIW dapat digunakan untuk pasangan register X, Y, dan Z, dan untuk pasangan register R24:R25 yang tidak memiliki nama tambahan dan tidak mengijinkan akses SRAM dan lokasi Memori Program. R24:R25 merupakan pasangan memori yang cocok untuk penanganan nilai 16-bit.

Membuat Tabel

Seringkali kita perlu membuat suatu tabel data untuk melakukan operasi-operasi di dalam program yang kita buat. Di sini kita membahas bagaimana suatu perintah dituliskan untuk membentuk suatu tabel menggunakan pengarah .DB dan .DW. dengan perintah tersebut Anda dapat memasukkan daftar nilai (data)bytewise atau wordwise.

Data bytewise ditata dalam format sepeti berikut:

.DB 123, 45, 67, 89 ; data empat byte

.DB “data teks” ; data karakter ASCII

Anda harus selalu menulis data berjumlah genap, jika tidak maka assembler akan menambahkan nilai nol pada bagian akhir daftar nilai yang barangkali tidak Anda harapkan.

Daftar data yang sama dapat Anda tuliskan dalam wordwise, sebagaimana contoh berikut:

.DB 12345,6789 ; daftar 2 word

Selain data berupa konstanta, anda juga dapat memasukkan label (target lompatan), seperti contoh berikut:

Label1:

[. . perintah . .]

Label2;

[. . perintah lainnya . .]

Tabel:

.DB label1,Label2 ; daftar label

Penggunaan khusus register pointer adalah untuk mengakses dirinya sendiri. Register terletak pada 32-byte pertama dalam mikrokontroler (0x0000 sampai 0x001F). Akses ini hanya akan bermanfaat apabila Anda harus menyalin isi register ke SRAM atau EEPROM atau sebaliknya.

Penggunaan utama pointer adalah untuk mengakses tabel dengan nilai tetapan pada memori program. Sebagai contoh, tabel dengan 10 niali 16-bit dengan nilai kelima dibaca ke R25:R25.

Table_1:

.DW 0x1234, 0x2345, 0x3456, 0x4568, 0x5678 ;

.DW 0x6789, 0x789A, 0x89AB, 0x9ABC, 0xABCD;

Read5:

LDI ZH, HIGH (Table_1*2) ;

LDI ZL, LOW (Table_1*2) ;

ADIW ZL, 10 ;

LPM ;

MOV R24, R0 ;

ADIW ZL, 1 ;

LPM ;

MOV R25, R0 ;

Port

Port merupakan gerbang yang menghubungkan CPU dengan komponen lain baik internal maupun eksternal. CPU berkomunikasi dengan komponen-komponen tersebut, membaca nilai atau menulis suatu niali padanya. Port yang paling sering digunakan adalah register flag yang kepadanya dituliskan nilai hasil operasi sebelumnya dan syarat percabangan dibaca darinya.

Port AVR memiliki alamat tetap yang digunakan untuk berkomunikasi dengan CPU. Alamat Port pada AVR sudah tetap dan tidak bergantung pada tipe mikrokontroler AVR. Misalkan saja, alamat port B adalah 0x18. Anda tidak perlu menghafal alamat port-port tersebut, karena masing-masing port memiliki nama alias yang didefinisikan dalam file include (file header) dari masing-masing mikrokontroler. Dalam file include, Port B didefinisikan menggunakan baris berikut:

.EQU PORTB, 0x18

Port biasanya diorganisasikan dalam bilangan 8 bit, amaun juga dapat diakses sebagai 8 single bit. Bila single bit hendak digunakan, maka Anda dapat jhuga menggunakan nama yang didefinisikan dalam file include. Dengan mengikuti aturan penamaan tersebut, anda tidak perlu mengingat-ingat posisi bit tersebut dalam suatu port. Sebagai contoh, MCU General Control Register yang diberi nama MCUCR berisi sejumlah single contoh bit yang mengendalikan kerja mikrokontroler secara umum. MCUCR merupakan sebuah port yang dikemas dengan 8 control bit, dengan namanya masing-masing (ISC00, ISC01, . .). Sehingga apabila anda ingin membawa mikrokontroler Anda pada kondisi sleep, anda perlu tahu dari data sheet bagaimana anda harus mengeset bit yang bersangkutan.

.DEF my_setting = R16

1di my_setting = 0b00100000

out MCUCR, my_setting

sleep

Perintah OUT akan membawa isi register my_setting, yang berisi Sleep-Enable-Bit bernama SE, ke port MCUCR dan mengeset mikrokontroler ke kondisi sleep apabila perintah SLEEP dieksekusi.

Pada perintah diatas, seluruh isi register my_setting akan disalin ke MCUCR. Dari contoh di atas dapat anda lihat bahwa bit SE (bit5) berlogika “1”(set) sedangkan Sleep-Mode-Bit bernama SM (bit4) akan di-clear(“0”). Ini berakibat system masuk ke mode idle atau half-sleep (setengah tidut) yang akan membuat tidak ada eksekusi perintah berikutnya yang dilakukan, namun system tetap akan bereaksi terhadap interupsi timer dan interupsi eksternal lainnya. Mode sleep yang lain dalam AVR adalah mode power-down. Untuk masuk dalam mode ini, pertama SE harus diset dan bit SM juga harus diset. Apabila program mendapatkan instruksi SLEEP, maka mikrokontroler hanya bisa dibangunkan oleh reset eksternal, reset akibat WDT overflow atau interupsi eksternal pada NIT0 atau INT1.

Untuk membaca isi suatu port, Anda dapat menggunakan instruksi IN. Berikut ini contoh penggunaannya di dalam program.

.DEF my_read = R16

IN my_read, MCUCR

Penggalan program di atas akan membaca isi port MCUCR dan menyalinya dalam register my_read. Pada beberapa port, terdapat sejumlah bit yang tidak terdefinisikan atau tidak digunakan. Bila bit-bit tersebut dibaca, maka hasil yang diperoleh adalah nol (“0”).

Semakin sering Anda membaca port 8-bit, maka anda harus memperhatikan seluruh perubahan status port tersebut. Terkadang anda tidak perlu membaca keseluruhan isi port dan memisahkan bit yang berkaitan saja. Untuk keperluan ini, Anda dapat menggunakan instruksi yang tepat dan memberikan kesempatan untuk eksekusi perintah pada level bit tertentu. Mengeset atau meng-clear bit suatu port juga dapat Anda lakukan tanpa harus membaca dan menulis bit-bit lain dalam port tersebut. Perintah-perintah tersebut adalah SBI (Set Bit I/O) dan CBI (Clear Bit I/O). Contoh penggunaan instruksi ini adalah sebagai berikut:

.EQU ActiveBit = 2

SBI PortB, ActiveBit

CBI PortB, ActiveBit

Kedua instruksi di atas memiliki kelemahan, yakni hanya port yang berlokasi pada alamat kurang dari 0x20 yang dapat diakses. Port dengan alamat di atas 0x20 tidak dapat diakses menggunakan cara ini. Pada kasus lain, port dapat diakses dengan cara lain. Cara lain untuk mengakses port adalah dengan menggunakan perintah akses SRAM, seperti ST dan LD. Caranya adalah dengan menambahkan 0x20 pada alamat port. Berikut ini ditunjukkan cara pengaksesan tersebut.

.DEF my_port = R16

1di ZH, HIGH (PortB+32)

1di ZL, LOW (PortB+32)

1d my_Port, Z

Penggunaan cara diatas hanya pada khusus tertentu saja.

Mengakses SRAM

SRAM merupakan memori dalam mikrokontroler AVR yang tidak dapat diakses langsung dari CPU. Apabila Anda ingin mengakses lokasi memori ini, anda perlu menggunakan register sebagai media penyimpan sementara. Proses pengaksesan SRAM jelas memerlukan waktu yang lebih lama dibanding dengan pengaksesan register itu sendiri, karena register merupakan memori yang berada di dalam CPU. Namun disisi lain, tipe paling rendah dari AVR saja memiliki 128 byte SRAM, ukuran yang cukup besar disbanding dengan jumlah register yang hanya 32 buah. Pada AVR tipe AT90S8515 ke atas, terdapat fitur tambahan yang memungkinkan kita untuk menyambungkan dengan RAM eksternal guna memperbesar ukuran SRAM internal yang hanya 512 byte. Dari sudut pandang assembler, pengaksesan Ram eksternal sama persis dengan pengaksesan SRAM internal. Tidak ada perintah khusus yang diperuntukkan dalam pengaksesan RAM eksternal.

Terdapat berbagai kemudahan yang ditawarkan apabila kita menggunakan memori SRAM. Tidak hanya akses dengan alamat tetap yang diperbolehkan, tetapi kita juga dapat menggunakan pointer untuk mengakses lokasi memori. Dengan demikian, floating access terhadap beberapa lokasi dapat deprogram. Dengan cara ini, Anda dapat membangun sebuah ring buffer untuk penyimpanan sementara suatu nilai atau tabel kalkulasi. Hal ini ternyata tidak mungkin dilakukan apabila hanya menggunakan register.

Hal lain yang berhubungan dengan itu adalah akses dengan menggunakan sebuah offset pada suatu alamat awal yang tetap dalam satu register pointer. Dalam kasus ini, alamat tetap disimpan dalam register pointer, nilai konstanta ditambahkan pada alamat tersebut dan akses baca/tulis dilakukan pada alamat tersebut menggunakan sebuah offset.

Selanjutnya akan membicarakan penggunaan SRAM sebagai stack. Anda dapat melakukan push terhadap suatu nilai ke dalam stack, menjadi isi suatu register, mengembalikan alamat utama untuk pemanggilan subrutin atau mengembalikan alamat utama untuk sebuah interupsi yang dipicu hardware.

Dalam penggunaan SRAM, Anda perlu terlebih dahulu mendefinisikan alamat yang hendak Anda gunakan. Alamat SRAM yang dapat digunakan adalah mulai dari 0x0060 hingga batas akhir SRAM fisik dari jenis AVR yang anda gunakan.

Anda dapat menyalin isi register R1 ke dalam lokasi pertama SRAM dengan perintah berikut.

STS 0x0060, R1

Sedangkan untuk operasi sebaliknya, yaitu menyalin isi SRAM pada alamat 0x0060 ke dalam register R1, dapat anda lakukan dengan menggunakan perintah:

LDS R1, 0x0060

Untuk memudahkan Anda dalam melakukan Akses terhadap memori SRAM, Anda dapat memberi nama simbolik yang mudah diingat untuk alamat SRAM tersebut. Dengan cara ini, Anda tidak perlu lagi menuliskan bilangan heksa dari alamat 0x0060 Anda beri nama temp_satu. Anda dapat menuliskan dalam program sebagai berikut:

.EQU temp_satu = 0x0060

STS temp_satu, R1

Dengan penamaan seperti di atas, Anda akan lebih mudah untuk mengingat lokasi yang anda inginkan.

Cara pengaksesan SRAM yang lain adalah dengan menggunakan pointer. Untuk keperluan ini, Anda membutuhkan dua buah register yang digunakan untuk mengalamati 16-bit lokasi. Anda dapat menggunakan pasangan register X, Y, dan Z. Pasangan register tersebut mengizinkan kita untuk melakukan akses terhadap lokasi yang mereka tunjuk secara langsung (misalnya dengan ST X, r1), yang ditunjuk setelah nilai alamat di-decremen (misalnya dengan ST X, R1) atau dengan increment alamat (dengan ST +X, R1). Contoh pengaksesan tiga sel memori adalah sebagai berikut:

.EQU temp_satu = 0x0060

.DEG reg_satu = r1

.DEF reg_dua = R2

.DEF reg_tiga = R3

LDI XH, HIGH (temp_satu)

LDI XL, LOW (temp_satu)

LD reg_satu, X+

LD reg_dua, X+

LD reg_tiga, X

Bentuk ketiga merupakan bentuk pengaksesan yang cukup jarang dilakukan, misalkan saja kita sangat sering mengakses tiga buah lokasi SRAM. Sementara kita memiliki sisa pasangan register, kita akan berusahan untuk menggunakannya untuk keperluan tersebut. Bila kita menggunakan instruksi LD/ST, Anda harus selalu mengubah pointer apabila anda ingin mengakses lokasi yang lain. Hal itu sungguh tidak menyenangkan. Untuk menghindarinya, anda dapat menggunakan pengaksesan dengan offset, yang cukup membingungkan bagi para pemula. Selam akses berlangsung, isi register tidak pernah berubah. Alamat dihitung menggunakan penjumlahan sementara terhadap nilai offset yang tetap. Dari contoh di atas, pengaksesan lokasi 0x0062 akan tampak seperti berikut:

Pertama, pointer register kita gunakan menunjuk lokasi 0x0060.

.EQU temp_satu = 0x0060

.DEF reg_satu = R1

LDI YH, HIGH (temp_satu)

LDI YL, LOW (temp_satu)

[ . . . ]

Kemudian bila di suatu tempat dalam program kita hendak mengakses lokasi SRAM 0x0062, kita dapat menggunakan perintah berikut:

STD Y+2, reg_satu

Perhatikan bahwa 2 tidak hanya ditambahkan sementara terhadap Y. Penambahan sementara seperti ini tidak dapat dilakukan untuk pointer register X, hanya Y dan Z saja.

Perintah lain yang masih berhubungan degnan pengaksesan SRAM dengan menggunakan offset adalah seperti berikut:

LDD reg_satu, Y+2

SRAM juga umum digunakan sebagai stavk dalam program assembler. Stavk memiliki struktur LAST-In-First-Out, artinya yang terakhir masuk dalam stack akan menjadi yang pertama keluar. Untuk menggunakan SRAM sebagai stack, pertama ANDa perlu mendefinisikan stack pointer. Stack pointer merupakan pointer 16-bit, maka dapat diakses layaknya sebuah port. Kedua registernya bernama SPH:SPL. SPH merupakan byte atas (MSB), sedangkan SPL merupakan byte bawah (LSB). Hal ini hanya berlaku untuk AVR dengan kapasitas SRAM lebih dari 256 byte. Bila tidak, maka SPH tidak didefinisikan dan tidak dapat digunakan.

screenhunter_02-nov-05-1501.gif

 

Gambar 5.3 Metoda Penanganan Stack

Untuk membangun stack, stack pointer harus dimuati dengan alamat tertinggi SRAM.

.DEF reg_satu = R16

LDI reg_satu, HIGH (RAMEND)

OUT SPH, reg_satu

LDI reg_satu. LOW (RAMEND)

OUT SPL, reg_satu

Nilai RAMEND tentu saja tergantung pada jenis AVR yang anda gunakan. Nilai ini juga didefinisikan dalam file header standar masing-masing jenis AVR. Untuk file 2313def.inc, nilai ini dinyatakan dalam baris berikut:

.equ RAMEND = $xxx

File 2313def.inc dimasukkan dalam program yang anda buat menggunakan pengarah INCLUDE pada awal kode.

Penggunaan STACK

Menggunakan stack dalam program cukup mudah. Isi register didorong pada stack dengan perintah seperti berikut:

PUSH reg_satu

Apabila anda kini ingin mendapatkan isi register tadi, Anda cukup menuliskan perintah berikut:

POP reg_satu

Dengan instruksi POP, anda akan mendapatkan nilai yang terkhir didorong ke stack.

Perintah menggunakan PUSH dan POP hanya bermanfaat apabila isi register masih Anda perlukan pada baris lain berikutnya, semua register telah terpakai atau tidak terdapat tempat lain yang dapat anda gunakan untuk menyimpan nilai tersebut. Bila kondisi-kondisi tersebut tidak terpenuhi, maka penggunaan stack tidak akan bermanfaat dan hanya akan membuang waktu saja.

Penggunaan stack yang lain adalah pada saat Anda memanggil suatu subrutin. Dalam hal ini, stack akan anda perlukan untuk menyimpan lokasi di mana anda memanggil suatu subrutin. Alamat tersebut nantinya akan digunakan untuk kembali lagi setelah subrutin selesai dieksekusi. Pada saat program memanggila suatu subrutin, maka alamat tersebut akan didorong ke stack menggunakan instruksi PUSH dan setelah subrutin selesai dieksekusi, alamat dalam stack akan dimunculkan kembali menggunakan instruksi POP. Eksekusi program kemudian akan dilanjutkan tepat pada instruksi setelah instruksi pemanggilan subrutin berada.

RCALL subrutin1

[…] program selanjutnya berada

subrutin1: ;subrutin yang dipanggil1

[…]melakukan sesuatu

[…]ingin kembali

RET

Selama mengeksekusi instruksi RCALL sementara PC telah di increment, alamat 16-bit didorong ke stack. Setelah Program menemukan instruksi RET, isi program counter dimuati kembali dengan alamat dalam stack.

Penanganan interupsi hardware tidak mungkin dilakukan tanpa stack. Interupsi akan memotong aliran eksekusi program, apapun yang sedang dilakukan saat itu. Program lalau menuju pada rutin interupsi dan mengeksekusinya. Setelah itu, program harus kembali ke lokasi sebelum terjadinya interupsi untuk melanjutkan pekerjaannya. Hal ini memerlukan suatu tempat penyimpanan sementara, yaitu stack.

Dalam menggunakan stack, seringkali terjadi berbagai masalah, terutama bagi anda yang belum terbiasa dengan stack. Cara pintar untuk menggunakan stack adalah menggunakan tanpa harus mengatur stack pointer. Karena jika pointer ini diset ke nol “0” pada awal program, pointer akan menunjuk pada register R0.

Kondisi Reset

Pad saat catu daya mikrokontroler ON, maka mikrokontroler akan mulai bekerja dari kondisi reset. Program counter akan menunjuk nilai nol dank ode pada alamat pertama memori program akan dieksekusi. Selain pada saat pertama catu daya dihidupkan, terhadap beberapa keadaan yang membuat PC bernilai nol dan masuk pada kondisi reset. Hal-hal berikut akan membawa program dalam mikrokontroler masuk ke dalam kondisi reset:

1. Pada saat Power ON.

2. Saat reset eksternal terjadi, yaitu ketika pin reset diaktifkan.

3. Pada saat Watchdog Timer mencapai nilai maksimum (overflow). Watchdog Timer merupakan pewaktu independent yang harus anda reset dari waktu ke waktu sebelum mencapai nilai maksimum, jika tidak maka mikroprosesor akan restart.

Reset mokrokontroler yang diakibatkan oleh WDT terjadi apabila WDT dienable melalui program dan isi WDT mencapai nilai maksimum. Dalam kondisi default, WDT tidak aktif (disable). Untuk mengenabel WDT, diperlukan suatu perintah terhadap port WDT. Sedangkan untuk mencegah terjadinya reset akibat WDT mencapai nilai maksimum, maka Anda harus mengembalikan nilai WDT menjadi nol sebelum mencapai nilai maksimum. Hal itu dapat anda lakukan dengan menggunakan perintah WDR.

Sesudah eksekusi reset, yang akan membuat semua register dan port dalam keadaan default, kode pada alamat 0000 akan dieksekusi. Selama eksekusi, PC akan sudah di-incremen dank ode berikutnya akan dibaca untuk dipegang pada fetch buffer. Teknik ini dinamakan fetch during execution. Dengan teknik inilah satu clock osilator untuk setiap kode, kecuali untuk percabangan dan lompatan. Ini sungguh sangat mengagumkan.

Perintah pertama yang akan dieksekusi selalu berlokasi pada alamat 0000. Untuk mengatakan pad software assembler bahwa program yang anda buat dimulau dari alamat ini, anda dapat menggunakan pengarah CSEG dan ORG. Penulisannya dalam program adalah seperti berikut:

.CSEG

.ORG 0000

Pengarah yang pertama, menyatakan bahwa assembler berada pada kode segment. Sedangkan pengarah ORG akan menyatakan, bahwa kode setelah pengarah ini akan dituliskan pada alamat 0000 dalam Memori program. Bila program anda akan dimulai dari alamat 0000, maka penggunaan kode pengarah ini tidak mutlak. Anda dapat membuangnya tanpa akan mendapatkan error. Namun bila anda menghendaki program anda dimulai pada alamat lain, maka anda perlu menuliskannya. Pengarah ORG juga dapat anda gunakan pada saat Anda ingin membuat suatu tabel data pada code segment.

Seperti telah disampaikan sebelumnya, kode pertama selalu dimulai dari alamat 0000. Alamat 0000 ini juga disebut sebagai reset vector yang merupakan alamat yang akandituju apabila terjadi kondisi reset. Beberapa alamat sesudah reset vector merupakan interrupt vector, misalnya 0001, 0002, dan seterusnya. Interrupt vector merupakan alamat yang akan dituju apabila interrupt diijinkan dan kemudianinterrupt tersebut terjadi. Posisi yang disebut sebagai vector mungkin akan berbeda untuk masing-masing AVR dan bergantung pada ada/tidaknya interrupt internal dan eksternal. Perintah untuk menangani terjadinya interupsi harus ditempatkan pada vector interupsi. Bila anda menggunakan interupsi, maka kode pertama dalam reset vector harus merupakan perintah lompatan. Hal ini agar program yang anda jalankan tidak mengeksekusi rutin interupsi sebelum terjadinya interupsi yang anda inginkan. Demikian juga dengan perintah pada vector interrupsi, mestinya juga merupakan perintah lompatan menuju rutin interupsi yang anda inginkan dan dapat anda tempatkan pada bagaian lain program yang bukan merupakan vector interupsi.

Bentuk umum rangkaian program yang biasa digunakan adalah sebagai berikut:

.CSEG

.ORG 0000

RJMP Start

RJMP Rutin_Int1

RJMP Rutin_Int2

[…disini merupakan tempat untuk vector interupsi yang lain…]

Rutin_Int1:

[…berisi rutin program untuk penanganan interupsi1…]

Rutin_Int2:

[…berisi rutin program untuk interusi2…]

[…Rutin Interupsi yang lain…]

Start: ; Di sini awal dari program anda

[…program utama anda berada…]

.EXIT

Perintah RJMP akan menghasilkan lompatan nemuju label yang ditunjuk. Nama label diakhiri dengan tanda titik dua (“:”).

Aliran program dan linier, kecuali bila terdapat perubahan rangkaian eksekusi. Perubahan rangkaian eksekusi dapat terjadi apabila program menemukan kondisi percabangan atau interupsi. Percabangan merupakan hal yang sangat lazim digunakan dan terjadi apabila salah satu kondisi dalam percabangan bersyarat terjadi.

Sebagai contoh, anda hendak membuat pencacah 32-bit menggunakan empat register, R1 hingga R4. Lest significant byte dalam R1 di-incrfemen. Setiap kali register R1 overflow saat operasi increment tersebut (yakni ketika dicapai nilai 255+1=0), maka anda harus increment register R2. Begitu seterusnya sampai R4.

Untuk melakukan increment pada saat register, anda dapat menggunakan instruksi INC. Apabila terjadi overflow saat eksekusi INC R1, bit Z (zero) dalam status register akan diset :1:. Bit C yang diset ketika overflow tidak akan berubah selama eksekusi INC. Zero bit dan Zero-flag cukup untuk anda gunakan untuk mendeteksi terjadinya overflow.

Bila Zero-bit diset, Anda harus melakukan eksekusi increment tambahan terhadap register yang lain. Interupsi percabangan yang dapat kita gunakan adalah BRNE ((Branch if Not Equal). Selain BRNE, terdapat instruksi percabangan lain yaitu BRNZ (Branch if not Zero).

Penggalan program untuk melakukan pencacahan naik 32-bit tampak seperti berikut:

Count 32:

INC R1

BRNE Count 32

INC R2

BRNE Count 32

INC R3

BRNE Count 32

INC R4

Instruksi percabangan yang merupakan kebalikan BRNE adalah BREQ (BRanch if Equal).

Untuk melakukan percabangan, anda tidak harus menggunakan instruksi-instruksi percabangan di atas yang mengacu pada perubahan Zero-bit. Anda dapat pula menggunakan bit status yang menggunakan bit status yang lain untuk melakukan percabangan. Berikut ini instruksi-instruksi percabangan dalam AVR.

Tabel 5.3 Daftar Instruksi percabangan dan Kondisi yang mempengaruhinya.

INSTRUKSI

OPERAN

DESKRIPSI

FLAG

CPSE

Rd, Rr

Compare, skip if Equal

Z

CP

Rd, Rr

Compare

Z

CPC

Rd, Rr

Compare with Carry

Z

CPI

Rd, k

Compare Register with Immediate

Z

SBRC

Rr, b

Skip if Bit in Register Cleared

Rr(b)

SBRS

Rr, b

Skip if Bit in Register is Set

Rr(b)

SBIC

P, b

Skip if Bit in I/O Register Cleared

I/O(P,b)

SBIS

P, b

Skip if Bit in I/O is Set

I/O(P,b)

BRBS

S, k

Branch is status Flag Set

S

BRBC

S, k

Branch is status Flag Clear

S

BREQ

K

Branch if Equal

Z

BRNE

K

Branch if Not Equal

Z

BRCS

K

Branch if Carry Set

C

BRCC

K

Branch if Carry Cleared

C

BRSH

K

Branch if Same or Higher

C

BRLO

K

Branch if Lower

C

BRMI

K

Branch if Minus

N

BRPL

K

Branch if Plus

N

BRGE

K

Branch if Greater or Equal, Signed

N,v

BRLT

K

Branch if Less Than Zero, Signed

N,v

BRHS

K

Branch if Half-carry Flag Set

H

BRHC

K

Branch if Half-carry Flag Cleared

H

BRTS

K

Branch if T-Flag Set

T

BRTC

K

Branch if T-Flag Cleared

T

BRVS

K

Branch if Overflow Flag is Set

V

BRVS

K

Branch if Overflow Flag is Cleared

V

BRIE

K

Branch if Interrupt Enabled

I

BRID

K

Branch if Interupt Disabled

I

Pewaktuan Eksekusi Program

Salah satu kelebihan AVR disbanding mikrokontroler yang lain terletak pada kecepatannya dalam melakukan eksekusi program. AVR membutuhkan waktu satu siklus clock untuk melakukan eksekusi terhadap satu instruksi. Bila AVR bekerja pada clock input 4 MHz, maka waktu satu siklus instruksi adalah 250 ns, sedangkan bila anda memasang kristal osilator 10 MHz sebagai clock input, waktu yang dibutuhkan untuk melakukan eksekusi sebuah instruksi adalah 100 ns. Waktu yang dibutuhkan untuk mengeksekusi sebuah instruksi dinamakan waktu siklus instruksi (instruction clyces time), yang nilainya bergantung pada kristal yang anda gunakan sebagai input clock. Namun demikian, Anda perlu tahu bahwa terdapat beberapa instruksi yang membutuhkan lebih dari satu instruksi, yaitu untuk instruksi percabangan atau lompatan. Instruksi-instruksi tersebut mungkin membutuhkan lebih dari satu siklus instruksi (bila percabangan dilakukan).

Apabila anda ingin membuat program anda melakukan dengan waktu yang tepat, mungkin anda akan memerlukan instruksi NOP. Instruksi ini tidak akan mengerjakan apapun, kecuali hanya melewatkan waktu eksekusi saja. Instruksi NOP (No Operation), dapat digunakan untuk membuat sebuah delay (tunda) pendek.

Misalkan anda bekerja dengan clock input 4 MHz dan Anda menghendaki delay 1 us, anda dapat menggunakan instruksi NOP dengan menempatkannya dalam program sebanyak empat buah.

NOP

NOP

NOP

NOP

Namun bila Anda hendak membuat delay 1 ms, tidak berarti anda harus menggunakan instruksi ini sebanyak 4000 buah. Hal ini merupakan hal bodoh dan hanya menyita ruang dalam Memori Program. Yang perlu anda lakukan hanyalah membuat sebuah delay menggunakan pencacah dan beberapa instruksi percabangan. Dengan element tersebut, anda dapat membuat suatu loop dimana waktu eksekusi yang diperlukan senilai dengan delay yang anda inginkan. Pada prinsipnya, delay menggunakan loop dibangun menggunakan pencacah yang akan menghitung naik atau turun dan apabila suatu kondisi di capai, maka program akan keluar dari loop tersebut.

Sebagai contoh, kita akan membuat suatu delay menggunakan pencacah 8-bit.

CLR R1

Count:

DEC R1

BREQ Count

Pencacah 16-bit juga dapat anda gunakan untuk membuat suatu delay dengan tepat, misalkan seperti ini:

LDI ZH, HIGH (65535)

LDI ZH, LOW (65535)

Count :

SBWIN ZL, 1

BRNE Count

Hal yang perlu anda perhatikan dalam membangaun suatu delay adalah menghitung berapa siklus instruksi yang dilakukan untuk menyelesaikan delay tersebut. Hal ini terkadang cukup membuat kita pusing. Ingat bahwa eksekusi instruksi lompatan dapat membutuhkan waktu lebih dari satu siklus instruksi. Anda harus Melakukan kalkulasi terhadap semua proses eksekusi, yang semestinya dapat dirumuskan dengan persamaan tertentu sesuai dengan model loop yang anda buat. Apabila anda menginginkan kemudahan dalam menghitung lama waktu delay, anda dapat mengujinya menggunakan simulator ataupun software assembler/compiler yang dilengkapi dengan penghitung waktu instruksi.

Macro

Apabila anda sering menggunakan suatu runtun program tertentu di dalam program anda, maka rangkaian program tersebut tidak harus selalu anda tuliskan aetiap kali anda membutuhkannya. Anda dapat menjadikan rangkaian program tersebut sebagai suatu makro dan anda dapat menggunakannya beberapa kali dalam program seperti yang anda inginkan. Untuk menggunakan suatu makro, Anda cukup memanggil namanya saja.

Makro merupakan suatu rangkaian kode program yang berisi instruksi-instruksi, yang dapat anda gunakan kembali dalam program dengan hanya menyebutkan namanya saja. Sebagai contoh, kita akan membuat sebuah macro yang merupakan delay 1 us pada clock 4 MHz dengan nama Delay1.

.MACRO Delay1

NOP

NOP

NOP

NOP

.ENDMACRO

Makro tersebut dapat anda panggil bila anda membutuhkan suatu delay 1 us tanpa harus menuliskan kembali kode program yang sama.

[…instruksi-instruksi dalam program anda…]

Delay1

[…instruksi-instruksi berikutnya…]

Delay1 ;Anda kembali ingin menggunakan delay1

[…selanjutnya lagi…]

Dengan cara ini, maka delay1 yang berisi 4 buah NOP akan dimasukkan dalam kode sumber program saat proses asembli/kompilasi.

Penggunaan macro, pada dasarnya hanya memberikan kemudahan dalam penulisan dan editing kode sumber program yang Anda buat. Dari segi software Asembler, penggunaan makro tidak memberikan keuntungan yang berarti.

Apalagi ruang memori AVR anda cukup terbatas, penggunaan makro tidak begitu dianjurkan. Dalam kasus ini, anda sebaiknya menggunakan subrutin yang dapat anda panggil setiap waktu. Penggunaan subrutin akan sangat menghemat ruang memori program pada AVR anda.

Terdapat perbedaan yang cukup mendasar antara macro dan subrutin. Pada penggunaan macro, kode akan tetap dituliskan dalam Memori Program setiap nama macro disebutkan, sedangkan pada subrutin hanya dituliskan sekali dalam Memori Program. Bila subrutin hendak digunakan, yang perlu anda lakukan adalah memanggilnya dengan instruksi RCALL.

Untuk subrutin delay 10 siklus instruksi, anda dapat menuliskan rangkaian perintah berikut ini:

Delay10:

NOP

NOP

NOP

RET

Sebuah subrutin harus diawali dengan label dan diakhiri dengan instruksi RET. Sedangkan RET1 digunakan untuk mengakhiri rutin instrupsi.

Dalam contoh di atas subrutin Delay10 hanya terdapat 3 buah instruksi NOP dan sebuah instruksi RET. Sepuluh siklus eksekusi diperoleh dari kalkulasi seluruh eksekusi instruksi tersebut. Sepuluh siklus instruksi tersebut diperoleh dari 3 siklus untuk NOP dan 4 siklus untuk RET. Sisanya, yaitu 3 siklus digunakan untuk memanggil subrutin tersebut.

Pemanggilan subrutin Delay10 dilakukan seperti berikut ini:

[…perintah dalam program anda…]

RCAAL Delay10 ;memanggila subrutin Delay10

[…perintah lain berikutnya…]

Instruksi RCAAL berarti memanggil suatu alamat relative tertentu, yaitu yang dinyatakan dengan label. Jarak relative lompatandari pemanggilan ini akan dihitung oleh assembler/compiler. Pada penggunaan subrutin, eksekusi program akan mengalami lompatan menuju subrutin yang dipanggila dan setelah eksekusi terhadap subrutin tersebut selesai (menemukan instruksi RET), aliran program akan kembali meneruskan perintah berikutnya.

Bila anda ingin menuju suatu lokasi tertentu dalam program, anda dapat menggunakan instruksi RJMP (Relative JuMP). Instruksi RCAAL dan RJMP merupakan instruksi percabangan tidak beryarat , yang akan mengalihkan aliran program tanpa mensyaratkan kondisi tertentu. Instruksi RJMP tidak dapat digunakan untuk memanggil suatu subrutin, karena instruksi ini tidak melakukan pendorongan PC ke Stack yang mengakibatkan ketika ditemui instruksi RET, program tidak dapat mendapatkan kembali nilai PC sebelumnya (saat eksekusi RJMP).

Ilustrasi pemanggilan subrutin dengan RCALL dan lompatan menggunakan RJMP ditunjukkan dalam gambar 5.4.

screenhunter_03-nov-05-1505.gif

Gambar 5.4 Aliran Program Untuk RCALL dan RJMP

Percabangan Bersyarat

Untuk melakukan percabangan dengan memperhatikan kondisi tertentu, Anda perlu menggunakan instruksi percabangan bersyarat. Instruksi percabangan bersarat akan melakukan lompatan menuju suatu rangkaian program (berlabel) apabila suatu kondisi dipenuhi atau suatu kondisi tidak dipenuhi. Apabila anda ingin memanggil suatu subruti, dengan syarat suatu kondisi terepenuhi, anda dapat menggunakan perintah seperti berikut:

SBRC R1, 7 ; Lewati instruksi berikutnya bila bit7, R1 “0”

RCALL Delay10 ; Panggil Rutin Delay10

[…instruksi berikutnya…]

Instruksi SBRC (Skip next instruction if Bit in Register is Clear) merupakan instruksi pengecek kondisi bit dari suatu register. Instruksi ini akan melewatkan satu instruksi berikutnya apabila bit b yang register Rx berlogika nol (“0”). Dalam contoh diatas, RCALL hanya akan dieksekusi apabila bit 7 dalam register R1 berlogika “0”. Bila bit 7 dalam register R1 berlogika “1”maka perintah RCALL tidak akan dieksekusi, yang berarti subrutin delay10 tidak akan dipanggil.

Bila anda menghendaki sebaliknya, yakni subrutin Delay10 hanya dieksekusi apabila bit7 dalam register R1 berlogika “1”, maka anda dapat menggunakan instruksi lai yang serupa, yaitu SBRS (Skip next instruction if Bit in Register is Set).

Instruksi percabangan bersyarat yang lain adalah CPSE (Compare two registers, and Skip next instruction if Equal).

CPSE R1, R2 ; Compare R1 and R2, skip if equal

RCALL SomeSubroutine ; Call SomeSubroutine

Anda juga dapat melakukan percabangan bersyarat berdasarkan kondisi bit tertentu didalam port. Instruksi yang dapat anda gunakan adalah SBIC atau SBIC. SBIC (Skip next instruction if Bit in I/O space is Clear) berarti lewatkan satu instruksi berikutnya apabila bit b pada port berlogika “0”. Sebaliknya, instruksi SBIS akan melewatkan satu instruksi berikutnya apabila bit dalam port yang ditunjuk berlogika “1”.

SBIC PortB, 0 ; Lewati instruksi berikutnya bila bit0, portB “0”

RJMP ATarget ; Jump to the label ATarget

Dalam contoh di atas, instruksi RJMP hanya akan dieksekusi apabila bit 0 dalam portB berlogika “0”. Untuk menggunakan Instruksi ini, anda perlu mengetahui, bahwa hanya 16 port pertama yang dapat dilakukan akses per bit-nya.

Interupsi

Apabila anda membuat suatu aplikasi mikrokontroler, tentunya anda menghendaki agar system tersebut dapat berinteraksi dengan dunia luar. Sebagai contoh, anda tentu akan lebih menyukai aplikasi yang dapat memberi respon ketika anda beri masukan dari pada salah satu pin, dari pada system yang hanya melakukan suatu pola kegiatan yang tidak memperdulikan input yang anda berikan. Agar suatu system aplikasi yang anda buat dapat bereaksi terhadap input yang diberikan, anda dapat menggunakan metoda polling atau dengan menggunakan interupsi. Metoda polling merupakan cara pengecekan terhadap adanya suatu perubahan kondisi dengan menggunakan suatu loop. Dengan bahasa yang labih sederhana, metoda polling akan mengecek suatu pin input atau status lain secara rutin selama menjalankan pekerjaan utamanya. Namun bila masukan yang terjadi berupa suatu pulsa yang sangat pendek, sedangkan periode pengecekan dari polling relative lama, maka perubahan input tadi bisa saja terdeteksi. Agar perubahan kondisi yang terjadi dapat selalu terdeteksi, penggunaan interupsi merupakan solusi yang sangat tepat.

Interupsi dalam mikrokontroler merupakan cara bagaimana system memberikan respon terhadap suatu kondisi masukan tertentu, ketika proses pekerjaan sedang berlangsung. Apabila eksekusi dienable dan terjadi suatu interupsi, system akan meninggalkan pekerjaannya, menuju pada rutin penanganan interupsi yang sesuai dan setelah selesai selesai akan kembali melanjutkan pekerjaan.

Interupsi dapat terjadi akibat dipicu oleh adanya trigger dari input internal maupun interupsi eksternal hardware. Untuk menggunakan interupsi dalam system aplikasi Anda, hal pertama harus anda lakukan adalah enable interupsi flag. AVR memiliki satu bit untuk enable interupsi yang bernama Interrupt Enable Flag. Bit ini dapat anda set dengan menggunakan perintah SEI (Set Enable Interrupt).

Apabila kondisi terjadi, misalnya terjadi perubahan pada bit port, mikrokontroler akan mendorong nilai PC ke dalam stack. Bila tidak, maka mikrokontroler tidak akan dapat kembali pada lokasi ketika terjadinya interupsi, yang berada dapat kembali pada lokasi ketika terjadinya interupsi, ;yang dapat berada di mana saja dan kapan saja. Setelah menyelesaikan rutin interupsi, program akan melanjutkan pekerjaannya. Terjadinya interupsi, akan membawa program menuju vector interupsi yang sesuai. Biasanya, kode yang terdapat dalam vector interupsi adalah intruksi JUMP untuk mengarahkan program menuju rutin interupsi yang telah dibuat. Vector interupsi merupakan lokasi kusus yang akan dituju oleh program apabila terjadi interupsi dan hal itu tergantung pada komponen hardware dan kondisi-kondisi yang hendak ditangani dengan interupsi. Semakin banyak komponen hardware dan kondisi interupsi yang dapat ditangani, akan semakin banyak vector interupsi. Daftar vector intrupsi untuk beberapa tipe AVR ditunjukkan dalam tabel berikut.

Dari data di atas tampak bahwa masing-masing tipe AVR memiliki perbedaan kemampuan untuk menangani interupsi. Semakin atas, interupsi di atas memiliki prioritas yang semakin tinggi. Apabila dua buah interupsi terjadi bersamaan, maka interupsi dengan alamat yang lebih rendah yang akan ditangani terlebih dahulu. Interupsi dengan vector interupsi yang lebih tinggi harus menunggu sampai interupsi dengan prioritas lebih tinggi diselesaikan. Untuk mendisable terjadinya interupsi yang lebih rendah, dalam rutin interupsi harus memuat program untuk mendisable flag Interupsi.

Tabel 5.4 Interrupt Vector Untuk Beberapa AVR

Name

Int Vector Adress

Triggered by …

2313

2323

8515

RESET

0000

0000

0000

Hardware Reset, Power-on Reset, Watchdog Reset

INTO

0001

0001

0001

Level change on the external INT0-Pin

INT1

0002

0002

Level change on the external INT1-Pin

TIMER1 CAPT

0003

0003

Capture event on Timer 1

TIMER1 COMPA

0004

Timer1= Compore A

TIMER1 COMPB

0005

Timer1= Compore B

TIMER1 COMP1

0004

Timer1= Compore 1

TIMER1 OVF

0005

0006

Timer1 Overflow

TIMER0 OVF

0006

0002

0007

Timer0 Overflow

SPI STC

0008

Serial transmit complete

UART RX

0007

0009

UART char in receive buffer available

UART UDRE

0008

000A

UART transmitter ran empty

UART TX

0009

000B

UART All sent

ANA COMP

000C

Analog Comparator

Bila pekerjaan dalam rutin interupsi telah selesai, dalam bagian akhir rutin interupsi harus terdapat kode untuk mengenabel kembali flag tersebut. Untuk mengeset ulang bit I-status dapat dilakukan dengan dua cara. Yang pertama dengan instruksi RETI dan yang kedua menggunakan SEI/RET.

RETI

Atau dengan

SET

RET

Cara kedua berbeda dengan cara pertama. Untuk mudahnya, sebaiknya anda gunakan cara pertama, yaitu dengan RETI.

Hal yang sangat penting dalam penggunaannya adalah bagaimana mengamankan data dan kondisi-kondisi sebelum terjadinya interupsi, sehingga tidak hilang atau berubah akibat pelaksanaan rutin interupsi. Oleh karena itu, instruksi pertama dalam rutin interupsi harus merupakan instruksi untuk menyimpan isi register ke stack dan instruksi terakhir sebelum RETI merupakan instruksi untuk memunculkannya kembali dari stack.

.CSEG ; Code_Segment, mulai di sini

.ORG 0000 ; Alamat 0000

RJMP Mulai ; Reset vector 0000

RJMP IService ; 0001=Int-Vektor pertama, INTO service routine

[…] vector interupsi yang lain

Mulai: ; Di sini program utama dimulai

[…]

IService: ; Here we start with the Interrupt-Service-Routine

PUSH R16; save a registr to stack

IN R16, SREG; read status register

PUSH R16; and put on stack

[…] Here the Int-Service-Routine does something and uses R16

POP R16; get previous flag register from stack

OUT SREG,R16 ; restore old status

POP R16; get previous content of R16 from the stack

RETI ; and return from int

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: