; Replacement for Cyrus AM/FM tuner controller (MAB8441) and LCD (2x20 HD44780) ; v0.0 200926 Start project ; v0.1 200927 Add LCD ; v0.2 200928 Read buttons ; v0.3 200929 HEX display decoder ; v0.4 200929 Frequency index and readout via interrupt ; v0.5 200930 Calculate frequency display from index ; v0.6 200930 Put frequency on display ; v0.7 201003 Store FRINDX in EEPROM, scan speedup ; v0.8 201003 Manual/Autoscan ; v0.9 201004 STEREO and STOP signals ; v0.10 201004 Level ADC ; v0.11 201004 Level display (14 bars) LIST P=16F818, F=INHX8M #include <p16f818.inc> __CONFIG _WDT_OFF & _PWRTE_OFF & _INTRC_IO & _MCLR_ON & _BODEN_OFF & _LVP_OFF & _CPD_ON & _WRT_ENABLE_OFF & _DEBUG_OFF & _CCP1_RB2 & _CP_ALL ERRORLEVEL -302 ; remove message about using proper bank ; Equates RESET_V EQU 0x00 ; Address of RESET Vector OSC_FREQ EQU D'4000000' ; Internal Oscillator Frequency is 4 MHz (OSCCON) ; Registers FLAGS EQU 0x20 ; Various flags LCDAdd EQU 0x21 ; LCD Character Address LCDByte EQU 0x22 ; Byte to send to LCD TEMP1 EQU 0x23 ; Temp register TEMP2 EQU 0x24 ; Temp register d1 EQU 0x25 ; Delay register d2 EQU 0x26 ; Delay register I2CBUF EQU 0x27 ; Used for I2C data I2CCNT EQU 0x28 ; Used for I2C bitbanger FRINDX EQU 0x29 ; Frequency Index FR10MC EQU 0x2A ; 10 MHz display value FR1MC EQU 0x2B ; 1 MHz display value FR01MC EQU 0x2C ; 0.1 MHz display value DB0 EQU 0x2D ; TSA6057 config byte 0 DB1 EQU 0x2E ; TSA6057 config byte 1 SCANCTR EQU 0x30 ; Scan speed counter EEBUF EQU 0x31 ; Used for writing a byte to EEPROM ; Defines #define SCL PORTB,0 ; I2C Clock #define SDA PORTB,1 ; I2C Data #DEFINE LCD_EN PORTB,2 #DEFINE LCD_RS PORTB,3 #DEFINE LCD_D4 PORTB,4 #DEFINE LCD_D5 PORTB,5 #DEFINE LCD_D6 PORTB,6 #DEFINE LCD_D7 PORTB,7 #DEFINE MUTE PORTA,1 ; MUTE output (active HIGH) #DEFINE MONO PORTA,2 ; MONO (VCO Stop) (active LOW OUTPUT) #DEFINE UP PORTA,3 ; Up button (active LOW) #DEFINE DN PORTA,4 ; Down button (active LOW) #DEFINE STEREO PORTA,6 ; Stereo indicator from MPX (active low) #DEFINE STOP PORTA,7 ; Search STOP from demod (active low) #DEFINE NAK FLAGS,0 ; Not Acknowledge after I2C byte #DEFINE MANSCAN FLAGS,1 ; Used for debouncing buttons and automatic tuning #DEFINE AUTOSCAN FLAGS,2 ; AN0 (SIGMET) has no label defined ORG 0 GOTO START ORG 4 ; Interrupts ; Timer0 Interrupt Handler BCF INTCON,TMR0IF ; Clear TMR0 interrupt (every 58 ms) CALL UPDATEDISPLAY ; Shows STEREO and signal level bar BTFSS DN ; DN pressed? GOTO WriteDN ; Yes BTFSS UP ; UP pressed? GOTO WriteUP ; Yes CLRF TMR0 RETFIE WriteDN CALL LONGDLY ; Extra delay to catch short keypress CALL BlankSTEREO BSF MUTE MOVLW 0x0A MOVWF SCANCTR ; Preload Scan Speed Counter DNScanFast INCF SCANCTR,F ; Ensure scan test passes DNScanSlow DECF FRINDX,F MOVLW 0xCE ; Test for invalid index (>0xCD) SUBWF FRINDX,W BTFSS STATUS,C ; Invalid value? GOTO $+3 ; No MOVLW 0xCD ; Handle rollover MOVWF FRINDX MOVFW FRINDX ; Get correct value for display CALL LOADPLL CALL FREQDISPLAY BTFSC AUTOSCAN ; Autoscan ongoing? GOTO DNAuto ; Yes BTFSC MANSCAN ; Manual scan ongoing? GOTO DNMan ; Yes BTFSC DN ; DN pressed again? GOTO BTNExit ; Yes BSF MANSCAN DNCont DECFSZ SCANCTR,F ; Scan speed fast? GOTO $+2 ; No GOTO DNScanFast DNSlow ; Slow scan speed in case of Autoscan to provide time for correct STOP operation CALL LONGDLY CALL LONGDLY GOTO DNScanSlow DNAuto BTFSS STOP ; STOP active (low)? GOTO BTNExit BTFSC DN ; DN pressed again to cancel autoscan? GOTO DNSlow ; No CALL LONGDLY BTFSS DN ; Yes, released? GOTO $-2 ; No, not released GOTO BTNExit ; Yes, released DNMan BTFSC DN BSF AUTOSCAN ; No, released, manual scan ended GOTO DNCont ; Yes, held WriteUP CALL LONGDLY ; Extra delay to catch short keypress CALL BlankSTEREO BSF MUTE MOVLW 0x0A MOVWF SCANCTR ; Preload Scan Speed Counter UPScanFast INCF SCANCTR,F ; Ensure scan zero test passes UPScanSlow INCF FRINDX,F MOVLW 0xCE ; Test for index rollover SUBWF FRINDX,W BTFSC STATUS,C ; Invalid value? CLRF FRINDX ; Yes MOVFW FRINDX ; No CALL LOADPLL CALL FREQDISPLAY BTFSC AUTOSCAN ; Autoscan ongoing? GOTO UPAuto ; Yes BTFSC MANSCAN ; Manual scan ongoing? GOTO UPMan ; Yes BTFSC UP ; UP pressed again? GOTO BTNExit ; Yes BSF MANSCAN UPCont DECFSZ SCANCTR,F ; Scan speed fast? GOTO $+2 ; No GOTO UPScanFast UPSlow ; Slow scan speed in case of Autoscan to provide time for correct STOP operation CALL LONGDLY CALL LONGDLY GOTO UPScanSlow UPAuto BTFSS STOP ; STOP active (low)? GOTO BTNExit BTFSC UP ; UP pressed again to cancel autoscan? GOTO UPSlow ; No CALL LONGDLY BTFSS UP ; Yes, released? GOTO $-2 ; No, not released GOTO BTNExit ; Yes, released UPMan BTFSC UP BSF AUTOSCAN ; No, released, manual scan ended GOTO UPCont ; Yes, held BTNExit BCF MANSCAN BCF AUTOSCAN CALL LONGDLY MOVFW FRINDX ; Get current index to store in EEPROM MOVWF EEBUF CLRW ; Point to EEPROM Address 0x00 CALL EEPROMWRITE ; Save index CLRF TMR0 BCF MUTE RETFIE ; Subroutines (I2C) I2CSTART BCF SDA CALL I2CDELAY BCF SCL CALL I2CDELAY RETURN I2CBYTE ; Sends byte in W MOVWF I2CBUF MOVLW 0x08 MOVWF I2CCNT NEXTBIT BCF STATUS,C ; Clear carry RLF I2CBUF,F ; Rotate MSB into carry BTFSC STATUS,C ; Carry clear? BSF SDA ; No, set SDA BTFSS STATUS,C ; Carry set? BCF SDA ; No, clear SDA CALL I2CDELAY BSF SCL ; Send clock CALL I2CDELAY BCF SCL ; Done clock DECFSZ I2CCNT,F GOTO NEXTBIT ; ACK handler BSF STATUS,RP0 ; Select Bank 1 BSF TRISB,1 ; Set SDA as input to float SDA line BCF STATUS,RP0 ; Select Bank 0 BSF NAK CALL I2CDELAY BSF SCL ; Solicit ACK CLRF I2CCNT TESTACK BTFSC SDA ; SDA pulled low? GOTO CONTACK ; No, continue testing for ACK until timeout (~20 ms) BCF NAK ; Clear NAK GOTO EXITACK ; Exit loop CONTACK DECFSZ I2CCNT,F GOTO TESTACK EXITACK BSF STATUS,RP0 ; Select Bank 1 BCF TRISB,1 ; Set SDA as output BCF STATUS,RP0 ; Select Bank 0 BTFSC NAK ; NAK handler GOTO START ; Timeout, no ACK, force reset BCF SCL CALL I2CDELAY RETURN I2CSTOP BCF SDA CALL I2CDELAY BSF SCL CALL I2CDELAY BSF SDA RETURN I2CDELAY NOP ; 8 us delay NOP NOP NOP RETURN LOADPLL MOVFW FRINDX ; Get frequency index CLRF DB1 MOVWF DB0 RLF DB0,F RLF DB1,F ; Shift one bit into DB1 RLF DB0,F RLF DB1,F ; Shift one bit into DB1 RLF DB0,F RLF DB1,F ; Shift one bit into DB1 MOVLW 0xF8 ANDWF DB0,F ; Blank two LSBs MOVLW 0xB1 ADDWF DB0,F ; Add offset BTFSC STATUS,C ; Carry set? GOTO $+3 ; No MOVLW 0x1E ; Yes GOTO $+2 MOVLW 0x1F ADDWF DB1,F CALL I2CSTART MOVLW 0xC4 ; Address CALL I2CBYTE CLRW ; Subaddress (00) CALL I2CBYTE MOVFW DB0 CALL I2CBYTE MOVFW DB1 CALL I2CBYTE CALL I2CSTOP RETURN EEPROMREAD ; W contains address to read, at return contains read data BANKSEL EEADR ; Select Bank of EEADR MOVWF EEADR ; Data Memory Address to read from W BANKSEL EECON1 ; Select Bank of EECON1 BCF EECON1, EEPGD ; Point to Data memory BSF EECON1, RD ; EE Read BANKSEL EEDATA ; Select Bank of EEDATA MOVF EEDATA, W ; W = EEDATA RETURN EEPROMWRITE ; W contains address to write, data is in EEBUF BANKSEL EECON1 ; Select Bank of EECON1 BTFSC EECON1, WR ; Wait for write GOTO $-1 ; to complete BANKSEL EEADR ; Select Bank of EEADR MOVWF EEADR ; Data Memory Address to write BANKSEL EEBUF MOVFW EEBUF ; Data to write from buffer BANKSEL EEDATA MOVWF EEDATA ; Data Memory Value to write BANKSEL EECON1 ; Select Bank of EECON1 BCF EECON1, EEPGD ; Point to DATA memory BSF EECON1, WREN ; Enable writes MOVLW 0x55 MOVWF EECON2 ; Write 55h MOVLW 0xAA MOVWF EECON2 ; Write AAh BSF EECON1, WR ; Set WR bit to begin write BCF EECON1, WREN ; Disable writes BANKSEL PORTB ; Select BANK0 RETURN ; Subroutines (LCD) LCDPOS ; makes WREG the current LCD position BCF LCD_RS MOVWF LCDByte ; Valid values 0x80-0x8F, 0xC0-0xCF CALL LCDBYTE BSF LCD_RS CALL LONGDLY ; Needed for the LCD to process the command RETURN LCDCLR ; clears the entire display BCF LCD_RS ; Instruction mode MOVLW 0x01 MOVWF LCDByte CALL LCDBYTE BSF LCD_RS ; Character mode CALL LONGDLY ; Clearing the LCD takes ages, so a larger delay is needed RETURN LCDBYTE ; sends the byte in WREG to the LCD in 4bit fashion. Set LCD_RS as appropriate (0: instruction, 1: character) MOVWF LCDByte BCF LCD_D7 ; Clear data bits BCF LCD_D6 BCF LCD_D5 BCF LCD_D4 BTFSC LCDByte,7 ; Load high nibble BSF LCD_D7 BTFSC LCDByte,6 BSF LCD_D6 BTFSC LCDByte,5 BSF LCD_D5 BTFSC LCDByte,4 BSF LCD_D4 BSF LCD_EN ; Strobe EN NOP BCF LCD_EN BCF LCD_D7 ; Clear data bits BCF LCD_D6 BCF LCD_D5 BCF LCD_D4 BTFSC LCDByte,3 ; Load low nibble BSF LCD_D7 BTFSC LCDByte,2 BSF LCD_D6 BTFSC LCDByte,1 BSF LCD_D5 BTFSC LCDByte,0 BSF LCD_D4 BSF LCD_EN ; Strobe EN NOP BCF LCD_EN CALL SHORTDLY ; blocks until most instructions are done RETURN SHORTDLY ; around 221us, 217 cycles MOVLW 0x48 MOVWF d1 SHORTDLY_0 DECFSZ d1,F GOTO SHORTDLY_0 ;4 cycles (including call) RETURN LONGDLY ; 92ms delay, 92153 cycles MOVLW 0xFE MOVWF d1 MOVLW 0x48 MOVWF d2 LONGDLY_0 DECFSZ d1,F GOTO $+2 DECFSZ d2,F GOTO LONGDLY_0 ;3 cycles NOP NOP ;4 cycles (including call) RETURN HEXDISPLAY ; Decodes the byte in WREG and displays its HEX value at current position, handy for debugging MOVWF TEMP1 MOVWF TEMP2 RRF TEMP1,F RRF TEMP1,F RRF TEMP1,F RRF TEMP1,F MOVLW 0x0F ANDWF TEMP1,F ; Blank high nibble MOVLW 0x30 ADDWF TEMP1,F ; Add to get the numbers 0-9 MOVLW 0x3A SUBWF TEMP1,W ; Test if >9 BTFSS STATUS,C ; Carry set? GOTO $+3 ; No, value not >9 MOVLW 0x07 ADDWF TEMP1,F ; Add to get A-F MOVFW TEMP1 CALL LCDBYTE ; Show high nibble MOVLW 0x0F ANDWF TEMP2,F ; Blank high nibble MOVLW 0x30 ADDWF TEMP2,F ; Add to get the numbers 0-9 MOVLW 0x3A SUBWF TEMP2,W ; Test if >9 BTFSS STATUS,C ; Carry set? GOTO $+3 ; No, value not >9 MOVLW 0x07 ADDWF TEMP2,F ; Add to get A-F MOVFW TEMP2 CALL LCDBYTE ; Show low nibble RETURN FREQDISPLAY ; Decodes index to frequency display MOVLW 0x7D ; Test for >= 100 MHz SUBWF FRINDX,W BTFSC STATUS,C ; >= 100 MHz? GOTO TEST100MC ; Yes MOVLW 0x19 ; Test for >= 90 MHz SUBWF FRINDX,W BTFSC STATUS,C ; >= 90 MHz? GOTO TEST90MC ; Yes MOVLW 0x38 ; < 90 MHz MOVWF FR10MC MOVFW FRINDX ; Get index ADDLW 0x4B ; Calculate 1 MHz value MOVWF TEMP1 ; Save 1 MHz value GOTO TESTMC TEST100MC MOVWF TEMP1 ; Save 1 MHz value MOVLW 0x30 MOVWF FR10MC ; Set 10 MHz to "100" MOVFW FRINDX SUBLW 0x7D GOTO TESTMC TEST90MC MOVWF TEMP1 ; Save 1 MHz value MOVLW 0x39 MOVWF FR10MC TESTMC MOVLW 0x0A ; 0.x MHz SUBWF TEMP1,F BTFSS STATUS,C GOTO TEST0MC MOVLW 0x0A ; 1.x MHz SUBWF TEMP1,F BTFSS STATUS,C GOTO TEST1MC MOVLW 0x0A ; 2.x MHz SUBWF TEMP1,F BTFSS STATUS,C GOTO TEST2MC MOVLW 0x0A ; 3.x MHz SUBWF TEMP1,F BTFSS STATUS,C GOTO TEST3MC MOVLW 0x0A ; 4.x MHz SUBWF TEMP1,F BTFSS STATUS,C GOTO TEST4MC MOVLW 0x0A ; 5.x MHz SUBWF TEMP1,F BTFSS STATUS,C GOTO TEST5MC MOVLW 0x0A ; 6.x MHz SUBWF TEMP1,F BTFSS STATUS,C GOTO TEST6MC MOVLW 0x0A ; 7.x MHz SUBWF TEMP1,F BTFSS STATUS,C GOTO TEST7MC MOVLW 0x0A ; 8.x MHz SUBWF TEMP1,F BTFSS STATUS,C GOTO TEST8MC SUBWF TEMP1,F ; Compensate for compensation MOVLW 0x39 MOVWF FR1MC ; Store 9 MHz display value GOTO TEST100KC TEST8MC MOVLW 0x38 MOVWF FR1MC ; Store 8 MHz display value GOTO TEST100KC TEST7MC MOVLW 0x37 MOVWF FR1MC ; Store 7 MHz display value GOTO TEST100KC TEST6MC MOVLW 0x36 MOVWF FR1MC ; Store 6 MHz display value GOTO TEST100KC TEST5MC MOVLW 0x35 MOVWF FR1MC ; Store 5 MHz display value GOTO TEST100KC TEST4MC MOVLW 0x34 MOVWF FR1MC ; Store 4 MHz display value GOTO TEST100KC TEST3MC MOVLW 0x33 MOVWF FR1MC ; Store 3 MHz display value GOTO TEST100KC TEST2MC MOVLW 0x32 MOVWF FR1MC ; Store 2 MHz display value GOTO TEST100KC TEST1MC MOVLW 0x31 MOVWF FR1MC ; Store 1 MHz display value GOTO TEST100KC TEST0MC MOVLW 0x30 MOVWF FR1MC ; Store 0 MHz display value TEST100KC MOVLW 0x3A ; Compensate previous test and create ASCII code (30-39) ADDWF TEMP1,W MOVWF FR01MC ; Print the frequency MOVLW 0x80 CALL LCDPOS ; Set display leftmost corner MOVLW 0x30 SUBWF FR10MC,W ; Test for 100 MHz BTFSS STATUS,Z ; 100 MHz? GOTO $+3 ; No MOVLW 0x31 ; Print "1" GOTO $+2 MOVLW 0x20 ; Print " " CALL LCDBYTE MOVFW FR10MC CALL LCDBYTE MOVFW FR1MC ; Print 1 MHz CALL LCDBYTE MOVLW 0x2E ; Print "." CALL LCDBYTE MOVFW FR01MC ; Print 0.1 MHz CALL LCDBYTE RETURN UPDATEDISPLAY MOVLW 0xC0 ; 2nd row, leftmost position CALL LCDPOS BTFSC STEREO GOTO NotSTEREO MOVLW 0x53 ; Print "S" CALL LCDBYTE MOVLW 0x54 ; Print "T" CALL LCDBYTE MOVLW 0x45 ; Print "E" CALL LCDBYTE MOVLW 0x52 ; Print "R" CALL LCDBYTE MOVLW 0x45 ; Print "E" CALL LCDBYTE MOVLW 0x4F ; Print "O" CALL LCDBYTE GOTO LevelDisplay NotSTEREO MOVLW 0x20 ; Print " " CALL LCDBYTE MOVLW 0x20 ; Print " " CALL LCDBYTE MOVLW 0x20 ; Print " " CALL LCDBYTE MOVLW 0x20 ; Print " " CALL LCDBYTE MOVLW 0x20 ; Print " " CALL LCDBYTE MOVLW 0x20 ; Print " " CALL LCDBYTE LevelDisplay MOVLW 0xCF CALL LCDPOS ; Show level character in lower right corner BSF ADCON0,GO ; Start A/D (SIGMET) CONV0 NOP BTFSC ADCON0,GO ; Test if done GOTO CONV0 MOVFW ADRESH ; Move 8 bit A/D result to W MOVWF TEMP1 ; Save in TEMP register ADDLW 0xF1 BTFSC STATUS,C ; Level > -110 dBm? GOTO LEVEL2 ; Yes MOVLW 0x01 CALL LCDBYTE ; Print 2 bar MOVLW 0x8F CALL LCDPOS ; Blank level in upper right corner MOVLW 0x20 CALL LCDBYTE ; Print " " RETURN LEVEL2 MOVFW TEMP1 ; Get SIGMET ADDLW 0xED BTFSC STATUS,C ; Level > -105 dBm? GOTO LEVEL3 ; Yes MOVLW 0x02 CALL LCDBYTE ; Print 3 bar MOVLW 0x8F CALL LCDPOS ; Blank level in upper right corner MOVLW 0x20 CALL LCDBYTE ; Print " " RETURN LEVEL3 MOVFW TEMP1 ; Get SIGMET ADDLW 0xE8 BTFSC STATUS,C ; Level > -100 dBm? GOTO LEVEL4 ; Yes MOVLW 0x03 CALL LCDBYTE ; Print 4 bar MOVLW 0x8F CALL LCDPOS ; Blank level in upper right corner MOVLW 0x20 CALL LCDBYTE ; Print " " RETURN LEVEL4 MOVFW TEMP1 ; Get SIGMET ADDLW 0xDD BTFSC STATUS,C ; Level > -95 dBm? GOTO LEVEL5 ; Yes MOVLW 0x04 CALL LCDBYTE ; Print 5 bar MOVLW 0x8F CALL LCDPOS ; Blank level in upper right corner MOVLW 0x20 CALL LCDBYTE ; Print " " RETURN LEVEL5 MOVFW TEMP1 ; Get SIGMET ADDLW 0xCF BTFSC STATUS,C ; Level > -90 dBm? GOTO LEVEL6 ; Yes MOVLW 0x05 CALL LCDBYTE ; Print 6 bar MOVLW 0x8F CALL LCDPOS ; Blank level in upper right corner MOVLW 0x20 CALL LCDBYTE ; Print " " RETURN LEVEL6 MOVFW TEMP1 ; Get SIGMET ADDLW 0xC3 BTFSC STATUS,C ; Level > -85 dBm? GOTO LEVEL7 ; Yes MOVLW 0x06 CALL LCDBYTE ; Print 7 bar MOVLW 0x8F CALL LCDPOS ; Blank level in upper right corner MOVLW 0x20 CALL LCDBYTE ; Print " " RETURN LEVEL7 MOVFW TEMP1 ; Get SIGMET ADDLW 0xBD BTFSC STATUS,C ; Level > -80 dBm? GOTO LEVEL8 ; Yes MOVLW 0x07 CALL LCDBYTE ; Print 8 bar MOVLW 0x8F CALL LCDPOS ; Blank level in upper right corner MOVLW 0x20 CALL LCDBYTE ; Print " " RETURN LEVEL8 MOVLW 0x07 CALL LCDBYTE ; Print 8 bar (still lower right corner) MOVLW 0x8F CALL LCDPOS ; Move to upper right corner MOVFW TEMP1 ; Get SIGMET ADDLW 0xB8 BTFSC STATUS,C ; Level > -75 dBm? GOTO LEVEL9 ; Yes MOVLW 0x00 CALL LCDBYTE ; Print 1 bar RETURN LEVEL9 MOVFW TEMP1 ; Get SIGMET ADDLW 0xB0 BTFSC STATUS,C ; Level > -70 dBm? GOTO LEVELA ; Yes MOVLW 0x01 CALL LCDBYTE ; Print 2 bar RETURN LEVELA MOVFW TEMP1 ; Get SIGMET ADDLW 0xA2 BTFSC STATUS,C ; Level > -65 dBm? GOTO LEVELB ; Yes MOVLW 0x02 CALL LCDBYTE ; Print 3 bar RETURN LEVELB MOVFW TEMP1 ; Get SIGMET ADDLW 0x92 BTFSC STATUS,C ; Level > -60 dBm? GOTO LEVELC ; Yes MOVLW 0x03 CALL LCDBYTE ; Print 4 bar RETURN LEVELC MOVFW TEMP1 ; Get SIGMET ADDLW 0x84 BTFSC STATUS,C ; Level > -55 dBm? GOTO LEVELD ; Yes MOVLW 0x04 CALL LCDBYTE ; Print 5 bar RETURN LEVELD MOVFW TEMP1 ; Get SIGMET ADDLW 0x79 BTFSC STATUS,C ; Level > -50 dBm? GOTO LEVELE ; Yes MOVLW 0x05 CALL LCDBYTE ; Print 6 bar RETURN LEVELE MOVFW TEMP1 ; Get SIGMET ADDLW 0x72 BTFSC STATUS,C ; Level > -45 dBm? GOTO FULL ; Yes MOVLW 0x06 CALL LCDBYTE ; Print 6 bar RETURN FULL MOVLW 0x07 CALL LCDBYTE ; Print 7 bar RETURN BlankSTEREO MOVLW 0xC0 ; 2nd row, leftmost position CALL LCDPOS MOVLW 0x20 ; Print " " CALL LCDBYTE MOVLW 0x20 ; Print " " CALL LCDBYTE MOVLW 0x20 ; Print " " CALL LCDBYTE MOVLW 0x20 ; Print " " CALL LCDBYTE MOVLW 0x20 ; Print " " CALL LCDBYTE MOVLW 0x20 ; Print " " CALL LCDBYTE RETURN START ; Init stuff CLRF STATUS ; Do initialization, select Bank 0 CLRF INTCON ; Clear int-flags, disable interrupts CLRF PCLATH ; Keep in lower 2KByte CLRF CCP1CON MOVLW B'11111001' BANKSEL TRISA MOVWF TRISA ; RA7-3 Inputs, RA2,1 Outputs, AN0 Input CLRF TRISB ; RB7-0 Outputs MOVLW B'00000110' ; Timer0, prescaler 1:128 MOVWF OPTION_REG MOVLW B'01100000' ; 4 MHz clock MOVWF OSCCON MOVLW B'00001110' ; AN0 Analog input, AN1-4 Digital IO, ADRESH only (ADRESL discarded) MOVWF ADCON1 MOVLW B'01000001' ; AD conv ON, AN0 Selected, Fosc/8 (T(AD)=1us) BANKSEL ADCON0 MOVWF ADCON0 CLRF PORTB ; Make all PORT B outputs low CLRF FLAGS CLRF LCDAdd MOVLW 0x69 MOVWF FRINDX ; Set index to 98.0 MHz CLRF FR10MC CLRF FR1MC CLRF FR01MC BSF SCL BSF SDA BSF MONO BSF MUTE ; DEBUG ; GOTO WriteDN ; Init LCD CALL LONGDLY ; Set LCD to 4-bit mode MOVLW B'00110011' ; 2x 8bit resets CALL LCDBYTE CALL SHORTDLY MOVLW B'00110011' ; 2x 8bit resets CALL LCDBYTE CALL SHORTDLY MOVLW B'00110010' ; 8bit reset then 4bit reset CALL LCDBYTE CALL SHORTDLY MOVLW B'00101100' ; Function Set - 4bit, 2 lines CALL LCDBYTE CALL SHORTDLY MOVLW B'00000110' ; Set entry mode (move cursor to right after each write) CALL LCDBYTE CALL SHORTDLY MOVLW B'00001100' ; turn display on and cursor off CALL LCDBYTE CALL SHORTDLY MOVLW B'00000001' ; Display Clear CALL LCDBYTE CALL LONGDLY ; Should wait for BUSY flag to clear but we cannot read it... MOVLW B'00000010' ; Cursor Home CALL LCDBYTE CALL LONGDLY MOVLW B'01000000' ; Set CGRAM Address for top line of character 0x00 CALL LCDPOS CLRW CALL LCDBYTE ; Write CGRAM Data for top line of character 0x00 CLRW CALL LCDBYTE ; Write CGRAM Data for 2nd line of character 0x00 CLRW CALL LCDBYTE ; Write CGRAM Data for 3rd line of character 0x00 CLRW CALL LCDBYTE ; Write CGRAM Data for 4th line of character 0x00 CLRW CALL LCDBYTE ; Write CGRAM Data for 5th line of character 0x00 CLRW CALL LCDBYTE ; Write CGRAM Data for 6th line of character 0x00 CLRW CALL LCDBYTE ; Write CGRAM Data for 7th line of character 0x00 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for bottom line of character 0x00 (cursor) CLRW CALL LCDBYTE ; Write CGRAM Data for top line of character 0x01 CLRW CALL LCDBYTE ; Write CGRAM Data for 2nd line of character 0x01 CLRW CALL LCDBYTE ; Write CGRAM Data for 3rd line of character 0x01 CLRW CALL LCDBYTE ; Write CGRAM Data for 4th line of character 0x01 CLRW CALL LCDBYTE ; Write CGRAM Data for 5th line of character 0x01 CLRW CALL LCDBYTE ; Write CGRAM Data for 6th line of character 0x01 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for 7th line of character 0x01 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for bottom line of character 0x01 CLRW CALL LCDBYTE ; Write CGRAM Data for top line of character 0x02 CLRW CALL LCDBYTE ; Write CGRAM Data for 2nd line of character 0x02 CLRW CALL LCDBYTE ; Write CGRAM Data for 3rd line of character 0x02 CLRW CALL LCDBYTE ; Write CGRAM Data for 4th line of character 0x02 CLRW CALL LCDBYTE ; Write CGRAM Data for 5th line of character 0x02 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for 6th line of character 0x02 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for 7th line of character 0x02 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for bottom line of character 0x02 CLRW CALL LCDBYTE ; Write CGRAM Data for top line of character 0x03 CLRW CALL LCDBYTE ; Write CGRAM Data for 2nd line of character 0x03 CLRW CALL LCDBYTE ; Write CGRAM Data for 3rd line of character 0x03 CLRW CALL LCDBYTE ; Write CGRAM Data for 4th line of character 0x03 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for 5th line of character 0x03 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for 6th line of character 0x03 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for 7th line of character 0x03 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for bottom line of character 0x03 CLRW CALL LCDBYTE ; Write CGRAM Data for top line of character 0x04 CLRW CALL LCDBYTE ; Write CGRAM Data for 2nd line of character 0x04 CLRW CALL LCDBYTE ; Write CGRAM Data for 3rd line of character 0x04 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for 4th line of character 0x04 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for 5th line of character 0x04 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for 6th line of character 0x04 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for 7th line of character 0x04 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for bottom line of character 0x04 CLRW CALL LCDBYTE ; Write CGRAM Data for top line of character 0x05 CLRW CALL LCDBYTE ; Write CGRAM Data for 2nd line of character 0x05 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for 3rd line of character 0x05 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for 4th line of character 0x05 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for 5th line of character 0x05 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for 6th line of character 0x05 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for 7th line of character 0x05 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for bottom line of character 0x05 CLRW CALL LCDBYTE ; Write CGRAM Data for top line of character 0x06 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for 2nd line of character 0x06 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for 3rd line of character 0x06 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for 4th line of character 0x06 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for 5th line of character 0x06 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for 6th line of character 0x06 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for 7th line of character 0x06 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for bottom line of character 0x06 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for top line of character 0x07 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for 2nd line of character 0x07 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for 3rd line of character 0x07 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for 4th line of character 0x07 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for 5th line of character 0x07 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for 6th line of character 0x07 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for 7th line of character 0x07 MOVLW 0x1F CALL LCDBYTE ; Write CGRAM Data for bottom line of character 0x07 ; Done init LCD ; Show banner MOVLW 0x85 ; 6th position top line CALL LCDPOS MOVLW 0x43 ; C CALL LCDBYTE MOVLW 0x79 ; y CALL LCDBYTE MOVLW 0x72 ; r CALL LCDBYTE MOVLW 0x75 ; u CALL LCDBYTE MOVLW 0x73 ; s CALL LCDBYTE MOVLW 0xC2 ; 3rd postition bottom line CALL LCDPOS MOVLW 0x41 ; A CALL LCDBYTE MOVLW 0x4D ; M CALL LCDBYTE MOVLW 0x2F ; / CALL LCDBYTE MOVLW 0x46 ; F CALL LCDBYTE MOVLW 0x4D ; M CALL LCDBYTE MOVLW 0x20 ; space CALL LCDBYTE MOVLW 0x54 ; T CALL LCDBYTE MOVLW 0x75 ; u CALL LCDBYTE MOVLW 0x6E ; n CALL LCDBYTE MOVLW 0x65 ; e CALL LCDBYTE MOVLW 0x72 ; r CALL LCDBYTE ; Restore index from EEPROM CLRW CALL EEPROMREAD BANKSEL FRINDX MOVWF FRINDX ; Restored Frequency Index ; Init TSA5067 CALL LOADPLL CALL I2CSTART MOVLW 0xC4 ; Address CALL I2CBYTE MOVLW 0x02 ; Subaddress (02) CALL I2CBYTE MOVLW 0xA4 ; DB2 (BS: Sink current -> FM) CALL I2CBYTE CLRW ; DB3 CALL I2CBYTE CALL I2CSTOP MOVLW 0x10 ; Show banner for about one second MOVWF TEMP1 CALL LONGDLY DECFSZ TEMP1,F GOTO $-2 BCF MUTE CALL LCDCLR ; Clear display CALL LONGDLY MOVLW 0x83 ; Set cursor at the "." position CALL LCDPOS MOVLW 0x2E ; . CALL LCDBYTE MOVLW 0x20 ; " " CALL LCDBYTE MOVLW 0x20 ; " " CALL LCDBYTE MOVLW 0x4D ; M CALL LCDBYTE MOVLW 0x48 ; H CALL LCDBYTE MOVLW 0x7A ; z CALL LCDBYTE CALL FREQDISPLAY MOVLW B'10100000' ; Enable global (GIE), Timer0 (T0IE) interrupts MOVWF INTCON GOTO $ ; Loop forever ORG 0x2100 ; EEPROM Data DE 0x69 ; FRINDX END