;VOLUME CONTROL PROGRAM V1.0 FOR PIC 12CE519 AND PGA2310 / CS3310 ; ;COPYRIGHT ERROCK.CO.UK 2003-4 (EXCLUDING EEPROM CODE SECTION FROM MICROCHIP INC) ; ; ; WHEN PROGRAMMING THE PIC, SET THE FOLLOWING CONFIGURATION BITS: ; OSCILLATOR - INTERNAL RC ; WATCHDOG TIMER - OFF ; MASTER CLEAR ENABLE - INTERNAL ; CODE PROTECT - OFF (DON'T CARE) ; ;**************************************************************************** ;**************************************************************************** ;CODE FOR PIC 12CE519 MICRO, TO CONTROL A BURRBROWN PGA2310 (OR A CRYSTAL CS3310) ;VOLUME CONTROL IC, USING A ROTARY ENCODER, SINGLE MUTE/MODE SWITCH, AND ONE LED. ;CONNECTIONS: GP0-ROTARY ENC B, GP1-ROTARY ENC A, GP3-MODE SWITCH, GP2-NOT CS, GP4-SCLK, GP5-SDI/LED ;THE INITIAL POWER UP VOLUME CAN BE SET BY THE USER AND IS STORED IN THE E2RAM. ;THE VOLUME LEVEL IS RAMPED UP FROM POWER ON OVER A FEW SECONDS. A FASTRAMP (OVER 1 SEC) ;IS USED FOR MUTE ON/OFF. ; ;**************************************************************************** ;**************************************************************************** ; ;**************************************************************************** ;**************************************************************************** ;THIS CODE MAY BE USED FREE OF CHARGE FOR HOME CONSTRUCTOR PROJECTS. ;PLEASE CONTACT ERROCK.CO.UK IF YOU WISH TO USE THIS SOFTWARE FOR COMMERCIAL ;APPLICATIONS. ; ;**************************************************************************** ;**************************************************************************** ;**************************************************************************** ;**************************************************************************** ; VARIABLE DEFINITION ;**************************************************************************** ;**************************************************************************** TMR0 EQU 0x01 PC EQU 0x02 STATUS EQU 0x03 GPIO EQU 0x06 CARRYBIT EQU 0x00 ZEROBIT EQU 0x02 PAGE0 EQU 0x05 MODESWBIT EQU 0x03 ROTENCABIT EQU 0x01 ROTENCBBIT EQU 0x00 LEDBIT EQU 0x05 ; CLEAR, LED ON ::: SET, LED OFF; SAME LINE AS VOL CONTROL SDI COUNTER EQU 0x07 CURVOL EQU 0x08 INITVOL EQU 0x09 ;USED TO STATE THE VOLUME SETTING THAT IS TO BE RAMPED UP BALOFFSETL EQU 0x0A ;A POSITIVE NUMBER MEANS A GAIN REDUCTION IN THAT CHANNEL BALOFFSETR EQU 0x0B ;***BOTH NAMES USE THE SAME MEMORY LOCATION !!! WAITTIME EQU 0x0C REPEATCOUNT EQU 0x0C ;***BOTH NAMES USE THE SAME MEMORY LOCATION !!! STEPSIZE EQU 0x0F ;***BOTH NAMES USE THE SAME MEMORY LOCATION !!! RAMPBASE EQU 0x10 ;USED FOR RAMPING UP NUMROTENCSTEPS EQU 0x10 ;USED BY VOLSPEED - HOLDS THE NUMBER OF STEPS ;OF THE ROTARY ENCODER IN THE LAST TIME WINDOW ;***BOTH NAMES USE THE SAME MEMORY LOCATION !!! TEMPVAR EQU 0x12 VOLSPEED EQU 0x14 ;USED TO STORE HOW QUICKLY THE VOL CTRL IS BEING ROTATED - 0..4 MODESW EQU 0x15 ;MODESWITCH COUNTER FOR DEBOUNCE ROTENCA EQU 0x16 ;ROTARY ENCODER A - COUNTER FOR DEBOUNCE ROTENCB EQU 0x17 ;ROTARY ENCODER B - COUNTER FOR DEBOUNCE MUTECOUNTER EQU 0x1A ;COUNTER INCREMENTS WHEN THE MUTE BUTTON IS PRESSED AND HELD LEDFLASHSEQUENCE EQU 0x1C ; HOLDS THE 8 STEP LED FLASHING SEQUENCE LEDFLASHSTEP EQU 0x1D ;THE INDEX 7..0 TO THE VAR ABOVE LEDFLASHCOUNTER EQU 0x1E ;THE TIME DELAY COUNTER BETWEEN STEPS ;**************************************************************************** ; EEPROM SECTION BELOW ;**************************************************************************** PC_OFFSET EQU 0x1F ; PC offset register (low order 4 bits), ;value based on operating mode of EEPROM. ;Also, bit 7 used for EE_OK flag EEADDR EQU 0x13 ; EEPROM Address EEBYTE EQU 0x0D ; Byte sent to or received from ; EEPROM (control, address, or data) EEDATA EQU 0x19 ; EEPROM Data ;*************************** BIT DEFINITIONS **************************** SCL EQU 0x07 ; EEPROM Clock, SCL (I/O bit 7) SDA EQU 0x06 ; EEPROM Data, SDA (I/O bit 6) EE_OK EQU 0x07 ; Bit 7 in PC_OFFSET used as OK flag for EE ;*************************************************************************** ; END OF EEPROM SECTION ;**************************************************************************** ;MODEBIT SECTION BELOW - VARIABLE, THEN EACH BIT MODEBITS EQU 0x0E ;VARIABLE VOLRAMPUP EQU 0x00 VOLNEW EQU 0x01 ;SET IF THE VOLUME CHANGED, SO NEEDS TO BE SENT FASTRAMP EQU 0x02 VOLRAMPDN EQU 0x03 FIRSTRAMPUP EQU 0x04 TIMERCHANGE EQU 0x05 ;SINGLE BIT TO SHOW IF THE TIMER CHANGED DURING THE LAST LOOP LEFTCHMUTE EQU 0x06 RGHTCHMUTE EQU 0x07 ;MUTEBITS SECTION BELOW - VARIABLE, THEN EACH BIT MUTEBITS EQU 0x11 ;VARIABLE VOL EQU 0x00 ;THIS BIT IS SET WHEN THE ROTARY ENCODER DRIVES THE VOLUME MUTE EQU 0x01 BALANCE EQU 0x02 ;THIS BIT IS SET WHEN THE ROTARY ENCODER DRIVES THE BALANCE PRESETVOL EQU 0x03 ;THIS BIT IS SET WHEN THE ROTARY ENCODER DRIVES THE PRESET VOL IGNORENEXTVOLRELEASE EQU 0x05 ;THIS IS BIT IS USED TO FORCE THE DECODING ROUTINE TO IGNORE THE NEXT RELEASE OF THE BUTTON CWROTATE EQU 0x06 ATCWROTATE EQU 0x07 ;DECODED INPUTS SECTION BELOW - VARIABLE, THEN EACH BIT DECINP EQU 0x18 ;VARIABLE DECROTENCA EQU 0x00 DECROTENCB EQU 0x01 DECMODESW EQU 0x02 DECCHGRENA EQU 0x04 DECCHGRENB EQU 0x05 DECCHGMDSW EQU 0x06 ;LED FLASH - LAST KNOWN STATE FOR LED FLASH PROCEDURE - VARIABLE THEN EACH BIT LASTLEDMODE EQU 0x1B ; VARIABLE LEDMUTE EQU 0x00 LEDVOL EQU 0x01 LEDBAL EQU 0x02 LEDPRESETVOL EQU 0x03 LEDVOLMAX EQU 0x04 LEDBALEQUAL EQU 0x05 LEDREPEATSEQ EQU 0x07 ; SET IF THE FLASHING SEQUENCE MUST REPEAT ;**************************************************************************** ;**************************************************************************** ; CONSTANTS DEFINED BELOW ;**************************************************************************** ;**************************************************************************** LEDFLASHDURATION EQU 0x06 ;**************************************************************************** ;**************************************************************************** ; START OF CODE ;**************************************************************************** ;**************************************************************************** ORG 00h GOTO MAINPROG ;JUMP TO MAIN PROGRAM ;**************************************************************************** ;**************************************************************************** ; DISTANT SUBROUTINES ; ; DUE TO THE PAGE MEMORY RESTRICTION IN THE PIC FOR SUBROUTINE CALLS ; BELOW ARE DUMMY SUBROUTINES, WHICH JUMP TO THE REAL SUBROUTINES ; USING GOTO STATEMENTS. (FORMAT: L+NAME = START D+NAME = END) ; ; THE FIRST BLOCK BELOW ARE IN THE SECOND MEMORY PAGE. ; ;**************************************************************************** ;**************************************************************************** ROTENCAOFF BSF STATUS,PAGE0 ;GO TO UPPER MEMORY PAGE GOTO LROTENCAOFF DROTENCAOFF RETLW 0 ; ROTENCAON BSF STATUS,PAGE0 ;GO TO UPPER MEMORY PAGE GOTO LROTENCAON DROTENCAON RETLW 0 ; ROTENCBOFF BSF STATUS,PAGE0 ;GO TO UPPER MEMORY PAGE GOTO LROTENCBOFF DROTENCBOFF RETLW 0 ; ROTENCBON BSF STATUS,PAGE0 ;GO TO UPPER MEMORY PAGE GOTO LROTENCBON DROTENCBON RETLW 0 ; MODESWPRESS BSF STATUS,PAGE0 ;GO TO UPPER MEMORY PAGE GOTO LMODESWPRESS DMODESWPRESS RETLW 0 ; MODESWREL BSF STATUS,PAGE0 ;GO TO UPPER MEMORY PAGE GOTO LMODESWREL DMODESWREL RETLW 0 ; SETUPRAMPUP BSF STATUS,PAGE0 ;GO TO UPPER MEMORY PAGE GOTO LSETUPRAMPUP DSETUPRAMPUP RETLW 0 ; RUNLEDFLASH BSF STATUS,PAGE0 ;GO TO UPPER MEMORY PAGE GOTO LRUNLEDFLASH DRUNLEDFLASH RETLW 0 ; PROCESSMUTECTR BSF STATUS,PAGE0 ;GO TO UPPER MEMORY PAGE GOTO LPROCESSMUTECTR DPROCESSMUTECTR RETLW 0 ; CLOCKBAL BSF STATUS,PAGE0 ;GO TO UPPER MEMORY PAGE GOTO LCLOCKBAL DCLOCKBAL RETLW 0 ; ATCLOCKBAL BSF STATUS,PAGE0 ;GO TO UPPER MEMORY PAGE GOTO LATCLOCKBAL DATCLOCKBAL RETLW 0 ; CLOCKVOL BSF STATUS,PAGE0 ;GO TO UPPER MEMORY PAGE GOTO LCLOCKVOL DCLOCKVOL RETLW 0 ; ATCLOCKVOL BSF STATUS,PAGE0 ;GO TO UPPER MEMORY PAGE GOTO LATCLOCKVOL DATCLOCKVOL RETLW 0 ; CLOCKMUTE BSF STATUS,PAGE0 ;GO TO UPPER MEMORY PAGE GOTO LCLOCKMUTE DCLOCKMUTE RETLW 0 ; SETVOL BSF STATUS,PAGE0 ;GO TO UPPER MEMORY PAGE GOTO LSETVOL DSETVOL RETLW 0 ; E2WRITEBYTE MOVLW 0x0A ;ATTEMPTS THIS TEN TIMES THEN GIVES UP MOVWF REPEATCOUNT RETRYWRITE CLRF TEMPVAR ;BIT 0 SET TO 1 IF WRITING BSF TEMPVAR,0 ;BIT 1 OF TEMPVAR SET IF AN ERROR BSF STATUS,PAGE0 ;GO TO UPPER MEMORY PAGE GOTO WRITE_BYTE DE2WRITEBYTE ;RETURN POINT FROM THE WRITE_BYTE ROUTINE ;CHECK TO SEE IF WRITE WAS OK BTFSS TEMPVAR,1 ;BIT 1 SET IF AN ERROR GOTO RETURNTOCALLPOINT ;WRITE WAS OK SO RETURN ;IF HERE, WRITE FAILED - RETRY IF POSSIBLE DECFSZ REPEATCOUNT,1 GOTO RETRYWRITE RETURNTOCALLPOINT MOVF EEADDR,0 ADDWF PC,1 ;ADDS EEADDR ONTO THE PROG COUNTER GOTO ENDSTOREVOL ;EEADDR=0 - RETURN TO PRESET VOLUME GOTO ENDSTOREBALL ;EEADDR=1 - RETURN TO BALANCE LEFT GOTO ENDSTOREBALR ;EEADDR=2 - RETURN TO BALANCE RIGHT ; E2READBYTE MOVLW 0x0A ;ATTEMPTS THIS TEN TIMES THEN GIVES UP MOVWF REPEATCOUNT RETRYREAD CLRF TEMPVAR ;BIT 0 SET TO 0 IF READING ;BIT 1 OF TEMPVAR SET IF AN ERROR BSF STATUS,PAGE0 ;GO TO UPPER MEMORY PAGE GOTO READ_RANDOM DE2READBYTE ;CHECK TO SEE IF READ WAS OK BTFSS TEMPVAR,1 ;BIT 1 SET IF AN ERROR RETLW 0 ;WRITE WAS OK SO RETURN ;IF HERE, READ FAILED - RETRY IF POSSIBLE DECFSZ REPEATCOUNT,1 GOTO RETRYREAD RETLW 0 ;**************************************************************************** ;**************************************************************************** ; ROUTINES BELOW ARE IN THE UPPER HALF OF THE FIRST MEMORY PAGE ;**************************************************************************** ;**************************************************************************** USEROTENC GOTO LUSEROTENC DUSEROTENC RETLW 0 ; PROCESSMDSW GOTO LPROCESSMDSW DPROCESSMDSW RETLW 0 ; PROCESSVOLSPEED GOTO LPROCESSVOLSPEED DPROCESSVOLSPEED RETLW 0 ; WAIT GOTO LWAIT DWAIT RETLW 0 ; RAMPDOWN GOTO LRAMPDOWN DRAMPDOWN RETLW 0 ; SETUPRAMPDN GOTO LSETUPRAMPDN DSETUPRAMPDN RETLW 0 ;**************************************************************************** ;**************************************************************************** ; END OF DISTANT SUBROUTINES ;**************************************************************************** ;**************************************************************************** ;**************************************************************************** ;**************************************************************************** ; MAIN PROGRAM BELOW ;**************************************************************************** ;**************************************************************************** ; START UP SECTION MAINPROG MOVLW 0x07 OPTION MOVLW 0x0B TRIS GPIO CLRF DECINP ;CLEARS ALL DECODED INPUT LINES CLRF VOLSPEED CLRF CURVOL CLRF MODEBITS BSF MODEBITS,FIRSTRAMPUP ;THE INITIAL RAMPUP AFTER POWER, IS SLOWER THAN AN UNMUTE. CLRF MUTEBITS BSF MUTEBITS,VOL ;ROTARY ENCODER WILL DRIVE THE VOLUME SETTING CALL LOADINIT ;LOADS VOL FROM E2 CLRF MUTECOUNTER CLRF LASTLEDMODE CLRF LEDFLASHSEQUENCE CLRF LEDFLASHSTEP CLRF LEDFLASHCOUNTER ;REMAIN SILENT (MUTED) FOR 1.5 SECS MOVLW 0xFE ;0.75 SECS MOVWF WAITTIME CALL WAIT MOVLW 0xFE ;0.75 SECS MOVWF WAITTIME CALL WAIT CLRF MODESW ;CLEARS ALL DEBOUNCE COUNTERS CLRF ROTENCA CLRF ROTENCB MOVLW 0x0F ;ROTARY ENCOCDER DEBOUNCE COUNTERS SET TO CURRENT PIN STATE BTFSS GPIO,ROTENCABIT MOVWF ROTENCA ;LOW SO SET COUNTER TO MAXIMUM (FROM W REG) BTFSS GPIO,ROTENCBBIT MOVWF ROTENCB ;LOW SO SET COUNTER TO MAXIMUM (FROM W REG) CALL SETUPRAMPUP ;**************************************************************************** ;MAIN PROGRAM LOOP BELOW ;**************************************************************************** MAINLOOP ;CHECK THE TIMER, AND SEE IF IT IS NOW OVER THE RESET THRESHOLD (IE. 35+ms) MOVLW 0x88 ;35ms SUBWF TMR0,0 BTFSC STATUS,CARRYBIT BSF MODEBITS,TIMERCHANGE ;IE. GREATER THAN OR EQUAL TO 35ms BTFSC MODEBITS,TIMERCHANGE CLRF TMR0 BTFSS MODEBITS,TIMERCHANGE GOTO SKIPPROCESSVOLSPEED ;SKIP VOLSPEED SECTION IF THE TIMER HAS NOT CHANGED. ;IF HERE, TIMER HAS CHANGED, SO CHECK IF VOLSPEED CAN BE PROCESSED BTFSS MODEBITS,VOLRAMPUP CALL PROCESSVOLSPEED ;VOLSPEED ONLY ADJUSTED IF NOT RAMPING VOL UP ;(THIS IS DUE TO THE SHARED USE OF THE VARIABLE NUMROTENCSTEPS/RAMPBASE.) SKIPPROCESSVOLSPEED ;TEST STATE OF INPUT DEVICES AND DRIVE DEBOUNCE COUNTERS ;FIRST - MODESWITCH (MUTE ETC) - DUE TO PULLUP, PIN HIGH WHEN RELEASED. BTFSS GPIO,MODESWBIT CALL MODESWPRESS ;BUTTON IS PRESSED SO INC COUNTER BTFSC GPIO,MODESWBIT CALL MODESWREL ;BUTTON IS RELEASED SO DEC COUNTER ;SECOND - ROTARY ENCODER PIN A BTFSS GPIO,ROTENCABIT CALL ROTENCAOFF ;LOW SO INC COUNTER BTFSC GPIO,ROTENCABIT CALL ROTENCAON ;HIGH SO DEC COUNTER ;THIRD - ROTARY ENCODER PIN B BTFSS GPIO,ROTENCBBIT CALL ROTENCBOFF ;LOW SO INC COUNTER BTFSC GPIO,ROTENCBBIT CALL ROTENCBON ;HIGH SO DEC COUNTER ;END OF DEBOUNCE COUNTERS ETC ;TEST THE STATES OF THE DECODED INPUTS (AFTER DEBOUNCE) AND CHANGE ; SETTINGS ACCORDINGLY IF NEEDED BTFSC DECINP,DECCHGMDSW CALL PROCESSMDSW ;CALLED IF THE DECODED MODE SW HAS CHANGED STATE ;IF BOTH A & B CHANGED TOGETHER, THEN MUST SCRAP DATA BECAUSE MAY MAKE WRONG DECISION MOVF DECINP,0 ANDLW 0x30 MOVWF TEMPVAR MOVLW 0x30 SUBWF TEMPVAR,0 ;RESULT WILL BE ZERO, IF BOTH BITS WERE SET TOGETHER BTFSC STATUS,ZEROBIT BCF DECINP,DECCHGRENA ;BOTH BITS WERE SET, SO CLEAR FLAG BTFSC STATUS,ZEROBIT BCF DECINP,DECCHGRENB ;BOTH BITS WERE SET, SO CLEAR FLAG BTFSC DECINP,DECCHGRENA CALL PROCESSROTENCA BTFSC DECINP,DECCHGRENB CALL PROCESSROTENCB ;END OF TESTING STATES OF THE DECODED INPUTS BTFSC DECINP,DECMODESW CALL PROCESSMUTECTR ;CALLED IF THE MODE SWITCH IS BEING HELD ;CODE BELOW CALLS THE RELEVANT ROUTINES IF THE ROTARY ENCODER HAS MOVED CW OR ATCW BTFSC MUTEBITS,CWROTATE CALL USEROTENC BTFSC MUTEBITS,ATCWROTATE CALL USEROTENC ;TEST RAMP STATES TO ALTER VOLUME AUTOMATICALLY BTFSC MODEBITS,VOLRAMPUP CALL RAMPUP ;VOL RAMP UP IS CALLED IF BIT SET BTFSC MODEBITS,VOLRAMPDN CALL RAMPDOWN ;VOL RAMP DOWN IS CALLED IF BIT SET ;END OF TESTING RAMP STATES ;CALLS THE VOLUME SETTING ROUTINE - THE WHOLE POINT OF THIS PROGRAM! BTFSC MODEBITS,VOLNEW CALL SETVOL ;ROUTINE CALLED IF VOL HAS CHANGED BCF MODEBITS,VOLNEW CALL RUNLEDFLASH BCF MODEBITS,TIMERCHANGE ;RESETS READY FOR START OF LOOP, TO ENSURE ONLY USED ONCE GOTO MAINLOOP ;**************************************************************************** ;**************************************************************************** ; END OF MAIN PROGRAM LOOP ABOVE ;**************************************************************************** ;**************************************************************************** ;**************************************************************************** ;**************************************************************************** ; SUBROUTINES ;**************************************************************************** ;**************************************************************************** ; SUBROUTINE STOREBAL - STORES BALANCE TO E2 MEMORY STOREBAL ;STORE THE BALANCE-LEFT MOVLW 0x01 MOVWF EEADDR ;WRITE ADDRESS 1 = BALANCE-LEFT MOVF BALOFFSETL,0 MOVWF EEDATA ;BALANCE LEFT LOADED IN READY GOTO E2WRITEBYTE ENDSTOREBALL ;STORE THE BALANCE-RIGHT MOVLW 0x02 MOVWF EEADDR ;WRITE ADDRESS 2 = BALANCE-RIGHT MOVF BALOFFSETR,0 MOVWF EEDATA ;BALANCE RIGHT LOADED IN READY GOTO E2WRITEBYTE ENDSTOREBALR RETLW 0 ;END OF SUBROUTINE - RETURNS 0 (DON'T CARE) ;*******END OF SUBROUTINE STOREBAL ****************************************** ;**************************************************************************** ; SUBROUTINE STOREPRESETVOL - STORES PRESET VOL INTO E2 MEMORY STOREPRESETVOL ;STORE THE VOLUME CLRF EEADDR ;SET WRITE ADDRESS TO ZERO MOVF CURVOL,0 MOVWF EEDATA ;CURVOL LOADED IN READY GOTO E2WRITEBYTE ENDSTOREVOL MOVF CURVOL,0 MOVWF INITVOL ;JUST IN CASE YOU SWITCH MUTE OFF, AFTER GOING INTO ; MUTE MODE BY TURNING THE ROTARY ENCODER ANTICLOCKWISE. RETLW 0 ;END OF SUBROUTINE - RETURNS 0 (DON'T CARE) ;*******END OF SUBROUTINE STOREPRESETVOL ************************************ ;**************************************************************************** ;SUBROUTINE ROTENCTABLE - A TABLE USED BY SUBROUTINES PROCESSROTENCA/B, TO DETERMINE THE ; ROTATION DIRECTION. ROTENCTABLE ADDWF PC,1 ;ADDS THE W REG TO THE PROG COUNTER RETLW 2 ;0 - A CHANGED FIRST = CW, B CHANGED FIRST = ATCW RETLW 1 ;1 - A CHANGED FIRST = ATCW, B CHANGED FIRST = CW RETLW 1 ;2 - A CHANGED FIRST = ATCW, B CHANGED FIRST = CW RETLW 2 ;3 - A CHANGED FIRST = CW, B CHANGED FIRST = ATCW ;*******END OF SUBROUTINE ROTENCTABLE *************************************** ;**************************************************************************** ;SUBROUTINE PROCESSROTENCA - CALLED IF THE DEBOUNCED PINS FROM THE ROTARY ENC HAVE CHANGED ; TO DETERMINE THE DIRECTION - CLOCKWISE OR ANTI-CLOCKWISE PROCESSROTENCA INCF NUMROTENCSTEPS,1 MOVF DECINP,0 ANDLW 0x03 ;W CONTAINS THE MASKED VALUE, RANGE 0..3 CALL ROTENCTABLE ;RETURNS WITH 1 OR 2 IN THE W REG - 2=CW, 1=ATCW IF PIN A CHANGED FIRST (OPPOSITE FOR B) ;IF IT RETURNS WITH 4 (0100) THEN THE ROTATION CHANGE IS EFFECTIVELY IGNORED. MOVWF TEMPVAR ;CLEAR THE ROTATION FLAGS IN MUTEBITS - CWROTATE AND ATCWROTATE MOVLW 0x3F ANDWF MUTEBITS,1 ;TEST DIRECTION AND THEN SET DIRECTION FLAGS BTFSC TEMPVAR,0 BSF MUTEBITS,CWROTATE BTFSC TEMPVAR,1 BSF MUTEBITS,ATCWROTATE ;NOW CLEAR THE DECODED ROTARY ENCODER PIN CHANGE FLAG - DECCHGRENA BCF DECINP,DECCHGRENA RETLW 0 ;*******END OF SUBROUTINE PROCESSROTENCA ************************************ ;**************************************************************************** ;SUBROUTINE PROCESSROTENCB - CALLED IF THE DEBOUNCED PINS FROM THE ROTARY ENC HAVE CHANGED ; TO DETERMINE THE DIRECTION - CLOCKWISE OR ANTI-CLOCKWISE PROCESSROTENCB INCF NUMROTENCSTEPS,1 MOVF DECINP,0 ANDLW 0x03 ;W CONTAINS THE MASKED VALUE, RANGE 0..3 CALL ROTENCTABLE BTFSC MUTEBITS,BALANCE GOTO SKIPSETDIRECTIONFLAGS ;IF IN BALANCE MODE, ONLY WANT 0.5dB STEPS, SO IGNORE ROTENCB ;RETURNS WITH 1 OR 2 IN THE W REG - 1=CW, 2=ATCW IF PIN A CHANGED FIRST (OPPOSITE FOR B) ;IF IT RETURNS WITH 4 (0100) THEN THE ROTATION CHANGE IS EFFECTIVELY IGNORED. MOVWF TEMPVAR ;CLEAR THE ROTATION FLAGS IN MUTEBITS - CWROTATE AND ATCWROTATE MOVLW 0x3F ANDWF MUTEBITS,1 ;TEST DIRECTION AND THEN SET DIRECTION FLAGS BTFSC TEMPVAR,0 BSF MUTEBITS,ATCWROTATE BTFSC TEMPVAR,1 BSF MUTEBITS,CWROTATE SKIPSETDIRECTIONFLAGS ;NOW CLEAR THE DECODED ROTARY ENCODER PIN CHANGE FLAG - DECCHGRENB BCF DECINP,DECCHGRENB RETLW 0 ;*******END OF SUBROUTINE PROCESSROTENCB ************************************ ;**************************************************************************** ; SUBROUTINE LOADINIT - LOADS VOL FROM E2 LOADINIT ;READ THE VOLUME CLRF EEADDR ;READ ADDRESS 0 = VOLUME CALL E2READBYTE MOVF EEDATA,0 BTFSC STATUS,ZEROBIT BCF MUTEBITS,VOL ;IF VOLUME IS ZERO, IN MUTE MODE BTFSC STATUS,ZEROBIT BSF MUTEBITS,MUTE ;IF VOLUME IS ZERO, IN MUTE MODE MOVWF INITVOL ;READ THE BALANCE-LEFT INCF EEADDR,1 ;READ ADDRESS 1 = BALANCE-LEFT CALL E2READBYTE MOVF EEDATA,0 MOVWF BALOFFSETL ;READ THE BALANCE-RIGHT INCF EEADDR,1 ;READ ADDRESS 2 = BALANCE-RIGHT CALL E2READBYTE MOVF EEDATA,0 MOVWF BALOFFSETR RETLW 0 ;END OF SUBROUTINE - RETURNS 0 (DON'T CARE) ;*******END OF SUBROUTINE LOADINIT ****************************************** ;**************************************************************************** ;SUBROUTINE RAMPUP - USED TO RAMP UP THE VOLUME AFTER POWER UP RAMPUP MOVF INITVOL,0 XORWF CURVOL,0 BTFSC STATUS,ZEROBIT BCF MODEBITS,VOLRAMPUP ; =0 CASE, SO SETS TO FALSE BTFSS MODEBITS,VOLRAMPUP BCF MODEBITS,FIRSTRAMPUP ;NO MORE RAMPING UP TO DO BTFSS MODEBITS,VOLRAMPUP CLRF RAMPBASE ;CLEARED AS THE VARIABLE IS SHARED BTFSS MODEBITS,VOLRAMPUP RETLW 0 ;NO MORE RAMPING UP TO DO ;IF HERE, THEY ARE NOT THE SAME MOVLW 0x01 BTFSC MODEBITS,FASTRAMP MOVLW 0x04 ;IF FAST RAMP, WANT 2dB/STEP MOVWF TEMPVAR LOOPRU DECF TEMPVAR,1 INCF CURVOL,1 MOVF INITVOL,0 XORWF CURVOL,0 BTFSC STATUS,ZEROBIT CLRF TEMPVAR MOVF TEMPVAR,1 BTFSS STATUS,ZEROBIT GOTO LOOPRU ;ONLY DOES ONCE, IF FASTRAMP = FALSE BSF MODEBITS,VOLNEW ;WANT THE VOLUME TO BE SENT ;CODE BELOW ONLY INCREMENTS THE STEPSIZE WAITING TIME, WHEN THE VOLUME IS WITHIN THE LAST 40DB RANGE MOVF RAMPBASE,0 SUBWF CURVOL,0 BTFSC STATUS,CARRYBIT INCF STEPSIZE,1 ;CURVOL >= RAMPBASE, SO NOW IN RANGE MOVF STEPSIZE,0 MOVWF WAITTIME CALL WAIT ;1.5MSEC DELAY RETLW 0 ;END OF SUBROUTINE (DON'T CARE) ;*******END OF SUBROUTINE RAMPUP ******************************************** ;**************************************************************************** ;SUBROUTINE SETUPRAMPDN - USED TO INITIALISE THE VARIABLES BEFORE ;CALLING RAMPDOWN LSETUPRAMPDN MOVLW 0x50 ;NUMBER OF STEPS FOR 40DB RANGE MOVWF STEPSIZE BSF MODEBITS,VOLRAMPDN BCF MODEBITS,VOLRAMPUP ;SET THE MODE GOTO DRAMPDOWN ;END OF SUBROUTINE (DON'T CARE) ;*******END OF SUBROUTINE SETUPRAMPDN *************************************** ;**************************************************************************** ;SUBROUTINE RAMPDOWN ;USED TO RAMP AUDIO DOWN TO MUTE LRAMPDOWN MOVF CURVOL,1 BTFSC STATUS,ZEROBIT ;IS CURVOL AT 0? BCF MODEBITS,VOLRAMPDN BTFSS MODEBITS,VOLRAMPDN GOTO DRAMPDOWN ;IF HERE, CURVOL IS NOT AT ZERO, SO WORK TO DO MOVLW 0x01 BTFSC MODEBITS,FASTRAMP MOVLW 0x04 ;MOVE 2dB/STEP IF FASTRAMP MOVWF TEMPVAR LOOPRD DECF TEMPVAR,1 DECF CURVOL,1 BTFSC STATUS,ZEROBIT CLRF TEMPVAR ;IF ZERO THEN WANT TO STOP DECF STEPSIZE,1 BTFSC STATUS,ZEROBIT INCF STEPSIZE,1 ;STEPSIZE MUST ALWAYS BE AT LEAST 1 MOVF TEMPVAR,1 BTFSS STATUS,ZEROBIT GOTO LOOPRD BSF MODEBITS,VOLNEW ;WANT THE VOLUME TO BE SENT MOVF STEPSIZE,0 MOVWF WAITTIME CALL WAIT GOTO DRAMPDOWN ;END SUBROUTINE RAMP DOWN (DON'T CARE) ;*******END OF SUBROUTINE RAMPDOWN ****************************************** ;**************************************************************************** ;SUBROUTINE USEROTENC - THIS ROUTINE SETS THE VOL/BALANCE/PRESET VOL LUSEROTENC ;CW - VOLUME MOVLW 0x41 XORWF MUTEBITS,0 BTFSC STATUS,ZEROBIT CALL CLOCKVOL ;ATCW - VOLUME MOVLW 0x81 XORWF MUTEBITS,0 BTFSC STATUS,ZEROBIT CALL ATCLOCKVOL ;CW - MUTE (SO, MUTE IS SWITCHED OFF...) MOVLW 0x42 XORWF MUTEBITS,0 BTFSC STATUS,ZEROBIT CALL CLOCKMUTE ;CW - BALANCE MOVLW 0x44 XORWF MUTEBITS,0 BTFSC STATUS,ZEROBIT CALL CLOCKBAL ;ATCW - BALANCE MOVLW 0x84 XORWF MUTEBITS,0 BTFSC STATUS,ZEROBIT CALL ATCLOCKBAL ;CW - PRESET VOLUME MOVLW 0x48 XORWF MUTEBITS,0 BTFSC STATUS,ZEROBIT CALL CLOCKVOL ;NORMAL VOL ROUTINE CALLED - ONLY DIFFERENT WHEN STORED ;ATCW - PRESET VOLUME MOVLW 0x88 XORWF MUTEBITS,0 BTFSC STATUS,ZEROBIT CALL ATCLOCKVOL ;NORMAL VOL ROUTINE CALLED - ONLY DIFFERENT WHEN STORED ;ASSUME VOLUME NEEDS TO BE SENT TO CHIP BSF MODEBITS,VOLNEW BCF MUTEBITS,CWROTATE BCF MUTEBITS,ATCWROTATE GOTO DUSEROTENC ;*******END OF SUBROUTINE USEROTENC ***************************************** ;**************************************************************************** ;SUBROUTINE PROCESSMDSW - CALLED IF THE DECODED MODE SWITCH HAS CHANGED LPROCESSMDSW BCF DECINP,DECCHGMDSW ;SET TEMPVAR TO HOLD A VALUE AS FOLLOWS: ;11h SW PRESSED, VOL MODE ;12h SW PRESSED, MUTE MODE ;14h SW PRESSED, BAL MODE ;18h SW PRESSED, PRESET VOL MODE ;01h SW RELEASED, VOL MODE ;02h SW RELEASED, MUTE MODE ;04h SW RELEASED, BAL MODE ;08h SW RELEASED, PRESET VOL MODE ;21h SW PRESSED, VOL MODE, IGNORENEXTVOLRELEASE ;BIT 5 OF MUTEBITS USED FOR IGNORENEXTVOLRELEASE ;(STOPS MUTE BEING SWITCHED ON, WHEN RETURNING TO VOL MODE ; FROM MUTE, BALANCE, PRESET MODES) MOVF MUTEBITS,0 ANDLW 0x2F ;MASKS OUT BITS 7,6,4 MOVWF TEMPVAR BTFSC DECINP,DECMODESW BSF TEMPVAR,4 ;BIT 4 SET IF SWITCH IS CURRENTLY PRESSED BTFSS DECINP,DECMODESW CLRF MUTECOUNTER ;IF HERE, RELEASED ;NOW, JUMP TO NESTED SUBROUTINES ;11h SW PRESSED, VOL MODE MOVLW 0x11 XORWF TEMPVAR,0 BTFSC STATUS,ZEROBIT GOTO PUSHVOL ;12h SW PRESSED, MUTE MODE MOVLW 0x12 XORWF TEMPVAR,0 BTFSC STATUS,ZEROBIT GOTO PUSHMUTE ;14h SW RELEASED, BAL MODE MOVLW 0x14 XORWF TEMPVAR,0 BTFSC STATUS,ZEROBIT GOTO PUSHBAL ;18h SW RELEASED, PRESET VOL MODE MOVLW 0x18 XORWF TEMPVAR,0 BTFSC STATUS,ZEROBIT GOTO PUSHPRESET ;21h SW PRESSED, VOL MODE, IGNORENEXTVOLRELEASE MOVLW 0x21 XORWF TEMPVAR,0 BTFSC STATUS,ZEROBIT BCF MUTEBITS,IGNORENEXTVOLRELEASE ;01h SW RELEASED, IN VOL MODE, SO GO INTO MUTE MODE MOVLW 0x01 XORWF TEMPVAR,0 BTFSC STATUS,ZEROBIT GOTO RELVOL ;IF HERE, THEN IN ONE OF THE THREE RELEASE MODES BELOW ;02h SW RELEASED, MUTE MODE ;04h SW RELEASED, BAL MODE ;08h SW RELEASED, PRESET VOL MODE ;DO NOTHING ENDPROCESSMDSW GOTO DPROCESSMDSW ;NESTED SUBROUTINES FOR THIS ROUTINE PUSHVOL ;PRESSED IN VOL MODE. START COUNTER TO SEE HOW LONG BUTTON IS HELD PRESSED. MOVLW 0x01 MOVWF MUTECOUNTER GOTO ENDPROCESSMDSW RELVOL ;RELEASE IN VOL MODE. TURN MUTE ON BCF MUTEBITS,VOL BSF MUTEBITS,MUTE BSF MODEBITS,FASTRAMP CALL SETUPRAMPDN MOVF CURVOL,0 BTFSS STATUS,ZEROBIT ;PROTECTS AGAINST ZERO BEING STORED IN INITVOL. MOVWF INITVOL GOTO ENDPROCESSMDSW PUSHMUTE ;PRESSED IN MUTE MODE ;FIRST, CHECK THAT INITVOL IS NOT ZERO! STAY IN MUTE IN THAT CASE MOVF INITVOL,1 BTFSC STATUS,ZEROBIT GOTO ENDPROCESSMDSW CLRF MUTEBITS BSF MUTEBITS,VOL BSF MODEBITS,FASTRAMP CLRF MUTECOUNTER CALL SETUPRAMPUP BSF MUTEBITS,IGNORENEXTVOLRELEASE GOTO ENDPROCESSMDSW PUSHBAL ;PRESSED IN BALANCE MODE CLRF MUTEBITS BSF MUTEBITS,VOL CLRF MUTECOUNTER CALL STOREBAL BSF MUTEBITS,IGNORENEXTVOLRELEASE GOTO ENDPROCESSMDSW PUSHPRESET ;PRESSED IN PRESET MODE CLRF MUTEBITS BSF MUTEBITS,VOL CLRF MUTECOUNTER CALL STOREPRESETVOL BSF MUTEBITS,IGNORENEXTVOLRELEASE GOTO ENDPROCESSMDSW ;*******END OF SUBROUTINE PROCESSMDSW *************************************** ;**************************************************************************** ;SUBROUTINE PROCESSVOLSPEED ;THIS SETS THE VALUE OF VOLSPEED VARIABLE, USED TO DETERMINE ;HOW QUICKLY THE USER IS ROTATING THE CONTROL. VOLUME IS INCREASED ;IN LARGER STEP SIZES IF THE CONTROL IS ROTATED QUICKLY! ;THIS IS CALLED WHEN THE TIMERCHANGE BIT IS SET (IE. A NEW TIME WINDOW). LPROCESSVOLSPEED MOVLW 0x09 SUBWF NUMROTENCSTEPS,0 BTFSC STATUS,CARRYBIT GOTO VOLSPEED9 ;SO, MORE THAN 9 STEPS IN LAST TIME WINDOW MOVLW 0x05 SUBWF NUMROTENCSTEPS,0 BTFSC STATUS,CARRYBIT GOTO VOLSPEED5 ;SO, MORE THAN 5 STEPS IN LAST TIME WINDOW ;IF HERE, THEN LESS STEPS THAN THRESHOLDS IN THE LAST TIME WINDOW ;SO SET VOLSPEED TO DEFAULT OF 1 FOR VOLUME (=1dB PER STEP) CLRF VOLSPEED ENDVOLSPEED CLRF NUMROTENCSTEPS GOTO DPROCESSVOLSPEED ;NESTED ROUTINES BELOW: VOLSPEED9 MOVLW 0x02 MOVWF VOLSPEED GOTO ENDVOLSPEED VOLSPEED5 MOVLW 0x01 MOVWF VOLSPEED GOTO ENDVOLSPEED ;*******END OF SUBROUTINE PROCESSVOLSPEED *********************************** ;**************************************************************************** ;SUBROUTINE WAIT ;APPROX IN 2.3MSEC BLOCKS ; NUMBER OF BLOCKS NEEDED IS LOADED INTO WAITTIME BEFORE CALLING ;THE ROUTINE IS EXCLUSIVE - NO OTHER FUNCTIONS ARE POSSIBLE. LWAIT NOP LOOPW3 MOVLW 0x03 ;2.3MSEC PER CALL MOVWF COUNTER LOOPW2 MOVLW 0xFF MOVWF TEMPVAR LOOPW1 DECFSZ TEMPVAR,1 GOTO LOOPW1 DECFSZ COUNTER,1 GOTO LOOPW2 DECFSZ WAITTIME,1 GOTO LOOPW3 GOTO DWAIT ;*******END OF SUBROUTINE WAIT ********************************************** ;**************************************************************************** ;**************************************************************************** ;**************************************************************************** ;CODE BELOW IS IN THE LOWER HALF OF THE UPPER MEMORY PAGE OF THE ROM ; (512..767) ;**************************************************************************** ;**************************************************************************** ORG 0x200 ;UPPER MEMORY PAGE IN ROM ; Based on Microchip program: FLASH51X.ASM V1.10 ;These routines provide the following functionality: ; write byte random address ; read byte random address ; read byte next address ; ; If the operation is successful, bit 7 of PC_OFFSET will be set, and ; the functions will return W=1. If the memory is busy with a write ; cycle, it will not ACK the command. The functions will return with ; bit 7 of PC_OFFSET cleared and and W will be set to 0. ; ; Must reside on the lower half of code page (address 0-FF). ; ;*************************************************************************** ;*************************** EEPROM Subroutines ************************** ;*************************************************************************** ; Communication for EEPROM based on I2C protocol, with Acknowledge. ; ; Write_Byte: Byte write routine ; Inputs: EEPROM Address EEADDR ; EEPROM Data EEDATA ; Outputs: Return 01 in W if OK, else return 00 in W ; ; Read_Random: Read EEPROM byte at supplied address ; Inputs: EEPROM Address EEADDR ; Outputs: EEPROM Data EEDATA ; Return 01 in W if OK, else return 00 in W ; ; Note: EEPROM subroutines will set bit 7 in PC_OFFSET register if the ; EEPROM acknowledged OK, else that bit will be cleared. This bit ; can be checked instead of refering to the value returned in W ;*************************************************************************** ; ; OPERATION: ; Byte Write: ; load EEADDR and EEDATA ; then CALL BYTE_WRITE ; ; Read Random: ; Load EEADDR ; then CALL READ_RANDOM ; data read returned in EEDATA ; ;*************************************************************************** ;********************** Set up EEPROM control bytes ************************ ;*************************************************************************** WRITE_BYTE MOVLW B'10000000' ; PC offset for write byte. EE_OK: bit7 = '1' GOTO INIT_WRITE_CONTROL READ_RANDOM MOVLW B'10000011' ; PC offset for read random. EE_OK: bit7 = '1' INIT_WRITE_CONTROL MOVWF PC_OFFSET ; Load PC offset register, value preset in W MOVLW B'10100000' ; Control byte with write bit, bit 0 = '0' START_BIT BCF GPIO,SDA ; Start bit, SDA and SCL preset to '1' ;******* Set up output data (control, address, or data) and counter ******** ;*************************************************************************** PREP_TRANSFER_BYTE MOVWF EEBYTE ; Byte to transfer to EEPROM already in W MOVLW 0x08 ; Counter to transfer 8 bits MOVWF COUNTER ;************ Clock out data (control, address, or data) byte ************ ;*************************************************************************** OUTPUT_BYTE BCF GPIO,SCL ; Set clock low during data set-up RLF EEBYTE, F ; Rotate left, high order bit into carry bit BCF GPIO,SDA ; Set data low, if rotated carry bit is BTFSC STATUS,CARRYBIT ; a '1', then: BSF GPIO,SDA ; reset data pin to a one, otherwise leave low NOP ; delay, allow pullup to raise SDA BSF GPIO,SCL ; clock data into EEPROM DECFSZ COUNTER, F ; Repeat until entire byte is sent GOTO OUTPUT_BYTE NOP ; Needed to meet Timing (Thigh=4000nS) ;************************** Acknowledge Check ***************************** ;*************************************************************************** BCF GPIO,SCL ; Set SCL low, 0.5us < ack valid < 3us NOP ; Needed to meet Timing (Tlow= 4700nS) BSF GPIO,SDA NOP NOP NOP NOP ; Tlow=??nS BSF GPIO,SCL ; Raise SCL, EEPROM acknowledge still valid BTFSC GPIO,SDA ; Check SDA for acknowledge (low) BCF PC_OFFSET,EE_OK ; If SDA not low (no ack), set error flag BCF GPIO,SCL ; Lower SCL, EEPROM release bus BTFSS PC_OFFSET,EE_OK ; If no error continue, else stop bit GOTO STOP_BIT ;***** Set up program counter offset, based on EEPROM operating mode ***** ;*************************************************************************** MOVF PC_OFFSET,0 ANDLW B'00001111' ADDWF PC, F GOTO INIT_ADDRESS ;PC offset=0, write control done, send address GOTO INIT_WRITE_DATA ;PC offset=1, write address done, send data GOTO STOP_BIT ;PC offset=2, write done, send stop bit GOTO INIT_ADDRESS ;PC offset=3, write control done, send address GOTO INIT_READ_CONTROL ;PC offset=4, send read control GOTO READ_BIT_COUNTER ;PC offset=5, set counter and read byte GOTO STOP_BIT ;PC offset=6, random read done, send stop ;********** Initalize EEPROM data (address, data, or control) bytes ****** ;*************************************************************************** INIT_ADDRESS INCF PC_OFFSET, F ; Increment PC offset to 2 (write) or to 4 (read) MOVF EEADDR,0 ; Put EEPROM address in W, ready to send to EEPROM GOTO PREP_TRANSFER_BYTE INIT_WRITE_DATA INCF PC_OFFSET, F ; Increment PC offset to go to STOP_BIT next MOVF EEDATA,0 ; Put EEPROM data in W, ready to send to EEPROM GOTO PREP_TRANSFER_BYTE INIT_READ_CONTROL BSF GPIO,SCL ; Raise SCL NOP BSF GPIO,SDA ; raise SDA INCF PC_OFFSET, F ; Increment PC offset to go to READ_BIT_COUNTER next MOVLW B'10100001' ; Set up read control byte, ready to send to EEPROM GOTO START_BIT ; bit 0 = '1' for read operation ;************************** Read EEPROM data ***************************** ;*************************************************************************** READ_BIT_COUNTER BSF GPIO,SDA ; set data bit to 1 so we're not pulling bus down. NOP BSF GPIO,SCL MOVLW 0x08 ; Set counter so 8 bits will be read into EEDATA MOVWF COUNTER READ_BYTE BSF GPIO,SCL ; Raise SCL, SDA valid. SDA still input from ack BSF STATUS,CARRYBIT ; Assume bit to be read = 1 BTFSS GPIO,SDA ; Check if SDA = 1 BCF STATUS,CARRYBIT ; if SDA not = 1 then clear carry bit RLF EEDATA, F ; rotate carry bit (=SDA) into EEDATA; BCF GPIO,SCL ; Lower SCL BSF GPIO,SDA ; reset SDA DECFSZ COUNTER, F ; Decrement counter GOTO READ_BYTE ; Read next bit if not finished reading byte BSF GPIO,SCL NOP BCF GPIO,SCL ;****************** Generate a STOP bit and RETURN *********************** ;*************************************************************************** STOP_BIT BCF GPIO,SDA ; SDA=0, on TRIS, to prepare for transition to '1' BSF GPIO,SCL ; SCL = 1 to prepare for STOP bit NOP ; equivalent 4 NOPs neccessary for I2C spec Tsu:sto = 4.7us NOP NOP NOP BSF GPIO,SDA ; Stop bit, SDA transition to '1' while SCL high ;GO BACK TO READ OR WRITE CALLING ROUTINE - LOOK AT BIT 0 IN TEMPVAR BTFSC TEMPVAR,0 GOTO RETURNTOWRITE ;IF HERE, THEN READING A BYTE BCF TEMPVAR,1 ; if no error, CLEAR BIT 1 IN TEMPVAR BTFSS PC_OFFSET,EE_OK ; Check for error BSF TEMPVAR,1 ; if error, SET BIT 1 IN TEMPVAR BCF STATUS,PAGE0 GOTO DE2READBYTE RETURNTOWRITE ;IF HERE, THEN WRITING A BYTE BCF TEMPVAR,1 ; if no error, CLEAR BIT 1 IN TEMPVAR BTFSS PC_OFFSET,EE_OK ; Check for error BSF TEMPVAR,1 ; if error, SET BIT 1 IN TEMPVAR BCF STATUS,PAGE0 GOTO DE2WRITEBYTE ;**************************************************************************** ;************************ End EEPROM Subroutines ************************** ;**************************************************************************** ;SUBROUTINE PROCESSMUTECTR - LOOKS AT THE MUTE COUNTER TO SEE HOW LONG THE MUTE ; BUTTON HAS BEEN HELD FOR, AND CHANGES THE STATE OF FLAGS IN MUTEBITS ACCORDINGLY. ; 0..2 SECS = VOL/MUTE MODE, 2..9 SECS = BALANCE MODE, GREATER THAN 9 SECS = PRESET VOL MODE LPROCESSMUTECTR BTFSS MODEBITS,TIMERCHANGE GOTO ENDPROCMTE ;DON'T DO THE SUBROUTINE IF THE TIMER HASN'T CHANGED MOVF MUTECOUNTER,1 BTFSC STATUS,ZEROBIT GOTO ENDPROCMTE ;IF MUTE COUNTER =0, THEN NOT RUNNING, SO DO NOTHING ;NEXT, MUTECOUNTER >=1, SO INCREMENT UP TO 255 INCF MUTECOUNTER,1 BTFSC STATUS,ZEROBIT DECF MUTECOUNTER,1 ;WRAPPED ROUND TO 0, SO DEC TO 255 ;NOW CHECK IF THE COUNTER HAS PASSED ANY THRESHOLDS MOVLW 0xF0 ANDWF MUTEBITS,1 ;CLEAR ALL THE MUTEBITS MODE FLAGS, SO THEN JUST SET THE ONE NEEDED ; MOVLW 0xFE ;9 SECS (8.9SECS ACTUALLY...) - PRESET VOL SUBWF MUTECOUNTER,0 BTFSC STATUS,CARRYBIT BSF MUTEBITS,PRESETVOL ;CARRYBIT SET IF >= 9 SECS BTFSC STATUS,CARRYBIT GOTO ENDPROCMTE ; MOVLW 0x39 ;2 TO 9 SECS - BALANCE SUBWF MUTECOUNTER,0 BTFSC STATUS,CARRYBIT BSF MUTEBITS,BALANCE ;CARRYBIT SET IF >= 2 SECS BTFSC STATUS,CARRYBIT GOTO ENDPROCMTE ; ;IF HERE MUST BE LESS THAN 2 SECS BSF MUTEBITS,VOL ENDPROCMTE BCF STATUS,PAGE0 GOTO DPROCESSMUTECTR ;*******END OF SUBROUTINE PROCESSMUTECTR ************************************ ;**************************************************************************** ;SUBROUTINE CLOCKBAL - CALLED IF IN BALANCE MODE AND THE KNOB HAS BEEN ROTATED ; ONE STEP CLOCKWISE - SO MAKING THE RIGHT CHANNEL LOUDER THAN THE LEFT LCLOCKBAL ;IF RIGHT CHANNEL MUTED THEN UNMUTE RIGHT CHANNEL CLRF TEMPVAR BTFSC MODEBITS,RGHTCHMUTE BSF TEMPVAR,0 ;STORE THE OLD MUTE SETTING BTFSC TEMPVAR,0 BCF MODEBITS,RGHTCHMUTE BTFSC TEMPVAR,0 GOTO ENDCLKBAL ;ELSIF RIGHT CHANNEL OFFSET > 0, THEN DEC RIGHT CHANNEL OFFSET CLRF TEMPVAR MOVF BALOFFSETR,1 BTFSC STATUS,ZEROBIT BSF TEMPVAR,0 BTFSS TEMPVAR,0 DECF BALOFFSETR,1 BTFSS TEMPVAR,0 GOTO ENDCLKBAL ;ELSE (IE. RIGHT CHANNEL OFFSET = 0) INC LEFT CHANNEL OFFSET, OR MUTE LEFT INCF BALOFFSETL,1 MOVLW 0x1F ;31 DECIMAL - 1 = 15dB RANGE SUBWF BALOFFSETL,0 BTFSC STATUS,CARRYBIT ;IF NEGATIVE, THEN IN RANGE BSF MODEBITS,LEFTCHMUTE ;OUT OF RANGE SO MUTE LEFT BTFSC STATUS,CARRYBIT DECF BALOFFSETL,1 ENDCLKBAL BCF STATUS,PAGE0 GOTO DCLOCKBAL ;*******END OF SUBROUTINE CLOCKBAL ****************************************** ;**************************************************************************** ;SUBROUTINE ATCLOCKBAL - CALLED IF IN BALANCE MODE AND THE KNOB HAS BEEN ROTATED ; ONE STEP ANTI-CLOCKWISE - SO MAKING THE LEFT CHANNEL LOUDER THAN THE RIGHT LATCLOCKBAL ;IF LEFT CHANNEL MUTED THEN UNMUTE LEFT CHANNEL CLRF TEMPVAR BTFSC MODEBITS,LEFTCHMUTE BSF TEMPVAR,0 ;STORE THE OLD MUTE SETTING BTFSC TEMPVAR,0 BCF MODEBITS,LEFTCHMUTE BTFSC TEMPVAR,0 GOTO ENDATCLKBAL ;ELSIF LEFT CHANNEL OFFSET > 0, THEN DEC LEFT CHANNEL OFFSET CLRF TEMPVAR MOVF BALOFFSETL,1 BTFSC STATUS,ZEROBIT BSF TEMPVAR,0 BTFSS TEMPVAR,0 DECF BALOFFSETL,1 BTFSS TEMPVAR,0 GOTO ENDATCLKBAL ;ELSE (IE. LEFT CHANNEL OFFSET = 0) INC RIGHT CHANNEL OFFSET, OR MUTE RIGHT INCF BALOFFSETR,1 MOVLW 0x1F ;31 DECIMAL - 1 = 15dB RANGE SUBWF BALOFFSETR,0 BTFSC STATUS,CARRYBIT ;IF NEGATIVE, THEN IN RANGE BSF MODEBITS,RGHTCHMUTE ;OUT OF RANGE SO MUTE RIGHT BTFSC STATUS,CARRYBIT DECF BALOFFSETR,1 ENDATCLKBAL BCF STATUS,PAGE0 GOTO DATCLOCKBAL ;*******END OF SUBROUTINE ATCLOCKBAL **************************************** ;**************************************************************************** ;SUBROUTINE CLOCKVOL - CLOCKWISE ROTATION OF THE VOLUME KNOB - AUDIO BECOMES LOUDER ; NORMALLY IN 0.5dB STEPS, BUT MORE STEPS DEPENDING ON VOLSPEED. LCLOCKVOL ;IF RAMPING UP OR DOWN, THEN STOP NOW AS THE ROTARY ENCODER HAS BEEN USED. BCF MODEBITS,VOLRAMPUP BCF MODEBITS,VOLRAMPDN ;INITIAL VOL INCREASE BY 1 STEP IF POSSIBLE INCF CURVOL,1 BTFSC STATUS,ZEROBIT DECF CURVOL,1 ;ZERO BECAUSE WRAPPED ROUND, SO RESET TO MAX ;MORE STEPS, DEPENDING ON VOLSPEED VALUE? MOVF VOLSPEED,0 MOVWF TEMPVAR ;IF VOLSPEED = 0 THEN STOP HERE BTFSC STATUS,ZEROBIT GOTO ENDCLKVOL LOOPCV INCF CURVOL,1 BTFSC STATUS,ZEROBIT DECF CURVOL,1 DECFSZ TEMPVAR,1 GOTO LOOPCV ENDCLKVOL BCF STATUS,PAGE0 GOTO DCLOCKVOL ;*******END OF SUBROUTINE CLOCKVOL ****************************************** ;**************************************************************************** ;SUBROUTINE ATCLOCKVOL - ANTI-CLOCKWISE ROTATION OF THE VOLUME KNOB - AUDIO BECOMES QUIETER ; NORMALLY IN 0.5dB STEPS, BUT MORE STEPS DEPENDING ON VOLSPEED. LATCLOCKVOL ;IF RAMPING UP OR DOWN, THEN STOP NOW AS THE ROTARY ENCODER HAS BEEN USED. BCF MODEBITS,VOLRAMPUP BCF MODEBITS,VOLRAMPDN ;INITIAL VOL DECREASE BY 1 STEP IF POSSIBLE MOVF CURVOL,1 BTFSC STATUS,ZEROBIT GOTO ENDATCLKVOL ;IF CURVOL = 0 ALREADY, THEN STOP HERE BTFSS STATUS,ZEROBIT DECF CURVOL,1 ;MORE STEPS, DEPENDING ON VOLSPEED VALUE? BTFSC STATUS,ZEROBIT GOTO ISCURVOLNOWZERO ;IF CURVOL = 0 THEN STOP HERE MOVF VOLSPEED,0 MOVWF TEMPVAR ;IF VOLSPEED = 0 THEN STOP HERE BTFSC STATUS,ZEROBIT GOTO ENDATCLKVOL LOOPATCV DECF CURVOL,1 BTFSC STATUS,ZEROBIT GOTO ISCURVOLNOWZERO ;CURVOL NOW = 0 SO STOP HERE DECFSZ TEMPVAR,1 GOTO LOOPATCV ISCURVOLNOWZERO MOVF CURVOL,1 BTFSS STATUS,ZEROBIT GOTO ENDATCLKVOL ;IF CURVOL IS NOT ZERO, THEN GO TO END ;IF HERE, CURVOL IS NOW ZERO (DUE TO THIS ROUTINE), SO SET INTO MUTE MODE ; ONLY IF NOT IN PRESET VOL MODE! BTFSS MUTEBITS,PRESETVOL BCF MUTEBITS,VOL BTFSS MUTEBITS,PRESETVOL BSF MUTEBITS,MUTE ;WHEN MUTE IS TURNED OFF, VOLUME WILL RETURN TO LAST INITVOL VALUE ; EITHER THE VOL SETTING WHEN THE MUTE BUTTON WAS LAST USED, OR ; THE PRESET VOL SETTING. ENDATCLKVOL BCF STATUS,PAGE0 GOTO DATCLOCKVOL ;*******END OF SUBROUTINE ATCLOCKVOL **************************************** ;**************************************************************************** ;SUBROUTINE CLOCKMUTE - UN-MUTES, IF VOL KNOB ROTATED CLOCKWISE IN MUTE MODE LCLOCKMUTE CLRF MUTEBITS BSF MUTEBITS,VOL CLRF MUTECOUNTER BSF MODEBITS,VOLNEW INCF CURVOL,1 ;SET THE VOLUME TO 1 BCF STATUS,PAGE0 GOTO DCLOCKMUTE ;*******END OF SUBROUTINE CLOCKMUTE ***************************************** ;**************************************************************************** ;SUBROUTINE SETVOL ;USED TO SEND THE VOLUME SETTING REQUIRED TO THE IC LSETVOL BSF GPIO,2 ;DISABLE CS BCF GPIO,4 ;DROP SCLK ;RIGHT CHANNEL ;BALANCE CORRECTION IF NEEDED MOVF BALOFFSETR,0 SUBWF CURVOL,0 BTFSS STATUS,CARRYBIT CLRW ;IF CARRY=0 THE CURRENT VOL IS LESS THAN BAL OFFSET, SO MUTE BTFSC MODEBITS,RGHTCHMUTE CLRW ;MUTE IF MUTE BIT SET MOVWF TEMPVAR BCF GPIO,2 ;ENABLE CS ;NOW SEND THE BALANCE CORRECTED VOLUME SETTING MOVLW 0x08 MOVWF COUNTER LOOPSV BCF GPIO,4 ;DROP SCLK RLF TEMPVAR,1 BTFSC STATUS,CARRYBIT BSF GPIO,5 ;CARRY BIT = 1 BTFSS STATUS,CARRYBIT BCF GPIO,5 ;CARRY BIT = 0 NOP ;TIMING WAIT BSF GPIO,4 ;RAISE SCLK NOP ;TIMING WAIT DECFSZ COUNTER,1 GOTO LOOPSV ;LEFT CHANNEL ;BALANCE CORRECTION IF NEEDED MOVF BALOFFSETL,0 SUBWF CURVOL,0 BTFSS STATUS,CARRYBIT CLRW ;IF CARRY=0 THE CURRENT VOL IS LESS THAN BAL OFFSET, SO MUTE BTFSC MODEBITS,LEFTCHMUTE CLRW ;MUTE IF MUTE BIT SET MOVWF TEMPVAR BCF GPIO,4 ;DROP SCLK ;NOW SEND THE BALANCE CORRECTED VOLUME SETTING MOVLW 0x08 MOVWF COUNTER LOOPSV1 BCF GPIO,4 ;DROP SCLK RLF TEMPVAR,1 BTFSC STATUS,CARRYBIT BSF GPIO,5 ;CARRY BIT = 1 BTFSS STATUS,CARRYBIT BCF GPIO,5 ;CARRY BIT = 0 NOP ;TIMING WAIT BSF GPIO,4 ;RAISE SCLK NOP ;TIMING WAIT DECFSZ COUNTER,1 GOTO LOOPSV1 BCF GPIO,4 ;DROP SCLK BSF GPIO,2 ;DISABLE CS BCF STATUS,PAGE0 GOTO DSETVOL ;END OF SUBROUTINE - RETURNS 0 (DONT CARE) ;*******END OF SUBROUTINE SETVOL ******************************************** ;**************************************************************************** ;**************************************************************************** ;**************************************************************************** ;CODE BELOW IS IN THE UPPER HALF OF THE UPPER MEMORY PAGE OF THE ROM ; (776..1024) ;**************************************************************************** ;**************************************************************************** ORG 0x308 ;UPPER MEMORY PAGE IN ROM ;SUBROUTINE SETUPRAMPUP - USED TO CONFIGURE THE VARIABLES ETC ;PRIOR TO RAMPUP AT POWER UP. LSETUPRAMPUP CLRF STEPSIZE INCF STEPSIZE,1 ;STEPSIZE = 1 BSF MODEBITS,VOLRAMPUP BCF MODEBITS,VOLRAMPDN MOVLW 0x50 SUBWF INITVOL,0 ;IF CARRY = 1 - SO WITHIN RANGE BTFSC STATUS,CARRYBIT MOVWF RAMPBASE BTFSC STATUS,CARRYBIT GOTO ENDSETURP ;ELSE CARRY =0 - SO OUT OF RANGE - PREPROCESS DATA READY FOR RAMPUP ROUTINE CLRF RAMPBASE ;THIS WILL CAUSE THE STEPSIZE TO ALWAYS INCREMENT MOVLW 0x50 MOVWF TEMPVAR MOVF INITVOL,0 SUBWF TEMPVAR,1 ;TEMPVAR NOW HOLDS THE NUMBER OF "MISSING" STEPS ;NOW LOOP UNTIL TEMPVAR IS ZERO, WHILST INCREMENTING THE STEPSIZE TO MAKE APPARENTLY "IN RANGE" LOOPSUR INCF STEPSIZE,1 DECFSZ TEMPVAR,1 GOTO LOOPSUR ENDSETURP BCF STATUS,PAGE0 GOTO DSETUPRAMPUP ;*******END OF SUBROUTINE SETUPRAMUP **************************************** ;**************************************************************************** ;SUBROUTINES BELOW FOR DEBOUNCE COUNTERS LMODESWPRESS ;BUTTON IS PRESSED SO INC COUNTER BCF DECINP,DECCHGMDSW CLRF TEMPVAR MOVLW 0x50 ;TEST TO SEE IF AT FULL RANGE XORWF MODESW,0 BTFSS STATUS,ZEROBIT BSF TEMPVAR,0 ;SET IF NOT AT FULL RANGE AT START BTFSS STATUS,ZEROBIT INCF MODESW,1 MOVLW 0x50 ;TEST TO SEE IF AT FULL RANGE XORWF MODESW,0 BTFSC STATUS,ZEROBIT BSF TEMPVAR,1 ;SET IF FULL RANGE NOW MOVLW 0x03 XORWF TEMPVAR,0 BTFSC STATUS,ZEROBIT BSF DECINP,DECMODESW BTFSC STATUS,ZEROBIT BSF DECINP,DECCHGMDSW BCF STATUS,PAGE0 GOTO DMODESWPRESS ;*******END OF SUBROUTINE MODESWPRESS *************************************** ;**************************************************************************** LMODESWREL ;BUTTON IS RELEASED SO DEC COUNTER BCF DECINP,DECCHGMDSW CLRF TEMPVAR MOVF MODESW,1 ;TEST TO SEE IF CURRENTLY ZERO BTFSS STATUS,ZEROBIT BSF TEMPVAR,0 ; SET IF NOT ZERO AT START OF SUBROUTINE BTFSS STATUS,ZEROBIT DECF MODESW,1 MOVF MODESW,1 ;TEST TO SEE IF CURRENTLY ZERO BTFSC STATUS,ZEROBIT BSF TEMPVAR,1 ;SET IF ZERO NOW MOVLW 0x03 XORWF TEMPVAR,0 BTFSC STATUS,ZEROBIT BCF DECINP,DECMODESW BTFSC STATUS,ZEROBIT BSF DECINP,DECCHGMDSW BCF STATUS,PAGE0 GOTO DMODESWREL ;*******END OF SUBROUTINE MODESWREL ***************************************** ;**************************************************************************** LROTENCAOFF ;LOW SO INC COUNTER BCF DECINP,DECCHGRENA CLRF TEMPVAR MOVLW 0x1A ;TEST TO SEE IF AT FULL RANGE (WAS 1A) XORWF ROTENCA,0 BTFSS STATUS,ZEROBIT BSF TEMPVAR,0 ;SET IF NOT AT FULL RANGE AT START BTFSS STATUS,ZEROBIT INCF ROTENCA,1 MOVLW 0x1A ;TEST TO SEE IF AT FULL RANGE (WAS 1A) XORWF ROTENCA,0 BTFSC STATUS,ZEROBIT BSF TEMPVAR,1 ;SET IF FULL RANGE NOW MOVLW 0x03 XORWF TEMPVAR,0 BTFSC STATUS,ZEROBIT BSF DECINP,DECROTENCA BTFSC STATUS,ZEROBIT BSF DECINP,DECCHGRENA BCF STATUS,PAGE0 GOTO DROTENCAOFF ;*******END OF SUBROUTINE ROTENCAOFF **************************************** ;**************************************************************************** LROTENCAON ;HIGH SO DEC COUNTER BCF DECINP,DECCHGRENA CLRF TEMPVAR MOVF ROTENCA,1 ;TEST TO SEE IF CURRENTLY ZERO BTFSS STATUS,ZEROBIT BSF TEMPVAR,0 ; SET IF NOT ZERO AT START OF SUBROUTINE BTFSS STATUS,ZEROBIT DECF ROTENCA,1 MOVF ROTENCA,1 ;TEST TO SEE IF CURRENTLY ZERO BTFSC STATUS,ZEROBIT BSF TEMPVAR,1 ;SET IF ZERO NOW MOVLW 0x03 XORWF TEMPVAR,0 BTFSC STATUS,ZEROBIT BCF DECINP,DECROTENCA BTFSC STATUS,ZEROBIT BSF DECINP,DECCHGRENA BCF STATUS,PAGE0 GOTO DROTENCAON ;*******END OF SUBROUTINE ROTENCAON ***************************************** ;**************************************************************************** LROTENCBOFF ;LOW SO INC COUNTER BCF DECINP,DECCHGRENB CLRF TEMPVAR MOVLW 0x1A ;TEST TO SEE IF AT FULL RANGE (WAS 1A) XORWF ROTENCB,0 BTFSS STATUS,ZEROBIT BSF TEMPVAR,0 ;SET IF NOT AT FULL RANGE AT START BTFSS STATUS,ZEROBIT INCF ROTENCB,1 MOVLW 0x1A ;TEST TO SEE IF AT FULL RANGE (WAS 1A) XORWF ROTENCB,0 BTFSC STATUS,ZEROBIT BSF TEMPVAR,1 ;SET IF FULL RANGE NOW MOVLW 0x03 XORWF TEMPVAR,0 BTFSC STATUS,ZEROBIT BSF DECINP,DECROTENCB BTFSC STATUS,ZEROBIT BSF DECINP,DECCHGRENB BCF STATUS,PAGE0 GOTO DROTENCBOFF ;*******END OF SUBROUTINE ROTENCBOFF **************************************** ;**************************************************************************** LROTENCBON ;HIGH SO DEC COUNTER BCF DECINP,DECCHGRENB CLRF TEMPVAR MOVF ROTENCB,1 ;TEST TO SEE IF CURRENTLY ZERO BTFSS STATUS,ZEROBIT BSF TEMPVAR,0 ; SET IF NOT ZERO AT START OF SUBROUTINE BTFSS STATUS,ZEROBIT DECF ROTENCB,1 MOVF ROTENCB,1 ;TEST TO SEE IF CURRENTLY ZERO BTFSC STATUS,ZEROBIT BSF TEMPVAR,1 ;SET IF ZERO NOW MOVLW 0x03 XORWF TEMPVAR,0 BTFSC STATUS,ZEROBIT BCF DECINP,DECROTENCB BTFSC STATUS,ZEROBIT BSF DECINP,DECCHGRENB BCF STATUS,PAGE0 GOTO DROTENCBON ;*******END OF SUBROUTINE ROTENCBON ***************************************** ;**************************************************************************** LRUNLEDFLASH ; PROCEDURE TO FLASH THE LED. ; CHECKS STATUS FIRST. ; IN MUTE MODE? BTFSS MUTEBITS,MUTE GOTO TESTVOL ; IF HERE, THEN IN MUTE MODE CLRF LASTLEDMODE BSF LASTLEDMODE,LEDMUTE ; LED SHOULD BE PERMANENTLY ON IN MUTE MODE MOVLW 0xFF; LIGHT THE LED MOVWF LEDFLASHSEQUENCE CLRF LEDFLASHSTEP MOVLW 0x07 MOVWF LEDFLASHCOUNTER GOTO FLASHLED ; END OF MUTE TESTVOL ;IN VOLUME MODE? BTFSS MUTEBITS,VOL GOTO TESTBAL ; IF HERE, IN VOLUME MODE ; CHECK TO SEE IF VOLUME IS AT MAX MOVLW 0xFF ;MAX VOLUME SETTING XORWF CURVOL,0 BTFSC STATUS,ZEROBIT GOTO MAXVOL ; IF HERE, IN VOL MODE, NOT AT MAX SETTING, SO LED PERMANENTLY OFF CLRF LASTLEDMODE BSF LASTLEDMODE,LEDVOL CLRF LEDFLASHSEQUENCE MOVLW 0x07 MOVWF LEDFLASHSTEP MOVLW LEDFLASHDURATION MOVWF LEDFLASHCOUNTER GOTO FLASHLED ;END OF VOL MODE MAXVOL ; IF HERE, VOLUME IS AT MAX SETTING ;FIRST COMPARE TO SEE IF STATE HAS CHANGED SINCE LAST TIME BTFSC LASTLEDMODE,LEDVOLMAX GOTO FLASHLED ; ALREADY IN THIS MODE, SO DON'T CHANGE ; IF HERE, STATE HAS CHANGED, SO RESET THE VARIABLES CLRF LASTLEDMODE BSF LASTLEDMODE,LEDVOLMAX MOVLW 0x07 MOVWF LEDFLASHSTEP MOVLW 0xF8 MOVWF LEDFLASHSEQUENCE MOVLW LEDFLASHDURATION MOVWF LEDFLASHCOUNTER GOTO FLASHLED ; END OF MAX VOL TESTBAL ; IS IT IN BALANCE MODE? BTFSS MUTEBITS,BALANCE GOTO TESTPRESETVOL ; IF HERE, IN BALANCE MODE ; NOW CHECK TO SEE IF BALANCE IS EQUAL - (INVERTS THE LED ON/OFF SEQUENCE) ; IF EQUAL, THEN BOTH BALOFFSET VARS WILL BE BOTH ZERO AND THE SAME!!! MOVF BALOFFSETL,0 XORWF BALOFFSETR,0 BTFSC STATUS,ZEROBIT GOTO BALEQUAL ;IF HERE, THEN BALANCE IS NOT EQUAL ;FIRST COMPARE TO SEE IF STATE HAS CHANGED SINCE LAST TIME BTFSC LASTLEDMODE,LEDBAL GOTO FLASHLED ; ALREADY IN THIS MODE, SO DON'T CHANGE ; IF HERE, STATE HAS CHANGED, SO RESET THE VARIABLES CLRF LASTLEDMODE BSF LASTLEDMODE,LEDBAL BSF LASTLEDMODE,LEDREPEATSEQ ;SET FLAG TO REPEAT THE CYCLE MOVLW 0x07 MOVWF LEDFLASHSTEP MOVLW 0xA0 MOVWF LEDFLASHSEQUENCE MOVLW LEDFLASHDURATION MOVWF LEDFLASHCOUNTER GOTO FLASHLED ;END OF BALANCE BALEQUAL ;IF HERE, BALANCE IS EQUAL ;FIRST COMPARE TO SEE IF STATE HAS CHANGED SINCE LAST TIME BTFSC LASTLEDMODE,LEDBALEQUAL GOTO FLASHLED ; ALREADY IN THIS MODE, SO DON'T CHANGE ; IF HERE, STATE HAS CHANGED, SO RESET THE VARIABLES CLRF LASTLEDMODE BSF LASTLEDMODE,LEDBALEQUAL BSF LASTLEDMODE,LEDREPEATSEQ ;SET FLAG TO REPEAT THE CYCLE MOVLW 0x07 MOVWF LEDFLASHSTEP MOVLW 0x5F MOVWF LEDFLASHSEQUENCE MOVLW LEDFLASHDURATION MOVWF LEDFLASHCOUNTER GOTO FLASHLED ;END OF BALANCE TESTPRESETVOL ; IS IT IN PRESETVOL MODE? BTFSS MUTEBITS,PRESETVOL GOTO FLASHLED ;ERROR!!!!, MODE NOT SET CORRECTLY!!! SHOULD NOT BE HERE ;IF HERE, THEN IN PRESET VOL MODE ;FIRST COMPARE TO SEE IF STATE HAS CHANGED SINCE LAST TIME BTFSC LASTLEDMODE,LEDPRESETVOL GOTO FLASHLED ; ALREADY IN THIS MODE, SO DON'T CHANGE ; IF HERE, STATE HAS CHANGED, SO RESET THE VARIABLES CLRF LASTLEDMODE BSF LASTLEDMODE,LEDPRESETVOL BSF LASTLEDMODE,LEDREPEATSEQ ;SET FLAG TO REPEAT THE CYCLE MOVLW 0x07 MOVWF LEDFLASHSTEP MOVLW 0xAA MOVWF LEDFLASHSEQUENCE MOVLW LEDFLASHDURATION MOVWF LEDFLASHCOUNTER GOTO FLASHLED ;END OF PRESETVOL ;END OF CHECKING ROUTINES FLASHLED ;NOW ACTUALLY RUN THE COUNTERS AND FLASHING SEQUENCE ;RUN THE TIME DELAY BTFSS MODEBITS,TIMERCHANGE GOTO DRIVETHELED ;IF NO TIMER CHANGE, THEN JUST SET THE LED ANYWAY ; IF HERE, THEN THE TIMER HAS CHANGED SINCE LAST TIME MOVF LEDFLASHCOUNTER,1 BTFSC STATUS,ZEROBIT ;IS THE LEDFLASHCOUNTER = 0? INCF LEDFLASHCOUNTER,1 ;IT WAS ALREADY ZERO, SO ADD 1 TO PREVENT UNDERFLOW DECFSZ LEDFLASHCOUNTER,1 GOTO DRIVETHELED ;COUNTER IS NOT YET ZERO, SO NO MORE TO DO ;IF HERE, COUNTER IS NOW ZERO MOVF LEDFLASHSTEP,1 BTFSS STATUS,ZEROBIT ;IS THE FLASH STEP INDEX ALREADY AT BIT=0? GOTO CHANGELEDSTEP ; NO. SO, CHANGE THE STEP INDEX. (7..0) ; IF HERE, LED FLASH STEP WAS ALREADY ZERO ;CAN THE COUNTER BE RESET? BTFSS LASTLEDMODE,LEDREPEATSEQ GOTO DRIVETHELED ; NO. DON'T RESET THE COUNTER - IE. SEQUENCE STOPS ; IF HERE, RESET THE COUNTER AND STEP MOVLW LEDFLASHDURATION MOVWF LEDFLASHCOUNTER ; LOAD THE COUNTER WITH THE CONSTANT DURATION MOVLW 0x08 MOVWF LEDFLASHSTEP ; RESET THE STEP TO BIT=7 GOTO DRIVETHELED CHANGELEDSTEP ; MOVE THE STEP INDEX ALONG ONE BIT (7..0) DECF LEDFLASHSTEP,1 MOVLW LEDFLASHDURATION MOVWF LEDFLASHCOUNTER ; RELOAD THE COUNTER WITH THE CONSTANT DURATION RLF LEDFLASHSEQUENCE,1 BTFSS STATUS,CARRYBIT BCF LEDFLASHSEQUENCE,0 BTFSC STATUS,CARRYBIT BSF LEDFLASHSEQUENCE,0 GOTO DRIVETHELED DRIVETHELED ; THE CODE TO ACTUALLY SWITCH THE LED ON/OFF !!! ;NOTE THE STATE IS INVERTED TO ILLUMINATION OUTPUT BTFSC LEDFLASHSEQUENCE,7 BSF GPIO,LEDBIT BTFSS LEDFLASHSEQUENCE,7 BCF GPIO,LEDBIT BCF STATUS,PAGE0 GOTO DRUNLEDFLASH ;*******END OF SUBROUTINE RUNLEDFLASH *************************************** ;**************************************************************************** END ;**************************************************************************** ;**************************************************************************** ; END OF ALL CODE (MAIN PROGRAM AND SUBROUTINES) ;**************************************************************************** ;****************************************************************************