; CC5X Version 3.1I, Copyright (c) B Knudsen Data ; C compiler for the PICmicro family ; ************ 30. Jan 2004 22:00 ************* processor 16F630 radix DEC PCL EQU 0x02 STATUS EQU 0x03 FSR EQU 0x04 PORTA EQU 0x05 TRISA EQU 0x85 PCLATH EQU 0x0A INTEDG EQU 6 Carry EQU 0 Zero_ EQU 2 RP0 EQU 5 INTF EQU 1 INTE EQU 4 GIE EQU 7 PORTC EQU 0x07 CMCON EQU 0x19 TRISC EQU 0x87 data_byte_in EQU 0x29 cursor_position EQU 0x2A s1 EQU 0x20 s2 EQU 0x21 sv_FSR EQU 0x22 j EQU 0x23 i EQU 0x24 i_2 EQU 0 c EQU 0x27 d EQU 0x25 incoming_string EQU 0x25 x EQU 0x26 x_2 EQU 0x25 y EQU 0x27 ci EQU 0x27 GOTO main ; FILE D:\Pics\code\16F630\SerLCD\serlcd-v1.c ;/* ; 1-16-04 ; Copyright Spark Fun Electronics 2004 ; ; Uses 16F630 to drive Parallel LCD with Serial Commands. ; ; Thanks to Olimex for providing the original C test code for the PIC-MT-C w/ 16F873 ; ; 1-17-04 Started migrating 16F873A code to 16F630 ; ; 1-17-04pm Works well from user keyboard input. No busy flag checking yet. ; Ok, busy flag works. ; ; 1-19-04 Got commands to pass through after decimal 254 is seen. The special 8-bit data ; mode command is also correctly ignored. ; ;*/ ;#define Clock_4MHz ;#define Baud_9600 ; ;#include "d:\Pics\c\16F630.h" // device dependent interrupt definitions ;#include "d:\Pics\c\int16CXX.H" ; ;#pragma config|= 0x3194 //Internal Oscilator ; ;//Hardware port definitions ;#define E PORTC.1 ;#define R_W PORTC.0 ;#define RS PORTA.1 ;#define Serial_In_BB PORTA.2 ;#define Serial_Out_BB PORTA.5 ;#define D7 PORTC.2 ;#define D6 PORTC.3 ;#define D5 PORTC.4 ;#define D4 PORTC.5 ; ;//Constant definitions ;#define FALSE 0 ;#define TRUE 1 ; ;#define CLR_DISP 0b.0000.0001 //Clear display ; ;#define CUR_HOME 0b.0000.0010 //Move cursor home and clear screen memory ;#define CUR_RIGHT 0b.0001.0100 //Move cursor one to right ;#define CUR_LEFT 0b.0001.0000 //Move cursor one to left ; ;#define SCROLL_RIGHT 0b.0001.1100 //Scroll entire screen right one space ;#define SCROLL_LEFT 0b.0001.1000 //Scroll entire screen left one space ; ;#define DISP_ON 0b.0000.1100 //Turn visible LCD on ;#define DISP_OFF 0b.0000.1000 //Turn visible LCD off ; ;#define UNDERLINE_ON 0b.0000.1110 //Turn on underlined cursor ;#define UNDERLINE_OFF 0b.0000.1100 //Turn off underlined cursor ; ;#define BLINKCUR_ON 0b.0000.1101 //Turn on blinking box cursor ;#define BLINKCUR_OFF 0b.0000.1100 //Turn off blinking box cursor ; ;#define DUALCUR_ON 0b.0000.1111 //Turn on blinking box and underline cursor ;#define DUALCUR_OFF 0b.0000.1100 //Turn off blinking box and underine cursor ; ;#define SET_CURSOR 0b.1000.0000 //SET_CURSOR + X : Sets cursor position to X ; ;#define ENTRY_INC 0b.0000.0110 // ;#define DD_RAM_ADDR 0b.1000.0000 // ;#define DD_RAM_ADDR2 0b.1100.0000 // ;#define CG_RAM_ADDR 0b.0100.0000 // ; ;uns8 data_byte_in; ;uns8 cursor_position; ; ;//Interrupt Vectors ;#pragma origin 4 ORG 0x0004 ;interrupt serverX( void) ;{ serverX ; int_save_registers MOVWF s1 SWAPF STATUS,W MOVWF s2 ; char sv_FSR = FSR; // save FSR if required MOVF FSR,W MOVWF sv_FSR ; ; if(INTF) //RA2 Change Interrupt BCF 0x03,RP0 BTFSS 0x0B,INTF GOTO m007 ; { ; uns8 j, i; ; ; for(i = 0 ; i < 20 ; i++); CLRF i m001 MOVLW .20 SUBWF i,W BTFSC 0x03,Carry GOTO m002 INCF i,1 GOTO m001 ; ; for(j = 0 ; j < 7 ; j++) m002 CLRF j m003 MOVLW .7 SUBWF j,W BTFSC 0x03,Carry GOTO m006 ; { ; data_byte_in = rr(data_byte_in); RRF data_byte_in,1 ; //data_byte_in.7 = !Serial_In_BB; //Reverse polarity for RS232 systems ; data_byte_in.7 = Serial_In_BB; //Sample the port, should be in middle of the bit BCF data_byte_in,7 BTFSC PORTA,2 BSF data_byte_in,7 ; for(i = 0 ; i < 12 ; i++); CLRF i m004 MOVLW .12 SUBWF i,W BTFSC 0x03,Carry GOTO m005 INCF i,1 GOTO m004 ; nop(); nop(); nop(); //Clocks out to 104us between each bit m005 NOP NOP NOP ; } INCF j,1 GOTO m003 ; ; data_byte_in = rr(data_byte_in); m006 RRF data_byte_in,1 ; data_byte_in.7 = Serial_In_BB; //Sample the port, should be in middle of the bit BCF data_byte_in,7 BTFSC PORTA,2 BSF data_byte_in,7 ; ; //Clear INT Flag ; INTF = 0; BCF 0x0B,INTF ; } ; ; FSR = sv_FSR; // restore FSR if saved m007 MOVF sv_FSR,W MOVWF FSR ; int_restore_registers SWAPF s2,W MOVWF STATUS SWAPF s1,1 SWAPF s1,W ;} RETFIE ; ;void boot_up(void); ;void send_char(uns8); ;void send_cmd(uns8); ;void delay_ms(uns16); ;void send_string(const char* incoming_string); ;void delay_ms(uns16); ;bit busy_flag(void); ; ;void main( void ) ;{ _const1 MOVWF ci CLRF PCLATH MOVF ci,W ANDLW .31 ADDWF PCL,1 RETLW .32 RETLW .32 RETLW .83 RETLW .112 RETLW .97 RETLW .114 RETLW .107 RETLW .70 RETLW .117 RETLW .110 RETLW .46 RETLW .99 RETLW .111 RETLW .109 RETLW .0 RETLW .32 RETLW .32 RETLW .32 RETLW .83 RETLW .101 RETLW .114 RETLW .76 RETLW .67 RETLW .68 RETLW .32 RETLW .118 RETLW .49 RETLW .46 RETLW .48 RETLW .0 RETLW .0 RETLW .0 main ; //Initialize LCD and PIC ; boot_up(); BCF 0x03,RP0 CALL boot_up ; ; while(1) ; { ; //Wait for incoming command to wake us up... ; sleep(); BCF 0x03,RP0 m008 SLEEP ; nop(); //Executes after wake-up and before INTF runs NOP ; ; //Check for special LCD command ; if (data_byte_in == 254) MOVF data_byte_in,W XORLW .254 BTFSS 0x03,Zero_ GOTO m009 ; { ; //Wait for incoming command to wake us up... ; sleep(); SLEEP ; nop(); //Executes after wake-up and before INTF runs NOP ; ; //Ignore the one command that will send the LCD into 8-bit mode ; if ( (data_byte_in >> 4) != 3 ) //If not 0b.0000.0011, then send it to LCD SWAPF data_byte_in,W ANDLW .15 XORLW .3 BTFSC 0x03,Zero_ GOTO m008 ; send_cmd(data_byte_in); MOVF data_byte_in,W CALL send_cmd ; } ; else BCF 0x03,RP0 GOTO m008 ; { ; send_char(data_byte_in); m009 MOVF data_byte_in,W CALL send_char ; ; cursor_position++; INCF cursor_position,1 ; ; if (cursor_position == 16) //End of line 1 MOVF cursor_position,W XORLW .16 BTFSS 0x03,Zero_ GOTO m010 ; { ; send_cmd(SET_CURSOR + 64); MOVLW .192 CALL send_cmd ; cursor_position = 64; MOVLW .64 MOVWF cursor_position ; } ; else if (cursor_position == 80) //End of line 2 BCF 0x03,RP0 GOTO m008 m010 MOVF cursor_position,W XORLW .80 BTFSS 0x03,Zero_ GOTO m008 ; { ; send_cmd(SET_CURSOR + 0); MOVLW .128 CALL send_cmd ; cursor_position = 0; CLRF cursor_position ; } ; } ; ; } BCF 0x03,RP0 GOTO m008 ; ; ;} ; ;//Initializes the various ports and interrupts ;//Also inits the LCD ;void boot_up(void) ;{ boot_up ; //Setup Ports ; //ANSEL = 0b.0000.0000; //Disable ADC on all pins - Only on the 16F676 ; CMCON = 0b.0000.0111; //Turn off comparator on RA port MOVLW .7 MOVWF CMCON ; ; PORTA = 0b.0000.0000; CLRF PORTA ; TRISA = 0b.0000.0100; MOVLW .4 BSF 0x03,RP0 MOVWF TRISA ; ; PORTC = 0b.0000.0000; BCF 0x03,RP0 CLRF PORTC ; TRISC = 0b.0000.0000; //0 = Output, 1 = Input BSF 0x03,RP0 CLRF TRISC ; ; //Init LCD ; RS = 0; BCF 0x03,RP0 BCF PORTA,1 ; R_W = 0; BCF PORTC,0 ; ; //Tell the LCD we are using 4bit data communication ; delay_ms(1500); MOVLW .220 MOVWF x_2 MOVLW .5 MOVWF x_2+1 CALL delay_ms ; D7 = 0; BCF PORTC,2 ; D6 = 0; BCF PORTC,3 ; D5 = 1; BSF PORTC,4 ; D4 = 1; BSF PORTC,5 ; E = 1; E = 0; BSF PORTC,1 BCF PORTC,1 ; ; delay_ms(100); MOVLW .100 MOVWF x_2 CLRF x_2+1 CALL delay_ms ; D7 = 0; BCF PORTC,2 ; D6 = 0; BCF PORTC,3 ; D5 = 1; BSF PORTC,4 ; D4 = 1; BSF PORTC,5 ; E = 1; E = 0; BSF PORTC,1 BCF PORTC,1 ; ; delay_ms(100); MOVLW .100 MOVWF x_2 CLRF x_2+1 CALL delay_ms ; D7 = 0; BCF PORTC,2 ; D6 = 0; BCF PORTC,3 ; D5 = 1; BSF PORTC,4 ; D4 = 1; BSF PORTC,5 ; E = 1; E = 0; BSF PORTC,1 BCF PORTC,1 ; ; delay_ms(10); MOVLW .10 MOVWF x_2 CLRF x_2+1 CALL delay_ms ; D7 = 0; BCF PORTC,2 ; D6 = 0; BCF PORTC,3 ; D5 = 1; BSF PORTC,4 ; D4 = 0; BCF PORTC,5 ; E = 1; E = 0; BSF PORTC,1 BCF PORTC,1 ; ; send_cmd(DISP_ON); MOVLW .12 CALL send_cmd ; send_cmd(CLR_DISP); MOVLW .1 BCF 0x03,RP0 CALL send_cmd ; //LCD Init Complete ; ; send_string(" SparkFun.com"); CLRF incoming_string BCF 0x03,RP0 CALL send_string ; send_cmd(SET_CURSOR + 64); MOVLW .192 CALL send_cmd ; send_string(" SerLCD v1.0"); MOVLW .15 MOVWF incoming_string BCF 0x03,RP0 CALL send_string ; delay_ms(2500); MOVLW .196 MOVWF x_2 MOVLW .9 MOVWF x_2+1 CALL delay_ms ; send_cmd(CLR_DISP); MOVLW .1 CALL send_cmd ; ; cursor_position = 0; CLRF cursor_position ; ; //Setup interrupts for incoming RX ; //INTEDG = 1; //Int on rising edge change - Used for direct RS232 interfaces ; INTEDG = 0; //Int on rising edge change - Used for TTL embedded systems BCF 0x81,INTEDG ; INTE = 1; //Enable the RA2 Int, for incoming serial commands/characters BSF 0x0B,INTE ; GIE = 1; BSF 0x0B,GIE ; ;} RETURN ; ;//Checks and returns the busy_flag ;bit busy_flag(void) ;{ busy_flag ; bit i; ; ; TRISC = 0b.0011.1100; //0 = Output, 1 = Input MOVLW .60 BSF 0x03,RP0 MOVWF TRISC ; ; RS = 0; BCF 0x03,RP0 BCF PORTA,1 ; R_W = 1; //Tell LCD to output status BSF PORTC,0 ; ; E = 1; BSF PORTC,1 ; i = D7; //Read data bit 7 - Busy Flag BCF 0x28,i_2 BTFSC PORTC,2 BSF 0x28,i_2 ; E = 0; BCF PORTC,1 ; ; E = 1; E = 0; //Toggle E to get the second four bits of the status byte - but we don't care BSF PORTC,1 BCF PORTC,1 ; ; return(i); BCF 0x03,Carry BTFSC 0x28,i_2 BSF 0x03,Carry RETURN ; ;} ; ;//Sends an ASCII character to the LCD ;void send_char(uns8 c) ;{ send_char MOVWF c ; while(busy_flag()); m011 CALL busy_flag BTFSC 0x03,Carry GOTO m011 ; ; R_W = 0; //set LCD to write BCF PORTC,0 ; RS = 1; //set LCD to data mode BSF PORTA,1 ; ; //Control lines will always be output ; //And here the data lines are output ; TRISC = 0b.0000.0000; //0 = Output, 1 = Input BSF 0x03,RP0 CLRF TRISC ; ; D7 = c.7; BCF 0x03,RP0 BTFSS c,7 BCF PORTC,2 BTFSC c,7 BSF PORTC,2 ; D6 = c.6; BTFSS c,6 BCF PORTC,3 BTFSC c,6 BSF PORTC,3 ; D5 = c.5; BTFSS c,5 BCF PORTC,4 BTFSC c,5 BSF PORTC,4 ; D4 = c.4; BTFSS c,4 BCF PORTC,5 BTFSC c,4 BSF PORTC,5 ; E = 1; E = 0; //Toggle the Enable Pin BSF PORTC,1 BCF PORTC,1 ; ; D7 = c.3; BTFSS c,3 BCF PORTC,2 BTFSC c,3 BSF PORTC,2 ; D6 = c.2; BTFSS c,2 BCF PORTC,3 BTFSC c,2 BSF PORTC,3 ; D5 = c.1; BTFSS c,1 BCF PORTC,4 BTFSC c,1 BSF PORTC,4 ; D4 = c.0; BTFSS c,0 BCF PORTC,5 BTFSC c,0 BSF PORTC,5 ; E = 1; E = 0; BSF PORTC,1 BCF PORTC,1 ;} RETURN ; ;//Sends an LCD command ;void send_cmd(uns8 d) ;{ send_cmd MOVWF d ; while(busy_flag()); m012 CALL busy_flag BTFSC 0x03,Carry GOTO m012 ; ; R_W = 0; //set LCD to write BCF PORTC,0 ; RS = 0; //set LCD to data mode BCF PORTA,1 ; ; //Control lines will always be output ; //And here the data lines are output ; TRISC = 0b.0000.0000; //0 = Output, 1 = Input BSF 0x03,RP0 CLRF TRISC ; ; D7 = d.7; BCF 0x03,RP0 BTFSS d,7 BCF PORTC,2 BTFSC d,7 BSF PORTC,2 ; D6 = d.6; BTFSS d,6 BCF PORTC,3 BTFSC d,6 BSF PORTC,3 ; D5 = d.5; BTFSS d,5 BCF PORTC,4 BTFSC d,5 BSF PORTC,4 ; D4 = d.4; BTFSS d,4 BCF PORTC,5 BTFSC d,4 BSF PORTC,5 ; E = 1; E = 0; BSF PORTC,1 BCF PORTC,1 ; ; D7 = d.3; BTFSS d,3 BCF PORTC,2 BTFSC d,3 BSF PORTC,2 ; D6 = d.2; BTFSS d,2 BCF PORTC,3 BTFSC d,2 BSF PORTC,3 ; D5 = d.1; BTFSS d,1 BCF PORTC,4 BTFSC d,1 BSF PORTC,4 ; D4 = d.0; BTFSS d,0 BCF PORTC,5 BTFSC d,0 BSF PORTC,5 ; E = 1; E = 0; BSF PORTC,1 BCF PORTC,1 ;} BSF 0x03,RP0 RETURN ; ;//Sends a given string to the LCD. Will start printing from ;//current cursor position. ;void send_string(const char *incoming_string) ;{ send_string ; uns8 x; ; ; for( x = 0 ; incoming_string[x] != '\0' ; x++ ) CLRF x m013 MOVF x,W ADDWF incoming_string,W CALL _const1 XORLW .0 BTFSC 0x03,Zero_ GOTO m014 ; send_char(incoming_string[x]); MOVF x,W ADDWF incoming_string,W CALL _const1 CALL send_char INCF x,1 GOTO m013 ; ;} m014 RETURN ; ;//General short delay ;void delay_ms(uns16 x) ;{ delay_ms ; //Clocks out at 1002us per 1ms ; int y; ; for ( ; x > 0 ; x--) m015 MOVF x_2,W IORWF x_2+1,W BTFSC 0x03,Zero_ GOTO m019 ; for ( y = 0 ; y < 108 ; y++); CLRF y m016 BTFSC y,7 GOTO m017 MOVLW .108 SUBWF y,W BTFSC 0x03,Carry GOTO m018 m017 INCF y,1 GOTO m016 m018 DECF x_2,1 INCF x_2,W BTFSC 0x03,Zero_ DECF x_2+1,1 GOTO m015 m019 RETURN ORG 0x2007 DATA 3194H END ; *** KEY INFO *** ; 0x0004 48 word(s) 2 % : serverX ; 0x0083 80 word(s) 3 % : boot_up ; 0x00E4 46 word(s) 2 % : send_char ; 0x0112 47 word(s) 2 % : send_cmd ; 0x014F 19 word(s) 0 % : delay_ms ; 0x0141 14 word(s) 0 % : send_string ; 0x00D3 17 word(s) 0 % : busy_flag ; 0x0059 42 word(s) 2 % : main ; 0x0034 37 word(s) 1 % : _const1 ; RAM usage: 11 bytes (8 local), 53 bytes free ; Maximum call level: 4 (+1 for interrupt) ; Total of 351 code words (34 %)