Categories
Mikrokontroler

C vs Assembly MCS-51: Kasus LED Flip-flop

Jika Anda memiliki dan sudah membaca atau mempelajari buku saya (Belajar Mikrokontroler AT89C51/52/55), tentunya Anda masih inget dengan program pertama yang saya tulis dengan tujuan untuk menghidupkan dan mematikan LED secara flip-flop atau bergantian yang terpasang di P1. Berikut saya sertakan lagi program ASM-nya:

;-- BAB3_01.ASM -----------------------------------------------------------
;
; Lampu flip-flop pada Port 1
;
;--------------------------------------------------------------------------
        ORG   0H        ; program ditempatkan pada lokasi 0000H
;
MULAI:  MOV   P1,#10101010B     ; LED P1.4 s/d P1.7 nyala (heksa= #0FH)
        ACALL DELAY             ; lakukan penundaan sesaat (sub. DELAY)
        MOV   P1,#01010101B     ; LED P1.0 s/d P1.3 nyala (heksa= #0F0H)
        ACALL DELAY             ; lakukan penundaan sesaat (sub. DELAY)
        SJMP  MULAI             ; ulangi lagi dari awal
;
;-subrutin DELAY-----------------------------------------------------------
;
; subrutin ini hanya sekedar melakukan penundaan sesaat dengan cara
; mengulangi proses (pengurangan isi register) hingga dicapai suatu
; kondisi tertentu
;
;--------------------------------------------------------------------------
DELAY:  MOV   R0,#5H            ; Isi Register R0 dengan 5 (5x ulang)
DELAY1: MOV   R1,#0FFH          ; Isi Register R1 dengan 255 (255x ulang
DELAY2: MOV   R2,#0             ; Isi register R2 dengan 0 (256x ulang)
        DJNZ  R2,$              ; R2=R2-1, jika R2 belum 0 ulangi lagi
        DJNZ  R1,DELAY2         ; R1=R1-1, jika R1 belum 0 ulangi DELAY2
        DJNZ  R0,DELAY1         ; R0=R0-1, jika R0 belum 0 ulangi DELAY1
        RET                     ; Kembali ke pemanggil subrutin DELAY

        END

Kali ini saya tulis dalam Bahasa C menggunakan kompiler MikroC untuk mikrokontroler AT89S8252 dengan frekuensi kristal 12 MHz. Berikut program dalam Bahasa C-nya…

void main() {
     P1 = 0b10101010;
     Delay_ms(500);
     P1 = 0b01010101;
     Delay_ms(500);
}

Saat disimulasikan maupun dicoba hasilnya sama persis, kecuali masalah tundaan yang berbeda, tetapi konsepnya sama semua yaitu menghidupkan dan mematikan lampu LED secara flip-flop (atau bergantian). Namun apa yang terjadi dengan hasil kompilasi program Bahasa C-nya, mau tahu? Jangan kaget, inilah hasilnya:

_main:
    MOV 129, #128
;bab3_01.c,1 ::         void main() {
;bab3_01.c,2 ::         P1 = 0b10101010;
    MOV 144, #170
;bab3_01.c,3 ::         Delay_ms(500);
    MOV R5, 2
    MOV R6, 255
    MOV R7, 255
    NOP
    DJNZ R7, -3
    DJNZ R6, -7
    DJNZ R5, -11
    MOV R6, 255
    MOV R7, 255
    NOP
    DJNZ R7, -3
    DJNZ R6, -7
    MOV R6, 141
    MOV R7, 255
    NOP
    DJNZ R7, -3
    DJNZ R6, -7
    MOV R7, 8
    NOP
    DJNZ R7, -3
    NOP
    NOP
;bab3_01.c,4 ::         P1 = 0b01010101;
    MOV 144, #85
;bab3_01.c,5 ::         Delay_ms(500);
    MOV R5, 2
    MOV R6, 255
    MOV R7, 255
    NOP
    DJNZ R7, -3
    DJNZ R6, -7
    DJNZ R5, -11
    MOV R6, 255
    MOV R7, 255
    NOP
    DJNZ R7, -3
    DJNZ R6, -7
    MOV R6, 141
    MOV R7, 255
    NOP
    DJNZ R7, -3
    DJNZ R6, -7
    MOV R7, 8
    NOP
    DJNZ R7, -3
    NOP
    NOP
;bab3_01.c,6 ::         }
    SJMP #254
; end of _main

Wow, ternyata pemanggilan fungsi Delay_ms(500) di-implementasikan begitu saja, tidak ada pengubahan ke dalam bentuk sub-rutin, sehingga bisa Anda bayangkan begitu panjang programnya, padahal penggunaan Delay_ms(500) 2 kali menghasilkan 2 rentetan instruksi yang sama persis! Serta bukan menggunakan pewaktu tetapi permainan register di dalam AT89. Bagaimana kalau program Bahasa C-nya saya ubah menjadi…

void tunda_donk() {
     Delay_ms(500);
}
void main() {
     P1 = 0b10101010;
     tunda_donk();
     P1 = 0b01010101;
     tunda_donk();
}

Hasilnya? Ini dia, berbeda dengan sebelumnya…

_tunda_donk:
;bab3_01a.c,1 ::         void tunda_donk() {
;bab3_01a.c,2 ::         Delay_ms(500);
    MOV R5, 2
    MOV R6, 255
    MOV R7, 255
    NOP
    DJNZ R7, -3
    DJNZ R6, -7
    DJNZ R5, -11
    MOV R6, 255
    MOV R7, 255
    NOP
    DJNZ R7, -3
    DJNZ R6, -7
    MOV R6, 141
    MOV R7, 255
    NOP
    DJNZ R7, -3
    DJNZ R6, -7
    MOV R7, 8
    NOP
    DJNZ R7, -3
    NOP
    NOP
;bab3_01a.c,3 ::         }
    RET
; end of _tunda_donk

_main:
    MOV 129, #128
;bab3_01a.c,4 ::         void main() {
;bab3_01a.c,5 ::         P1 = 0b10101010;
    MOV 144, #170
;bab3_01a.c,6 ::         tunda_donk();
    LCALL _tunda_donk+0
;bab3_01a.c,7 ::         P1 = 0b01010101;
    MOV 144, #85
;bab3_01a.c,8 ::         tunda_donk();
    LCALL _tunda_donk+0
;bab3_01a.c,9 ::         }
    SJMP #254
; end of _main

Sekarang terbentuklah subrutin dalam ASM-nya, sehingga tidak ada 2 rentetan istruksi yang sama seperti ditemukan sebelumnya. Hal-hal seperti inilah yang harus kita perhatikan jika menuliskan program untuk mikrokontroler (apa saja) menggunakan bahasa Tingkat Tinggi (seperti C, BASIC, dll) agar bisa diperoleh program yang optimal dan baik. Keunikan lain dari Bahasa C vs Assembly bisa Anda di artikel “C vs Assembly MCS-51: Kasus unik Aritmetika!“.

Semoga bermanfaat!