UTS_Rivaldi

Program untuk UTS
 avatar
unknown
assembly_x86
5 days ago
11 kB
9
Indexable
; =====================================================================
; Project: ATmega328 3-Digit 7-Segment Display with Interrupt Buttons
; Target : ATmega328
; Clock  : 1 MHz (External or Internal RC calibrated)
; IDE    : Microchip Studio
; Author : M. Fajar Rivaldi NIM 04221001(Balikpapan)
; Date   : 2025-04-16 (Waktu Balikpapan)
; =====================================================================

.INCLUDE "m328def.inc" ; Definisi register untuk ATmega328

; --- Definisi Register ---
.DEF temp       = r16 ; Register serbaguna
.DEF result     = r17 ; Menyimpan hasil perhitungan (+10 atau -10)
.DEF disp_val   = r18 ; Menyimpan nilai absolut untuk konversi digit
.DEF digit1_pat = r19 ; Pola segmen untuk digit 1 (tanda/-)
.DEF digit2_pat = r20 ; Pola segmen untuk digit 2 (puluhan)
.DEF digit3_pat = r21 ; Pola segmen untuk digit 3 (satuan)
.DEF d_tens     = r22 ; Digit puluhan (0-9)
.DEF d_units    = r23 ; Digit satuan (0-9)
.DEF temp2      = r24 ; Register serbaguna tambahan
.DEF dly_cnt_1  = r25 ; Counter delay 1 (untuk Delay_10ms)
.DEF dly_cnt_2  = r26 ; Counter delay 2 (untuk Delay_10ms)

; --- Definisi Konstanta ---
.EQU SEG_A = 6
.EQU SEG_B = 5
.EQU SEG_C = 4
.EQU SEG_D = 3
.EQU SEG_E = 2
.EQU SEG_F = 1
.EQU SEG_G = 0
.EQU SS1_PIN = PB3 ; Digit 1 (Tanda) Control Pin (Active LOW)
.EQU SS2_PIN = PB2 ; Digit 2 (Puluhan) Control Pin (Active LOW)
.EQU SS3_PIN = PB1 ; Digit 3 (Satuan) Control Pin (Active LOW)
.EQU BTN1_PIN = PD2 ; Button 1 (INT0) -> +10
.EQU BTN2_PIN = PD3 ; Button 2 (INT1) -> -10
.EQU SEG_MINUS = (1<<SEG_G) ; Pola untuk tanda '-' (hanya segmen G)
.EQU SEG_BLANK = 0x00       ; Pola untuk blank
.EQU ALL_DIGITS_OFF = (1<<SS1_PIN)|(1<<SS2_PIN)|(1<<SS3_PIN) ; Masker untuk mematikan semua digit

; --- Alokasi Memori Data (SRAM) ---
.DSEG
current_digit: .BYTE 1 ; Variabel di SRAM untuk melacak digit aktif (1, 2, atau 3)

; --- Segmen Kode ---
.CSEG

; --- Vektor Interrupt ---
.ORG 0x0000
    RJMP RESET          ; Reset Handler (Alamat 0x0000)
.ORG INT0addr           ; External Interrupt 0 Vector Address (Alamat 0x0002)
    RJMP INT0_ISR       ; INT0 Handler (Button 1)
.ORG INT1addr           ; External Interrupt 1 Vector Address (Alamat 0x0004)
    RJMP INT1_ISR       ; INT1 Handler (Button 2)
.ORG OVF0addr           ; Timer0 Overflow Vector Address (Alamat 0x001A atau sesuai def file)
    RJMP TIMER0_OVF_ISR ; Timer0 Overflow Handler (Display Multiplexing)
; --- Akhir Tabel Vektor ---

; --- Program Utama Dimulai Setelah Vektor Tertinggi ---
RESET:
    ; Inisialisasi Stack Pointer
    LDI temp, HIGH(RAMEND)
    OUT SPH, temp
    LDI temp, LOW(RAMEND)
    OUT SPL, temp

    ; --- Konfigurasi Port ---
    ; PORTC (Segments): Output, Semua Mati (Blank)
    LDI temp, 0xFF
    OUT DDRC, temp
    LDI temp, SEG_BLANK
    OUT PORTC, temp
    ; PORTB (Digits): Output, Semua Mati (HIGH untuk Active Low)
    LDI temp, (1<<SS1_PIN)|(1<<SS2_PIN)|(1<<SS3_PIN)
    OUT DDRB, temp
    IN temp, PORTB
    ORI temp, ALL_DIGITS_OFF
    OUT PORTB, temp
    ; PORTD (Buttons): Input
    CLR temp
    OUT DDRD, temp
    ; Optional: Aktifkan pull-up internal jika tidak ada eksternal
    ; LDI temp, (1<<BTN1_PIN)|(1<<BTN2_PIN)
    ; OUT PORTD, temp

    ; --- Inisialisasi Variabel ---
    CLR result
    ; Set pola awal ke blank (meskipun akan diatur oleh Disable_Display)
    LDI digit1_pat, SEG_BLANK
    LDI digit2_pat, SEG_BLANK
    LDI digit3_pat, SEG_BLANK

    ; --- Konfigurasi Interrupt ---
    ; External Interrupts: INT0/INT1 aktif pada SETIAP PERUBAHAN LOGIKA
    LDI temp, (0<<ISC11)|(1<<ISC10) | (0<<ISC01)|(1<<ISC00) ; ISC10=1, ISC00=1 -> Any logical change
    STS EICRA, temp
    ; Aktifkan INT0 & INT1
    LDI temp, (1<<INT1)|(1<<INT0)
    OUT EIMSK, temp

    ; --- Konfigurasi Timer0 ---
    ; Prescaler clk/8, TAPI Timer Overflow Interrupt DIMATIKAN awalnya
    LDI temp, (1<<CS01)
    OUT TCCR0B, temp
    CLR temp            ; Pastikan TOIE0 = 0
    STS TIMSK0, temp    ; Gunakan STS untuk TIMSK0

    ; Aktifkan Global Interrupts
    SEI

MAIN_LOOP:
    NOP                 ; Tidak melakukan apa-apa, semua dikendalikan interrupt
    RJMP MAIN_LOOP

; --- Interrupt Service Routines (ISR) ---

; ISR untuk Tombol 1 (INT0) - Aktif pada setiap perubahan PD2
INT0_ISR:
    PUSH temp
    IN temp, SREG       ; Simpan SREG
    PUSH temp

    ; Cek kondisi pin PD2 saat ini
    SBIS PIND, BTN1_PIN ; Loncat jika pin PD2 = 1 (HIGH - Dilepas)
    RJMP INT0_Pressed   ; Jika pin PD2 = 0 (LOW - Ditekan)

INT0_Released:          ; Blok ini dieksekusi jika PD2 HIGH (Tombol dilepas)
    RCALL Disable_Display ; Matikan tampilan & Timer Interrupt
    RJMP INT0_Exit      ; Langsung keluar

INT0_Pressed:           ; Blok ini dieksekusi jika PD2 LOW (Tombol ditekan)
    LDI result, 10      ; Set nilai untuk ditampilkan
    RCALL Update_Display_Data ; Hitung pola segmen
    RCALL Enable_Display ; Aktifkan tampilan & Timer Interrupt
    ; Lanjut ke Exit

INT0_Exit:
    POP temp            ; Restore SREG
    OUT SREG, temp
    POP temp
    RETI                ; Return from Interrupt

; ISR untuk Tombol 2 (INT1) - Aktif pada setiap perubahan PD3
INT1_ISR:
    PUSH temp
    IN temp, SREG       ; Simpan SREG
    PUSH temp

    ; Cek kondisi pin PD3 saat ini
    SBIS PIND, BTN2_PIN ; Loncat jika pin PD3 = 1 (HIGH - Dilepas)
    RJMP INT1_Pressed   ; Jika pin PD3 = 0 (LOW - Ditekan)

INT1_Released:          ; Blok ini dieksekusi jika PD3 HIGH (Tombol dilepas)
    RCALL Disable_Display ; Matikan tampilan & Timer Interrupt
    RJMP INT1_Exit      ; Langsung keluar

INT1_Pressed:           ; Blok ini dieksekusi jika PD3 LOW (Tombol ditekan)
    LDI result, -10     ; Set nilai untuk ditampilkan
    RCALL Update_Display_Data ; Hitung pola segmen
    RCALL Enable_Display ; Aktifkan tampilan & Timer Interrupt
    ; Lanjut ke Exit

INT1_Exit:
    POP temp            ; Restore SREG
    OUT SREG, temp
    POP temp
    RETI                ; Return from Interrupt

; ISR untuk Timer0 Overflow - Multiplexing Display (HANYA AKTIF JIKA DIPANGGIL ENABLE_DISPLAY)
TIMER0_OVF_ISR:
    PUSH temp
    IN temp, SREG
    PUSH temp
    PUSH temp2
    PUSH digit1_pat     ; Simpan register pola
    PUSH digit2_pat
    PUSH digit3_pat

    ; 1. Matikan SEMUA digit (Set pin HIGH untuk Active Low)
    IN temp, PORTB
    ORI temp, ALL_DIGITS_OFF
    OUT PORTB, temp

    LDS temp2, current_digit ; Muat digit mana yang akan ditampilkan (1, 2, atau 3)

    ; 2. Pilih pola dan aktifkan digit yang sesuai
    CPI temp2, 1
    BREQ DispDigit1_ISR
    CPI temp2, 2
    BREQ DispDigit2_ISR
    ; Jika bukan 1 atau 2, lanjut ke Digit 3

DispDigit3_ISR:         ; Tampilkan Digit 3 (Satuan)
    MOV temp, digit3_pat
    OUT PORTC, temp
    IN temp, PORTB
    ANDI temp, ~(1<<SS3_PIN) ; Aktifkan Digit 3 (Set pin LOW)
    OUT PORTB, temp
    LDI temp2, 1
    RJMP UpdateCurrentDigit_ISR ; Selalu JUMP ke update

DispDigit1_ISR:         ; Tampilkan Digit 1 (Tanda)
    MOV temp, digit1_pat
    OUT PORTC, temp
    IN temp, PORTB
    ANDI temp, ~(1<<SS1_PIN) ; Aktifkan Digit 1 (Set pin LOW)
    OUT PORTB, temp
    LDI temp2, 2
    RJMP UpdateCurrentDigit_ISR ; Selalu JUMP ke update

DispDigit2_ISR:         ; Tampilkan Digit 2 (Puluhan)
    MOV temp, digit2_pat
    OUT PORTC, temp
    IN temp, PORTB
    ANDI temp, ~(1<<SS2_PIN) ; Aktifkan Digit 2 (Set pin LOW)
    OUT PORTB, temp
    LDI temp2, 3
    RJMP UpdateCurrentDigit_ISR ; *** FIX: TAMBAHKAN JUMP ini agar timing sama ***

UpdateCurrentDigit_ISR:
    STS current_digit, temp2 ; Simpan nomor digit berikutnya ke SRAM

TIMER0_OVF_Exit:
    POP digit3_pat
    POP digit2_pat
    POP digit1_pat
    POP temp2
    POP temp
    OUT SREG, temp
    POP temp
    RETI

; Mengaktifkan Timer Overflow Interrupt untuk memulai multiplexing
Enable_Display:
    PUSH temp
    LDI temp, (1<<TOIE0)    ; Siapkan bit untuk mengaktifkan Timer0 OVF Int
    STS TIMSK0, temp        ; Gunakan STS untuk TIMSK0
    POP temp
    RET

; Mematikan Timer Overflow Interrupt dan mematikan display
Disable_Display:
    PUSH temp
    ; 1. Matikan Timer0 OVF Interrupt
    CLR temp                ; Siapkan 0
    STS TIMSK0, temp        ; Gunakan STS untuk TIMSK0
    ; 2. Matikan Segmen
    LDI temp, SEG_BLANK
    OUT PORTC, temp
    ; 3. Matikan Digit Select
    IN temp, PORTB
    ORI temp, ALL_DIGITS_OFF
    OUT PORTB, temp
    POP temp
    RET

; Update Pola Segment berdasarkan nilai di 'result' (Sama seperti sebelumnya)
Update_Display_Data:
    PUSH ZL
    PUSH ZH
    PUSH temp
    PUSH temp2
    PUSH disp_val
    PUSH d_tens
    PUSH d_units

    MOV disp_val, result
    TST disp_val
    BRMI Result_Negative_Sub

Result_Positive_Or_Zero_Sub:
    LDI digit1_pat, SEG_BLANK
    RJMP Convert_Value_Sub

Result_Negative_Sub:
    LDI digit1_pat, SEG_MINUS
    NEG disp_val

Convert_Value_Sub:
    CLR d_tens
    CLR d_units
    CPI disp_val, 10
    BRLO Val_Less_Than_10_Sub
    LDI d_tens, 1
    LDI d_units, 0
    RJMP Get_Patterns_Sub

Val_Less_Than_10_Sub:
    MOV d_units, disp_val

Get_Patterns_Sub:
    MOV temp, d_tens
    RCALL Get_Segment_Code
    MOV digit2_pat, temp
    MOV temp, d_units
    RCALL Get_Segment_Code
    MOV digit3_pat, temp

Update_Exit_Sub:
    POP d_units
    POP d_tens
    POP disp_val
    POP temp2
    POP temp
    POP ZH
    POP ZL
    RET

; Ambil kode segmen dari tabel (Sama seperti sebelumnya)
Get_Segment_Code:
    PUSH temp2
    PUSH r0
    LDI ZL, LOW(Segment_Table*2)
    LDI ZH, HIGH(Segment_Table*2)
    MOV temp2, temp
    CLR temp
    ADD ZL, temp2
    ADC ZH, temp
    LPM
    MOV temp, r0
    POP r0
    POP temp2
    RET

; Delay - Tidak lagi dipanggil oleh ISR utama, tapi mungkin berguna nanti
Delay_10ms:
    PUSH dly_cnt_1 ; Simpan register yang dipakai delay (r25)
    PUSH dly_cnt_2 ; Simpan register yang dipakai delay (r26)
    LDI dly_cnt_1, 40
Delay_Outer_Loop:
    LDI dly_cnt_2, 85
Delay_Inner_Loop:
    DEC dly_cnt_2
    BRNE Delay_Inner_Loop
    DEC dly_cnt_1
    BRNE Delay_Outer_Loop
    POP dly_cnt_2 ; Kembalikan register
    POP dly_cnt_1 ; Kembalikan register
    RET

; =====================================================================
; Tabel Pola Segment (Common Cathode)
; =====================================================================
.ALIGN 2
Segment_Table:
.DB     0x7E, 0x30, 0x6D, 0x79, 0x33, 0x5B, 0x5F, 0x70, 0x7F, 0x7B
; --- Akhir Tabel ---

; =====================================================================
; Akhir Program 
; =====================================================================
Editor is loading...
Leave a Comment