;********************************************************************** ; This file is a basic code template for assembly code generation * ; on the PIC16F628A. This file contains the basic code * ; building blocks to build upon. * ; Refer to the MPASM User's Guide for additional information on * ; features of the assembler (Document DS33014). * ; Refer to the respective PIC data sheet for additional * ; information on the instruction set. * ; * ;********************************************************************** ; * ; Filename: DivergenceMeter.asm * ; Date: 5-12-2012 * ; File Version: 1.05 (REMEMBER to update number in code!) * ; * ; Author: Tom Titor * ; Company: /a/ * ; * ;********************************************************************** ; Files Required: P16F628A.INC * ;********************************************************************** ; * ; Notes: Had to take out "& _DATA_CP_OFF " from template __CONFIG * ; line because it resulted in error. Why? The line was: * ; __CONFIG _CP_OFF & _DATA_CP_OFF & _LVP_OFF & _BOREN_OFF & _MCLRE_ON & _WDT_OFF & _PWRTE_ON & _INTOSC_OSC_NOCLKOUT * ; * ; Using internal oscillator 4 MHz (default) * ; * ; * ; 0.00 Had to set MCLRE_OFF in config since that pin floats * ; unconnected on my board. * ; 0.01 Had to turn comparators off to get PORTA to work as * ; inputs, and then stupid typo in doing so wasted hours. * ; 0.1 (1/31) Able to display a digit on the tubes. * ; 0.2 (2/1) Able to display worldline number to all 8 tubes. * ; 0.3 (2/1) Testing animation of number. * ; 0.37(2/2) More animation messin' * ; 0.4 (2/6) Worldline number random rolls work! * ; 0.43(2/7) Adjustable brightness with fading pulse at end * ; 0.44(2/13) Worked on long/short button pushes. * ; 0.45(2/15) Adding I2C to talk to DS1307 Real-time Clock chip * ; using Andrew D. Vassallo's bit banging from piclist.com * ; (2/17) Works. Long time debugging since it apparently * ; MUST have the backup battery in there to work reliably. * ; 0.5 (2/17) Working on the Clock display and interface. * ; 0.6 (2/19) Clock works. Working on settings interface. * ; 0.7 (2/21) Basic settings done: Time / Date / Brightness. * ; 0.75(2/22) Added preset world lines from anime/visual novel. * ; 0.8 (2/25) Added manual world line entry. Added random beta * ; and neg. world lines. Put useful things in subroutines. * ; 0.85(2/27) Date format pref (MM DD YY or DD MM YY) done. * ; 0.90(2/28) Tube blanking hours. Fun2 roll at top of hour. * ; 1.0 (3/3) Time adjustment implemented and tested. * ; All originally planned features have been implemented. * ; 1.01 (3/22) Fixed bug in setting 12/24-hour format from * ; the value stored in EEPROM location 7F. * ; 1.02 (3/30) Changed so the device starts up in clock mode. * ; Mainly because if there is a power outage, you don't * ; want the device to wake up and stay with one number on * ; the nixie tubes for an extended period. * ; 1.03 (4/20) Fixed error in Year-setting routine. * ; 1.04 (5/11) Fixed error in error routine that reports "666" * ; if the clock chip does not respond. This did not work * ; right at power-up because the tube power was still off, * ; so I added lines to turn tubes on to the error handler. * ; ALSO added version number display. The version number * ; will be displayed as long as switch 2 is held on the way * ; into the Settings menu. * ; 1.05 (5/12) Works for either DS1307 or DS3232 clock chips. * ; * ;********************************************************************** list p=16f628A ; list directive to define processor #include "C:\Program Files\Microchip\MPASM Suite\P16F628A.INC" ; processor specific variable definitions errorlevel -302 ; suppress message 302 from list file __CONFIG _CP_OFF & _LVP_OFF & _BOREN_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _INTOSC_OSC_NOCLKOUT ; '__CONFIG' directive is used to embed configuration word within .asm file. ; The lables following the directive are located in the respective .inc file. ; See data sheet for additional information on configuration word settings. ;***** VARIABLE DEFINITIONS wTmp EQU 0x7E ; variable used for context saving statusTmp EQU 0x7F ; variable used for context saving ShadowA equ 20 ; shadow register for PORTA ShadowB equ 21 ; shadow register for PORTB Delay1 equ 22 ; for delay Delay2 equ 23 ; for delay Counter equ 24 ; counter ; NOTE! The following 26 registers must be in the order below! LeftDP equ 25 ; Flags for left decimal places RightDP equ 26 ; Flags for right decimal places T0 equ 27 ; Number for Tube 0 (rightmost). An 11(base 10) in these means no digit in that tube. T1 equ 28 ; etc. T2 equ 29 ; . T3 equ 2A ; . T4 equ 2B ; . T5 equ 2C ; . T6 equ 2D ; . T7 equ 2E ; Number for Tube 7 (leftmost) TR0 equ 2F ; Run length for Tube 0 (rightmost) (i.e., cycles to run until digits halt) TR1 equ 30 ; etc. TR2 equ 31 ; . TR3 equ 32 ; . TR4 equ 33 ; . TR5 equ 34 ; . TR6 equ 35 ; . TR7 equ 36 ; Run length for Tube 7 (leftmost) V0 equ 37 ; Values for tubes to stop at (using alternate animation method) V1 equ 38 ; . V2 equ 39 ; . V3 equ 3A ; . V4 equ 3B ; . V5 equ 3C ; . V6 equ 3D ; . V7 equ 3E ; . Flag equ 3F ; Flag register n equ 40 ; Work register used by Loader m equ 41 ; Work register used by Loader LDP equ 42 ; Work register used by Loader RDP equ 43 ; Work register used by Loader random equ 44 ; random number work equ 45 ; Work register for use inside any subroutine bright equ 46 ; Brightness value 0 (dimmest) to 7 (brightest) currently in use. incMin equ 47 ; Register to hold Minimum while incrementing settings incMax equ 48 ; Register to hold Maximum while incrementing settings oldMin equ 49 ; Register to hold old minutes (so we can tell if they were changed) blankStart equ 4A ; Register to hold starting hour of tube blanking blankEnd equ 4B ; Register to hold ending hour of tube blanking hourCount equ 4C ; Register to count down hours until time adjustment oldHour equ 4D ; Register to track start of hour LED equ 0 ; LED is bit 0 in PORTB HVE equ 1 ; High Voltage Enable is bit 1 in PORTB CLK equ 2 ; Clock line for serial-to-parallel drivers is bit 2 in PORTB NBL equ 3 ; NOT Blank for serial-to-parallel drivers is bit 3 in PORTB DAT equ 4 ; Data line for serial-to-parallel drivers is bit 4 in PORTB NLE equ 5 ; NOT Latch Enable for serial-to-parallel drivers is bit 5 in PORTB SW1 equ 2 ; Switch 1 is bit 2 in PORTA SW2 equ 3 ; Switch 2 is bit 3 in PORTA short1 equ 0 ; Short press of Button 1 was made long1 equ 1 ; Long press of Button 1 was made short2 equ 2 ; Short press of Button 2 was made (or any press...not tracking long) long2 equ 3 ; (reserved in case I want to track long pressed of Button 2) Done equ 4 ; Flag Bit 4 used to see if world line animation is done Slide equ 5 ; Flag Bit 5 used for 'slide loading' in Loader (1=slide) APnow equ 6 ; Flag Bit 6 keeps track of whether current time is AM or PM (1=PM) Clk12 equ 7 ; Flag Bit 7 is 12/24 hour preference flag (1=12 hour clock) negWL equ 7 ; Bit 7 of Eflag is for negative world lines. toggl equ 6 ; Bit 6 of Eflag is for toggling beta equ 5 ; Bit 5 of Eflag is for beta world line deBounceDly equ d'30' ; Set the constant for the deBounce delay time ; Variables for I2C routines need to be accessable in Bank1, so I'll start them at 70h (where there are registers availble to both Banks 0 and 1). GenCount equ 70 ; General-purpose counter/scratch register Mem_Loc equ 71 ; Memory address within DS1307 chip to access Data_Buf equ 72 ; Byte read from DS1307 gets stored here Out_Byte equ 73 ; Used to hold byte to be written to DS1307 Eflag equ 74 ; Flag bit register brightSet equ 75 ; Clock Brightness preference by user (also here so it can be loaded from EEPROM 7Eh while we are in Bank 1) dateDMY equ 76 ; Date setting peference by user 1= prefers DD MM YY 0= prefers MM DD YY (read from in EEPROM 7Dh) pointer equ 77 ; Pointer to track EEPROM address (accessible from both Banks) timeAdj equ 78 ; Time adjustment register (number of hours between time adjustments) timeFast equ 79 ; Time adjustment for Fast or Slow clock (1=fast 0=slow) ; Define port pins for I2C access of DS1307: SCL clock line is RA0. SDA data line is RA1. ; The lines have 10K pullup resistors and will be used in passive control mode where the outputs ; are set to zero, and then controlled by setting and clearing TRISA,0 and TRISA,1. Setting TRIS ; bit high will make pin an input, and the resistor will pull the line connected to that high-Z ; pin high (1). Clearing TRIS bit makes pin an output, and the zero will be output to make the ; line low (0). This must be done in Bank1 where the TRIS register can be accessed. Why all this? ; Because this way the I2C slave (DS1307) can pull the high line low in response. ; Where the assembler sees the symbols defined below, they are the same as the "TRISA,n" stuff ; (or as "PORTA,n" in Bank0). #define SCL TRISA,0 #define SDA TRISA,1 ;********************************************************************** ORG 0x000 ; processor reset vector goto Main ; go to beginning of program ;====================== ;Interrupt routines ORG 0x004 ; interrupt vector location movwf wTmp ; save off current W register contents movf STATUS,w ; move status register into W register movwf statusTmp ; save off contents of STATUS register ; isr code can go here or be located as a call subroutine elsewhere movf statusTmp,w ; retrieve copy of STATUS register movwf STATUS ; restore pre-isr STATUS register contents swapf wTmp,f swapf wTmp,w ; restore pre-isr W register contents retfie ; return from interrupt ;====================== ;Subroutines RunLength addwf PCL,f ; Lookup Table for run lengths (appropriate random number in W... 0-7, 0-15, 0-63) retlw d'20' ; The first 8 are multiples of 10, for use when tube 7 returns to starting digit. retlw d'30' ; The first 16 are multiples of 5, for use when two cycles return digits to same. retlw d'40' ; The rest of the 64 are spaced to give good stopping distribution. retlw d'50' ; retlw d'50' ; retlw d'60' ; retlw d'60' ; retlw d'70' ; Last of the first 8 retlw d'15' ; retlw d'25' ; retlw d'35' ; retlw d'45' ; retlw d'55' ; retlw d'55' ; retlw d'55' ; retlw d'65' ; Last of the first 16 retlw d'18' ; retlw d'19' ; retlw d'22' ; retlw d'23' ; retlw d'24' ; retlw d'26' ; retlw d'27' ; retlw d'28' ; retlw d'29' ; retlw d'31' ; retlw d'32' ; retlw d'33' ; retlw d'34' ; retlw d'36' ; retlw d'37' ; retlw d'38' ; retlw d'39' ; retlw d'41' ; retlw d'42' ; retlw d'43' ; retlw d'44' ; retlw d'46' ; retlw d'47' ; retlw d'48' ; retlw d'49' ; retlw d'16' ; retlw d'51' ; retlw d'17' ; retlw d'52' ; retlw d'68' ; retlw d'53' ; retlw d'67' ; retlw d'21' ; retlw d'69' ; retlw d'54' ; retlw d'56' ; retlw d'56' ; retlw d'64' ; retlw d'57' ; retlw d'57' ; retlw d'66' ; retlw d'58' ; retlw d'58' ; retlw d'63' ; retlw d'59' ; retlw d'59' ; retlw d'61' ; retlw d'62' ; Last of 64 ;-------- deBounce ; Debounce delay with brightness control bsf ShadowB,NBL ; Set bit for tubes NOT Blanked movfw Delay2 ; Get current Delay2 value andlw b'00000111' ; Keep only 3 rightmost digits (0 to 7) subwf bright,w ; See if result is greater than brightness number btfss STATUS,C ; If Y= max, result will Carry flag will be set btfsc STATUS,C ; If C clear, go increment. goto setToMin ; If C set, go put incMin in. incBCD incf Data_Buf,f ; Increment the packed BCD. This might cause right digit to go to hex A... movlw b'00001111' ; so let's get that digit... andwf Data_Buf,w ; by doing this... sublw b'00001010' ; so we can compare to hex A btfss STATUS,Z ; Is that digit hex A? If it is, Z=1 goto valueOK ; If Z is not set, we are fine and quit movlw b'11110000' ; If Z is set... andwf Data_Buf,f ; ...do this AND to zero out the right digit... movlw b'00010000' ; ...and add one to the left digit... addwf Data_Buf,f ; ...and done! goto valueOK ; setToMin movfw incMin ; Take the packed BCD pattern of incMin... movwf Data_Buf ; ...and put it into Data_Buf. goto valueOK ; valueOK call FillT1T0 ; Fill new value into tubes call Loader ; goto Increment ; ;-------- ; Routine to send a 1 to the serial-to-parallel drivers. send1 bsf ShadowB,DAT ; Set Data line high for one bsf ShadowB,CLK ; Set clock high movfw ShadowB ; Copy ShadowB... movwf PORTB ; ...to PORTB bcf ShadowB,CLK ; Set clock low movfw ShadowB ; Copy ShadowB... movwf PORTB ; ...to PORTB return ;------- ; Routine to send a 0 to the serial-to-parallel drivers. send0 bcf ShadowB,DAT ; Set Data line high for one bsf ShadowB,CLK ; Set clock high movfw ShadowB ; Copy ShadowB... movwf PORTB ; ...to PORTB bcf ShadowB,CLK ; Set clock low movfw ShadowB ; Copy ShadowB... movwf PORTB ; ...to PORTB return ;------- RandomNum movlw d'63' ; Pseudo-random number generator addwf random,w ; newRandom = 3 x oldRandom + 63 addwf random,w ; addwf random,f ; movfw random ; return ; ;------- ; Call with: DS1307 register address in Mem_Loc ; Returns with: byte in Data_Buf ReadDS1307 bcf STATUS,RP0 ; Bank0 movfw ShadowA ; Clear bits RA0 and RA1 in shadowA and PORTA... andlw b'11111100' ; ...for passive control of the I2C lines (if one of those pins gets movwf ShadowA ; ...set as output, these zeros will make the line low, and if the movwf PORTA ; ...pin is set as (Hi-Z) inputs, a resistor pulls the line high. bsf STATUS,RP0 ; Select Bank 1 for TRISA access (passive SCL/SDA control) bsf SDA ; Let SDA line get pulled high (by setting it as a input) bsf SCL ; Let SCL line get pulled high (by setting it as a input) bcf SDA ; START condition = data line going low while clock line is high movlw b'11010000' ; Send Write (to set address before reading) call Byte_Out ; btfsc Eflag,0 ; Eflag bit0 will be set if no ACK received from DS1307 goto Err_Routine ; NOTE: MUST USE "RETURN" FROM THAT ROUTINE movfw Mem_Loc ; Memory location we want to read is in Mem_Loc call Byte_Out ; ...and needs to be in W when Byte_Out is called btfsc Eflag,0 ; goto Err_Routine ; bcf SCL ; Pull clock line low in preparation for 2nd START bit nop ; bsf SDA ; Data line gets pulled high - data transition during clock low bsf SCL ; Clock line gets pulled high to begin generating START bcf SDA ; 2nd START condition as data line goes low movlw b'11010001' ; Request data read from DS1307 register call Byte_Out ; btfsc Eflag,0 ; goto Err_Routine ; ; Note that Byte_Out leaves with SDA line freed to allow slave to send data in to master. call Byte_In ; movfw Data_Buf ; put result into W register for returning from CALL bcf SCL ; extra cycle for SDA line to be freed from DS1307 nop ; bcf SDA ; ensure SDA line low before generating STOP bsf SCL ; pull clock high for STOP bsf SDA ; STOP condition = data line goes high while clock line is high bcf STATUS,RP0 ; leave with Bank 0 active as default return ;------- ; Save each byte as it's written ; Call with: a DS1307 resister address in Mem_Loc, byte to be sent in Data_Buf ; Returns with: nothing returned WriteDS1307 bcf STATUS,RP0 ; Bank0 movfw ShadowA ; Clear bits RA0 and RA1 in shadowA and PORTA andlw b'11111100' ; ...for passive control of the I2C lines (if one of those pins gets movwf ShadowA ; ...set as output, these zeros will make the line low, and if the movwf PORTA ; ...pin is set as (Hi-Z) inputs, a resistor pulls the line high. bsf STATUS,RP0 ; select Bank 1 for TRISB access (passive SCL/SDA control) bsf SDA ; ensure SDA line is high bsf SCL ; clock high gets pulled high bcf SDA ; START condition = data line going low while clock is high movlw b'11010000' ; Send Write code (to set address first) call Byte_Out ; btfsc Eflag,0 ; Eflag bit0 gets set of not ACK received from DS1307 goto Err_Routine ; NOTE: MUST USE "RETURN" FROM THAT ROUTINE movfw Mem_Loc ; Send the memory location to wite to... call Byte_Out ; ...now btfsc Eflag,0 ; goto Err_Routine ; movfw Data_Buf ; move data byte to be sent to W call Byte_Out ; btfsc Eflag,0 ; goto Err_Routine ; bcf SCL ; extra cycle for SDA line to be freed from DS1307 nop ; bcf SDA ; Ensure SDA line low before generating STOP... bsf SCL ; pull clock high for STOP.. bsf SDA ; STOP condition = data line goes high. bcf STATUS,RP0 ; Leave with Bank 0 active by default return ;------- ; This routine reads one byte of data from the DS307 real-time Clock chip into Data_Buf Byte_In clrf Data_Buf ; movlw 0x08 ; 8 bits to receive movwf GenCount ; ControlIn rlf Data_Buf,f ; Shift bits into buffer bcf SCL ; Pull clock line low nop ; bsf SCL ; Clock line gets pulled high to read bit bcf STATUS,RP0 ; Select Bank 0 to read PORTA bits directly! btfss SDA ; Test bit from DS1307 (if bit=clear, skip because Data_Buf is clear) goto $+3 ; Jump ahead 3 instructions bsf STATUS,RP0 ; Select Bank 1 to access variables (Don't think I need this [could nop], but I'll leave it.) bsf Data_Buf,0 ; Read bit into 0 first, then eventually shift to 7 bsf STATUS,RP0 ; Select Bank 1 to access variables (Don't think I need this [could nop], but I'll leave it.) decfsz GenCount,f ; goto ControlIn ; return ;------- ; This routine sends out the byte in the W register and then waits for ACK from DS1307 (256us timeout period) Byte_Out movwf Out_Byte ; Byte to send was in W...now also in Out_Byte movlw 0x08 ; 8 bits to send movwf GenCount ; rrf Out_Byte,f ; shift right in preparation for next loop ControlOut rlf Out_Byte,f ; shift bits out of buffer bcf SCL ; pull clock line low nop ; btfsc Out_Byte,7 ; send current "bit 7" goto BitHigh ; bcf SDA ; goto ClockOut ; BitHigh bsf SDA ; ClockOut bsf SCL ; pull clock high after sending bit decfsz GenCount,f ; goto ControlOut ; bcf SCL ; pull clock low for ACK change bsf SDA ; free up SDA line for slave to generate ACK nop ; wait for slave to pull down ACK nop nop bsf SCL ; pull clock high for ACK read clrf GenCount ; reuse this register as a timeout counter (to 256us) to test for ACK WaitForACK bsf STATUS,RP0 ; select Bank1 for GenCount access (Don't think I need this [could nop], but I'll leave it.) incf GenCount,f ; increase timeout counter each time ACK is not received btfsc STATUS,Z ; Z will be clear until we increment GenCount all the way up to zero (after 256 times) goto No_ACK_Rec ; bcf STATUS,RP0 ; select Bank0 to test SDA PORTA input directly! btfsc SDA ; test pin. If clear, EEPROM is pulling SDA low for ACK goto WaitForACK ; ...otherwise, continue to wait bsf STATUS,RP0 ; select Bank1 as default during these routines bcf Eflag,0 ; clear flag bit (ACK received) return ;------- ; No ACK received from DS1307 (must use "return" from here) ; Set a flag bit to indicate failed write and check for it upon return. No_ACK_Rec bsf Eflag,0 ; set flag bit return ; returns to Byte_Out routine (Bank 1 selected) ;------- ; No ACK received from slave. This is the error handler. Err_Routine bcf STATUS,RP0 ; make sure I'm in Bank0 to flash LED call FillBlanks ; fill tubes with blanks movlw d'6' ; Put error code "666" in tubes 0-2 movwf T2 movwf T1 movwf T0 clrf LeftDP ; Clear the decimal points clrf RightDP call Loader ; Load the display bsf ShadowB,NBL ; set NOT Blanking high (tubes no longer blanked), bsf ShadowB,HVE ; and Set High Voltage Enable ON to display the tubes now, too. movfw ShadowB ; Copy ShadowB... movwf PORTB ; ...to PORTB Crash666 goto Crash666 ; Infinite loop crash. ; And unused below, just for the look of things: return ; returns to INITIAL calling routine ;------ Fun clrf T7 ; Zero out the leftmost tube for most random world lines bcf Eflag,beta ; Clear the beta world line flag. bcf Eflag,negWL ; Clear negative world line flag. movfw TMR0 ; Seed 0-255 randomly by switch release that got us here movwf random ; Store the random number. ; Other worldline branchings will go here: call RandomNum ; Gets 0-255 in W andlw b'11111100' ; This will clear the right two bits of W and leave the rest unaltered. If W is now zero, it ; must have been 0 to 3 before the AND. btfsc STATUS,Z ; See if the random number is now zero (4 out of 256 chance) bsf Eflag,negWL ; If so, make this a negative world line (first tube will show up blank). andlw b'11110000' ; This will clear the right three bits of W and leave the rest unaltered. If W is now zero, it ; must have been 0 to 15 before the AND. btfsc STATUS,Z ; See if W is now zero (16 out of 256 chance it is) bsf Eflag,beta ; Display a beta world line number (1.xxxxxx) ; (Of course, it was 0, we already flagged it as negative WL) call RandomNum ; Gets 0-255 in W andlw b'00000111' ; 0-7 in W call RunLength ; Gets runlength that's a multiple of 10 for tube 7 movwf TR7 ; so leftmost tube will return to 0. btfsc Eflag,beta ; But if we got a beta world line... incf TR7,f ; increment the run length so it will stop at one. clrf TR6 ; Decimal point tube does no incrementing. FillRunLens movlw TR5 ; ADDRESS of TR5 movwf FSR ; for indirect addressing. nextRL call RandomNum ; Gets 0-255 in W andlw b'00111111' ; 0-63 in W call RunLength ; Gets tube's run length movwf INDF ; and puts it in TRn decf FSR,f ; Decrement for next tube movlw T7 ; ADDRESS of T7 register (below the TRn registers) subwf FSR,w ; Does FSR minus T7;s address btfss STATUS,Z ; see if result is zero goto nextRL ; no...go get runlength for next tube ; yes...all TRn filled call animate ; return ; ;------- animate bcf Flag,Done ; Clear bit Done of Flag for tracking if animation is done. movfw TR7 ; Load TR7 runlength into W btfsc STATUS,Z ; and see if it's zero. goto chkNeg ; If zero, skip to tubes 5 thru 0 (7 has already stopped) decf TR7,f ; If not zero, do tube 7. Decrement runlength. bsf Flag,Done ; Set bit so we know we haven't finished aniation. incf T7,f ; Increment T7 value movlw d'10' ; See if it went over 9... subwf T7,w ; btfsc STATUS,C ; If new T7 < 10, C=0 clrf T7 ; so clear T7 to zero if it reached 10. goto IncTubes ; On to tubes 5-0 chkNeg movlw d'10' ; Before we go one to tubes 5-0, check to see if this is a negative world line... btfsc Eflag,negWL ; movwf T7 ; ...If it is, we blank tube 7. IncTubes movlw TR5 ; ADDRESS of TR5 movwf FSR ; for indirect addressing nextTube movfw INDF ; Put TRn runlength into W btfsc STATUS,Z ; and see if it's zero. goto notthis ; If zero, don't do this tube (done animating it), and go to next one. decf INDF,f ; If not zero, do this tube. Decrement runlength. bsf Flag,Done ; Set bit so we know we haven't finished aniation. movlw d'8' ; Subtract 8 from FSR so it points subwf FSR,f ; to Tn instead of TRn incf INDF,f ; Increment Tn movlw d'10' ; See if it went over 9... subwf INDF,w ; btfsc STATUS,C ; If new Tn < 10, C=0 clrf INDF ; so clear Tn to zero if it reached 10. movlw d'8' ; Add 8 back into FSR to addwf FSR,f ; put it back to TRn notthis decf FSR,f ; Decrement to do next tube movlw T7 ; ADDRESS of T7 register (below the TRn registers) subwf FSR,w ; Does FSR minus T7's address btfss STATUS,Z ; If we have done all the tubes, Zero flag will be clear. goto nextTube ; if Zero not clear, go do next tube ; We get here if all tubes done. btfss Flag,Done ; See if no tubes were changed (Flag,Done would be clear). goto alldone ; No tubes changed...we are finished call Loader ; Display the new number in the tubes movlw d'30' ; Delay to see the number call delay ; goto animate ; And go to the next animation step. alldone call Pulse ; Animation done. Do flash at end of animation return ; ;------ Pulse movlw d'7' ; Flash full brightness movwf bright ; movlw d'200' ; Flash at end of animation call delay ; movlw d'6' ; Fade to level 6 brightness movwf bright ; movlw d'50' ; call delay ; movlw d'5' ; Fade to level 5 brightness movwf bright ; movlw d'40' ; call delay ; movlw d'4' ; Fade to level 4 brightness movwf bright ; movlw d'30' ; call delay ; movlw d'3' ; Fade to level 3 brightness movwf bright ; return ; ;------ Fun2 movfw TMR0 ; Seed 0-255 randomly by switch release that got us here movwf random ; Store the random number. FillRuns movlw TR7 ; ADDRESS of TR7 movwf FSR ; for indirect addressing. nextRLen call RandomNum ; Gets 0-255 in W andlw b'00111111' ; 0-63 in W call RunLength ; Gets tube's run length movwf INDF ; and puts it in TRn decf FSR,f ; Decrement for next tube movlw T7 ; ADDRESS of T7 register (below the TRn registers) subwf FSR,w ; Does FSR minus T7's address btfss STATUS,Z ; see if result is zero goto nextRLen ; no...go get runlength for next tube ; yes...all TRn filled clrf TR6 ; Decimal point tube does no incrementing. I could have not filled it, but it seems simpler to just clear it now. call animate2 ; return ;------ ; animate2 is different from animate in that when it stops it will be displaying V7-V0 values. animate2 bcf Flag,Done ; Clear bit Done of Flag, for tracking if animation is done. IncTubes2 movlw TR7 ; ADDRESS of TR7 movwf FSR ; for indirect addressing nextTube2 movfw INDF ; Bring TRn runlength into W btfsc STATUS,Z ; and see if it's zero. goto notthis2 ; If zero, this tube's run length has run out (done animating it), and go to next one. decf INDF,f ; If not zero, do this tube. Decrement runlength. movfw INDF ; Let's see if it just got to zero after the decrement above btfss STATUS,Z ; goto keepon ; If it was decremented to zero, we go on as before movlw d'8' ; But if the runtime just decremented to zero, let's make sure it has it's final value in it: addwf FSR,f ; Add 8 to FSR to get the corresponding Vn register movfw INDF ; and take the value from that register movwf work ; hold it here for a while movlw d'16' ; then point tho the corresponding Tn tube subwf FSR,f ; by adjusting FSR 16 registers down movfw work ; grabbing the value movwf INDF ; and putting it into Tn movlw d'8' ; Then let's bring FSR back to the TRn registers, but one register lower than before addwf FSR,f ; so we can do the next tube. goto notthis2 ; keepon bsf Flag,Done ; Set bit so we know we haven't finished aniation. movlw d'8' ; Subtract 8 from FSR so it points subwf FSR,f ; to Tn instead of TRn incf INDF,f ; Increment Tn movlw d'10' ; See if it went over 9... subwf INDF,w ; btfsc STATUS,C ; If new Tn < 10, C=0 clrf INDF ; so clear Tn to zero if it reached 10. movlw d'8' ; Add 8 back into FSR to addwf FSR,f ; put it back to TRn notthis2 decf FSR,f ; Decrement for next tube. movlw T7 ; ADDRESS of T7 register (below the TRn registers) subwf FSR,w ; This does FSR minus T7's address btfss STATUS,Z ; If we have gone through all the tubes another time, Zero flag will be clear. goto nextTube2 ; if Zero not clear, go do next tube ; We get here if all tubes done. btfss Flag,Done ; See if no tubes were changed (Flag,Done would be clear). goto alldone2 ; No tubes changed...we are finished call Loader ; Display the new number in the tubes movlw d'30' ; Delay to see the number call delay ; goto animate2 ; And go to the next animation step. alldone2 call Loader ; Final load call Pulse ; Animation done. Do flash at end of animation return ; ;------ ; Routin copies T0-T7 into V0-V7 moveNumber movlw T0 ; ADDRESS of T0 movwf FSR ; for indirect addressing. nextMove movfw INDF ; Get Tn movwf work ; put it in work movlw d'16' ; Change the FSR pointer by +16 to point addwf FSR,f ; to the corresponding Vn register movfw work ; Get the value movwf INDF ; and put it where it Vn movlw d'15' ; Change the FSR pointer by -15 to point subwf FSR,f ; to the T(n+1) register movlw TR0 ; ADDRESS of TR0 (which is right above T7) subwf FSR,w ; Test to see if FSR is pointing to TR0 btfss STATUS,Z ; which will be true if the Zero bit is set; goto nextMove ; If it's not true, we go do the next tube's values return ; And if it is true, we are all done moving and get here, so Return. ;------ Loader movfw LeftDP ; Routine to load a number into all 8 tubes. Values are in T0-T7, LeftDP, and RightDP. movwf LDP ; Make copies of LeftDP and RightDP so contents are not destroyed. movfw RightDP ; movwf RDP ; movlw T7 ; Put the *ADDRESS* of T7 register into W ("T7" is equated to that address) movwf FSR ; ...and then into the File Select Register. We can now access the number we want displayed on a tube using INDF. loopLoad rlf LDP,f ; Rotate a dp flag into the Carry bit btfsc STATUS,C ; Is the dp flag set? goto dpset ; ...yes, jump to dpset. call send0 ; ...no, so send 0 to the shift registers. goto digi ; and then jump to continue with the digit. dpset call send1 ; dp flag was set, so send 1 to shift registers digi movlw d'9' ; Put 9 into m. This will decrement as we go through loopdigi. movwf m clrf n ; Start with n=0. This will increment as we go through loopdigi. loopdigi incf n,f ; Increment n (n is the number we compare against the digit we want to show). movfw n ; Get the current n... subwf INDF,w ; See if the digit we want to display equals n by subtract n from that digit (via INDF) and leave result in W btfsc STATUS,Z ; If that digit=n (Zero flag will be set from subtraction), then... goto yesdigi ; ...goto yesdigi call send0 ; ...otherwise send a 0 to the shift registers. goto nextshift ; and check the next bit to shift yesdigi call send1 ; Digit=n, so send a 1 to the shift registers. nextshift decfsz m,f ; Decrement m and see if we are done. goto loopdigi ; ...if not done go back to loopdigi movfw INDF ; When we get here we still need to see if the digit is a zero btfsc STATUS,Z ; If that digit=0 (Zero flag will be set from moving it into W), then... goto yeszero ; ...goto yeszero call send0 ; ...otherwise send a 0 to the shift registers. goto checkRDP ; and check the next bit to shift yeszero call send1 ; Digit=n, so send a 1 to the shift registers. checkRDP rlf RDP,f ; Digit is done, so check for right decimal point btfsc STATUS,C ; Is the dp flag set? goto dpset2 ; ...yes, jump. call send0 ; ...no, so send 0 to the shift registers. goto tubeDone ; and then jump to continue dpset2 call send1 ; dp flag was set, so send 1 to shift registers tubeDone decf FSR,f ; Decrement File Select Register to do next tube. btfss Flag,Slide ; "Slide Loading" flag goto noSlide ; If Flag,Slide is clear, normal load (skip this next stuff) LatchSlide bsf ShadowB,NLE ; Latch the result sf current tubes: movfw ShadowB ; Copy ShadowB... movwf PORTB ; ...to PORTB (Latches load when NLE is high) bcf ShadowB,NLE ; Get ready to lock the latches. bsf ShadowB,NBL ; Set NOT Blanking high (tubes no longer blanked) while I'm at it movfw ShadowB ; Copy ShadowB... movwf PORTB ; ...to PORTB (Latches lock when NLE is low) movlw d'80' ; Pause for display call delay noSlide movlw RightDP ; Put the *ADDRESS* of the RightDP register into W ("RightDP" is equated to that address) subwf FSR,w ; ...and subtract it from FSR to see if we did all the tubes. btfss STATUS,Z ; If we haven't done all the tubes, Zero flag will be clear goto loopLoad ; so go back and do the next tube. Latch bsf ShadowB,NLE ; Latch the result: movfw ShadowB ; Copy ShadowB... movwf PORTB ; ...to PORTB (Latches load when NLE is high) bcf ShadowB,NLE ; Get ready to lock the latches. bsf ShadowB,NBL ; Set NOT Blanking high (tubes no longer blanked) while I'm at it movfw ShadowB ; Copy ShadowB... movwf PORTB ; ...to PORTB (Latches lock when NLE is low) return ;====================================================================== ;Program Start Main ; Main routine Init clrf PORTA ; Clear Port A clrf ShadowA ; Clear ShadowA movlw 0x07 ; Turn comparators off and movwf CMCON ; enable pins for I/O functions clrf PORTB ; Clear Port B clrf ShadowB ; Clear ShadowB bcf STATUS,RP1 ; First time, make sure this is also clear so the next command... bsf STATUS,RP0 ; Goes to Bank 1 movlw b'00101111' ; Set input/output pins in PORTA movwf TRISA ; RA0 is SCL (clock) to clock chip ; RA1 is SDA (data) to clock chip ; RA2 is button 1 ; RA3 is button 2 ; RA4-RA7 are not used (except RA5 is for programmer) movlw b'00000000' ; Set all pins as outputs movwf TRISB ; RB0 is LED output for testing ; RB1 is High Voltage Enable ; RB2 is Clock line to serial chips ; RB3 is NOT Blank line to serial chips ; RB4 is Data line to serial chips ; RB5 is NOT Latch Enable to serial chips ; RB6-RB7 are for programmer movlw b'11011111' ; Set TMR0 to clock off the internal clock, no prescaler (prescaler assigned to WDT) movwf 0x81 ; Huh... "OPTION" was not recognized here. Why? ; Read timeFast setting from EEPROM movlw 0x7B ; Address to read... movwf EEADR ; ...gets put here. bsf EECON1,RD ; EE Read movfw EEDATA ; W = EEDATA movwf timeFast ; Put it in its place (which is a register also available in Bank 1) ; Read timeAdj setting from EEPROM movlw 0x7C ; Address to read... movwf EEADR ; ...gets put here. bsf EECON1,RD ; EE Read movfw EEDATA ; W = EEDATA movwf timeAdj ; Put it in its place (which is a register also available in Bank 1) ; Read date format setting from EEPROM movlw 0x7D ; Address to read... movwf EEADR ; ...gets put here. bsf EECON1,RD ; EE Read movfw EEDATA ; W = EEDATA movwf dateDMY ; Put it in its place (which is a register also available in Bank 1) ; Read brightness setting from EEPROM movlw 0x7E ; Address to read... movwf EEADR ; ...gets put here. bsf EECON1,RD ; EE Read movfw EEDATA ; W = EEDATA movwf brightSet ; Put it in its place (which is a register also available in Bank 1) ; Read 12/24 clock setting from EEPROM movlw 0x7F ; Address to read... movwf EEADR ; ...gets put here. bsf EECON1,RD ; EE Read movfw EEDATA ; W = EEDATA (W will now have the 12/24 setting, either 00000001 for 12-hour, or 00000000 for 24-hour) bcf STATUS,RP0 ; Back to Bank 0 clrf Flag ; Clear the Flag register ; btfsc W,0 ; Clock preference setting from EEPROM is in W from before <-- ERROR HERE. Can't test bits in W like this! movwf work ; Move W to register "work"... btfsc work,0 ; ...and do the test there. bsf Flag,Clk12 ; Set the 12/24 flag based upon it. (1 = 12 hour) ; I am handling 12/24 setting myself and leaving DS1307 in 24 hour mode. movfw timeAdj ; Copy the timeAdj value into the movwf hourCount ; hour counter to track when time adjustments need to be made. ; Note that this will get reset if you unplug/replug the device, since it may have been previously partway ; through a count...so don't unplug for maximum accuracy (or reset time after unplug). But it will be close. ; Also, the hour counter won't count if you are playing in D.M. mode at the top of the hour. clrf Delay1 ; Will be used to loop 256 times movlw deBounceDly ; Will loop deBounce this many times (constant deifned in equates) movwf Delay2 ; Will be used to loop n times bcf ShadowB,LED ; Set bit for LED OFF in ShadowB bcf ShadowB,NBL ; Set Not Blanking low (this will blank the tubes) bcf ShadowB,HVE ; Set bit for High Voltage Enable OFF bcf ShadowB,NLE ; Set NOT Latch Enable low (transfer of bits from shift registers to latches is OFF) bcf ShadowB,CLK ; Set Clock line low (setting it high and back low will clock the serial chips...62 ns minimum pulse width) movfw ShadowB ; copy ShadowB to PORTB movwf PORTB ; clrf Eflag ; Clear the error flag register ; See if the Real Time Clock is running (or if loss of backup battery power has stopped it). clrf Mem_Loc ; First check CH (Clock Halt) bit in the seconds register (00h) to see if DS1307 is halted call ReadDS1307 ; Read the seconds register (Mem_Loc = 00h) from DS1307 btfsc Data_Buf,7 ; Test CH bit (bit 7) goto Start1307 ; ...if CH is set, DS1307 is stopped and needs startup ; ...if CH is clear, either DS1307 is running, or this may be a DS3232 (running or stopped). movlw 0x0F ; See if the DS3232 Clock is running by checking bit 7 of 0Fh in the clock chip movwf Mem_Loc ; call ReadDS1307 ; Read the 0Fh register (a control/status register in the DS3232; a RAM register in the DS1307) btfss Data_Buf,7 ; Oscillator Stopped Flag is bit 7 goto ClockON ; ...if OSF is clear, Clock was running (with battery backup) ; ...if we get here, this is either a stopped DS3232, or a running DS1307 that just ; happens to have RAM 0Fh bit 7 set. To test this, we will try writing a 1 to 0Fh Bit 0 ; which is a flag bit in the DS3232 that CAN'T have a 1 written to it. bcf Data_Buf,0 ; First we clear bit 0 call WriteDS1307 ; ...and write a zero to that bit in 0Fh (just in case there was a 1 there to bein with) bsf Data_Buf,0 ; ...then we SET bit 0 to 1 in Data_Buf call WriteDS1307 ; ...and write Data_Buf back to 0Fh nop ; call ReadDS1307 ; ...and then read back from 0Fh btfsc Data_Buf,0 ; ...so we can est bit 0 goto ClockON ; If the bit was 1, this can't be a DS3232, so must be a running DS1307. Leap! clrf Data_Buf ; If we get here, we have a stopped DS3232, so clear 0Fh and do clock setup call WriteDS1307 ; Clear the 0Fh register starts the DS3232 Clock. Start1307 clrf Mem_Loc ; Going to clear Seconds register (00h) clrf Data_Buf ; call WriteDS1307 ; Clearing the seconds register starts a halted DS1307 (and doesn't hurt a DS3232 startup) incf Mem_Loc,f ; Fill the clock with July 7, 2010, 12:30 PM (when first D-mail was sent) just for giggles (otherwise it would be 01/01/00 00:00:00) movlw b'00110000' ; 30 minutes movwf Data_Buf ; call WriteDS1307 ; Write to minutes RAM incf Mem_Loc,f ; movlw b'00010010' ; 12 hours movwf Data_Buf ; call WriteDS1307 ; Write to hours RAM incf Mem_Loc,f ; incf Mem_Loc,f ; movlw b'00101000' ; 28th movwf Data_Buf ; call WriteDS1307 ; Write to days RAM incf Mem_Loc,f ; movlw b'00000111' ; 7 (July) movwf Data_Buf ; call WriteDS1307 ; Write to months RAM incf Mem_Loc,f ; movlw b'00010000' ; 10 (2010) movwf Data_Buf ; call WriteDS1307 ; Write to years months RAM clrf Data_Buf ; Clear the Data_Buf so we can... movlw 0x14 ; Clear the blankStart and blankEnd values in clock's RAM (since they will be garbage) movwf Mem_Loc ; Address of RAM where blankStart is stored call WriteDS1307 ; Write a zero there incf Mem_Loc,f ; Address of RAM where blankEnd is stored is 0x15 call WriteDS1307 ; Write a zero there. ClockON movlw 0x02 ; Hours register in clock RAM movwf Mem_Loc ; Put it into Mem_Loc call ReadDS1307 ; Read the hours from DS1307 (result is in W and Data_Buf) movwf oldHour ; and store it in oldHour (to track hour changes) movlw 0x14 ; RAM location in clock where blankStart values is stored movwf Mem_Loc ; Put it into Mem_Loc call ReadDS1307 ; Read the vlaue from DS1307 (result is in W and Data_Buf) movwf blankStart ; and store it in blankStart (to track tube blanking) incf Mem_Loc,f ; Increment to 0x15 where blankEnd is stored call ReadDS1307 ; Read the value from DS1307 (result is in W and Data_Buf) movwf blankEnd ; and store it in blankEnd (to track tube blanking) clrf LeftDP ; Clear all left decimal places clrf RightDP ; Clear all right decimal places call FillBlanks ; Blank the tubes before powering up high voltage. call Loader ; Load blanks into tube drivers bsf ShadowB,NBL ; set NOT Blanking high (tubes no longer blanked) while I'm at it, bsf ShadowB,HVE ; and Set High Voltage Enable ON to display the tubes now, too. movfw ShadowB ; Copy ShadowB... movwf PORTB ; ...to PORTB ;End Init goto GetTime ; Start in clock mode. PreLoad movlw d'1' ; Load up Steins Gate worldline number movwf T7 movlw d'10' movwf T6 movlw d'0' movwf T5 movlw d'4' movwf T4 movlw d'8' movwf T3 movlw d'5' movwf T2 movlw d'9' movwf T1 movlw d'6' movwf T0 clrf LeftDP ; Clear all left decimal places clrf RightDP ; Clear all right decimal places bsf RightDP,6 ; Set right decimal point on for Tube 6 bsf ShadowB,NBL ; set NOT Blanking high (tubes no longer blanked) while I'm at it, bsf ShadowB,HVE ; and Set High Voltage Enable ON to display the tubes now, too. movfw ShadowB ; Copy ShadowB... movwf PORTB ; ...to PORTB call Loader ; Display the above numbers into the tubes. MainLoop ; Main work loop here movlw d'3' ; Set brightness value movwf bright ; bcf Eflag,negWL ; This bit only gets set for negative world lines call Buttons ; Call routine that watches the buttons btfsc Flag,short1 ; If there was a short press of Button 1... goto funtime ; ...go to tube animation fun. btfsc Flag,long1 ; If there was a long press of Button 1... goto WorldLines ; ...go oto preset sequence of World Lines goto GetTime ; We get here is 2 was pressed. Go to Time display. funtime call Fun ; Roll a random world line number with animation. goto MainLoop ; WorldLines clrf pointer ; Display world lines from anime and visual novel: movlw d'0' ; Start with the W.L. number we first see in the anime, movwf T7 ; then get to the next ones using tube runtimes that movlw d'10' ; are stored in EEPROM staring at 0x00 movwf T6 movlw d'3' movwf T5 movlw d'3' movwf T4 movlw d'7' movwf T3 movlw d'1' movwf T2 movlw d'8' movwf T1 movlw d'7' movwf T0 call Loader ; Display the above numbers into the tubes. ; We will get subsequent run lengths from EEPROM to reach next world lines loiter call Buttons ; Call routine that watches the buttons btfsc Flag,short1 ; If there was a short press of Button 1... goto WLnext ; ...go to the next world line btfsc Flag,long1 ; If there was a long press of Button 1... goto GetTime ; ...go to Clock display goto OwnTime ; We get here is 2 was pressed. Go to Enter Your Own Number WLnext movlw d'8' ; Going to get 8 tube runtimes from EEPROM movwf GenCount ; Use the general counter from the Clock I/O routines (it's free) movlw TR7 ; ADDRESS of tube 7 runtime register movwf FSR ; for indirect addressing. moreTRn bsf STATUS,RP0 ; Bank 1 movfw pointer ; Address to read... movwf EEADR ; ...gets put here. bsf EECON1,RD ; EE Read movfw EEDATA ; W = EEDATA bcf STATUS,RP0 ; Bank 0 movwf INDF ; Put runtime into register TRn incf pointer,f ; Increment for next EEPROM location decf FSR,f ; Decrement for next TR register decfsz GenCount,f ; All 8 done? goto moreTRn ; No. Keep filling TRn values movlw 0x78 ; Yes. See if this is the last world line in EEPROM (it's the negative one) subwf pointer,w ; If we are out of numbers, zero flag will be set by this subtraction btfsc STATUS,Z ; Zero bit set? bsf Eflag,negWL ; Yes. Flag the negative world line number call animate ; No. Roll the tubes! movlw 0x78 ; See if we have run out of our numbers in EEPROM subwf pointer,w ; If we are out of numbers, zero flag will be set by this subtraction btfss STATUS,Z ; Zero bit set? goto loiter ; No. Go wait for buttons to activate next number. goto MainLoop OwnTime call FillBlanks ; Routine to let you enter any number manually. Start with blanks. movlw T7 ; ADDRESS of T7 movwf pointer ; pointer will track the tube address nextDigi movfw pointer ; Use pointer movwf FSR ; to set indirect address clrf INDF ; Zero tube Tn more call Loader ; Display the number movfw pointer ; Loader destroys FSR, so use pointer movwf FSR ; to set indirect address again call Buttons ; Wait for buttons btfsc Flag,short1 ; If there was a short press of Button 1... goto incDigi ; ...go increment the digit btfsc Flag,long1 ; If there was a long press of Button 1... goto decDigi ; ...go decrement the digit ; We get here is 2 was pressed. Go to next digit (after seeing if we are done) decf pointer,f ; decrement pointer for next tube movlw RightDP ; ADDRESS of RightDP (the register below T0) subwf pointer,w ; If all tubes are full, this subtraction sets Zero flag btfsc STATUS,Z ; goto doneDigits ; movlw T6 ; ADDRESS of tube 6 subwf pointer,w ; Check to see if we are at tube 6 (if so, we want to skip it) btfsc STATUS,Z ; decf pointer,f ; Skips tube 6 goto nextDigi ; call Loader ; doneDigits movlw d'8' ; Going to blink 4 times (4 off, 4 on ...so 8 here) movwf GenCount ; using this counter blinkies movlw b'00001000' ; xorwf ShadowB,f ; movfw ShadowB ; movwf PORTB ; movlw d'10' ; Value for blink delay movwf work ; blinkie2 call delay100 ; decfsz work,f ; goto blinkie2 ; decfsz GenCount,f ; goto blinkies ; call moveNumber ; Copy the user's number from T0-T7 to V0-V7 waitin call Buttons ; Wait for any button btfsc Flag,short1 ; See if button 1 was pressed... goto spinOwn ; and if it was, spin the user's world line number. goto GetTime ; Otherwise, Finished with world line playing. Go Clock mode. spinOwn movlw b'01000000' ; Toggle the flag xorwf Eflag,f ; btfss Eflag,toggl ; goto myWorld ; call Fun ; Animate random world line goto waitin ; myWorld call Fun2 ; Animate that ends in number in V0-V7 goto waitin ; incDigi incf INDF,f ; movlw d'11' ; See if we have overrun to 11 (10 is allowed for blank tube) subwf INDF,w ; This subtraction will set Zero flag if we go to 11 btfsc STATUS,Z ; clrf INDF ; ...and if we do, we clear the digit goto more ; And we go for more inc/dec decDigi movfw INDF ; Load the tube value so we can check for zero btfsc STATUS,Z ; goto zipDigi ; Digit is zero, go set it to 10 decf INDF,f ; Decrement and go for more inc/dec goto more ; zipDigi movlw d'10' ; Tube was 0, so set to 10 (blank) movwf INDF goto more ; go for more inc/dec GetTime ; Time Display from DS1307 Clock Chip. movfw brightSet ; set brightness from brightSet value for clock display movwf bright ; wait123 btfsc PORTA,SW2 ; Wait for SW2 release goto wait123 ; call deBounce ; movlw d'10' ; Make Tubes 2 and 5 display no digit movwf T2 movwf T5 ReadSec bcf Flag,Slide call deBounce ; A little tube display time here (with dimming). clrf Mem_Loc ; Memory location of the seconds register of the DS1307 is 00h call ReadDS1307 ; Now let's read the seconds register from DS1307 (Mem_Loc still zero) ; Will return with seconds reg in W and Data_Buf andlw b'00001111' ; AND the W reg so only single digit of seconds (in BCD) remains subwf T0,w ; See if seconds value has changed... btfss STATUS,Z ; ...Z will be set if seconds has NOT changed goto NewSec ; ...so if Z is clear, handle the new second. call deBounce ; ...otherwise deBounce (for displaying time) and check the buttons. btfsc PORTA,SW1 ; Switch 1 pressed? goto pressed1 ; ...yes, go handle it. btfsc PORTA,SW2 ; Switch2 pressed? goto pressed2 ; ...yes, go handle it. goto ReadSec ; Neither button pressed. Go read seconds Clock again. pressed1 btfss ShadowB,HVE ; Are tubes blanked by High Voltage turned off? goto unblankem ; yes, go unblank them. Otherwise... btfsc PORTA,SW1 ; SW1 was pressed...(go back to D.M. display after release of SW1). goto pressed1 ; Waiting for release call deBounce ; goto PreLoad ; And off we go to the D.M. display. pressed2 btfss ShadowB,HVE ; Are tubes blanked by High Voltage turned off? goto unblankem ; yes, go unblank them. Otherwise... goto GetDate ; Go display date unblankem bsf ShadowB,HVE ; Set High Voltage Enable ON to display the tubes now. movfw ShadowB ; Copy ShadowB... movwf PORTB ; ...to PORTB wait456 btfsc PORTA,SW1 ; Wait for SW1 release goto wait456 ; goto GetTime ; (it will wait for SW2 release, and will deBounce) NewSec ; call deBounce ; First a little displaying time here. movfw Data_Buf ; Bring the seconds register's value into W. andlw b'00001111' ; AND the W reg so only the ones digit of seconds (in BCD) remains movwf T0 ; Put it into register for Tube 0 (rightmost) swapf Data_Buf,w ; Get the seconds tens digit by swapping nybbles from Data_Buf... andlw b'00001111' ; ...and keeping only the right nybble movwf T1 ; Put it in Tube 1 movfw Data_Buf ; Get the full seconds value again. sublw b'00110000' ; See if it's 30 (that's BCD) btfsc STATUS,Z ; If it is 30, the subtraction will set the Zero flag goto _30sec movfw Data_Buf ; Get the full seconds value again. sublw b'01011001' ; See if it's 59 (that's BCD) btfsc STATUS,Z ; If it is 59, the subtraction will set the Zero flag goto _00sec goto minutes ; ...otherwise we jump to the minutes. _30sec movlw d'40' ; Spin the digits and then get the date. movwf GenCount ; We will spin through n iterations of incrementing the tubes. clrf T2 ; Let the blank tubes play as well. clrf T5 ; clrf T7 ; ...and T7, too, in case I blanked leading zero of hours clrf LeftDP ; Clear the decimal points clrf RightDP nextSet movlw T0 ; ADDRESS of T0 movwf FSR ; for indirect addressing. nextTubeA incf INDF,f ; Increment the tube value movlw d'10' ; See if it went over 9 subwf INDF,w ; btfsc STATUS,C ; If new tube value <10, C=0 clrf INDF ; so clear bak to zero if it reached 10. incf FSR,f ; Increment to do next tube movlw TR0 ; ADDRESS of register above T7 subwf FSR,w ; FSR minus TR0 address btfss STATUS,Z ; If we incremented all the tubes, Z will be clear goto nextTubeA ; ...if clear, go increment next tube call Loader ; ...otherwise, Display call deBounce decfsz GenCount,f ; See if we are done spinning goto nextSet ; ...so if it's clear, go spin more goto GetDate ; Go display date. _00sec call FillBlanks bsf Flag,Slide call Loader call deBounce goto minutes ; WHY IS THIS HERE? minutes incf Mem_Loc,f ; Increment memory location to get minutes call ReadDS1307 ; andlw b'00001111' ; AND the W reg so only single digit of minutes (in BCD) remains movwf T3 ; Put it into register for Tube 3 swapf Data_Buf,w ; Get the minutes tens digit by swapping nybbles from Data_Buf... andlw b'00001111' ; ...and keeping only the right nybble movwf T4 ; Put it in Tube 4 hours incf Mem_Loc,f ; Increment memory location to get hours call ReadDS1307 ; andlw b'00001111' ; AND the W reg so only single digit of hours (in BCD) remains movwf T6 ; Put it into register for Tube 6 swapf Data_Buf,w ; Get the hours tens digit by swapping nybbles from Data_Buf... andlw b'00001111' ; ...and keeping only the right nybble movwf T7 ; Put it in Tube 7 btfss Flag,Clk12 ; See if 12 or 24 hour preference goto _do24 ; If flag is clear, 24 hour _do12 movfw T6 ; Get hours ones into W btfsc T7,0 ; See if bit 0 set (it will be if hour is 10-19) addlw d'10' ; ...if so, add 10 btfsc T7,1 ; See is bit 1 set (it will be if hour is 20-23) addlw d'20' ; ...if so, add 20 movwf n ; Now we have binary hours in W, and I'll save it in n bcf Flag,APnow ; Clear this bit means AM sublw d'11' ; See if hours<=11 btfsc STATUS,C ; ...if it is, C=1 goto AM ; ...and we jump bsf Flag,APnow ; It's PM, so set the flag to remember this movlw d'12' ; Subtract 12 from... subwf n,f ; ...the binary hours, and leave it in n (now 0 to 11) AM ; AM & PM calculated the same from here movfw n ; Move binary hours to W btfsc STATUS,Z ; If binary hours is zero, Z=1 goto zerohr ; ...and if so, we need to change the zero to 12 movlw d'10' ; subwf n,w ; See if binary hours<10 btfss STATUS,C ; ...if it is, C=0 goto under10 ; ..and we jump movwf T6 ; We are here if n>=10, and n-10 is still in W, so put it in T6 movlw d'1' ; and put a one in T7 movwf T7 ; goto done12 ; under10 movfw n ; n<10, so put n in T6 movwf T6 ; movlw d'10' ; and put 10 in T7 to blank it movwf T7 ; goto done12 ; zerohr movlw d'1' ; Put a 1 in T7 movwf T7 movlw d'2' ; Put a 2 in T6 movwf T6 done12 _do24 decimalpts clrf LeftDP ; Clear all left decimal places clrf RightDP ; Clear all right decimal places movlw b'00100100' ; Set decimal points btfss T0,0 ; See if seconds digit is odd or even goto evenSec movwf RightDP ; Set decimal points goto showTime evenSec movwf LeftDP ; ...or set other decimal points showTime movfw oldHour ; Before we display the time, let's do the top-of-the-hour check. Data_Buf still holds hours (BCD). Compare with oldHour. subwf Data_Buf,w ; btfsc STATUS,Z ; If the current Hour is the same as the oldHour value (subtraction is zero)... goto showTime2 ; ...continue with showing the time. TOPofHOUR movfw Data_Buf ; ...but if they were NOT the same, we get here. First, set oldHour to the current Hour value movwf oldHour ; subwf blankStart,w ; btfss STATUS,Z ; See if Hour is same as blankStart hour goto notBlnkSt ; ...if not, jump bcf ShadowB,HVE ; ...if so, blank the tubes by turning off the high voltage movfw ShadowB ; copy ShadowB to PORTB movwf PORTB notBlnkSt movfw Data_Buf ; subwf blankEnd,w ; btfss STATUS,Z ; See if Hour is same as blankEnd hour goto notBlnkEnd ; ...if not, jump bsf ShadowB,HVE ; ...if so, UN-blank the tubes by turning on the high voltage movfw ShadowB ; copy ShadowB to PORTB movwf PORTB ; NOTE that if the same hour is set to blank and unblank, it will do both...and remain unblanked. notBlnkEnd movfw timeAdj ; See if time Adj has been set (will be non-zero) btfsc STATUS,Z ; goto HourRoll ; If not (timeAdj=0) skip the handler decfsz hourCount,f ; If so, handle the time adjustment check goto HourRoll ; If the hour counter has not reached zero, do the normal doAdjust movwf hourCount ; If it has reached zero, do the adjustment. Begin by resetting the hourCount (as long as I have timeAdj in W now) clrf Mem_Loc ; Memory location of the seconds register of the DS1307 is 00h waitForOne call ReadDS1307 ; Now let's read the seconds register from DS1307 (Mem_Loc still zero). Will return with seconds reg in W and Data_Buf btfss Data_Buf,0 ; Wait until we hit 1 second goto waitForOne ; movlw d'2' ; If we are slow, jump ahead to 2 seconds after btfsc timeFast,0 ; But if we are fast, clear to 0 seconds after clrf Data_Buf ; by clearing Data_Buf back to zero seconds. call WriteDS1307 ; Write the value to the seconds register. We have jumped back or ahead by one second. HourRoll call moveNumber ; Top of the hour, so do a Divergence Meter style roll. movlw d'2' ; movwf V0 ; call Fun2 ; movfw brightSet ; set brightness from brightSet value for clock display movwf bright ; goto showTime2 showTime2 call Loader ; Display number call deBounce ; Wait a bit goto ReadSec ; Go read seconds from Clock again. GetDate movlw 0x04 ; Memory location of Date (days) in DS1307 movwf Mem_Loc ; call ReadDS1307 ; Read the date andlw b'00001111' ; AND the W reg so only single digit of date remains movwf T3 ; Put days ones digit in Tube 3 swapf Data_Buf,w ; Get the date (days) tens digit by swapping nybbles from Data_Buf... andlw b'00001111' ; ...and keeping only the right nybble movwf T4 ; Put it in Tube 4 incf Mem_Loc,f ; Increment Mem_Loc for Month register call ReadDS1307 ; Read the month andlw b'00001111' ; AND the W reg so only single digit of month remains movwf T6 ; Put months ones digit in Tube 6 swapf Data_Buf,w ; Get the month tens digit by swapping nybbles from Data_Buf... andlw b'00001111' ; ...and keeping only the right nybble movwf T7 ; Put it in Tube 7 incf Mem_Loc,f ; Increment Mem_Loc for Year register call GetT1T0b ; Since the year goes in T1 & T0, I can use this subroutine to load it. movlw d'10' ; Make sure Tubes 2 and 5 are blank movwf T2 ; movwf T5 ; clrf LeftDP ; Clear all left decimal places clrf RightDP ; Clear all right decimal places btfss dateDMY,0 ; See if they prefer DD MM YY format goto release2a ; If not, skip next part movfw T7 ; If so, do the swap movwf n ; store temporarily in n and m movfw T6 ; movwf m ; movfw T4 ; movwf T7 ; T4 now in T7 movfw T3 ; movwf T6 ; T3 now in T6 movfw n ; movwf T4 ; T7 now in T4 movfw m ; movwf T3 ; T6 now in T3 release2a btfsc PORTA,SW2 ; Wait for relese of SW2 (that got us here) goto release2a ; Still waiting call Loader ; display the date call deBounce ; Debounce from release of SW2 movlw d'120' ; Show date for this many deBounce times movwf Counter ; (With deBounce Delay2=30 and Counter=120, about 3 seconds) watch2a btfsc PORTA,SW2 ; Switch2 pressed again (to get to Settings)? goto Settings ; ...yes. Go handle Settings. btfsc PORTA,SW1 ; Switch1 pressed (to go set brightness)? goto SetBright ; ...yes. Go set brightness. call deBounce ; Wait some (tubes get dimmed during wait by deBounce) decfsz Counter,f ; Done counting? goto watch2a ; ...still counting. Go wait more. goto ReadSec ; Done counting. Go read seconds again. Settings call FillBlanks ; Blank the tubes bsf LeftDP,2 ; Set decimal point in tube 2 ; VERSION NUMBER GOES BELOW ************************** movlw d'1' ; Ones digit of version number. movwf T3 movlw d'0' ; Tenths digit of ersion number. movwf T1 movlw d'5' ; Hundredths digit of version number. movwf T0 call Loader ; display version number Settings2 btfsc PORTA,SW2 ; Wait for release of SW2 goto Settings2 call deBounce clrf LeftDP SetHours call FillBlanks ; Blank the tubes movlw d'0' ; Put setting number in Tubes 6 & 7 movwf T7 movlw d'1' movwf T6 movlw 0x02 ; Address of hours reg in DS1307 call GetT1T0 ; Subroutine gets value from Clock reg and puts into T1 & T0 call Loader ; display: 01____hh Where hh is hours clrf incMin ; Minimum hour setting is 00 (24-hour clock)...packed BCD movlw b'00100011' ; Maximum hour setting is 23...packed BCD movwf incMax ; call Increment ; Call routine to increment/decrement setting (returns when Button 2 pressed) call WriteDS1307 ; Write the new hour register value back to DS1307 SetMins movlw d'2' ; Put setting number in Tube 6 (still has 0 in T7) movwf T6 movlw 0x01 ; Address of minutes reg in DS1307 call GetT1T0 ; Subroutine gets value from Clock reg and puts into T1 & T0 call Loader ; display: 02____mm Where mm is minutes movfw Data_Buf ; Get the minute number... movwf oldMin ; ...and put it here so we can tell if it gets changed. clrf incMin ; Minimum minute setting is 00...packed BCD movlw b'01011001' ; Maximum minute setting is 59...packed BCD movwf incMax ; call Increment ; Call routine to increment/decrement setting (returns when Button 2 pressed) movfw oldMin ; Get the old minutes setting... subwf Data_Buf,w ; ...to see if it was changed to something different. btfsc STATUS,Z ; If there was no change Zero bit will be set goto noMinChange ; and we want to leave without writing any changes (we care, since seconds get reset, too). call WriteDS1307 ; Write the new minute register value back to DS1307 clrf Mem_Loc ; Address of seconds register is 0x00 clrf Data_Buf ; We will clear the seconds register as we set minutes call WriteDS1307 ; noMinChange ; Set1224 movlw d'3' ; Put setting number in Tube 6 (still has 0 in T7) movwf T6 loop1224 movlw b'00010010' ; We might want 12-hour time (that's 12 in packed BCD)... btfss Flag,Clk12 ; movlw b'00100100' ; But if the Clk12 flag is not set, want 24 hour time (that's 24 in packed BCD) movwf Data_Buf ; ...and we'll display whichever call FillT1T0 ; Use the entry point that reads nothing from the Clock. call Loader ; display: 03____12 or 03____24 call Buttons ; btfsc Flag,short2 ; If the Button 2 was pressed... goto done1224 ; ...go finish up this setting movlw b'10000000' ; ...otherwise, button 1 was pressed (short? long? don't care), so toggle the xorwf Flag,f ; ...setting for the 12/24 preference goto loop1224 ; Go for more toggling done1224 movlw d'1' ; When done, write the setting to EEPROM. (Babby's first EEPROM write!) btfss Flag,Clk12 ; Make W=1 if Clk12 flag is set, or W=0 if Clk12 flag is clear clrw ; (This clears W to 0 if bit was clear.) bsf STATUS,RP0 ; Bank 1 movwf EEDATA ; Moves number to be witten into EEDATA movlw 0x7F ; Move EEPROM address to be written to... movwf EEADR ; ...into EEADR. bsf EECON1,WREN ; Enable write movlw 0x55 ; movwf EECON2 ; Write 55h movlw 0xAA ; movwf EECON2 ; Write AAh bsf EECON1,WR ; Set WR bit ; begin write. I won't waitfor it to end because I won't mess with it anytime soon. bcf STATUS,RP0 ; Bank 0 SetDays movlw d'4' ; Put setting number in Tube 6 (still has 0 in T7) movwf T6 movlw 0x04 ; Address of date reg in DS1307 call GetT1T0 ; Subroutine gets value from Clock reg and puts into T1 & T0 call Loader ; display: 04____dd Where dd is days part of date movlw b'00000001' ; Minimum day setting is 01...packed BCD movwf incMin ; movlw b'00110001' ; Maximum day setting is 31...packed BCD movwf incMax ; (I'm not going to try to stop fools from setting Feb 31 or some such shit) call Increment ; Call routine to increment/decrement setting (returns when Button 2 pressed) call WriteDS1307 ; Write the new days register value back to DS1307 SetMonth movlw d'5' ; Put setting number in Tube 6 (still has 0 in T7) movwf T6 movlw 0x05 ; Address of month reg in DS1307 call GetT1T0 ; Subroutine gets value from Clock reg and puts into T1 & T0 call Loader ; display: 05____MM Where MM is months movlw b'00000001' ; Minimum month setting is 01...packed BCD movwf incMin ; movlw b'00010010' ; Maximum month setting is 12...packed BCD movwf incMax ; call Increment ; Call routine to increment/decrement setting (returns when Button 2 pressed) call WriteDS1307 ; Write the new month register value back to DS1307 SetYear movlw d'6' ; Put setting number in Tube 6 (still has 0 in T7) movwf T6 movlw 0x06 ; Address of year reg in DS1307 call GetT1T0 ; Subroutine gets value from Clock reg and puts into T1 & T0 call Loader ; display: 06____YY Where YY is the year movlw b'00000000' ; Minimum year setting is 00...packed BCD movwf incMin ; movlw b'10011001' ; Maximum year setting is 99...packed BCD movwf incMax ; call Increment ; Call routine to increment/decrement setting (returns when Button 2 pressed) call WriteDS1307 ; Write the new year register value back to DS1307 SetDateFormat movlw d'7' ; Put setting number in Tube 6 (still has 0 in T7) movwf T6 clrw ; Clear W movwf T1 ; Put zero in T1 movfw dateDMY ; Get date DMY setting (0= MM DD YY preferred. 1= DD MM YY preferred) movwf T0 ; Put it in T0 movwf Data_Buf ; Also put the value where Increment routine expects to find it call Loader ; display: 07____0x Where x is 0 or 1 movlw b'00000000' ; Minimum setting is 00...packed BCD movwf incMin ; movlw b'00000001' ; Maximum setting is 01...packed BCD movwf incMax ; call Increment ; Call routine to increment/decrement setting (returns when Button 2 pressed) movfw Data_Buf ; Get the result movwf dateDMY ; Put it into register...then write it to EEPROM bsf STATUS,RP0 ; Bank 1 movwf EEDATA ; Moves number to be witten into EEDATA movlw 0x7D ; Move EEPROM address to be written to... movwf EEADR ; ...into EEADR. bsf EECON1,WREN ; Enable write movlw 0x55 ; movwf EECON2 ; Write 55h movlw 0xAA ; movwf EECON2 ; Write AAh bsf EECON1,WR ; Set WR bit ; begin write. I won't wait for it to end because I won't mess with it anytime soon. bcf STATUS,RP0 ; Bank 0 SetBlankStart movlw d'8' ; Put setting number in Tube 6 (still has 0 in T7) movwf T6 movlw 0x14 ; Address of blankStart reg in DS1307 (I'm storing this in the clock's RAM) call GetT1T0 ; Subroutine gets value from Clock reg and puts into T1 & T0 call Loader ; display: 08____hh Where hh is hour to start tube blanking clrf incMin ; Minimum hour setting is 00 (24-hour clock)...packed BCD movlw b'00100011' ; Maximum hour setting is 23...packed BCD movwf incMax ; call Increment ; Call routine to increment/decrement setting (returns when Button 2 pressed) call WriteDS1307 ; Write the new blankStart value back to RAM in the DS1307 movfw Data_Buf ; And get the value to put it movwf blankStart ; ...into blankStart variable as well. SetBlankEnd movlw d'9' ; Put setting number in Tube 6 (still has 0 in T7) movwf T6 movlw 0x15 ; Address of blankEnd reg in DS1307 (I'm storing this in the clock's RAM) call GetT1T0 ; Subroutine gets value from Clock reg and puts into T1 & T0 call Loader ; display: 09____hh Where hh is hour to end tube blanking clrf incMin ; Minimum hour setting is 00 (24-hour clock)...packed BCD movlw b'00100011' ; Maximum hour setting is 23...packed BCD movwf incMax ; call Increment ; Call routine to increment/decrement setting (returns when Button 2 pressed) call WriteDS1307 ; Write the new blankEnd value back to RAM in the DS1307 movfw Data_Buf ; And get the value to put it movwf blankEnd ; ...into blankEnd variable as well. SetTimeAdjust movlw d'1' ; Put 1 in Tube 7 movwf T7 ; clrf T6 ; Put 0 in Tube 6 movfw timeAdj ; Get the time adjustment value movwf oldMin ; Use oldMin to see if a change is made (at the end) Bin2BCD movfw timeAdj ; Get the time adjustment value movwf T0 ; Put the whole thing into the ones (T0) to start clrf T1 ; Clear tens (T1) clrf T2 ; Clear hundreds (T2) dotens movlw d'10' ; Subtract dec. 10... subwf T0,w ; ...from what remains in the ones. Leave result in W. btfss STATUS,C ; Look to see if we went negative (if there were no more tens left, C will be clear. Yes, really.) goto dohundreds ; If there was no more tens left, jump to doing the hundreds. movwf T0 ; If we did get a ten out, move the subtraction result from W into the ones... incf T1,f ; ...and increment the tens. goto dotens ; ...and we go back to look for more tens. dohundreds movlw d'10' ; Subtract dec. 10... subwf T1,w ; ...from what remains in the tens. Leave result in W. btfss STATUS,C ; Look to see if we went negative (if there were no more hundreds left, C will be clear. Oh, yeah.) goto doneBCD ; If there are no more hundreds, we are done. movwf T1 ; If we did get a hundred, move the subtraction result from W into the tens... incf T2,f ; ...and increment the hundreds. goto dotens ; ...and go look for more hundreds. doneBCD clrf LeftDP ; BCD conversion done, and result is in T0-T2. Set DPs to indicate positive or negative. clrf RightDP ; btfsc timeFast,0 ; timeFast=1 for fast, =0 for slow (negative) goto showBCD ; If fast, go here movlw b'00001000' ; If slow, show DPs movwf LeftDP ; movwF RightDP ; showBCD call Loader call deBounce call Buttons btfsc Flag,short2 ; Exit if button 2 pressed goto exitTASet ; btfsc Flag,short1 ; If short1 press... goto incTAdj ; go increment decTAdj btfss timeFast,0 ; See if timeFast is set goto decSlow ; if not, go decrement negative movfw timeAdj ; See if timaAdj is zero btfsc STATUS,Z ; goto hitzipper ; if so, go here decf timeAdj,f ; if not, normal decrement goto Bin2BCD ; hitzipper clrf timeFast ; We went negative incf timeAdj,f ; increase in the negative direction goto Bin2BCD ; go display decSlow incf timeAdj,f ; If slow, "decrement" goes more negative btfss STATUS,Z ; See if we rolled over goto Bin2BCD ; if not, display bsf timeFast,0 ; if so, make use timeFast=1 at 255 decf timeAdj,f ; backup from 0 to 255. goto Bin2BCD ; go display incTAdj btfss timeFast,0 ; See if timeFast is set goto incSlow ; if not, go increment negative incf timeAdj,f ; Increment btfss STATUS,Z ; See if we incremented 255-->0 goto Bin2BCD ; If not, increment done... go display. decf timeAdj,f ; If so, put it back to 255... clrf timeFast ; and make timeFast flag negative (slow) goto Bin2BCD ; go display incSlow decf timeAdj,f ; If slow, "increment" brings you closer to zero btfss STATUS,Z ; See if we hit zero goto Bin2BCD ; If not, go display bsf timeFast,0 ; If so, set timeFast to 1 (fast) goto Bin2BCD ; go display exitTASet clrf LeftDP clrf RightDP movfw oldMin ; Get the previous value into W subwf timeAdj,w ; See if any change was made btfsc STATUS,Z ; goto noAdjChange ; If there was no change of th setting, jump past all this. movfw timeAdj ; Get the final timeAdj value into W movwf hourCount ; Set the hourCount to the new timeAdj bsf STATUS,RP0 ; Bank 1 movwf EEDATA ; Moves number to be witten into EEDATA movlw 0x7C ; Move EEPROM address to be written to... movwf EEADR ; ...into EEADR. bsf EECON1,WREN ; Enable write movlw 0x55 ; movwf EECON2 ; Write 55h movlw 0xAA ; movwf EECON2 ; Write AAh bsf EECON1,WR ; Set WR bit waitwrite btfsc EECON1,WR ; Wait until write is done goto waitwrite ; movfw timeFast ; Get the final timeFast value into W movwf EEDATA ; Moves number to be witten into EEDATA movlw 0x7B ; Move EEPROM address to be written to... movwf EEADR ; ...into EEADR. bsf EECON1,WREN ; Enable write movlw 0x55 ; movwf EECON2 ; Write 55h movlw 0xAA ; movwf EECON2 ; Write AAh bsf EECON1,WR ; Set WR bit bcf STATUS,RP0 ; Bank 0 noAdjChange SetBright btfsc PORTA,SW1 ; If we got here from Date, SW1 might still be pressed. Wait for release. goto SetBright ; call deBounce ; call FillBlanks ; Blank the tubes (in case I jump directly here) movlw d'1' ; Put setting number in Tubes 6 & 7 movwf T7 movlw d'1' movwf T6 movfw brightSet ; Get brightness preference for clock movwf T0 ; and put it into T0 for display. loopBrSet movfw T0 ; Update bright from T0 as we loop so the effect can be seen movwf bright ; call Loader ; display: 11_____B Where B is brightness 0-7 call Buttons ; btfsc Flag,short2 ; Exit if button 2 pressed goto exitBrSet ; btfsc Flag,short1 ; If short1 press... goto incBrSet ; go increment decBrSet movfw T0 btfss STATUS,Z ; If T0 is zero, allow no decrement decf T0,f ; Otherwise, decrement. goto loopBrSet ; incBrSet incf T0,f ; Increment brightness movlw b'00000111' ; To make sure it stays below 8, do this andwf T0,f ; and thing (it will roll to zero). goto loopBrSet ; exitBrSet movfw T0 ; Get the brightness movwf brightSet ; bsf STATUS,RP0 ; Bank 1 movwf EEDATA ; Moves number to be witten into EEDATA movlw 0x7E ; Move EEPROM address to be written to... movwf EEADR ; ...into EEADR. bsf EECON1,WREN ; Enable write movlw 0x55 ; movwf EECON2 ; Write 55h movlw 0xAA ; movwf EECON2 ; Write AAh bsf EECON1,WR ; Set WR bit ; begin write. I won't wait for it to end because I won't mess with it anytime soon. bcf STATUS,RP0 ; Bank 0 ; End of settings. goto GetTime ; ; initialize eeprom locations ORG 0x2100 DE 0x32, 0x00, 0x15, 0x11, 0x3E, 0x45, 0x23, 0x36 DE 0x47, 0x00, 0x11, 0x2B, 0x3D, 0x18, 0x27, 0x37 DE 0x3B, 0x00, 0x22, 0x18, 0x33, 0x38, 0x28, 0x44 DE 0x32, 0x00, 0x32, 0x14, 0x1E, 0x28, 0x1D, 0x3D DE 0x28, 0x00, 0x28, 0x0F, 0x34, 0x20, 0x12, 0x40 DE 0x32, 0x00, 0x31, 0x17, 0x35, 0x1B, 0x29, 0x40 DE 0x28, 0x00, 0x28, 0x0F, 0x35, 0x37, 0x16, 0x1B DE 0x32, 0x00, 0x27, 0x17, 0x1C, 0x39, 0x42, 0x25 DE 0x3C, 0x00, 0x1F, 0x11, 0x16, 0x3F, 0x37, 0x22 DE 0x3C, 0x00, 0x32, 0x23, 0x11, 0x19, 0x26, 0x3F DE 0x3C, 0x00, 0x15, 0x25, 0x11, 0x22, 0x31, 0x3F DE 0x3C, 0x00, 0x1E, 0x37, 0x12, 0x11, 0x2C, 0x45 DE 0x47, 0x00, 0x10, 0x1A, 0x31, 0x20, 0x24, 0x31 DE 0x3C, 0x00, 0x59, 0x79, 0x94, 0xB7, 0xD1, 0xF1 DE 0x1D, 0x00, 0x3E, 0x21, 0x11, 0x26, 0x37, 0x3F DE 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x05, 0x01 ; Above... ; Tube runtimes for pre-set world line number sequence are in the first 15 lines. ; 12/24-hour time format preference stored in 7F (last location) ; Clock brightness stored in 7E (second-to-last location). ; Date format stored in 7D ; Time adjustment timeAdj value in 7C ; Time adjustment fast or slow timeFast in 7B END ; directive 'end of program'