; GPR's (General Purpose Registers) are used for the following: ;H070 and H071: counters for short delay and utility delay ;H072 used to temporarily store characters ;H075 used as offset counter in our tables. ;H078 used for the lower byte from the analog converter ;H079 used for the upper byte from the analog converter ;H07A used to transfer the number to be displayed to the low or high ASCII subroutine list p=16F1455 ; list directive to define processor #include "p16F1455.inc" ; processor specific variable definitions __CONFIG _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_ON & _FCMEN_ON __CONFIG _CONFIG2, _WRT_OFF & _CPUDIV_NOCLKDIV & _USBLSCLK_48MHz & _PLLMULT_3x & _PLLEN_DISABLED & _STVREN_ON & _BORV_LO & _LPBOR_OFF & _LVP_ON errorlevel -302 , -207 ; suppress message 302 from list file banksel OSCCON movlw B'00101110' ; we need to slow down the processor for the LCD display driver. Max 2 Mhz. We'll run at 1 Mhz movwf OSCCON ; everything above this line is simply setting up the processor at 1 MHz. banksel TRISA movlw B'11011111' ; set up PORTA for inputs except bit 5 which we'll use as an output movwf TRISA banksel ANSELA ;Let's set up the Analog to Digital converter input bsf ANSELA,4 ; this sets RA4 as an analog input banksel ADCON1 movlw B'11110000' ; this will right justify the analog output and use the Frc clock movwf ADCON1 banksel ADCON0 movlw B'00001101' ; this turns on the analog to digital converter and connects it to RA4 movwf ADCON0 ;################we've now configured out inputs, outputs and analog converter call utility_delay ; waits about 0.8 seconds for display to initialize banksel TRISC clrf TRISC ; we can now set PORTC to all outputs ; we'll now set the display to 4 bit mode ;NOTE: all binary numbers must include all 8 bits. However, only the lower 4 bits are actually connected and therefore, used banksel LATC movlw B'00000010' ;send first command for 4 bit mode. The lower nibble is actually 0000, but not connected. This is the upper nibble movwf LATC ;note bit 5 is still low. This is our E line on the LCD display. call pulse_e banksel LATC movlw B'00000010' ;send upper nibble command to 4 bit mode. Note: Bit 4 is kept low to keep RS line low for a COMMAND movwf LATC call pulse_e ; We are now in 4 bit mode. banksel LATC movlw B'00001100' ;send lower nibble command to 4 bit mode and two line mode. movwf LATC ;Note: Bit 4 is still kept low to keep RS line low for a COMMAND call pulse_e ; we are now in 4 bit, 2 line mode. banksel LATC movlw B'00000000' ;send upper nibble to turn on display, set cursor. movwf LATC call pulse_e banksel LATC movlw B'00001111' ;send lower nibble to turn on display, set cursor. movwf LATC call pulse_e ; The display is now turned on, with a flashing underline cursor at the current character location ;from now on, to send characters, we must set bit 4 on LATC high ;here's where we lock and load our message, sending it one character at a time ;*********** Subroutine to call a table of characters, a Hex 00 means the end of the table, we can just check the 0 flag movlw 0 movwf H'075' ;this sets up our own pointer for the table lookup, using GPR at Hex address 075 clrw ;clear the W cause that's the number on our pointer we're startin' with. ;************************************************************************************************************************************* ;******************************Main routine which retrieves a character from the table and then writes it to the LCD display ;************************************************************************************************************************************* message_send1: call message_list1 movwf H'072' ;whatever character we retrieved is stored in GPR 072 clrw ;clear the W for our math function iorwf H'072',0 ;we perform an inclusive OR between the W and GPR 072. If there are ANY 1's in there, we won't get a 0 btfsc STATUS,2 ;if we came back with a 0, the zero bit on STATUS will now be set - leave this subroutine if we got a 0 from our table goto next_step swapf H'072',0 ;this swaps the two nibbles from GPR 072 and stuffs the result in the W register. ;NOTE: swapf *does not change* what's in the GPR unless we store it there (put a 1 after the comma in the command) andlw B'00001111' ; we now clear the upper nibble banksel LATC movwf LATC ;we loaded the upper nibble into the W and now sent it to the LCD display as the first nibble bsf LATC,4 ; and then manually set bit 4 on LATC which is the RS line on the LCD call pulse_e ;pulse the E line to load the number we just sent movf H'072',0 ;because our swapf command did NOT swap the nibbles in the GPR itself, we can now just load the GPR contents onto LATC banksel LATC ;and the lower nibble of our character will be put onto the LATC andlw B'00001111' ; we now clear the upper nibble movwf LATC bsf LATC,4 ; and then manually set bit 4 on LATC which is the RS line on the LCD call pulse_e ;pulse the E line to load the number we just sent incf H'075',1 ;increment our pointer movf H'075',0 ;load our pointer into the W register. This will affect WHICH retlw in our list it accesses goto message_send1 next_step: ;this is going to be our main loop which sets the cursor on the display to row 2, column 1, and then ;reads the analog input, and displays what it got on the LCD ;****************sets cursor to first address of second row where we'll write the analog reading**************** ;these lines now send a command to move the cursor to a new location. See downloadable display map to change it. banksel LATC movlw B'00001100' ;first nibble of address command for address H40 We must send H80 + H40 = HC0 movwf LATC ; and also bit 4 is set at 0 so the LCD knows it's getting a command, not a character call pulse_e banksel LATC movlw B'00000000' ; the second nibble of address command HC0 movwf LATC call pulse_e call short_delay ; Remember that some commands took up to 2 miliseconds to fulfill? We just sent a command, let's wait a short delay to let it finish. ;****************END sets cursor to first address of second row**************** ;****************let's read the analog input now ;NOTE: the analog input is a 10 bit number, not 8 bit. We'll read three nibbles and display them banksel ADCON0 bsf ADCON0,1 ;let's get that conversion started! adcheck: btfsc ADCON0,1 ;is it done yet? huh? huh? If it isn't, go back and check again. goto adcheck banksel ADRESL movf ADRESL,0 ;grab the lower byte, put it GPRAM movwf H'078' banksel ADRESH movf ADRESH,0 ; grab the upper byte, put in GPRAM movwf H'079' banksel ADCON0 bsf ADCON0,1 ; we grabbed the converted numbers, let's get the analog converter started working on the next conversion ;#########################Now reset the cursor to the start of row 2 banksel LATC movlw B'00001100' ;first nibble of address command for address H40 We must send H80 + H40 = HC0 movwf LATC ; and also bit 4 is set at 0 so the LCD knows it's getting a command, not a character call pulse_e banksel LATC movlw B'00000000' ; the second nibble of address command HC0 movwf LATC call pulse_e ;*********************we'll now convert the two analog bytes into three ASCII characters and send them to the display, highest nibble first ;******************************************************************************************************************************************* movf H'079',0 ; let's load up the first nibble, the lower nibble of the upper byte andlw B'00001111' ;remove the upper nibble movwf H'07A' ;move it to our GPR, keeping a copy in our W register sublw D'9' ; we need to check if the value is higher than 9, so we subtract 9 and check the borrow bit btfsc STATUS, 0 call ascii_prep_low ;comes back with 00110000 added to it for ASCII characters 0-9 call ascii_prep_high ; comes back with 01000001 added to it for ASCII characters A-F ;now that the number has been converted to ASCII, we send the character to the display. banksel LATC ;send the first nibble of our character to the LCD swapf H'07A',0 andlw B'00001111' ; clear the upper nibble so as to not set any upper bits high on LATC movwf LATC bsf LATC,4 ; and then manually set bit 4 on LATC which is the RS line on the LCD call pulse_e ;pulse the E line to send the lower portion of the nibble for the first character banksel LATC ;send the first nibble of our character to the LCD movf H'07A',0 ;load up lower nibble andlw B'00001111' ; clear the upper nibble so as to not set any upper bits high on LATC movwf LATC bsf LATC,4 ; and then manually set bit 4 on LATC which is the RS line on the LCD call pulse_e ;pulse the E line to send the lower portion of the nibble for the first character ;####################################convert the second nibble to ASCII value ;############################################################################# swapf H'078',0 ; let's load up the upper nibble of the lower byte andlw B'00001111' ;get rid of all of the upper nibble movwf H'07A';move it to our GPR sublw D'9' ; we need to check if the value is higher than 9, so we subtract 9 and check the borrow bit btfsc STATUS, 0 call ascii_prep_low ;comes back with 00110000 added to it for ASCII characters 0-9 call ascii_prep_high ; comes back with 01000001 added to it for ASCII characters A-F ;now that the number has been converted to ASCII, we send the character to the display. banksel LATC ;send the first nibble of our character to the LCD swapf H'07A',0 andlw B'00001111' ; clear the upper nibble so as to not set any upper bits high on LATC movwf LATC bsf LATC,4 ; and then manually set bit 4 on LATC which is the RS line on the LCD call pulse_e ;pulse the E line to send the lower portion of the nibble for the first character banksel LATC ;send the first nibble of our character to the LCD movf H'07A',0 ;load up lower nibble andlw B'00001111' ; clear the upper nibble so as to not set any upper bits high on LATC movwf LATC bsf LATC,4 ; and then manually set bit 4 on LATC which is the RS line on the LCD call pulse_e ;pulse the E line to send the lower portion of the nibble for the first character ;####################################convert the third nibble to ASCII value ;############################################################################# movf H'078',0 ; let's load up the lower nibble of the lower byte andlw B'00001111' ;get rid of all of the upper nibble movwf H'07A';Move it to our GPR sublw D'9' ; we need to check if the value is higher than 9, so we subtract 9 and check the borrow bit btfsc STATUS, 0 call ascii_prep_low ;comes back with 00110000 added to it for ASCII characters 0-9 call ascii_prep_high ; comes back with 01000001 added to it for ASCII characters A-F ;now that the number has been converted to ASCII, we send the character to the display. banksel LATC ;send the first nibble of our character to the LCD swapf H'07A',0 andlw B'00001111' ; clear the upper nibble so as to not set any upper bits high on LATC movwf LATC bsf LATC,4 ; and then manually set bit 4 on LATC which is the RS line on the LCD call pulse_e ;pulse the E line to send the lower portion of the nibble for the first character banksel LATC ;send the first nibble of our character to the LCD movf H'07A',0 ;load up lower nibble andlw B'00001111' ; clear the upper nibble so as to not set any upper bits high on LATC movwf LATC bsf LATC,4 ; and then manually set bit 4 on LATC which is the RS line on the LCD call pulse_e ;pulse the E line to send the lower portion of the nibble for the first character call utility_delay ;****************END sets cursor to first address of second row**************** banksel ADCON0 goto adcheck endless_loop goto endless_loop ;this subroutine converts a number 0-9 to the LCD in ASCII ascii_prep_low: movf H'07A',0 addlw B'00110000' movwf H'07A' return ascii_prep_high: movf H'07A',0 btfsc H'07A',5 ;checks if the number has already been modified to ASCII 0-9 return ; goes back unchanged if it has been modified addlw B'00110111' ; if it hasn't been modified, then we add the ASCII offset for characters A-F movwf H'07A' return ;*****************************Our first message to be sent************************************ message_list1: ;first message to be displayed addwf PCL,1 ; we add our count to the program counter! retlw "A" retlw "n" retlw "a" retlw "l" retlw "o" retlw "g" retlw " " retlw "R" retlw "e" retlw "a" retlw "d" retlw ":" retlw 00 utility_delay: ; this subroutine is a utility delay that counts down from 255 255 times. That's a total count of 65025. It takes approximately 0.8 seconds at 1 MHz movlw D'255' movwf H'070' ; load 255 into first register movlw D'255' movwf H'071' ; load 255 into second register subloop: decfsz H'070', 1 ; count down in first register till we hit 0 goto subloop movlw D'255' movwf H'070' ; load 255 into first register again decfsz H'071', 1 ; count down 1 on second register. If we're at 0, we've now gone through 255 loops of 255. Return back to the main program. goto subloop return pulse_e: banksel LATA bsf LATA,5 ;sends one pulse on the E line nop ; waitaminit nop ; waitaminit bcf LATA,5 ;sets E line to low nop ; waitaminit nop ; waitaminit return short_delay: ; this subroutine is a utility delay that counts down from 255 to 0. It takes approximately 3 miliseconds at 1 MHz. movlw D'255' movwf H'070' ; load 255 into first register shortloop: decfsz H'070', 1 ; count down in first register till we hit 0 goto shortloop return end