#include __CONFIG(_HS_OSC & _WDT_OFF & _MCLRE_OFF & _BOREN_OFF & _LVP_OFF & _DATA_CP_OFF & _CP_OFF); org 0x0000 goto MAIN_INIT org 0x0004 goto MY_INTERRUPT_HANDLER ;N.B. all sub routines must return with BANK 0 selected ;N.B. lower and higher nibbles are LCD nibbles, but they are stored in two bytes because bytes also contain status of LCD_E and LCD_RS #define LCDE 0 ;LCD Enable bit #define WRT 1 ;Ready for writing bit #define SKF 2 ;Skip frame bit #define U4B 3 ;Write upper four bits (high nibble) ;PORTB wiring #define RB0 0 ;RB0 => RS is wired to RB0 #define RB1 1 ;RB1 => E is wired to RB1 #define RB3 3 ;RB3 => LED is wired to RB3 ;binary constants #define b00000000 0x00 #define b00000001 0x01 #define b00001111 0x0f #define b00010000 0x10 #define b00011000 0x18 #define b00011111 0x1F #define b00100000 0x20 #define b01000000 0x40 #define b01010101 0x55 #define b01100000 0x60 #define b01110000 0x70 #define b10000000 0x80 #define b10101010 0xAA #define b11000000 0xC0 #define b11110000 0xF0 #define b11111111 0xFF ;Timer constants #define TMR_DELTA 0xF0 ;start at: 255 - x, overflow on 255+1 ;RAM data variables bank 0 cblock 0x20 MY_BITS W_TEMP STATUS_TEMP LCD_BUF_00 LCD_BUF_01 LCD_BUF_02 LCD_BUF_03 LCD_BUF_04 LCD_BUF_05 LCD_BUF_06 LCD_BUF_07 CNT_VAR CNT0 CNT1 CNT2 CNT3 CNT_RW ;number of items in LCD_BUF LCD_TMP ;buffer for tmp lcd data endc; MAIN_INIT: ;--- select bank 0 --- bcf STATUS, RP0; bcf STATUS, RP1; clrf PORTA; clrf PORTB; clrf MY_BITS clrf W_TEMP clrf STATUS_TEMP clrf CNT_RW clrf LCD_BUF_00 clrf LCD_BUF_01 clrf LCD_BUF_02 clrf LCD_BUF_03 clrf LCD_BUF_04 clrf LCD_BUF_05 clrf LCD_BUF_06 clrf LCD_BUF_07 clrf LCD_TMP clrf CNT_VAR clrf CNT0 clrf CNT1 clrf CNT2 clrf CNT3 ;--- select bank 1 --- bsf STATUS, RP0 ;disable all interrupts clrf INTCON ;GIE PEIE T0IE INTE RBIE T0IF INTF RBIF clrf PIE1 ;EEIE CMIE RCIE TXIE xxx CCP1IE TMR2IE TMR1IE movlw b11000000 ;RA0...RA5 as outputs movwf TRISA ;TRISA, bank 1 movlw b00000000 ;RB0...RB7 as outputs movwf TRISB ;TRISB, bank 1 ;--- select bank 0 --- bcf STATUS, RP0 ; clrf PIR1 ;EEIF CMIF RCIF TXIF xxx CCP1IF TMR2IF TMR1IF call start_lcd_timer; ;RS => is wired to RB0 ;E => is wired to RB1 ;Wait for more than 30ms ;after VDD rises to 4.5v movlw 0x80 ;wait > 30 msec; movwf CNT_VAR ;CNT_VAR bank 0 call delay_msec ; ;N: 0 = 1-line mode , 1 = 2-line mode ;F: 0 = 5 x 7 dots, 1 = 5 x 10 dots ; ;RS RW DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 ;0 0 0 0 1 0 X X X X ;0 0 0 0 1 0 X X X X ;0 0 N F X X X X X X call init_write_mode; movlw b00100000 ; movwf LCD_BUF_00 ;move w to LCD_BUFxx bank 0 incf CNT_RW, 1 ;RW index bank 0, write result back in CNT_RW movlw b00100000 ; movwf LCD_BUF_01 ;move w to LCD_BUFxx bank 0 incf CNT_RW, 1 ;RW index bank 0, write result back in CNT_RW movlw b01000000 ; movwf LCD_BUF_02 ;move w to LCD_BUFxx bank 0 incf CNT_RW, 1 ;RW index bank 0, write result back in CNT_RW movlw b01000000 ; movwf LCD_BUF_03 ;move w to LCD_BUFxx bank 0 incf CNT_RW, 1 ;RW index bank 0, write result back in CNT_RW bsf MY_BITS, WRT ;ready for writing data bank 0 movlw 0x80 ;wait >100 msec movwf CNT_VAR ;CNT_VAR bank 0 call delay_msec ; ;D: 0 display off, 1 display on ;C: 0 cursor off, 1 cursor on ;B: 0 blink off, 1 blink on ;RS RW DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 ;0 0 0 0 0 0 X X X X ;0 0 1 D C B X X X X call init_write_mode; movlw b00000000 ; movwf LCD_BUF_00 ;move w to LCD_BUFxx bank 0 incf CNT_RW, 1 ;RW index bank 0, write result back in CNT_RW movlw b11000000 ; movwf LCD_BUF_01 ;move w to LCD_BUFxx bank 0 incf CNT_RW, 1 ;RW index bank 0, write result back in CNT_RW bsf MY_BITS, WRT ;ready for writing data bank 0 movlw 0x80 ;wait >50 msec movwf CNT_VAR ;move w to CNT_VAR bank 0 call delay_msec; ;Clear Display ;RS RW DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 ;0 0 0 0 0 0 X X X X ;0 0 0 0 0 1 X X X X call init_write_mode; movlw b00000000 ; movwf LCD_BUF_00 ;move w to LCD_BUFxx bank 0 incf CNT_RW, 1 ;RW index bank 0, write result back in CNT_RW movlw b00010000 ; movwf LCD_BUF_01 ;move w to LCD_BUFxx bank 0 incf CNT_RW, 1 ;RW index bank 0, write result back in CNT_RW bsf MY_BITS, WRT ;ready for writing data bank 0 movlw 0x80 ;wait >50 msec movwf CNT_VAR ;move w to CNT_VAR bank 0 call delay_msec ; ;I/D: 0 decrement mode, 1 increment mode ;SH: 0 entire shift off, 1 entire shift on ;RS RW DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 ;0 0 0 0 0 0 X X X X ;0 0 0 1 I/D SH X X X X call init_write_mode; movlw b00000000 ; movwf LCD_BUF_00 ;move w to LCD_BUFxx bank 0 incf CNT_RW, 1 ;RW index bank 0, write result back in CNT_RW movlw b01100000 ; movwf LCD_BUF_01 ;move w to LCD_BUFxx bank 0 incf CNT_RW, 1 ;RW index bank 0, write result back in CNT_RW bsf MY_BITS, WRT ;ready for writing data bank 0 movlw 0x80 ;wait >100 msec movwf CNT_VAR ;move w to CNT_VAR bank 0 call delay_msec; MAIN_LOOP: movlw 0x00 ;set LCD position to 2 movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_position movlw 0x48 ;'H' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x61 ;'a' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x6C ;'l' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x6C ;'l' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x6F ;'o' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x20 ;' ' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x4D ;'M' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x6F ;'o' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x6E ;'n' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x69 ;'i' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x71 ;'q' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x75 ;'u' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x65 ;'e' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x01 ;wait 1 sec movwf CNT_VAR ;move w to CNT_VAR bank 0 call delay_sec; movlw 0x00 ;set LCD position to 0 movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_position movlw 0x4D ;'M' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x6F ;'o' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x69 ;'i' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x20 ;' ' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x49 ;'I' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x72 ;'r' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x69 ;'i' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x6E ;'n' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x61 ;'a' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x20 ;' ' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x20 ;' ' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x20 ;' ' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x20 ;' ' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x01 ;wait 1 sec movwf CNT_VAR ;move w to CNT_VAR bank 0 call delay_sec; movlw 0x00 ;set LCD position to 0 movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_position movlw 0x48 ;'H' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x6F ;'o' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x69 ;'i' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x20 ;' ' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x4a ;'J' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x61 ;'a' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x72 ;'r' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x6F ;'o' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x6D ;'m' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x69 ;'i' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x72 ;'r' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x20 ;' ' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x20 ;' ' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x01 ;wait 1 sec movwf CNT_VAR ;move w to CNT_VAR bank 0 call delay_sec; movlw 0x00 ;set LCD position to 0 movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_position movlw 0x77 ;'w' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x77 ;'w' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x77 ;'w' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x2e ;'.' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x66 ;'f' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x73 ;'s' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x61 ;'a' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x79 ;'y' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x73 ;'s' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x2e ;'.' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x65 ;'e' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x75 ;'u' movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char movlw 0x01 ;wait 1 sec movwf CNT_VAR ;move w to CNT_VAR bank 0 call delay_sec; goto MAIN_LOOP init_write_mode: bcf MY_BITS, WRT ;not ready for writing data to LCD movlw 0x00 movwf CNT_RW ; bsf MY_BITS, U4B ;upper four bits return set_char: call init_write_mode movf LCD_TMP, 0 ;write LCD_TMP to W andlw b11110000 ;get high nibble and move result in W movwf LCD_BUF_00 ;write high nible to LCD_BUF movlw b00000001 ;or with 1 in order to set LCD_RS iorwf LCD_BUF_00, 1 ;Inclusive OR and write back to LCD_BUF_00 incf CNT_RW, 1 ;RW index bank 0, write result back in CNT_RW movf LCD_TMP, 0 ; andlw b00001111 ;get lower nibble and move result in W movwf LCD_BUF_01 bcf STATUS, C ;clear carry rlf LCD_BUF_01,1 ;shift left and store result in LCD_BUF rlf LCD_BUF_01,1 rlf LCD_BUF_01,1 rlf LCD_BUF_01,1 movlw b00000001 ;or with 1 in order to set LCD_RS iorwf LCD_BUF_01, 1 ;Inclusive OR and write back to LCD_BUF_00 incf CNT_RW, 1 ;RW index bank 0, write result back in CNT_RW bsf MY_BITS, WRT ;ready for writing data bank 0 movlw 0x80 ; movwf CNT_VAR ;move w to CNT_VAR bank 0 call delay_usec; return set_position: call init_write_mode ;Set DDRAM Address 0 ;RS RW DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 ;0 0 1 0 AC5 AC4 AC3 AC2 AC1 AC0 movf LCD_TMP, 0 ;write LCD_TMP to W andlw b11110000 ;get high nibble and move result in W movwf LCD_BUF_00 ;write high nible to LCD_BUF movlw b10000000 ;set DB7 to 1 IORWF LCD_BUF_00, 1 ;write back to LCD_TMP incf CNT_RW, 1 ;RW index bank 0, write result back in CNT_RW movf LCD_TMP, 0 ;write LCD_TMP to W andlw b00001111 ;get lower nibble and move result in W movwf LCD_BUF_01 ; bcf STATUS, C ;clear carry rlf LCD_BUF_01, 1 ;shift left and store result in LCD_BUF rlf LCD_BUF_01, 1 rlf LCD_BUF_01, 1 rlf LCD_BUF_01, 1 ;movlw b10000000 ;set DB7 to 1 ;IORWF LCD_BUF_01, 1 ;write back to LCD_TMP incf CNT_RW, 1 ;RW index bank 0, write result back in CNT_RW bsf MY_BITS, WRT ;ready for writing data bank 0 movlw 0x80 ; movwf CNT_VAR ;move w to CNT_VAR bank 0 call delay_msec; return delay_sec: ;20 Mhz movf CNT_VAR, 0 ;1 cycle, move content of CNT_VAR to W movwf CNT0 ;1 cycle delay_sec_cnt0: movlw 0x60 ;1 cycle 96 movwf CNT1 ;1 cycle delay_sec_cnt1: movlw 0x45 ;1 cycle 69 movwf CNT2 ;1 cycle delay_sec_cnt2: movlw 0xFA ;1 cycle 250 movwf CNT3 ;1 cycle delay_sec_cnt3: decfsz CNT3 ;1 cycle goto delay_sec_cnt3 ;2 cycles decfsz CNT2 ;1 cycle goto delay_sec_cnt2 ;2 cycles decfsz CNT1 ;1 cycle goto delay_sec_cnt1 ;2 cycles decfsz CNT0 ;2 cycles goto delay_sec_cnt0 ;1 cycle return delay_msec: ;20 Mhz movf CNT_VAR, 0 ;1 cycle, move content of CNT_VAR to W movwf CNT0 ;1 cycle delay_msec_cnt0: movlw 0x28 ;1 cycle 40 movwf CNT1 ;1 cycle delay_msec_cnt1: movlw 0x28 ;1 cycle 40 movwf CNT2 ;1 cycle delay_msec_cnt2: decfsz CNT2 ;1 cycle goto delay_msec_cnt2 ;2 cycles decfsz CNT1 ;1 cycle goto delay_msec_cnt1 ;2 cycles decfsz CNT0 ;2 cycles goto delay_msec_cnt0 ;1 cycle return delay_usec: ;20 Mhz movf CNT_VAR, 0 ;1 cycle, move content of CNT_VAR to W movwf CNT0 ;1 cycle delay_usec_cnt0: nop ;1 cycle nop ;1 cycle decfsz CNT0 ;2 cycles goto delay_usec_cnt0 ;1 cycle return start_lcd_timer: ;--- BANK 1 --- bsf STATUS, RP0 ;select bank 1 ;disable all interrupts clrf INTCON ;GIE PEIE T0IE INTE RBIE T0IF INTF RBIF clrf PIE1 ;EEIE CMIE RCIE TXIE xxx CCP1IE TMR2IE TMR1IE bsf PCON, OSCF ;4 Mhz movlw b00011111 ; movwf TRISA ;TRISA, bank 1 movlw b00000000 ;RB0...RB7 as outputs movwf TRISB ;TRISB, bank 1 ;bit 7 RBPU: PORTB Pull-up Enable bit ; 1 = PORTB pull-ups are disabled ; 0 = PORTB pull-ups are enabled by individual port latch values ;bit 6 INTEDG: Interrupt Edge Select bit ; 1 = Interrupt on rising edge of RB0/INT pin ; 0 = Interrupt on falling edge of RB0/INT pin ;bit 5 T0CS: TMR0 Clock Source Select bit ; 1 = Transition on RA4/T0CKI/CMP2 pin ; 0 = Internal instruction cycle clock (CLKOUT) ;bit 4 T0SE: TMR0 Source Edge Select bit ; 1 = Increment on high-to-low transition on RA4/T0CKI/CMP2 pin ; 0 = Increment on low-to-high transition on RA4/T0CKI/CMP2 pin ;bit 3 PSA: Prescaler Assignment bit ; 1 = Prescaler is assigned to the WDT ; 0 = Prescaler is assigned to the Timer0 module ;bit 2-0 PS<2:0>: Prescaler Rate Select bits ; 0 = nPBPU INTEDG T0CS T0SE PSA PS<2:0>: Prescaler Rate Select bits movlw b00011000 ;pull-ups, internal oscillator, WDT prescalar, 128 movwf OPTION_REG ;OPTION_REG, bank 1 ;--- BANK 0 --- bcf STATUS, RP0 ;select bank 0 movlw U4B; movwf MY_BITS; movlw TMR_DELTA ;set initial value movwf TMR0; ;TMR0, bank 0 clrf PORTA ;PORTA, bank 0 clrf PORTB ;PORTB, bank 0 bsf INTCON, T0IE ;INTCON enable timer 0 overflow bsf INTCON, GIE ;enable interrupts return timer0_overflow: ;my_debug2: ; return ;my_debug_end2: ;--- BANK 0 --- bcf STATUS, RP0 bcf STATUS, RP1 t0if_set_data: ;--- BANK 0 --- bcf STATUS, RP0 ;select bank 0 bcf STATUS, RP1 ;select bank 0 btfss MY_BITS, SKF ;Bit test flag, skip if set 'Skip frame' goto t0if_nSKF ;SKF is not set, normal mode bcf MY_BITS, SKF ;clear SKF-flag and go to toggle LCD_E goto t0if_toggle_lcd_e t0if_nSKF: btfss MY_BITS, LCDE ;Bit test flag, skip if set LCD_E == LCD enable bit is set goto t0if_reset_lcd_e ;go to reset lcde btfss MY_BITS, WRT ;Bit test flag, skip if set WRT == ready to write data to LCD goto t0if_reset_lcd_e ;go to reset lcde bcf STATUS, C ;clear carry bcf STATUS, Z ;clear carry movf CNT_RW, 0 ;check if CNT_RW is 0 addlw b11111111 btfss STATUS, C ;if CNT_RW not is 0, then Carry flag will be set goto t0if_no_more_data ;go to toggle LCD_E movf LCD_BUF_00, 0 ;Move content of LCD_BUF_00 to W movwf PORTB ;Move content of W to PORTB movf LCD_BUF_01, 0 ;Move LCD_BUF one down, this could probably be optimized movwf LCD_BUF_00 movf LCD_BUF_02, 0 movwf LCD_BUF_01 movf LCD_BUF_03, 0 movwf LCD_BUF_02 movf LCD_BUF_04, 0 movwf LCD_BUF_03 movf LCD_BUF_05, 0 movwf LCD_BUF_04 movf LCD_BUF_06, 0 movwf LCD_BUF_05 movf LCD_BUF_07, 0 movwf LCD_BUF_06 clrf LCD_BUF_07 decf CNT_RW, 1 ;Decrement CNT_RW and store result in CNT_RW btfsc MY_BITS, U4B ;Bit test flag, skip if clear goto t0if_lower_nibble bsf MY_BITS, SKF ;After writing lower nibble, set skip frames flag. We don't wair for LCD is busy, have build in delay bsf MY_BITS, U4B ;Next write will be upper nibble of next frame goto t0if_toggle_lcd_e ;go to toggle LCD_E t0if_lower_nibble: bcf MY_BITS, U4B ;Next write will be lower nibble of current frame. goto t0if_toggle_lcd_e ;go to toggle LCD_E t0if_no_more_data: bcf MY_BITS, LCDE ;clear 'LCD Enable' bcf PORTB, 1; goto t0if_toggle_lcd_e t0if_reset_lcd_e: bcf PORTB, 1 ;clear PORTB RB1, bank 0 bcf MY_BITS, LCDE ;clear LCDE t0if_toggle_lcd_e: btfss MY_BITS, LCDE ;if LCDE is set, set RB1 and clear LCDE goto t0if_set_lcd_e; ;else clear RB1 and set LCDE bsf PORTB, 1 ;set PORTB RB1, bank 0 bcf MY_BITS, LCDE ;clear LCDE t0if_set_lcd_e: bcf PORTB, 1 ;set PORTB RB1, bank 0 bsf MY_BITS, LCDE ;clear LCDE movlw TMR_DELTA ;set initial value movwf TMR0; ;TMR0, bank 0 bcf INTCON, T0IF ;reset interrupt T0IF return MY_INTERRUPT_HANDLER: ;SAVING THE STATUS AND W REGISTERS IN RAM movwf W_TEMP ;copy W to temp register, could be in any bank swapf STATUS,W ;swap status to be saved into W bcf STATUS,RP0 ;change to bank 0 regardless of current bank movwf STATUS_TEMP ;save status to bank 0 register ;--- ISR --- bsf STATUS, RP0 ;select bank 1 btfsc INTCON, T0IF ;timer0 overflow? skip if clear call timer0_overflow ; ;--- end IF USR --- swapf STATUS_TEMP,W ;swap STATUS_TEMP register ;into W, sets bank to original state movwf STATUS ;move W into STATUS register swapf W_TEMP,F ;swap W_TEMP swapf W_TEMP,W ;swap W_TEMP into W retfie ;return from interrupt end