; 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