;********************************************************************** ; ; Filename: PWIBP100.ASM ; Date: 11th April 2007 ; Version: 1.00 First released complete version ; ; Files required: P16F871.INC (standard include file) ; ;********************************************************************** ; ; Copyright Philip Cadman G4JCP (2007) ; ; This software is freeware for non-commercial use ; Other uses please contact phil@g4jcp.freeserve.co.uk ; Use entirely at your own risk (as if you didn't know) ; ;********************************************************************** LIST P=16F871 ;Define processor #INCLUDE ;Register definitions, etc. RADIX DEC ;Decimal numbers ERRORLEVEL -302 ;Suppress bank messages VARIABLE CONF = 0x3FFF ;To make CONFIG word without long line CONF = CONF & _CP_OFF & _DEBUG_OFF & _WRT_ENABLE_OFF & _CPD_OFF CONF = CONF & _LVP_OFF & _BODEN_OFF & _PWRTE_ON & _WDT_OFF & _XT_OSC __CONFIG CONF ;Configuration word ;********************************************************************** ; Equates LPORTA EQU B'00101111' ;Band leds on port A LPORTB EQU B'00110110' ;Beacon leds on port B LPORTC EQU B'00111111' ;Beacon leds on port C LPORTD EQU B'11111111' ;Beacon leds on port D LCDPWR EQU PORTB ;LCD power control port BL EQU D'5' ;RB5 (backlight) RW EQU D'4' ;RB4 (read/-write select) VO EQU D'2' ;RB2 (contrast) VD EQU D'1' ;RB1 (Vdd) LCDCTL EQU PORTC ;LCD bus control RS EQU D'5' ;RC5 (register select) EN EQU D'4' ;RC4 (enable) LCDDAT EQU PORTD ;LCD data bus ;********************************************************************** ; Variables CBLOCK 0x20 ;RAM accessible in bank 0 and bank 2 RXCHAR ;Saved received char BAND ;Band l.e.d. to display BEACON ;Beacon l.e.d. to display PREVBAND ;Last received band number NEWBAND ;Band from current switch position LSTBAND ;Band from last read switch position ACTBAND ;Band last recognised and acted on DELAY1 ;Temporary variables DELAY2 ; PTR1 ; PTR2 ; TEMP1 ; TEMP2 ; SERTEMP ; LCDTEMP ; ENDC ;Ends at 0x6F CBLOCK 0x70 ;Common RAM accessible in all banks INT_W ;Saved W register (interrupts) INT_S ;Saved STATUS register (interrupts) ; INT_P ;Saved PCLATH register (interrupts) ;^^^^^ Un-comment if required ^^^^^ ONESEC ;Runs from 0 to 7 TIMER0 interrupts TENSEC ;Runs from 0 to 9 seconds DECSEC ;RTC tens of seconds (0 - 5) MINS ;RTC minutes (0 - 2) 3-minute cycle SLOT ;Ten-second beacon slot (1 - 18) UPDCLK ;Non-zero if 10-sec slot update required UPDBND ;Non-zero if band change update required UPDCOL ;Non-zero if l.c.d. ':' turn off required UPDTIM ;Non-zero if new l.c.d. time required ENDC ;End of common RAM (0x7F) ;********************************************************************** ; Code ORG 0x000 ;Reset vector NOP ;NOP so can patch a jump for debug CLRF PCLATH ;Ensure page bits are cleared GOTO COLD_START ; ;********************************************************************** ORG 0x004 ;Interrupt vector ;May as well put interrupt code here MOVWF INT_W ;Save W SWAPF STATUS,W ; MOVWF INT_S ;Save STATUS (swapped) ; BTFSS INTCON,T0IF ;Check for timer 0 interrupt GOTO NOT_TMR ;Jump if not BCF INTCON,T0IF ;Else clear timer 0 interrupt ; Timer 0 interupt every 125mS (2,048Hz / 256 = 8Hz) INCF ONESEC,F ;next 125mS MOVF ONESEC,W ; SUBLW D'8' ;Test for one full second BNZ TRYCOL ;Jump if not CLRF ONESEC ;Else set counter to zero BCF INTCON,INTF ; and clear any pending manual reset NOP ;Not sure whether NOPs are needed NOP ; (for interrupt logic to settle) NOP ; NOP ; BSF INTCON,INTE ; and reenable manual resets INCF TENSEC,F ;Increment ten second (slot) counter MOVF TENSEC,W ; SUBLW D'10' ;Test for 10 seconds gone BNZ TI02 ;Jump if not INCF UPDCLK,F ;Else set timer update flag CLRF TENSEC ; and reset counter INCF SLOT,F ;Increment to next beacon time slot ;No need to check as it will be reset ;to slot one at end of 3-minute cycle INCF DECSEC,F ;Update RTC for l.c.d. MOVF DECSEC,W ; SUBLW D'6' ;next minute? BNZ TI02 ;Jump if not CLRF DECSEC ;Else RTC ten-seconds back to zero INCF MINS,F ; and increment minute count MOVF MINS,W ; SUBLW D'3' ;End of three-minute cycle? BNZ TI02 ;Jump if not CLRF MINS ;Else RTC minutes back to zero CLRF SLOT ; and INCF SLOT,F ; set beacon slot to one ; TI02 INCF UPDTIM,F ;Update l.c.d. time display GOTO INTDONE ;Done ; TRYCOL MOVF ONESEC,W ;Get count SUBLW D'4' ;Test for 0.5 second SKPNZ ;Skip if not INCF UPDCOL,F ;Else set update l.c.d. 'colon' flag GOTO INTDONE ;Done ; End of timer interrupt code NOT_TMR BTFSS INTCON,INTF ;Check for external interrupt GOTO COLD_START ;Jump to reset if not (error) BCF INTCON,INTF ;Else clear external interrupt ; Manual reset input BCF INTCON,INTE ;Disable further external interrupts CLRF TMR0 ;Clear timer 0 NOP ;Probably no need BCF INTCON,T0IF ;Clear any pending timer 0 interrupt CLRF ONESEC ; and zero RTC and other counters CLRF TENSEC ; CLRF DECSEC ; CLRF MINS ; CLRF SLOT ; INCF SLOT,F ;SLOT starts at one not zero ; but BAND stays as before INCF UPDCLK,F ;Treat like 10-sec update required ; and drop through to interrupt exit ; Interrupt exit INTDONE SWAPF INT_S,W ;Retrieve STATUS (and unswap) MOVWF STATUS ;Restore STATUS SWAPF INT_W,F ;Swap saved W register SWAPF INT_W,W ;Unswap and restore W register RETFIE ;Return from interrupt ; End of page zero code ;********************************************************************** ; Note: CAT/LED lookup tables are also in page 0 - see later ;********************************************************************** ORG 0x100 COLD_START ;Main program begins CLRF INTCON ;No interrupts BCF STATUS,IRP ;FSR accesses 0x00 to 0xFF BCF STATUS,RP1 ;Direct addresses BCF STATUS,RP0 ; access bank 0 ; Note: Pre/postscaler defaults to WDT at reset ; (WDT is not used in this program - see __CONFIG ) ; This is okay as no prescale is needed for TIMER0 CLRWDT ;It's turned off anyway ; BSF STATUS,RP0 ;Bank 1 MOVLW B'10111111' ;No PORTB pull-ups, int on -ve edge RB0 MOVWF OPTION_REG ; TMR0 on RA4/T0CKI, inc on high to low ; Prescaler on WDT, value 1:128 MOVLW 0x06 ; MOVWF ADCON1 ;All PORTA pins set to digital I/O MOVLW 0xFF ; MOVWF TRISA ;PORTA all inputs MOVWF TRISB ;PORTB all inputs MOVWF TRISC ;PORTC all inputs MOVWF TRISD ;PORTD all inputs CLRF TRISE ;PORTE all outputs and PSP off CLRF PIE1 ;Turn off peripheral interrupts CLRF PIE2 ; ; BSF STATUS,RP1 ;Bank 3 CLRF EECON1 ;No EEPROM reads or writes ; BCF STATUS,RP0 ;Bank 2 CLRF EEDATA ;Clear EEPROM CLRF EEDATH ; data CLRF EEADR ; and CLRF EEADRH ; address ; BCF STATUS,RP1 ;Bank 0 CLRF CCP1CON ;No capture/compare CLRF T1CON ;TIMER1 off CLRF T2CON ;TIMER2 off CLRF PIR1 ;Clear interrupt flags CLRF PIR2 ;As above CLRF ADCON0 ;ADC off (ADCON1 already set up) CLRF PORTE ;PORTE all low ; CLRF ONESEC ;Clear RTC counters CLRF TENSEC ; CLRF DECSEC ; CLRF MINS ; CLRF SLOT ; INCF SLOT,F ;(SLOT starts at one) ; CLRF UPDCLK ;Clear update flags CLRF UPDBND ; CLRF UPDCOL ; CLRF UPDTIM ; ; CLRF LSTBAND ;Clear bandswitch update flags CLRF ACTBAND ; CLRF UPDBND ; ; CLRF PREVBAND ;Clear last received band number CLRF BAND ; CLRF BEACON ; ; Initialise UART for 4800 baud operation BSF STATUS,RP0 ;Bank 1 MOVLW D'12' ;BRG divisor MOVWF SPBRG ;4800 baud MOVLW B'00100000' ;Eight-bit charaters, transmitter on MOVWF TXSTA ; async mode, low speed BRG ; BCF STATUS,RP0 ;Bank 0 MOVLW B'10000000' ;Enable serial port, 8-bit characters MOVWF RCSTA ; receiver off, no address detect ; Now to check whether LED or LCD clock, or LED repeater ; RB7 RB6 Function ; 1 1 LED clock ; 1 0 LCD clock ; 0 1 LED repeater ; 0 0 undefined - defaults to LED repeater ; GOTO LCD_CLOCK ;## ; BTFSS PORTB,7 ;Repeater? GOTO LED_REPEATER ;Jump if yes (RB6 is don't care) BTFSS PORTB,6 ;Not a repeater, check for LCD GOTO LCD_CLOCK ;Jump if LCD clock ; GOTO LED_CLOCK ;Drop through ;********************************************************************** LED_CLOCK ;Initialise for LED clock CLRF PORTA ;All inputs, but clear o/p latches CLRF PORTB ;Set all leds to off CLRF PORTC ; CLRF PORTD ; BTFSC PORTB,3 ;Test active low (RB3=low)? GOTO LC01 ;If no, skip invert ; MOVLW LPORTB ;Active low so invert l.e.d. port pins MOVWF PORTB ; by writing l.e.d. mask to ports MOVLW LPORTC ; MOVWF PORTC ; MOVLW LPORTD ; MOVWF PORTD ; LC01 ;Now to set port directions BSF STATUS,RP0 ;Bank 1 MOVLW B'11001001' ; MOVWF TRISB ;Port B four l.e.d. outputs MOVLW B'11000000' ;bits 7/6 must be inputs for serial port MOVWF TRISC ;Port C six l.e.d. outputs MOVLW B'00000000' ; MOVWF TRISD ;Port D eight l.e.d. outputs BCF STATUS,RP0 ;Bank 0 ; BSF INTCON,INTE ;Enable external interrupt (RB0/INT) BSF INTCON,T0IE ;Enable TMR0 interrupt BSF INTCON,GIE ;Enable interrupts ; INCF UPDCLK,F ;Force a new display at switch on ; TLB01 CALL CHK_BAND ; TSTF UPDBND ;Band udate? SKPZ ;Skip if not GOTO SWITCH ;Else do bandswitch update ; TSTF UPDCLK ;Timeslot udate? SKPZ ;Skip if not GOTO TIME ;Else do timeslot update ; TSTF UPDCOL ;Colon upate? SKPZ ;Skip if not GOTO COLON ;Else do colon update ; TSTF UPDTIM ;L.C.D display time upate? SKPZ ;Skip if not GOTO LCDTIME ;Else do colon update ; GOTO TLB01 ;And loop SWITCH ;Bandswitch update CLRF UPDBND ;Clear update flag MOVF NEWBAND,W ;Get the new bandswitch position MOVWF ACTBAND ;Now the current active band BNZ SW01 ;Jump if not band zero (Z set by MOVF) ; CLRF BEACON ; CALL DISPBEACON ;Turn off beacon l.e.d.s CLRW ; CALL SEND_CHAR ;Send zero byte to turn off repeater GOTO TLB01 ;And loop ; SW01 DECF SLOT,W ;Find beacon number from slot and band MOVWF TEMP2 ;TEMP2 = SLOT - 1 DECF ACTBAND,W ;W = BAND - 1 SUBWF TEMP2,W ;W = (SLOT - 1) - (BAND - 1) SKPC ;Skip no borrow ADDLW D'18' ;Add 18 to wrap around ADDLW D'1' ;Now W = beacon number MOVWF BEACON ;Save CALL DISPBEACON ;Display new beacon l.e.d. SWAPF NEWBAND,F ;NEWBAND = <0.band><0.0.0.0> RLF NEWBAND,W ;W = <0.0.0.X> SWAPF NEWBAND,F ;NEWBAND = <0.0.0.0><0.band> as before ANDLW B'11100000' ;Mask lower bits (because of X above) ADDWF BEACON,W ;<7.6.5> band <4.3.2.1.0> beacon CALL SEND_CHAR ;Send data to repeater GOTO TLB01 ;And loop ; TIME ;Timeslot update CLRF UPDCLK ;Clear update flag TSTF ACTBAND ;Check the active bandswitch position BNZ TM01 ;Jump if not band zero ; Remaining routine is a copy of the switch code above ; This ensures that a byte is sent to the repeater every ten seconds ; regardless of the bandswitch position. CLRF BEACON ;Else keep l.e.d.s turned off CALL DISPBEACON ;Turn off beacon l.e.d.s CLRW ; CALL SEND_CHAR ;Send zero byte to turn off repeater GOTO TLB01 ;And loop ; TM01 DECF SLOT,W ;Find beacon number from slot and band MOVWF TEMP2 ;TEMP2 = SLOT - 1 DECF ACTBAND,W ;W = BAND - 1 SUBWF TEMP2,W ;W = (SLOT - 1) - (BAND - 1) SKPC ;Skip no borrow ADDLW D'18' ;Add 18 to wrap around ADDLW D'1' ;Now W = beacon number MOVWF BEACON ;Save CALL DISPBEACON ;Display new beacon l.e.d. SWAPF NEWBAND,F ;NEWBAND = <0.band><0.0.0.0> RLF NEWBAND,W ;W = <0.0.0.X> SWAPF NEWBAND,F ;NEWBAND = <0.0.0.0><0.band> as before ANDLW B'11100000' ;Mask lower bits (because of X above) ADDWF BEACON,W ;<7.6.5> band <4.3.2.1.0> beacon CALL SEND_CHAR ;Send data to repeater GOTO TLB01 ;And loop ; COLON ;Colon (half-second) update CLRF UPDCOL ;Clear update flag ;Nothing to do as no l.c.d. GOTO TLB01 ;And loop ; LCDTIME ;L.C.D. display time update CLRF UPDTIM ;Clear update flag ;Nothing to do as no l.c.d. GOTO TLB01 ;And loop ;********************************************************************** LCD_CLOCK ;Initialise for LCD clock CLRF PORTA ;All inputs, but clear o/p latches CLRF PORTB ;Set all outputs to low CLRF PORTC ; CLRF PORTD ; ;Now to set port directions BSF STATUS,RP0 ;Bank 1 ; MOVLW B'11001001' ;Port B 5=backlight 4=R/W MOVWF TRISB ; 2=Vo (contrast) 1=Vdd ; MOVLW B'11000000' ;Port C 5=RS 4=E 3..0 not used MOVWF TRISC ;7&6 must be inputs for serial port ; MOVLW B'00000000' ;Port D MOVWF TRISD ;l.c.d. data bus (outputs) D7..D0 ; BCF STATUS,RP0 ;Bank 0 ; BSF INTCON,INTE ;Enable external interrupt (RB0/INT) BSF INTCON,T0IE ;Enable TMR0 interrupt BSF INTCON,GIE ;Enable interrupts ; INCF UPDCLK,F ;Force a new display at switch on CALL LCD_POWERUP ;Turn on l.c.d. CALL GET_BAND ;Get bandswitch position? TSTF NEWBAND ;In zero position? BNZ LCD01 ;Jump if not ; else BCF LCDCTL,RS ;Force ALL l.c.d. data and BCF LCDCTL,EN ; control lines to zero CLRF LCDDAT ; CLRF LCDPWR ;And turn off l.c.d. CLRW ; BTFSS PORTB,3 ;Skip send if RB3 high CALL SEND_CHAR ;Send zero byte to turn off repeater ; LCD01 CALL CHK_BAND ;Read bandswitch and check TSTF UPDBND ;Band udate? SKPZ ;Skip if not GOTO LSWITCH ;Else do bandswitch update ; TSTF UPDCLK ;Timeslot udate? SKPZ ;Skip if not GOTO LTIME ;Else do timeslot update ; TSTF UPDCOL ;Colon upate? SKPZ ;Skip if not GOTO LCOLON ;Else do colon update ; TSTF UPDTIM ;L.C.D display time upate? SKPZ ;Skip if not GOTO LRTC ;Else do time display update ; MOVF ACTBAND,W ;Get active band number SUBWF PREVBAND,W ;Compare with last band SKPNZ ;If different then skip GOTO LCD01 ;Else same so can loop ; MOVF ACTBAND,W ;Get again MOVWF PREVBAND ;And update SKPNZ ;Band=0? flag set by MOVF GOTO LCD01 ;Don't send frequency if band=0 ;Now to send the new frequency BTFSS PORTB,3 ;Skip loop if RB3 high (CAT drive) GOTO LCD01 ;Else don't send frequency ; DECF ACTBAND,W ;Work with band-1 MOVWF PTR1 ;W=PTR1=band RLF PTR1,F ;Times 2 RLF PTR1,F ;Times 4 RLF PTR1,W ;Times 8 now in W ANDLW B'11111000' ;Force lower three bits to zero MOVWF PTR1 ;Points to first char of frequency MOVLW D'5' ;Counter for five bytes MOVWF PTR2 ;Save ;Table in page 0 (PCLATH=0) LNC02 MOVF PTR1,W ;Pointer into W CALL CAT_COMS ;Get byte CALL SEND_CHAR ;And send to rig INCF PTR1,F ;Next char DECFSZ PTR2,F ;Loop GOTO LNC02 ; if more GOTO LCD01 ;And loop LSWITCH ;Bandswitch update CLRF UPDBND ;Clear update flag TSTF ACTBAND ;Was bandswitch zero last time? SKPNZ ;Skip if not CALL LCD_POWERUP ;Else turn on the l.c.d. first MOVF NEWBAND,W ;Get the new bandswitch position MOVWF ACTBAND ;Now the current active band BNZ LSW01 ;Jump if not band zero (Z set by MOVF) CLRF BEACON ; BCF LCDCTL,RS ;Force ALL l.c.d. data and BCF LCDCTL,EN ; control lines to zero CLRF LCDDAT ; (just in case) CLRF LCDPWR ;And turn off l.c.d. CLRW ; BTFSS PORTB,3 ;Skip send if RB3 high CALL SEND_CHAR ;Send zero byte to turn off repeater GOTO LCD01 ;And loop ; LSW01 DECF SLOT,W ;Find beacon number from slot and band MOVWF TEMP2 ;TEMP2 = SLOT - 1 DECF ACTBAND,W ;W = BAND - 1 SUBWF TEMP2,W ;W = (SLOT - 1) - (BAND - 1) SKPC ;Skip no borrow ADDLW D'18' ;Add 18 to wrap around ADDLW D'1' ;Now W = beacon number MOVWF BEACON ;Save SWAPF NEWBAND,F ;NEWBAND = <0.band><0.0.0.0> RLF NEWBAND,W ;W = <0.0.0.X> SWAPF NEWBAND,F ;NEWBAND = <0.0.0.0><0.band> as before ANDLW B'11100000' ;Mask lower bits (because of X above) ADDWF BEACON,W ;<7.6.5> band <4.3.2.1.0> beacon BTFSS PORTB,3 ;Skip send if RB3 high CALL SEND_CHAR ;Send data to repeater CALL DISPLCD ;Display new band on l.c.d. GOTO LRTC ;And jump to display time routine LTIME ;Timeslot update CLRF UPDCLK ;Clear flag TSTF ACTBAND ;Check the active bandswitch position BNZ LTM01 ;Jump if not band zero ; Remaining routine is a copy of the switch code above ; This ensures that a byte is sent to the repeater every ten seconds ; regardless of the bandswitch position. CLRF BEACON ;Else keep l.e.d.s turned off CLRW ;L.C.D. should already be turned off BTFSS PORTB,3 ;Skip send if RB3 high CALL SEND_CHAR ;Send zero byte to turn off repeater GOTO LCD01 ;And loop ; LTM01 DECF SLOT,W ;Find beacon number from slot and band MOVWF TEMP2 ;TEMP2 = SLOT - 1 DECF ACTBAND,W ;W = BAND - 1 SUBWF TEMP2,W ;W = (SLOT - 1) - (BAND - 1) SKPC ;Skip no borrow ADDLW D'18' ;Add 18 to wrap around ADDLW D'1' ;Now W = beacon number MOVWF BEACON ;Save SWAPF NEWBAND,F ;NEWBAND = <0.band><0.0.0.0> RLF NEWBAND,W ;W = <0.0.0.X> SWAPF NEWBAND,F ;NEWBAND = <0.0.0.0><0.band> as before ANDLW B'11100000' ;Mask lower bits (because of X above) ADDWF BEACON,W ;<7.6.5> band <4.3.2.1.0> beacon BTFSS PORTB,3 ;Skip send if RB3 high CALL SEND_CHAR ;Send data to repeater CALL DISPLCD ;Display new beacon on l.c.d. GOTO LRTC ;And jump to display time routine LCOLON ;L.C.D. colon turn off CLRF UPDCOL ;Clear flag TSTF ACTBAND ;Check if display on (BAND<>0) SKPNZ ;Skip if display on GOTO LCD01 ;Else ignore MOVLW 0x80+0x4D ;Cursor to second line offset 13 CALL LCDINS ; MOVLW ' ' ;Change colon to space CALL LCDCHR ; GOTO LCD01 ;And loop LRTC ;L.C.D. time display update CLRF UPDTIM ;Clear flag TSTF ACTBAND ;Check if display on (BAND<>0) SKPNZ ;Skip if display on GOTO LCD01 ;Else ignore MOVLW 0x80+0x4C ;Cursor to second line offset 12 CALL LCDINS ; BCF INTCON,GIE ;Disable interrupts MOVF MINS,W ;Get minutes (0..2) ADDLW '0' ;Convert to ASCII CALL LCDCHR ;And display MOVLW ':' ;Colon CALL LCDCHR ; MOVF DECSEC,W ;Get tens of seconds (0..5) ADDLW '0' ;Convert to ASCII CALL LCDCHR ;And display MOVF TENSEC,W ;Get unit seconds (0..9) ADDLW '0' ;Convert to ASCII CALL LCDCHR ;And display BSF INTCON,GIE ;Enable interrupts GOTO LCD01 ;And loop ;********************************************************************** LED_REPEATER ;Initialise for LED repeater CLRF PORTA ;Set all leds to off CLRF PORTB ; CLRF PORTC ; CLRF PORTD ; BTFSC PORTB,3 ;Test active low (RB3=low)? GOTO LR01 ;If no, skip invert ; MOVLW LPORTA ;Active low so invert l.e.d. port pins MOVWF PORTA ; by writing l.e.d. mask to ports MOVLW LPORTB ; MOVWF PORTB ; MOVLW LPORTC ; MOVWF PORTC ; MOVLW LPORTD ; MOVWF PORTD ; LR01 ;Now to set port directions BSF STATUS,RP0 ;Bank 1 MOVLW B'11010000' ; MOVWF TRISA ;Port A outouts except RA4/T0CKI MOVLW B'11001001' ; MOVWF TRISB ;Port B four l.e.d. outputs MOVLW B'11000000' ;bits 7/6 must be inputs for serial port MOVWF TRISC ;Port C six l.e.d. outputs MOVLW B'00000000' ; MOVWF TRISD ;Port D eight l.e.d. outputs BCF STATUS,RP0 ;Bank 0 ; BSF RCSTA,CREN ;Turn on receiver ; Parking loop. Wait for received bytes RXLOOP BTFSC PIR1,RCIF ;Test receive flag GOTO NEWRXD ;Get byte if one received ; NOP ;Other stuff can go here NOP ; NOP ;This is the parking loop NOP ; NOP ;Add any background tasks here NOP ; NOP ;The NOPs just waste time NOP ; and stop the USART being NOP ; accessed every 2uS NOP ; ; GOTO RXLOOP ;Loop ;Byte received NEWRXD MOVF RCSTA,W ;Get status MOVWF TEMP1 ;And save in case of error MOVF RCREG,W ;Get byte MOVWF RXCHAR ;And save ; BTFSS TEMP1,OERR ;Check for overrun error GOTO NOOERR ;Skip if no error BCF RCSTA,CREN ;Error so clear CREN NOP ;Wait a bit BSF RCSTA,CREN ;Set CREN to reenable receiver NOOERR BTFSC TEMP1,FERR ;Check for framing error GOTO RXLOOP ;If error discard received char ;Else continue ; NEW_CHAR ;Update l.e.d.s in RXCHAR MOVF RXCHAR,W ;Band in <7..5> and beacon in <4..0> ANDLW B'00011111' ;Keep beacon number MOVWF BEACON ;Save SWAPF RXCHAR,F ;Top four bits to lower four RRF RXCHAR,W ;Shift right so band in <2..0> in W SWAPF RXCHAR,F ;Put back original byte ANDLW B'00000111' ;Keep band number MOVWF BAND ;Save ; CALL DISPBAND ;Display new band l.e.d. CALL DISPBEACON ;Display new beacon l.e.d. ; MOVF BAND,W ;Get received band number SUBWF PREVBAND,W ;Compare with last band SKPNZ ;If different then skip GOTO RXLOOP ;Else same so can loop ; MOVF BAND,W ;Get again MOVWF PREVBAND ;And update SKPNZ ;Band=0? flag set by MOVF GOTO RXLOOP ;Don't send frequency if band=0 ;Now to send the new frequency DECF BAND,W ;Work with band-1 MOVWF PTR1 ;W=PTR1=band RLF PTR1,F ;Times 2 RLF PTR1,F ;Times 4 RLF PTR1,W ;Times 8 now in W ANDLW B'11111000' ;Force lower three bits to zero MOVWF PTR1 ;Points to first char of frequency MOVLW D'5' ;Counter for five bytes MOVWF PTR2 ;Save ;Table in page 0 (PCLATH=0) NC02 MOVF PTR1,W ;Pointer into W CALL CAT_COMS ;Get byte CALL SEND_CHAR ;And send to rig INCF PTR1,F ;Next char DECFSZ PTR2,F ;Loop GOTO NC02 ; if more GOTO RXLOOP ;Now can go to loop ;********************************************************************** ; ORG 0x400 ;Subroutines ; ;********************************************************************** DELONG CLRF DELAY1 ;Long delay (about 197mS) CLRF DELAY2 ; DELONG1 DECFSZ DELAY2,F ; GOTO DELONG1 ; DECFSZ DELAY1,F ; GOTO DELONG1 ; RETURN ; ;********************************************************************** DLY50MS MOVLW D'25' ;Delay 50mS MOVWF DELAY1 ;Twenty five outer loops CLRF DELAY2 ;Inner delay 8*256uS (~2mS) D10A NOP ;1 NOP ;1 NOP ;1 NOP ;1 NOP ;1 DECFSZ DELAY2,F ;1 (mostly) GOTO D10A ;2 DECFSZ DELAY1,F ; GOTO D10A ; RETURN ; ;********************************************************************** SEND_CHAR ;Transmit character in W register CLRF SERTEMP ;Timeout counter SC01 BTFSC PIR1,TXIF ;2 TX ready flag, skip if not ready GOTO SC02 ;(-) TX is ready so continue NOP ;1 NOP ;1 10uS per loop NOP ;1 256 * 10uS = 2.5mS NOP ;1 One char at 4800 baud = 2.083mS NOP ;1 DECFSZ SERTEMP,F ;1(2) So we don't get stuck forever GOTO SC01 ;2 ; RETLW 0xFF ;Return with -1 in W (error) ; SC02 MOVWF TXREG ;Load transmit holding register RETLW 0x00 ;Return with zero in W (okay) ;********************************************************************** CHK_BAND ;Check for bandswitch update CALL GET_BAND ;Read switch position (NEWBAND) MOVF NEWBAND,W ;Into W SUBWF ACTBAND,W ;Compare with current band BZ NOBAND ;Jump to end if no change ; NEWB1 MOVF NEWBAND,W ;Get new switch position again SUBWF LSTBAND,W ;Compare with immediate last position BZ YESBAND ;New stable switch position ; MOVF NEWBAND,W ;Get new switch position yet again MOVWF LSTBAND ;Save new but not stable position CALL DLY50MS ;Wait a bit and try again CALL GET_BAND ;Read switch position GOTO NEWB1 ;And try again ; YESBAND INCF UPDBND,F ;Band has changed so set update flag ; NOBAND RETURN ;No change in bandswitch position ;********************************************************************** GET_BAND ;Read bandswitch position, return with MOVLW 0x05 ; band in NEWBAND: 0=20m .. 5=10m MOVWF NEWBAND ;Start with band=5 (10m) BTFSS PORTA,0 ;Switch on 10m positon? RETURN ;Yes so exit DECF NEWBAND,F ;No, so try for next band down BTFSS PORTA,1 ;Switch on 12m positon? RETURN ;Yes so exit DECF NEWBAND,F ;No, so try for next band down BTFSS PORTA,2 ;Switch on 15m positon? RETURN ;Yes so exit DECF NEWBAND,F ;No, so try for next band down BTFSS PORTA,3 ;Switch on 17m positon? RETURN ;Yes so exit DECF NEWBAND,F ;No, so try for next band down BTFSS PORTA,5 ;Switch on 20m positon? RETURN ;Yes so exit DECF NEWBAND,F ;No, but have to exit anyway RETURN ;Band=0 (l.e.d.s off) ;********************************************************************** ; The following code displays new l.e.d.s and ; tests for all ones (all l.e.d.s on) and ; tests for out of range (band=6 and beacon=19..30) DISPBAND ;Display new band l.e.d. MOVF BAND,W ;Get band number (possible 0..7) XORLW B'00000111' ;Test for band=7 (lamp test) BZ BANDLT ;All band l.e.d.s on MOVLW 0x06 ;Now test for out of range (band=6) SUBWF BAND,W ;Band=6? SKPNZ ;Skip if not band=6 RETURN ;Band=6 so ignore (out of range) ;Valid band number so display MOVF BAND,W ;Get (valid) band number CLRF PCLATH ;Page 0 CALL BAND_LED ;Get band l.e.d. bit (in W) BTFSS PORTB,3 ;Skip invert if active high XORLW LPORTA ;Invert if active low MOVWF PORTA ;Output RETURN ;Done BANDLT ;All band l.e.d.s on MOVLW LPORTA ;Band l.e.d.s BTFSS PORTB,3 ;Test active low (RB3=low)? XORLW LPORTA ;Set active low MOVWF PORTA ;Output RETURN ;Done ;********************************************************************** DISPBEACON ;Display new beacon l.e.d. MOVF BEACON,W ;Get beacon number (possible 0..31) XORLW B'00011111' ;Test for beacon=31 (lamp test) BZ BEACNLT ;If so goto lamp test ; MOVF BEACON,W ;Test for out of range (beacon>18) SUBLW D'18' ;Subtract W from 18 (18-W) ;Carry(not_borrow)=1 if beacon not >18 SKPC ;Skip if carry=1 (beacon<=18) RETURN ;out of range so ignore ;Valid beacon number so display MOVF BEACON,W ;Get (valid) beacon number ADDWF BEACON,W ;Times two ADDWF BEACON,W ;Times three MOVWF TEMP2 ;Points to first entry in table ; CLRF PCLATH ;Page 0 CALL BEACON_LED ;Get first band l.e.d. bit (in W) BTFSS PORTB,3 ;Skip invert if active high XORLW LPORTB ;Invert if active low MOVWF PORTB ;Output ; INCF TEMP2,W ;Second entry in table CALL BEACON_LED ;Get second band l.e.d. bit (in W) BTFSS PORTB,3 ;Skip invert if active high XORLW LPORTC ;Invert if active low MOVWF PORTC ;Output ; INCF TEMP2,F ;Second entry in table, then on to INCF TEMP2,W ; third entry in table CALL BEACON_LED ;Get third band l.e.d. bit (in W) BTFSS PORTB,3 ;Skip invert if active high XORLW LPORTD ;Invert if active low MOVWF PORTD ;Output ; RETURN ;Done BEACNLT ;All beacon l.e.d.s on MOVLW LPORTB ;Beacon l.e.d.s BTFSS PORTB,3 ;Skip invert if active high XORLW LPORTB ;Invert if active low (clear W) MOVWF PORTB ;Output ; MOVLW LPORTC ; BTFSS PORTB,3 ; XORLW LPORTC ; MOVWF PORTC ; ; MOVLW LPORTD ; BTFSS PORTB,3 ; XORLW LPORTD ; MOVWF PORTD ; ; RETURN ;Done ;********************************************************************** ; LCD Routines ; Note - all accesses to the l.c.d. should finish with ; CLRF LCDDAT ; to force all the l.c.d. data lines LOW ; Control lines should also be kept LOW so that when the l.c.d. is ; switched off, ALL data and control lines should already be LOW DISPLCD ;Display new band/beacon text ;Display beacon callsign first DECF BEACON,W ;Work with beacon-1 MOVWF PTR1 ;W=beacon pointer RLF PTR1,F ;Times 2 RLF PTR1,F ;Times 4 RLF PTR1,W ;Times 8 now in W ANDLW B'11111000' ;Force lower three bits to zero MOVWF PTR1 ;Points to first char of callsign MOVLW D'8' ;Counter for eight chars MOVWF PTR2 ;Save MOVLW 0x80 ;Cursor to beginning of first line CALL LCDINS ; MOVLW HIGH(CALLSIGN) ;Need to set up PCLATH MOVWF PCLATH ;Ready for call DI01 MOVF PTR1,W ;Pointer into W CALL CALLSIGN ;Get char CALL LCDCHR ;And display INCF PTR1,F ;Next char DECFSZ PTR2,F ;Loop GOTO DI01 ; if more MOVLW ' ' ;Space CALL LCDCHR ; MOVLW ' ' ;Space CALL LCDCHR ; ;Now to display the frequency DECF ACTBAND,W ;Work with band-1 MOVWF PTR1 ;W=PTR1=band RLF PTR1,F ;Times 2 RLF PTR1,F ;Times 4 RLF PTR1,W ;Times 8 now in W ANDLW B'11111000' ;Force lower three bits to zero MOVWF PTR1 ;Points to first char of frequency MOVLW D'6' ;Counter for six chars MOVWF PTR2 ;Save ;L.C.D. cursor should be in position MOVLW HIGH(FREQUENCY) ;Need to set up PCLATH MOVWF PCLATH ;Ready for call DI02 MOVF PTR1,W ;Pointer into W CALL FREQUENCY ;Get char CALL LCDCHR ;And display INCF PTR1,F ;Next char DECFSZ PTR2,F ;Loop GOTO DI02 ; if more ;Now to display beacon location DECF BEACON,W ;Work with beacon-1 MOVWF PTR1 ;W=beacon pointer ADDWF PTR1,F ;Times 2 ADDWF PTR1,F ;Times 3 ADDWF PTR1,F ;Times 4 MOVF PTR1,W ;Times 4 into W ADDWF PTR1,W ;Now times 8 ADDWF PTR1,F ;PTR1 is now beacon times 12 ; and points to first char of location MOVLW D'12' ;Counter for twelve chars MOVWF PTR2 ;Save MOVLW 0x80+0x40 ;Cursor to beginning of second line CALL LCDINS ; MOVLW HIGH(LOCATION) ;Need to set up PCLATH MOVWF PCLATH ;Ready for call DI03 MOVF PTR1,W ;Pointer into W CALL LOCATION ;Get char CALL LCDCHR ;And display INCF PTR1,F ;Next char DECFSZ PTR2,F ;Loop GOTO DI03 ; if more CLRF PCLATH ;Back to page zero RETURN ;Done LCD_POWERUP ;Turn on and initialise l.c.d. BCF LCDPWR,RW ;Ensure R/W is set to write BSF LCDPWR,VD ;Turn on l.c.d. logic power Vdd CALL DLY50MS ;Wait a little BSF LCDPWR,VO ;Turn on l.c.d. screen power Vo CALL DELONG ;Wait about 200mS ; MOVLW 0x38 ;Eight-bit initialisation CALL LCDINS ;(1st) see data sheet CALL DLY50MS ;Some delays are way too long ; MOVLW 0x38 ; CALL LCDINS ;(2nd) CLRF DELAY2 ;Delay 8*256uS (~2mS) LCD11 NOP ;1 NOP ;1 NOP ;1 NOP ;1 NOP ;1 DECFSZ DELAY2,F ;1 (mostly) GOTO LCD11 ;2 ; MOVLW 0x38 ;(3rd) CALL LCDINS ; CLRF DELAY2 ;Delay 8*256uS (~2mS) LCD12 NOP ;1 NOP ;1 NOP ;1 NOP ;1 NOP ;1 DECFSZ DELAY2,F ;1 (mostly) GOTO LCD12 ;2 ; MOVLW 0x38 ;Eight-bit, two lines, 5x7 dots CALL LCDINS ;Send MOVLW 0x08 ;Display off CALL LCDINS ; CALL LCDCLR ;Clear display MOVLW 0x06 ;Increment cursor, no display shift CALL LCDINS ; MOVLW 0x0C ;Display on, no cursor CALL LCDINS ; CALL LCDHOME ;Home cursor BSF LCDPWR,BL ;Turn on backlight RETURN ; LCDINS ;Send an instruction to the l.c.d MOVWF LCDDAT ;Output char to l.c.d. data bus NOP ; BSF LCDCTL,EN ;Enable high NOP ; BCF LCDCTL,EN ;Enable low MOVLW D'20' ;Wait 60uS MOVWF LCDTEMP ; CLRF LCDDAT ;Force low LCD18 DECFSZ LCDTEMP,F ;1 GOTO LCD18 ;2 Loop RETURN ; LCDCHR ;Send a character to the l.c.d. MOVWF LCDDAT ;Output char to l.c.d. data bus BSF LCDCTL,RS ;RS high NOP ; BSF LCDCTL,EN ;Enable high NOP ; BCF LCDCTL,EN ;Enable low NOP ; BCF LCDCTL,RS ;RS low MOVLW D'20' ;Wait 60uS MOVWF LCDTEMP ; CLRF LCDDAT ;Force low LCD19 DECFSZ LCDTEMP,F ;1 GOTO LCD19 ;2 Loop RETURN ; LCDCLR ;Clear l.c.d. MOVLW 0x01 ;Clear instruction MOVWF LCDDAT ;Output to l.c.d. data bus NOP ; BSF LCDCTL,EN ;Enable high NOP ; BCF LCDCTL,EN ;Enable low CLRF DELAY2 ;Delay 8*256uS (~2mS) CLRF LCDDAT ;Force low LCD21 NOP ;1 NOP ;1 NOP ;1 NOP ;1 NOP ;1 DECFSZ DELAY2,F ;1 (mostly) GOTO LCD21 ;2 RETURN ; LCDHOME ;Home l.c.d. cursor MOVLW 0x02 ;Home instruction MOVWF LCDDAT ;Output to l.c.d. data bus NOP ; BSF LCDCTL,EN ;Enable high NOP ; BCF LCDCTL,EN ;Enable low CLRF DELAY2 ;Delay 8*256uS (~2mS) CLRF LCDDAT ;Force low LCD31 NOP ;1 NOP ;1 NOP ;1 NOP ;1 NOP ;1 DECFSZ DELAY2,F ;1 (mostly) GOTO LCD31 ;2 RETURN ; ;********************************************************************** ; ; Lookup tables ; ;********************************************************************** ORG 0x080 ;PAGE 0 - CAT command strings CAT_COMS ;CAT command strings for rig control ;Commands are five bytes long ; but are padded to eight bytes ;Band number run from 0 to 4 ADDWF PCL,F ;Add band number 0 to 4 ;Band 0 - 20m DT 0x01,0x41,0x00,0x00,0x01,0x00,0x00,0x00 ;Band 1 - 17m DT 0x01,0x81,0x10,0x00,0x01,0x00,0x00,0x00 ;Band 2 - 15m DT 0x02,0x11,0x50,0x00,0x01,0x00,0x00,0x00 ;Band 3 - 12m DT 0x02,0x49,0x30,0x00,0x01,0x00,0x00,0x00 ;Band 4 - 10m DT 0x02,0x82,0x00,0x00,0x01,0x00,0x00,0x00 ORG 0x0B7 ;PAGE 0 - band leds BAND_LED ;Get band led data - leds are on port A ADDWF PCL,F ;Add band number 1 to 5 (or 0) RETLW B'00000000' ;Band number '0' is for leds off RETLW B'00100000' ;Band 1 - 20m RETLW B'00001000' ;Band 2 - 17m RETLW B'00000100' ;Band 3 - 15m RETLW B'00000010' ;Band 4 - 12m RETLW B'00000001' ;Band 5 - 10m ORG 0x0BF ;PAGE 0 - beacon leds BEACON_LED ;Get beacon led data ADDWF PCL,F ;Add beacon number 1 to 18 ;Beacon number '0' is for leds off RETLW B'00000000' ;Port B RETLW B'00000000' ;Port C RETLW B'00000000' ;Port D ;Beacon number 1 RETLW B'00000000' ;Port B RETLW B'00000001' ;Port C RETLW B'00000000' ;Port D ;Beacon number 2 RETLW B'00000000' ;Port B RETLW B'00000010' ;Port C RETLW B'00000000' ;Port D ;Beacon number 3 RETLW B'00000000' ;Port B RETLW B'00000100' ;Port C RETLW B'00000000' ;Port D ;Beacon number 4 RETLW B'00000000' ;Port B RETLW B'00001000' ;Port C RETLW B'00000000' ;Port D ;Beacon number 5 RETLW B'00000000' ;Port B RETLW B'00000000' ;Port C RETLW B'00000001' ;Port D ;Beacon number 6 RETLW B'00000000' ;Port B RETLW B'00000000' ;Port C RETLW B'00000010' ;Port D ;Beacon number 7 RETLW B'00000000' ;Port B RETLW B'00000000' ;Port C RETLW B'00000100' ;Port D ;Beacon number 8 RETLW B'00000000' ;Port B RETLW B'00000000' ;Port C RETLW B'00001000' ;Port D ;Beacon number 9 RETLW B'00000000' ;Port B RETLW B'00010000' ;Port C RETLW B'00000000' ;Port D ;Beacon number 10 RETLW B'00000000' ;Port B RETLW B'00100000' ;Port C RETLW B'00000000' ;Port D ;Beacon number 11 RETLW B'00000000' ;Port B RETLW B'00000000' ;Port C RETLW B'00010000' ;Port D ;Beacon number 12 RETLW B'00000000' ;Port B RETLW B'00000000' ;Port C RETLW B'00100000' ;Port D ;Beacon number 13 RETLW B'00000000' ;Port B RETLW B'00000000' ;Port C RETLW B'01000000' ;Port D ;Beacon number 14 RETLW B'00000000' ;Port B RETLW B'00000000' ;Port C RETLW B'10000000' ;Port D ;Beacon number 15 RETLW B'00000010' ;Port B RETLW B'00000000' ;Port C RETLW B'00000000' ;Port D ;Beacon number 16 RETLW B'00000100' ;Port B RETLW B'00000000' ;Port C RETLW B'00000000' ;Port D ;Beacon number 17 RETLW B'00010000' ;Port B RETLW B'00000000' ;Port C RETLW B'00000000' ;Port D ;Beacon number 18 RETLW B'00100000' ;Port B RETLW B'00000000' ;Port C RETLW B'00000000' ;Port D ;********************************************************************** ORG 0x60F ;Beacon callsigns ; NOTE arithmetic uses beacon numbers that run from 0 to 17 ; Remember to subtract one from the 'normal' beacon number ; Beacon calls are padded to eight characters ; Offset of 0x0F to put entries on 8-byte boundaries CALLSIGN ;Get beacon callsign ADDWF PCL,F ;Add beacon number 0 to 17 ; DT "4U1UN " ;Beacon 0 4U1UN DT "VE8AT " ;Beacon 1 VE8AT DT "W6WX " ;Beacon 2 W6WX DT "KH6WO " ;Beacon 3 KH6WO DT "ZL6B " ;Beacon 4 ZL6B DT "VK6RBP " ;Beacon 5 VK6RBP DT "JA2IGY " ;Beacon 6 JA2IGY DT "RR9O " ;Beacon 7 RR9O DT "VR2B " ;Beacon 8 VR2B DT "4S7B " ;Beacon 9 4S7B DT "ZS6DN " ;Beacon 10 ZS6DN DT "5Z4B " ;Beacon 11 5Z4B DT "4X6TU " ;Beacon 12 4X6TU DT "OH2B " ;Beacon 13 OH2B DT "CS3B " ;Beacon 14 CS3B DT "LU4AA " ;Beacon 15 LU4AA DT "OA4B " ;Beacon 16 OA4B DT "YV5B " ;Beacon 17 YV5B ;********************************************************************** ORG 0x6BF ;Beacon frequencies ; NOTE arithmetic uses band numbers that run from 0 to 4 ; Remember to subtract one from the 'normal' band number ; Band frequencies are six characters long but padded to eight ; Offset of 0x0F to put entries on 8-byte boundaries FREQUENCY ;Get band frequency ADDWF PCL,F ;Add band number 0 to 4 ; DT "14.100 " ;Band 0 (20m) 14.100 MHz DT "18.110 " ;Band 1 (17m) 18.110 MHz DT "21.150 " ;Band 2 (15m) 21.150 MHz DT "24.930 " ;Band 3 (12m) 24.930 MHz DT "28.200 " ;Band 4 (10m) 28.200 MHz ;********************************************************************** ORG 0x70F ;Beacon locations ; NOTE arithmetic uses beacon numbers that run from 0 to 17 ; Remember to subtract one from the 'normal' beacon number ; Beacon locations are padded to twelve characters ; Offset of 0x0F to put entries on even byte boundaries LOCATION ;Get beacon location ADDWF PCL,F ;Add beacon number 0 to 17 ; DT "New York " ;Beacon 0 4U1UN DT "Canada " ;Beacon 1 VE8AT DT "California " ;Beacon 2 W6WX DT "Hawaii " ;Beacon 3 KH6WO DT "New Zealand " ;Beacon 4 ZL6B DT "Australia " ;Beacon 5 VK6RBP DT "Japan " ;Beacon 6 JA2IGY DT "Russia " ;Beacon 7 RR9O DT "Hong Kong " ;Beacon 8 VR2B DT "Sri Lanka " ;Beacon 9 4S7B DT "S. Africa " ;Beacon 10 ZS6DN DT "Kenya " ;Beacon 11 5Z4B DT "Israel " ;Beacon 12 4X6TU DT "Finland " ;Beacon 13 OH2B DT "Madeira " ;Beacon 14 CS3B DT "Argentina " ;Beacon 15 LU4AA DT "Peru " ;Beacon 16 OA4B DT "Venezuela " ;Beacon 17 YV5B ;********************************************************************** END ;The End ;**********************************************************************