;************************************************************************** ; RADIOTMR.ASM ; ; PROGRAM: Weather forecast timer ; ; DESCRIPTION: turns on for the Radio 4 Shipping forecasts ; AUTHOR: Douglas Rice ; Copyright 1998 ; ; The Unit turns on the Radio Cassette for the Radio 4 Shipping Forecast ; The PIC16C84 chip stores the ON OFF times in BCD in the PIC EEPROM. ; ; Usage: Two Buttons - and short to GND on PRESS ; Normally only needs to be pressed. ; is only required to check or set the time ; ; There are two modes:- Normal use and Check/Set Mode. ; The button Cycles around the ON and OFF states. ; The (SET) LED stayes off throughout these states. ; ; The Check/Set mode is entered by pressing the button ; The SET LED goes from OFF to RED, ; the Radio Cassette is turned on, and beeps should be heard. ; wait for the 15 beeps to finish. ; ; sets the digit up and then is used to set the time. ; is used to move onto the next digit or state. ; ; To check the time: ; press and the tens of Hours digit of hh:mm is beeped out and the (SET) LED goes from RED to YELLOW. ; Press to move onto the units of Hours digit, and the (SET) LED goes GREEN ; Press to move onto the tens of Minutes digit, and the (SET) LED goes YELLOW ; Press to move onto the units of Minutes digit, and the (SET) LED goes GREEN ; Press to move onto the SET state and the (SET) LED goes RED ; Press to move back to the ON and OFF modes and the (SET) LED goes OFF ; ; ; The time digits are beeped out using the pattern ; ; 0 no beep ; ; 1 . ; ; 2 . . ; ; 3 . . . ; ; 4 . . . . ; ; 5 . . . . - ; ; 6 . . . . - . ; ; 7 . . . . - . . ; ; 8 . . . . - . . . ; ; 9 . . . . - . . . . ; ; So if is pressed by mistake, keep pressing ; ; To set the time enter the value of each digit by repeatedly pressing ; the button to increment the digit from zero. ; ; Once the time is entered, the (SET) should be on RED again. ; ; To update the time press when the SET LED is RED. A beep is heard to confirm this. ; ; When is pressed, the entered times sets the time with the seconds set to 46 seconds ; ; Checking the ON OFF times. ; The list of ON OF times is stored in the EEPROM ; The values are stored in BCD notation. There is a list of 8 ON and OFF times ; press to select value to beep out. if not pressed current time will be beeped out ; if pressed the first entry in the ON ; ; The unit Beeps out the Time signal every Minute, for recording onto tape. ; ; The RS232 output outputs at 1200 baud. Connect to RS232 without inversion. ; ; when setting the time, the display looks like: ; #0 now:11:59 - current time ; #1 On@:11:59 - Turn On power @11:59 ; #2Off@:12:05 - Turn Off power @12:05 ; ; To change the time: ; press and the H0 digit appears, and press to inc H0 ; #1 On@:11:59 1 - display entered value of H0 ; ; press and the 0H digit appears, and press to inc 0H ; #1 On@:11:59 13 - display entered value of 0H ; ; press and the M0 digit appears, and press to inc M0 ; #1 On@:11:59 13:1 - display entered value of M0 ; ; press and the 0M digit appears, and press to inc 0M ; #1 On@:11:59 13:14 - display entered value of 0M ; ; press and set appears, ; #1 On@:11:59 13:14set - press to accept, to cancel. ; ; The setting mode is left. ; ; When SET Bi colour LED is OFF, toggles radio On with beeps on minute, On without beeps and off ; On each second, the Serial Port outputs a display is tHH:MM:SS:status ; e.g. t21:34:45:Off ; or t21:34:45:On beep ; or t00:15:01:On ; ; To record the forecast, set the time to real time. ; Set the Cassette Recorder to record Radio 4. ; Toggle Radio Cassette to OFF and wait. ; ; After forecast has been recorded, Toggle on tape and rewind and listen, then ; set up to record the radio again. ; ; ; Crystal: 32kHz ; ; I/O used:- ; PORTA:0 NC used in state var ; PORTA:1 BiColour LED GREEN ; PORTA:2 BiColour LED RED ; PORTA:3 ; PORTA:4 . ; ; ; PORTB:7 IP: OPENED button SWITCH to GND ; PORTB:6 IP: ON/OFF button SWITCH to GND ; PORTB:5 IP: SET button SWITCH to GND ; PORTB:4 IP: NEXT button SWITCH to GND ; PORTB:3 Tactle Feedback LED Red half of Bi Colour LED ; PORTB:2 Beep Out, to Radio input via 33k resitor to Point that is recorded ; PORTB:1 1200 Baud RS232 of time on second hh:mm:ssCRLF ; PORTB:0 Radio On:/Off via 1K to Common emitter BFY51, also Green half of Bi colour LED ; ; (Bi Colour LED) {set Button} ; {NEXT Button } ; ; INCLUDE "p16F84.inc" ; ;************************************************************************** LIST P=16F84, R=DEC __idlocs 0x1234 __config _LP_OSC&_PWRTE_ON & _WDT_OFF ;-------------------------------------------------------------------------- ; Sec 1. Equates and Constants ;-------------------------------------------------------------------------- ; The General Purpose Registers start at the end of the ; Special Purpose Registers. ; IPMentState values ; in normal running or in time setting modes ; SET_NORM EQU 0 SET_SET EQU 2 ; STstate flag to indicate if beep is enabled. ; STstate is a variable of flag bits STrelay EQU 0 STbeep EQU 1 ; DoTimeSlice bits ; these bits are set to schedule a timer chain event DTsS4event EQU 0 ; DTsSevent EQU 1 DTsMevent EQU 2 DTsHevent EQU 3 DTopenedevent EQU 4 DTSRwrtEvent EQU 5 DTSbeepPause EQU 6 DTSbeepMachine EQU 7 ;-------------------------------------------------------------------------- ; Sec 1.1 Button and LED ;-------------------------------------------------------------------------- BUTTON_SET EQU 4 BUTTON_NEXT EQU 5 BUTTON_ONOFF EQU 6 BUTTON_OPENED EQU 7 ; If change then record time ; PORTA binary values LED_OFF EQU 0x00 LED_GREEN EQU 0x20 LED_RED EQU 0x40 LED_YELLOW EQU 0x60 ;-------------------------------------------------------------------------- ; Sec 1.2 Button and LED ;-------------------------------------------------------------------------- ; PORTB bits RELAY EQU 0 RS232OUT EQU 1 SPEAKER EQU 2 KEYFLASH EQU 3 ;-------------------------------------------------------------------------- ; Sec 2.0 Variables ;-------------------------------------------------------------------------- ; Variables start 0x0C ; ; Variables for FlashLED ( FL ) process ; ; DoTimeSlice Bits, to schedule, set bit ; 0 run onQtrSecondTick ; 1 run onSecondTick ; 2 run onMinuteTick ; 3 run onHourTick ; 4 not used ; 5 run Serial Port readout ; 6 BeepPause ; 7 run BeepMachine DoTimeSlice EQU 0x0C STstate EQU 0x0E CLtmr4sec EQU 0x0F ; counts quarter seconds CLnbcdS EQU 0x10 ; stores current time CLnbcdM EQU 0x11 CLnbcdH EQU 0x12 CLdbcdM EQU 0x15 ; stores the time being input CLdbcdH EQU 0x16 CLbbcdM EQU 0x18 ; stores the time being beeped out CLbbcdH EQU 0x19 CLTNum EQU 0x1A ; Index into EEPROM when updating an ON/OFF time CLTNumChk EQU 0x1C ; EEPROM index when testing for ON/OFF time LScnt EQU 0x1F ; For Loudspeaker beep generation LScnt2 EQU 0x20 IPlast EQU 0x21 ; Input variables IPnew EQU 0x22 IPbuttonEvent EQU 0x23 IPsetState EQU 0x24 SRout EQU 0x25 ; for RS232 routines SRcnt EQU 0x27 SoundCnt EQU 0x28 ; Counts beeps Sound5Cnt EQU 0x2A ; count for 5th beep DispState EQU 0x2B ; Display State OPcnt EQU 0x2C ; Count OPopcnt EQU 0x2D ; Count OPbufferStart EQU 0x30 ; 32 bytes of files that can store Dates ;-------------------------------------------------------------------------- ; Sec 3. Program Code ;-------------------------------------------------------------------------- ORG 0 GOTO Start ORG 4 GOTO Intrtn ;-------------------------------------------------------------------------- ; Sec 3.1 Main Program Init Code ;-------------------------------------------------------------------------- Start ; Enable Interupts MOVLW H'00' MOVWF INTCON ; Set up PortB:7 as output. BSF STATUS, RP0 MOVLW 0XF0 MOVWF TRISB MOVLW 0xE0 ; Make PORTA 3:0 outputs to drive LED display MOVWF TRISA BCF STATUS, RP0 CLRF DoTimeSlice CLRF IPsetState CLRF CLdbcdH CLRF CLdbcdM CLRF CLbbcdH CLRF CLbbcdM CLRF CLTNumChk CLRF SoundCnt CLRF DispState ; flush out RAM if POWER UP, but leave the same if MCLR BTFSS STATUS,NOT_PD GOTO Start2 ; set up the time logs, if the power has been reset. CLRWDT MOVLW 0x30 MOVWF FSR MOVLW 0x50-OPbufferStart MOVWF OPcnt MOVLW 0xFF Start1 MOVWF INDF INCFSZ FSR DECFSZ OPcnt GOTO Start1 MOVLW OPbufferStart MOVWF OPcnt MOVWF OPopcnt Start2 ; Change Prescaler CLRWDT ; Configure Tmr 0 BSF STATUS,RP0 ; Set up prescaller for 8192 / 16 = 512 ticks perseconds. MOVLW 0x0 + 2 ; For Tmr0 0=/2, 1=/4, 2=/8,3=/16 MOVWF OPTION_REG BCF STATUS,RP0 ; Set up prescaller for 8192 / 16 = 512 ticks perseconds. MOVLW 0x0 MOVWF CLnbcdS MOVLW 0x23 MOVWF CLnbcdH MOVLW 0x50 MOVWF CLnbcdM MOVLW 4 MOVWF CLtmr4sec CALL SoundInit ; Force on BEEP CALL STtoggleOn GOTO MainLoop ;-------------------------------------------------------------------------- ; Sec 3.2 Main Program ;-------------------------------------------------------------------------- MainLoop ; Enable Interupts ; Disable Interupts MLdisableInt ; CALL LSbeep CALL CLtimeslice ; Any events that exist BTFSC DoTimeSlice,DTsS4event ; On 1/4 Second Tick CALL SS4tick ; Any events that exist BTFSC DoTimeSlice,DTsSevent ; On Second Tick CALL SStick BTFSC DoTimeSlice,DTsMevent ; On Minute Tick CALL SMtick BTFSC DoTimeSlice,DTsHevent ; On Hour Tick CALL SHtick BTFSC DoTimeSlice,DTSRwrtEvent ; Serial Display CALL SRwrtTime BTFSS IPbuttonEvent,BUTTON_SET ; On BUTTON_SET Press CALL IPsetPressed BTFSS IPbuttonEvent,BUTTON_NEXT ; On BUTTON_NEXT Press CALL IPnextPressed BTFSS IPbuttonEvent,BUTTON_ONOFF ; On BUTTON_ONOFF Press CALL IPonoffPressed BTFSS IPbuttonEvent,BUTTON_OPENED ; On BUTTON_OPENED Press CALL IPopenedPressed GOTO MainLoop ;-------------------------------------------------------------------------- ; Sec 3.3 Jump Table for running or time setting mode ;-------------------------------------------------------------------------- IPsetJump ; Its not a CLICK or HOLD ADDWF IPsetState,W CLRF PCLATH ; Assume that the tabel is in the bottom 256 byte ; restrict to 32 states ANDLW 0x03 IF 0 != ( high ( IPjmpTable4End ) - high ( IPjmpTable4Start ) ) Error "Table straddles Page Boundary " ENDIF IPjmpTable4Start ADDWF PCL,f ; set choice State Table - limited to 8 states GOTO STtoggle ; SET:OFF,NEXT GOTO SoundInit ; SET:OFF,set GOTO SoundOneDigit ; SET:YELLOW,NEXT GOTO SoundNextDigit ; SET:YELLOW,set IPjmpTable4End ;-------------------------------------------------------------------------- ; Sec 3.4 Sound out the digits using beeps ;-------------------------------------------------------------------------- ; These routines are state machines that are used to beep out the time ; Initilize the two state machines. One is used to SoundInit ; Force Radio On ; CALL STturnOn MOVLW 0x0F MOVWF SoundCnt INCFSZ SoundCnt,F ; assume that it will never be zero MOVLW 5 MOVWF Sound5Cnt ; Start Beep machine with a slight pause BSF DoTimeSlice,DTSbeepPause BSF DoTimeSlice,DTSbeepMachine ; copy the current time into the Display registers MOVFW CLnbcdH MOVWF CLbbcdH MOVFW CLnbcdM MOVWF CLbbcdM ; Clear the digit input registers CLRF CLdbcdH CLRF CLdbcdM CLRF DispState CLRF CLTNum ; fall into next routine SoundOneDigit ; Start the Beep Machine for a digit ; prepare the beep machine by copying the digit of hh:mm to be beeped out IF 0 != ( high ( JMPT1 ) - high ( JMPT2 ) ) Error "Table straddles Page Boundary " ENDIF JMPT1 MOVLW high $ MOVWF PCLATH MOVFW DispState ADDWF PCL,F GOTO SoundOneDigit3 ; Preamble NOP SWAPF CLbbcdH,W ; Hh:mm preamble GOTO SoundOneDigit1 MOVFW CLbbcdH ; hH:mm preamble GOTO SoundOneDigit1 SWAPF CLbbcdM,W ; hh:Mm preamble GOTO SoundOneDigit1 MOVFW CLbbcdM ; hh:mM preamble GOTO SoundOneDigit1 GOTO SoundOneDigitLast ; Set preamble, no BeepMachine req NOP GOTO SoundOneDigitLast ; Turn off BeepMachine and leave NOP JMPT2 SoundOneDigit1 ; Limit the count to up to 15 beeps ANDLW 0x0F MOVWF SoundCnt INCFSZ SoundCnt,F ; assume that it will never be zero MOVLW 5 MOVWF Sound5Cnt ; Now start the Beep Machine but pause for key click to be heard BSF DoTimeSlice,DTSbeepPause BSF DoTimeSlice,DTSbeepMachine GOTO SoundOneDigit3 SoundOneDigitLast CLRF SoundCnt INCFSZ SoundCnt,F ; assume that it will never be zero MOVLW 5 MOVWF Sound5Cnt ; Stop the beep machine BCF DoTimeSlice,DTSbeepMachine ; finish BEEP Machine ; Start the Serial Out BSF DoTimeSlice,DTSRwrtEvent ; Start Serial Display SoundOneDigit3 IF 0 != ( high ( JMPT5 ) - high ( JMPT6 ) ) Error "Table straddles Page Boundary " ENDIF JMPT5 ; divide the count by two MOVLW high $ MOVWF PCLATH RRF DispState,W ; Move onto next state INCFSZ DispState,F INCFSZ DispState,F ADDWF PCL,F RETLW SET_SET+LED_RED ; Set up For First Time RETLW SET_SET+LED_YELLOW ; Set up For setting H0 RETLW SET_SET+LED_GREEN ; Set up For setting 0H RETLW SET_SET+LED_YELLOW ; Set up For setting M0 RETLW SET_SET+LED_GREEN ; Set up For setting 0M RETLW SET_SET+LED_RED ; Set up For to Set time RETLW SET_NORM+LED_OFF ; Leave Setting States. ; These should not be used RETLW SET_NORM+LED_OFF RETLW SET_SET+LED_YELLOW RETLW SET_SET+LED_YELLOW JMPT6 SoundNextDigit ; This increments the digit ; DispState is incremented by the time this can be pressed IF 0 != ( high ( JMPT3 ) - high ( JMPT4 ) ) Error "Table straddles Page Boundary " ENDIF JMPT3 MOVLW high $ MOVWF PCLATH ; divide the count by two RRF DispState,W ADDWF PCL,F NOP ; DispState has been incremented so start table at 1 GOTO SoundNextGetTimer ; 2 GOTO SoundNextSetH0 ; 4 GOTO SoundNextSet0H ; 6 GOTO SoundNextSetM0 ; 8 GOTO SoundNextSet0M ; 10 GOTO SoundNextSet ; 12 NOP NOP JMPT4 SoundNextGetTimer ; get the next ON /OFF time from the EEROM for BEEP out ; Overwrite the current time BSF CLTNum,7 ; Set the Most significant Bit to indicate setting EEPROM MOVFW CLTNum ANDLW 0x1F CALL EEread MOVWF CLbbcdH ; read 2nd digit INCF CLTNum,f MOVFW CLTNum ANDLW 0x1F CALL EEread MOVWF CLbbcdM INCF CLTNum,W ANDLW 0x3F ; Restrict to 16 Locations or bytes each MOVWF CLTNum BSF CLTNum,7 ; Set the Most significant Bit to indicate setting EEPROM RETLW SET_SET+LED_RED SoundNextSetH0 ; We have just MOVLW 0X10 ADDWF CLdbcdH,F MOVFW CLdbcdH ADDLW 0xD0 ; BC SoundNextSetH01 RETLW SET_SET+LED_YELLOW SoundNextSetH01 ; just clear both digits to save an instruction CLRF CLdbcdH RETLW SET_SET+LED_YELLOW SoundNextSet0H INCF CLdbcdH,f ; this will never carry to M0 MOVFW CLdbcdH ADDLW 0x06 BDC SoundNextSet0H2 ; check for 24 hours Allow 24:00 to be set so that the timer can be parked. MOVF CLdbcdH,w ADDLW 0x00 - 0x25 SKPNZ GOTO SoundNextSet0H2 ; its 24 so zero 0H digit RETLW SET_SET+LED_GREEN SoundNextSet0H2 ; unit counter carry to tens counter MOVLW 0xF0 ; digit has just incremented so windback ANDWF CLdbcdH,F ; clear ls digit back to zero RETLW SET_SET+LED_GREEN SoundNextSetM0 MOVLW 0X10 ADDWF CLdbcdM,F MOVFW CLdbcdM ADDLW 0xA0 BC SoundNextSetM01 ; check for 60 minutes RETLW SET_SET+LED_YELLOW SoundNextSetM01 MOVLW 0x0F ANDWF CLdbcdM,F RETLW SET_SET+LED_YELLOW SoundNextSet0M ; in (SET:SETH) inc pressed ; Stay in same state ; in (SET:SETH) inc pressed ; Stay in same state INCF CLdbcdM,f MOVF CLdbcdM,w ADDLW 0x06 BDC SoundNextSet0M2 RETLW SET_SET+LED_GREEN SoundNextSet0M2 ; unit counter carry to tens counter ; gone from 9 to A, so zero digit MOVLW 0xF0 ANDWF CLdbcdM,F RETLW SET_SET+LED_GREEN SoundNextSet ; Are we to update Current time or ON/OFF time in EEPROM BTFSS CLTNum,7 GOTO SoundNextSet0 ; Update an EEPROM register ; Write displayed HH:MM digits into current counter Display Time digits ; set up the EEadr ; CLTNum is +2 displayed DECF CLTNum,f MOVFW CLTNum ANDLW 0x1F MOVWF EEADR MOVFW CLdbcdM CALL EEwrt DECF CLTNum,f MOVFW CLTNum ANDLW 0x1F MOVWF EEADR MOVFW CLdbcdH CALL EEwrt INCF CLTNum,f INCF CLTNum,f CLRF STstate CALL STtoggle RETLW SET_NORM+LED_OFF SoundNextSet0 ; Copy Entered digits into Current time MOVFW CLdbcdH MOVWF CLnbcdH MOVWF CLbbcdH MOVFW CLdbcdM MOVWF CLnbcdM MOVWF CLbbcdM MOVLW 0x45 MOVWF CLnbcdS CALL LSbeeeep CLRF STstate CALL STtoggle RETLW SET_NORM+LED_OFF BeepOutTimeSlice ; ; This routine is the time slice routine called four time a second. ; there are Three nested machines, ; pauseMachine - pause after the long 5th beep ; beepMachine - one to beep out the digit ; dispMachine - one to work through the digits to be displayed. ; ; test for delay, are we pausing after the long 5th beep? ; BTFSS DoTimeSlice,DTSbeepPause GOTO BM0 ; on this 1/4 second, do not sound out so return now. BCF DoTimeSlice,DTSbeepPause RETURN BM0 BCF DoTimeSlice,DTSbeepPause ; Is BeepMachine running, if so SoundCnt <> 0 MOVF SoundCnt,F BNZ BeepMachine1 ; Now As state Machine has finished do a slice of Digit State machine ; Get the correct digit and prime the BeepMachine to beep out the digit ; then run a slice of beep machine. RETURN Pause ; INCFSZ DispState,F ; INCFSZ DispState,F BCF DoTimeSlice,DTSbeepMachine RETURN BeepMachine1 ; DECFSZ SoundCnt,F GOTO BM3 ; zero so do do not beep out and finishe beep machine BCF DoTimeSlice,DTSbeepMachine RETURN BM3 MOVLW 60 DECFSZ Sound5Cnt,F GOTO BM4 ; beep for a bit longer on every 5th Beep BSF DoTimeSlice,DTSbeepPause MOVLW 5 MOVWF Sound5Cnt MOVLW 120 BM4 CALL LSbeepn ; keep beep machine running until count is zero BSF DoTimeSlice,DTSbeepMachine RETURN ;-------------------------------------------------------------------------- ; Sec 4. Subroutines, procedures and functions ;-------------------------------------------------------------------------- ;-------------------------------------------------------------------------- ; Sec 4.1 Button Poll Routine ;-------------------------------------------------------------------------- IPtimeslice ; ----___ ; --_____ ; ; This reads all Port B inputs and looks for Press MOVFW IPnew MOVWF IPlast MOVFW PORTB MOVWF IPnew ; IP last contains new setting, IPlast contains previous COMF IPlast,W IORWF IPnew,W ; now force IPbuttonEvent bits to low for new pressed button ; the service routine should set the bit to clear the event. ANDWF IPbuttonEvent,F RETURN ;-------------------------------------------------------------------------- ; Sec 4.2 Loudspeaker tone generator, and Key Click ;-------------------------------------------------------------------------- LSblink MOVLW 0x60 MOVWF LScnt BSF PORTB,KEYFLASH BSF PORTB,SPEAKER LSblink0 DECFSZ LScnt,F GOTO LSblink0 BCF PORTB,KEYFLASH BCF PORTB,SPEAKER RETURN LSbeeeep MOVLW 0x60 GOTO LSbeepn LSbeep MOVLW 0x20 LSbeepn ; come here with duration in W ; make pause between beeps = beep length MOVWF LScnt MOVWF LScnt2 MOVLW 0 MOVWF PORTA ; disable beep if STstate,STbeep is set BTFSC STstate,STbeep GOTO LSbeep5 ; LSbeep0 BTFSC LScnt,0 GOTO LSbeep1 BSF PORTB,SPEAKER GOTO LSbeep2 LSbeep1 BCF PORTB,SPEAKER LSbeep2 DECFSZ LScnt,f GOTO LSbeep0 ; now delay for silence LSbeep3 GOTO LSbeep4 LSbeep4 NOP DECFSZ LScnt2,f GOTO LSbeep3 LSbeep5 SWAPF IPsetState,W MOVWF PORTA RETURN ;-------------------------------------------------------------------------- ; Sec 4.3 Clock Chain Routine ;-------------------------------------------------------------------------- CLtimeslice ; Assuming: ; Crystal = 32.768 kHz ; Prescaller ticks at Crystal / 4 or 8192 ticks per second. ; Prescaller set to divide by 8, so ; Tmr0 ticks at 128 ticks per second ; Tmr0 times out once per 2 seconds. ; BTFSS INTCON,T0IF RETURN ; TMR0 timeout BCF INTCON,T0IF BSF DoTimeSlice,DTsS4event ; This ticks 1 per second, ; DECFSZ CLtmr4sec,f RETURN ; divide by 4 MOVLW 4 MOVWF CLtmr4sec GOTO CLbcdS ;-------------------------------------------------------------------------- ; Sec 4.4 BDC Clock Chain Routine ;-------------------------------------------------------------------------- ; BCD Counter - Seconds CLbcdS BSF DoTimeSlice,DTsSevent INCF CLnbcdS,f MOVF CLnbcdS,w ; binary add bcd digits to make 60 overflow digits. ADDLW 0xA6 ; 10 + 6 = 16, overflows digit 6 for 10, 7 for 9, 8 for 8, 9 for 7, A for 6 BC CLbcdS1 BDC CLbcdS2 RETURN CLbcdS2 ; unit counter carry to tens counter MOVFW CLnbcdS ; Add 1 to tens, subtract units to zero ADDLW 0x10 - 0x0A MOVWF CLnbcdS RETURN CLbcdS1 CLRF CLnbcdS ; and on to the next counter ; BCD Counter - Minutes CLbcdM BSF DoTimeSlice,DTsMevent INCF CLnbcdM,f MOVF CLnbcdM,w ADDLW 0xA6 ; 10 + 6 = 16, overflows digit 6 for 10, 7 for 9, 8 for 8, 9 for 7, A for 6 BC CLbcdM1 BDC CLbcdM2 RETURN CLbcdM2 ; unit counter carry to tens counter MOVFW CLnbcdM ; Add 1 to tens, subtract units to zero ADDLW 0x10 - 0x0A MOVWF CLnbcdM RETURN CLbcdM1 CLRF CLnbcdM ; and on to the next counter ; BCD Counter Hours CLbcdH BSF DoTimeSlice,DTsHevent INCF CLnbcdH,f MOVF CLnbcdH,w ADDLW 0xA6 BC CLbcdH1 BDC CLbcdH2 ; check for 24 hours MOVF CLnbcdH,w ADDLW 0x00 - 0x24 SKPNZ CLRF CLnbcdH RETURN CLbcdH2 ; unit counter carry to tens counter MOVFW CLnbcdH ADDLW 0x10 - 0x0A MOVWF CLnbcdH RETURN CLbcdH1 CLRF CLnbcdH ; and on to the next counter RETURN ;-------------------------------------------------------------------------- ; Sec 4.5 Event Handler Routines - Timer ;-------------------------------------------------------------------------- SS4tick ; do this 4 times a second BCF DoTimeSlice,DTsS4event CALL IPtimeslice BTFSC DoTimeSlice,DTSbeepMachine CALL BeepOutTimeSlice RETURN SStick BCF DoTimeSlice,DTsSevent ; Only do serial display when Beep machine is not running as ; beeps and serial clash BTFSS DoTimeSlice,DTSbeepMachine BSF DoTimeSlice,DTSRwrtEvent NOP ; look for last five seconds of minute and beep out MOVLW -0x55 ADDWF CLnbcdS,W SKPC RETURN CALL LSbeep RETURN SMtick BCF DoTimeSlice,DTsMevent ; if an opened event has happened in the minute ; store it. BTFSS DoTimeSlice,DTopenedevent ; RETURN GOTO SMtick0 BCF DoTimeSlice,DTopenedevent ; Store the current time into the next register. MOVFW OPcnt MOVWF FSR MOVFW CLnbcdH MOVWF INDF INCFSZ OPcnt,f MOVFW OPcnt MOVWF FSR MOVFW CLnbcdM MOVWF INDF INCFSZ OPcnt,f MOVFW OPcnt ADDLW -0x50 ; Check if the end of memory SKPZ GOTO SMtick0 MOVLW OPbufferStart MOVWF OPcnt GOTO SMtick0 ; Check for event SMtick0 MOVFW CLTNumChk ANDLW 0x3F ; Restrict to 64 bytes of EEPROM CALL EEread INCF CLTNumChk,f SUBWF CLnbcdH,w BNZ SMtick1 ; Hour found MOVFW CLTNumChk ANDLW 0x3F ; Restrict to 64 bytes of EEPROM CALL EEread SUBWF CLnbcdM,w BNZ SMtick1 ; Minute Found CALL STturnOn SMtick1 INCF CLTNumChk,f MOVFW CLTNumChk ANDLW 0x3F ; Restrict to 64 bytes of EEPROM CALL EEread INCF CLTNumChk,f SUBWF CLnbcdH,w BNZ SMtick2 ; Hour found MOVFW CLTNumChk ANDLW 0x3F ; Restrict to 64 bytes of EEPROM CALL EEread SUBWF CLnbcdM,w BNZ SMtick2 ; Minute Found CALL STturnOff SMtick2 INCF CLTNumChk,f MOVFW CLTNumChk ADDLW -0x20 BNZ SMtick0 CLRF CLTNumChk MOVLW 0x80 CALL LSbeepn RETURN SHtick ; Turn Off On the Hour BCF DoTimeSlice,DTsHevent RETURN ;-------------------------------------------------------------------------- ; Sec 4.6 Event Handler Routine - Buttons ;-------------------------------------------------------------------------- ; come here and combine the current state and the current event to index into ; the state jump table. ; IPsetPressed BSF IPbuttonEvent,BUTTON_SET CALL LSblink MOVLW 1 CALL IPsetJump MOVWF IPsetState SWAPF IPsetState,W MOVWF PORTA RETURN IPnextPressed BSF IPbuttonEvent,BUTTON_NEXT CALL LSblink MOVLW 0 CALL IPsetJump MOVWF IPsetState SWAPF IPsetState,W MOVWF PORTA RETURN IPonoffPressed BSF IPbuttonEvent,BUTTON_ONOFF GOTO STtoggle RETURN IPopenedPressed ; Debounce to the minute so that only one opened time is stored BSF DoTimeSlice,DTopenedevent BSF IPbuttonEvent,BUTTON_OPENED RETURN ;-------------------------------------------------------------------------- ; Sec 4.7 Relay Control Routine ;-------------------------------------------------------------------------- STtoggle ; Rotate STstate around three values ; 0 = Relay Off ; 3 = Relay On, Beep On ; 2 = Relay On, Beep Off BTFSS STstate,STrelay GOTO STtoggleOn BTFSC STstate,STbeep GOTO STtoggleOff BSF STstate,STbeep RETLW SET_NORM STtoggleOn CALL STturnOn RETLW SET_NORM STtoggleOff CALL STturnOff RETLW SET_NORM STturnOn ; Turn on Radio and Tape to record forecast BSF STstate,STrelay BCF STstate,STbeep BSF PORTB,RELAY RETURN STturnOff ; Turn off Radio and Tape to record forecast BCF STstate,STrelay BCF STstate,STbeep BCF PORTB,RELAY RETURN ;-------------------------------------------------------------------------- ; Sec 4.8 EEprom Routines ;-------------------------------------------------------------------------- EEread ; w contains address BCF STATUS,RP0 MOVWF EEADR BSF STATUS,RP0 BSF EECON1,RD BCF STATUS,RP0 MOVFW EEDATA RETURN EEwrt ; blocking, EEADR and EEDATA set up. BCF STATUS,RP0 MOVWF EEDATA BSF STATUS,RP0 BCF INTCON,GIE BCF EECON1,EEIF BSF EECON1,WREN MOVLW 0x55 MOVWF EECON2 MOVLW 0xAA MOVWF EECON2 BSF EECON1,WR ; Now wait for EEwrt to finish write EEwaitForWrt ; block until EEPROM write has finished. BCF EECON1,WREN ; disable EROM BTFSS EECON1,EEIF GOTO EEwaitForWrt BCF EECON1,EEIF ; EEPROM finished BCF STATUS,RP0 RETURN ;-------------------------------------------------------------------------- ; Sec 4.9 Serial Out ;-------------------------------------------------------------------------- ; ; @ 8192 instructions a second, ; for 1200 baud, each bit = 6.82666 instructions ; ; ---_01234567P---- ; -> Start Stop ; The output signal is inverted by the driver transistor ; ; 8192/ instrns cumulative % er ; 1200 ; ; 0.000 0 ; start 6.827 7 7 102.54% ; 0 13.653 7 14 102.54% ; 1 20.480 7 21 102.54% ; 2 27.307 6 27 98.88% ; 3 34.133 7 34 99.61% ; 4 40.960 7 41 100.10% ; 5 47.787 7 48 100.45% ; 6 54.613 7 55 100.71% ; 7 61.440 6 61 99.28% ; 8 68.267 7 68 99.61% ; end 75.093 7 75 99.88% ; ; TX is via PORTA<1> SRtxChar ; Output a stop bit BCF PORTB,RS232OUT ; MOVLW 'U' MOVWF SRout NOP ; Output a start bit ; BSF PORTB,RS232OUT ; t=0 NOP ; t+1 NOP ; t+2 ; NOP ; t+3 ; These take 4 instruction cyles ; t=0 BTFSC SRout,0 ;=0 =1 t+4 GOTO SRtxChar0 ; t+1 instructions NOP ;t+2 t+6 BSF PORTB,RS232OUT ;t+3 t+7 GOTO SRtxChar0a ;t+4 SRtxChar0 BCF PORTB,RS232OUT ; t+3 NOP ; t+4 NOP ; t+5 SRtxChar0a NOP ;t+6 t+6 ; NOP ;t+7 t+7 ; t=0 BTFSC SRout,1 ; 1 if false, 2 if skip GOTO SRtxChar1 ; t+1 instructions NOP ;t+2 BSF PORTB,RS232OUT ;t+3 GOTO SRtxChar1a ;t+4 SRtxChar1 BCF PORTB,RS232OUT ; t+3 NOP ; t+4 NOP ; t+5 SRtxChar1a NOP ;t+6 t+6 ; NOP ;t+7 t+7 ; t=0 BTFSC SRout,2 ; 1 if false, 2 if skip GOTO SRtxChar2 ; t+1 instructions NOP ;t+2 BSF PORTB,RS232OUT ;t+3 GOTO SRtxChar2a ;t+4 SRtxChar2 BCF PORTB,RS232OUT ; t+3 NOP ; t+4 NOP ; t+5 SRtxChar2a NOP ;t+6 t+6 ; NOP ;t+7 t+7 ; t=0 BTFSC SRout,3 ; 1 if false, 2 if skip GOTO SRtxChar3 ; t+1 instructions NOP ;t+2 BSF PORTB,RS232OUT ;t+3 GOTO SRtxChar3a ;t+4 SRtxChar3 BCF PORTB,RS232OUT ; t+3 NOP ; t+4 NOP ; t+5 SRtxChar3a NOP ;t+6 t+6 ; NOP ;t+7 t+7 ; t=0 BTFSC SRout,4 ; 1 if false, 2 if skip GOTO SRtxChar4 ; t+1 instructions NOP ;t+2 BSF PORTB,RS232OUT ;t+3 GOTO SRtxChar4a ;t+4 SRtxChar4 BCF PORTB,RS232OUT ; t+3 NOP ; t+4 NOP ; t+5 SRtxChar4a NOP ;t+6 t+6 ; NOP ;t+7 t+7 ; t=0 BTFSC SRout,5 ; 1 if false, 2 if skip GOTO SRtxChar5 ; t+1 instructions NOP ;t+2 BSF PORTB,RS232OUT ;t+3 GOTO SRtxChar5a ;t+4 SRtxChar5 BCF PORTB,RS232OUT ; t+3 NOP ; t+4 NOP ; t+5 SRtxChar5a NOP ;t+6 t+6 ; NOP ;t+7 t+7 ; t=0 BTFSC SRout,6 ; 1 if false, 2 if skip GOTO SRtxChar6 ; t+1 instructions NOP ;t+2 BSF PORTB,RS232OUT ;t+3 GOTO SRtxChar6a ;t+4 SRtxChar6 BCF PORTB,RS232OUT ; t+3 NOP ; t+4 NOP ; t+5 SRtxChar6a NOP ;t+6 t+6 ; NOP ;t+7 t+7 ; t=0 BTFSC SRout,7 ; 1 if false, 2 if skip GOTO SRtxChar7 ; t+1 instructions NOP ;t+2 BSF PORTB,RS232OUT ;t+3 GOTO SRtxChar7a ;t+4 SRtxChar7 BCF PORTB,RS232OUT ; t+3 NOP ; t+4 NOP ; t+5 SRtxChar7a NOP ;t+6 t+6 ; NOP ;t+7 t+7 ; no 7th delay ; Stop Bit BCF PORTB,RS232OUT NOP NOP NOP NOP NOP NOP RETURN SRwrtHexNibble ; currently only displays 0..9, A..F ANDLW 0x0F ADDLW 0x06 ; is it A..F, if so trigger a digit overflow SKPNDC ADDLW 7; subtract 10, then add 'A'-'0' ADDLW 0x30-6 ; Subtract extra 6 added to cause DC MOVWF SRout GOTO SRtxChar ;-------------------------------------------------------------------------- ; Sec 4.9 Serial Out Display Procedure ;-------------------------------------------------------------------------- SRwrtTime ; Using the Input state machines construct a suitable display string ; out put to the serial port. MOVF IPsetState,f BNZ SRwrtBBcdTime ; This displays the time and status of the Radio MOVLW 't' CALL SRtxChar SWAPF CLnbcdH,W CALL SRwrtHexNibble MOVFW CLnbcdH CALL SRwrtHexNibble MOVLW ':' CALL SRtxChar SWAPF CLnbcdM,W CALL SRwrtHexNibble MOVFW CLnbcdM CALL SRwrtHexNibble MOVLW ':' CALL SRtxChar SWAPF CLnbcdS,W CALL SRwrtHexNibble MOVFW CLnbcdS CALL SRwrtHexNibble MOVLW ':' CALL SRtxChar MOVLW ' ' CALL SRtxChar SWAPF OPcnt,W CALL SRwrtHexNibble MOVFW OPcnt CALL SRwrtHexNibble MOVLW '-' CALL SRtxChar SWAPF OPopcnt,W CALL SRwrtHexNibble MOVFW OPopcnt CALL SRwrtHexNibble MOVLW ' ' CALL SRtxChar MOVFW OPopcnt MOVWF FSR SWAPF INDF,W CALL SRwrtHexNibble MOVFW INDF CALL SRwrtHexNibble INCFSZ OPopcnt,f MOVFW OPopcnt MOVWF FSR MOVLW ':' CALL SRtxChar SWAPF INDF,W CALL SRwrtHexNibble MOVFW INDF CALL SRwrtHexNibble INCFSZ OPopcnt,f MOVLW -0x50 ADDWF OPopcnt,w SKPZ GOTO SRwrtTime1 MOVLW 0x30 MOVWF OPopcnt SRwrtTime1 MOVLW ' ' CALL SRtxChar MOVLW 'o' CALL SRtxChar IF 0 != ( high ( JMPT7 ) - high ( JMPT8 ) ) Error "Table straddles Page Boundary " ENDIF JMPT7 MOVLW high $ MOVWF PCLATH MOVFW STstate ANDLW 0x03 ADDWF PCL,F GOTO SRwrtTimeDispT0 ; off GOTO SRwrtTimeDispT3 ; on beep GOTO SRwrtTimeDispT1 GOTO SRwrtTimeDispT2 ; on, no beep JMPT8 SRwrtTimeDispT0 MOVLW 'f' CALL SRtxChar MOVLW 'f' CALL SRtxChar GOTO SRwrtBBcdTime2 SRwrtTimeDispT1 MOVLW '1' CALL SRtxChar GOTO SRwrtBBcdTime2 SRwrtTimeDispT2 MOVLW 'n' CALL SRtxChar GOTO SRwrtBBcdTime2 SRwrtTimeDispT3 MOVLW 'n' CALL SRtxChar MOVLW ' ' CALL SRtxChar MOVLW 'b' CALL SRtxChar MOVLW 'e' CALL SRtxChar MOVLW 'e' CALL SRtxChar MOVLW 'p' CALL SRtxChar GOTO SRwrtBBcdTime2 SRwrtBBcdTime ; During time setting, now write out the register value, or now time MOVLW '#' CALL SRtxChar RRF CLTNum,W CALL SRwrtHexNibble MOVF CLTNum,F BNZ SRwrtBBcdTime1 ; current MOVLW ' ' CALL SRtxChar MOVLW 'n' CALL SRtxChar MOVLW 'o' CALL SRtxChar MOVLW 'w' CALL SRtxChar GOTO SRwrtBBcdTime3 SRwrtBBcdTime1 BTFSC CLTNum,1 ; test second bit GOTO SRwrtBBcdTime1a MOVLW 'O' CALL SRtxChar MOVLW 'f' CALL SRtxChar MOVLW 'f' CALL SRtxChar MOVLW '@' CALL SRtxChar GOTO SRwrtBBcdTime3 SRwrtBBcdTime1a MOVLW ' ' CALL SRtxChar MOVLW 'O' CALL SRtxChar MOVLW 'n' CALL SRtxChar MOVLW '@' CALL SRtxChar GOTO SRwrtBBcdTime3 SRwrtBBcdTime3 MOVLW ':' CALL SRtxChar SWAPF CLbbcdH,W CALL SRwrtHexNibble MOVFW CLbbcdH CALL SRwrtHexNibble MOVLW ':' CALL SRtxChar SWAPF CLbbcdM,W CALL SRwrtHexNibble MOVFW CLbbcdM CALL SRwrtHexNibble ; As each dicgit in HH:MM is selected display a bit more of it. MOVFW DispState ADDLW -4 BNC SRwrtBBcdTime2 MOVLW ' ' CALL SRtxChar SWAPF CLdbcdH,W CALL SRwrtHexNibble MOVFW DispState ADDLW -6 BNC SRwrtBBcdTime2 MOVFW CLdbcdH CALL SRwrtHexNibble MOVFW DispState ADDLW -8 BNC SRwrtBBcdTime2 MOVLW ':' CALL SRtxChar SWAPF CLdbcdM,W CALL SRwrtHexNibble MOVFW DispState ADDLW -10 BNC SRwrtBBcdTime2 MOVFW CLdbcdM CALL SRwrtHexNibble MOVFW DispState ADDLW -12 BNC SRwrtBBcdTime2 MOVLW 's' CALL SRtxChar MOVLW 'e' CALL SRtxChar MOVLW 't' CALL SRtxChar SRwrtBBcdTime2 MOVLW 0x0A CALL SRtxChar MOVLW 0x0D CALL SRtxChar BCF DoTimeSlice,DTSRwrtEvent RETURN ;-------------------------------------------------------------------------- ; Sec 5.0 Interrupt Routines ;-------------------------------------------------------------------------- Intrtn ; Which Interupt ? ; No Context Save in these routines. BTFSC INTCON,2 GOTO IntTmr0 BTFSC INTCON,1 GOTO Intfint BTFSC INTCON,0 GOTO IntRbport IntTmr0 BCF INTCON,2 RETFIE Intfint BCF INTCON,1 RETFIE IntRbport BCF INTCON,0 RETFIE ;-------------------------------------------------------------------------- ; Program End ;-------------------------------------------------------------------------- ;-------------------------------------------------------------------------- ; EEPROM data ;-------------------------------------------------------------------------- ORG 0x2100 ; first 2 on and off are general ones DE 0x24,0x00 ; 4 DE 0x24,0x00 DE 0x24,0x00 ; 5 DE 0x24,0x00 ; Time for the four Shipping forecasts DE 0x00,0x45 ; 0 DE 0x00,0x58 DE 0x05,0x33 ; 1 DE 0x05,0x47 DE 0x11,0x59 ; 2 DE 0x12,0x05 DE 0x17,0x54 ; 3 DE 0x18,0x00 ; Last four are general purpose DE 0x24,0x00 ; 6 DE 0x24,0x00 DE 0x24,0x00 ; 7 DE 0x24,0x00 END