; EMERGENCY EXCUSE GENERATOR Version 1.00 2010-01-01 ; http://avtanski.net/eeg #include __config (_INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _BOR_OFF & _IESO_OFF & _FCMEN_OFF) #include excuse.inc ; Uncomment this if the button is Normally Closed ;#define BTN_NC ; Define the dimensions of your LCD display here #define LCD_COLUMNS .20 #define LCD_ROWS .4 #define ADDR_ROW0 0x80 #define ADDR_ROW1 0xC0 #define ADDR_ROW2 0x94 #define ADDR_ROW3 0xD4 #if LCD_ROWS==4 #define ADDR_MSG1 ADDR_ROW1+(LCD_COLUMNS-0x10)/2 #define ADDR_MSG2 ADDR_ROW2+(LCD_COLUMNS-0x10)/2 #else ; assuming two rows #define ADDR_MSG1 ADDR_ROW0+(LCD_COLUMNS-0x10)/2 #define ADDR_MSG2 ADDR_ROW1+(LCD_COLUMNS-0x10)/2 #endif #define F_CAPITALIZE 0 cblock 0x20 RND RND1 TMP0 TMP1 TMP2 FLAGS COUNTER ROW COLUMN LOOKUP_TEMP IXH IXL DTH DTL CHAR CHARH STACK_PTR STACK:40 endc org 0x00 goto Start org 0x04 goto Start Start call Init #ifdef BTN_NC btfsc PORTA,2 #else btfss PORTA,2 #endif goto RND_Test bcf FLAGS,F_CAPITALIZE movlw TAB_1H movwf DTH movlw TAB_1L movwf DTL movlw ADDR_MSG1 call GenerateAtLocation movlw TAB_2H movwf DTH movlw TAB_2L movwf DTL movlw ADDR_MSG2 call GenerateAtLocation MainLoop #ifdef BTN_NC btfsc PORTA,2 #else btfss PORTA,2 #endif goto $-1 movlw 0x30 incf RND,f movwf TMP2 #ifdef BTN_NC btfss PORTA,2 #else btfsc PORTA,2 #endif goto $-4 call LCD_Wait decfsz TMP2,f goto $-4 bsf PORTB,4 call RunGenerator bcf PORTB,4 goto MainLoop Init banksel PORTC ; Init ports clrf PORTC clrf PORTB banksel ANSEL movlw b'00000000' movwf ANSEL movwf ANSELH banksel TRISC movlw b'00000000' movwf TRISC movlw b'00101111' movwf TRISB bcf OPTION_REG, 7 bsf WPUA,2 banksel WPUB clrf WPUB banksel PORTC call LCD_Wait ; Init LCD movlw 0x00 movwf PORTB clrf TMP2 Init_LCD_loop movf TMP2,w call Init_LCD_Table movwf PORTC call LCD_PulseZ incf TMP2,f movlw 0x0A subwf TMP2,w btfss STATUS,Z goto Init_LCD_loop bsf PORTB,7 return Init_LCD_Table movwf LOOKUP_TEMP clrf PCLATH movf LOOKUP_TEMP,w addwf PCL,f retlw b'00110000' retlw b'00111000' retlw b'00111000' retlw b'00111000' retlw b'00001000' retlw b'00000001' retlw b'00000110' retlw b'00001000' retlw b'00000010' retlw b'00001100' LCD_Row_Address_Table movwf LOOKUP_TEMP clrf PCLATH movf LOOKUP_TEMP,w addwf PCL,f retlw ADDR_ROW0 retlw ADDR_ROW1 retlw ADDR_ROW2 retlw ADDR_ROW3 LCD_PulseZ nop nop nop bsf PORTB,6 nop nop nop bcf PORTB,6 call LCD_Wait return LCD_Wait movlw 0x01 movwf TMP0 movlw 0x10 movwf TMP1 LCD_Wait_0 decfsz TMP0, f goto $+2 decfsz TMP1, f goto LCD_Wait_0 return Random movlw 0x04 movwf TMP2 Random_loop bcf PORTB,5 ; Prepare capacitor banksel TRISB bcf TRISB,5 banksel PORTB call LCD_Wait banksel TRISB bsf TRISB,5 ; Count discharge time banksel PORTB incf RND,f btfss PORTB,5 goto $-2 decfsz TMP2,f goto Random_loop movf RND,w movwf RND1 return GenerateAtLocation movwf PORTC bcf PORTB,7 call LCD_PulseZ bsf PORTB,7 clrf STACK_PTR goto Generate RunGenerator bsf FLAGS,F_CAPITALIZE call LCD_ClearScreen clrf STACK_PTR movlw TAB_0H movwf DTH movlw TAB_0L movwf DTL #ifdef BTN_NC btfsc PORTA,2 #else btfss PORTA,2 #endif goto $-1 Generate call Random call GetCharFromTable clrf TMP0 Generate_randomSelect incf TMP0,f movf CHAR,w xorwf TMP0,w btfsc STATUS,Z clrf TMP0 decfsz RND1,f goto Generate_randomSelect GenerateChar_loop movf TMP0,f btfsc STATUS,Z goto GenerateChar_readAddress call GetCharFromTable call GetCharFromTable decf TMP0,f goto GenerateChar_loop GenerateChar_readAddress call GetCharFromTable movwf IXH call GetCharFromTable movwf DTL movf IXH,w movwf DTH GenerateChar call GetCharFromTable movf CHAR,w btfss STATUS,Z goto GenerateChar_0 ; CHAR==0x00 movf STACK_PTR,f btfsc STATUS,Z return ; PopStack->(DTH,DTL) decf STACK_PTR,f decf STACK_PTR,f movlw low STACK addwf STACK_PTR,w movwf FSR movf INDF,w movwf DTH incf FSR,f movf INDF,w movwf DTL goto GenerateChar GenerateChar_0 movf CHAR,w sublw 0x01 ; ADDR btfss STATUS,Z goto GenerateChar_1 ; CHAR==0x01 call GetCharFromTable movwf IXH call GetCharFromTable movwf IXL ; PushStack(DTH,DTL) movlw low STACK addwf STACK_PTR,w movwf FSR movf DTH,w movwf INDF incf FSR,f movf DTL,w movwf INDF incf STACK_PTR,f incf STACK_PTR,f movf IXH,w movwf DTH movf IXL,w movwf DTL goto Generate GenerateChar_1 ; Prepare the char movf COLUMN,w sublw LCD_COLUMNS btfss STATUS,Z goto GenerateChar_outputChar ; Reached row end, see if there is another row below clrf COLUMN incf ROW,f movf ROW,w sublw LCD_ROWS btfsc STATUS,Z goto GenerateChar_pauseAndClear movf ROW,w call LCD_Row_Address_Table movwf PORTC bcf PORTB,7 call LCD_PulseZ bsf PORTB,7 GenerateChar_outputChar ; Do the actual output movf COLUMN,f btfss STATUS,Z goto GenerateChar_doOutput movlw 0x20 subwf CHAR,w btfsc STATUS,Z goto GenerateChar GenerateChar_doOutput incf COLUMN,f btfss FLAGS,F_CAPITALIZE goto GenerateChar_doOutput_cnt bcf STATUS,C movlw 0x61 subwf CHAR,w btfss STATUS,C goto GenerateChar_doOutput_cnt movlw 0x7B subwf CHAR,w btfsc STATUS,C goto GenerateChar_doOutput_cnt movlw 0x20 subwf CHAR,f GenerateChar_doOutput_cnt bcf FLAGS,F_CAPITALIZE movf CHAR,w movwf PORTC call LCD_PulseZ goto GenerateChar GenerateChar_pauseAndClear #ifdef BTN_NC btfsc PORTA,2 goto $-1 btfss PORTA,2 #else btfss PORTA,2 goto $-1 btfsc PORTA,2 #endif goto $-1 call LCD_ClearScreen goto GenerateChar_outputChar LCD_ClearScreen clrf ROW clrf COLUMN movlw b'00000001' movwf PORTC bcf PORTB,7 call LCD_PulseZ bsf PORTB,7 call LCD_Wait return GetCharFromTable rrf DTH,w andlw 0x1F bcf STATUS,RP0 bsf STATUS,RP1 movwf EEADRH bcf STATUS,RP1 rlf DTL,w movwf TMP2 rrf DTH,w rrf TMP2,w bsf STATUS,RP1 movwf EEADR bsf STATUS,RP0 bsf EECON1,EEPGD bsf EECON1,RD nop nop bcf STATUS,RP0 movf EEDAT,w bcf STATUS,RP1 movwf CHAR bsf STATUS,RP1 movf EEDATH,w bcf STATUS,RP1 movwf CHARH btfsc DTH,6 goto GetCharFromTable_inc bsf DTH,6 movlw 0x7F andwf CHAR,f movf CHAR,w return GetCharFromTable_inc rlf CHAR,w rlf CHARH,w movwf CHAR incf DTL,f bcf DTH,6 btfsc DTL,7 incf DTH,f bcf DTL,7 return RND_Test clrf RND call Random andlw 0x0F addlw 0x41 movwf PORTC call LCD_PulseZ goto RND_Test END