;The Original Analog and Digital Propeller Clock ;Analog and demo modes by Don Zehnder ;Digital code is from Bob Blick's original propellor clock ; ;sx3.asm ;5/10/01 sweep second hand, everything works great. Done? ; ; ;Processor: SX18AC, New version, running at 10 Mhz, in turbo mode ; ;Compared to the PIC16F84 running at 10 Mhz, interrupt frequency is 4X higher. ;This and several other key changes over the PIC version results in ;much less jitter of the hands in the analog mode. ; ;A version of THIS code, written for a PIC at 20 MHz would be almost as good ; ;Note that the SX18AC has only four in/out pins on PORTA, so the ;wiring has been changed to put the inner LEDs of the analog mode ;on an unused pin of PORTB. No longer need the bias resistor on the transistor associated ;with this. Should have done it this way to begin with ; ;Switches modes using a Hall Effect sensor ;mode 0: digital ;mode 1: analog ;mode 2: switches between analog and digital. Demo mode ; ;Assignments on portB, LEDs logic 0 = on. ;BIT LED (from center=0 to edge=6) ;0 0 ;1 1 ;2 2 ;3 3 ;4 4 ;5 5 ;6 6 ;7 inner LEDs logic 0 = on, switched w/ a transistor. ; ;Assignments on portA ;0 index external pull-up (normally high) ;1 outermost LED logic 0 = on, this makes the circle effect in the analog mode ;2 mode switch external pull-up (normally high) ;3 time setting external pull-up (normally high) ;---if doing hardware for the SX only (not for PIC), enable portA pullups, and omit external pullups. ; ;Analog Hands, portB bits: ;hours bit 0,1,2 and 7 ;min bit 0,1,2,3,4 and 7 ;seconds all bits ;10 MHz crystal. Timings given are for 10.00000 Mhz, can adjust for accuracy ;Motor runs counterclockwise at >1150 RPM. Index sensor is triggered at the 3 o'clock position. ;---------------------------------------------------------------------------------------------- include sx_new.inc ;do the FUSE and FUSEX here, since the sx_new.inc file is not properly setup to do it ERRORLEVEL -220 ;don't display "address exceeds range" warning ORG 1010h DATA b'000011001011' ;_FUSE DATA b'000001110011' ;_FUSEX ERRORLEVEL +220 ;restore warning message ;alternate names for some registers TMR0 EQU 01h ;=RTCC, real time clock/counter PORTA EQU 05h ;I/O ports PORTB EQU 06h PCL EQU 02h ;=PC ;******GLOBALS------0x07 to 0x0F of bank 0, 9 locations total--------- flags equ 0x07 ;b2=int, b1=minute, b0=prev_flag, b3=mode_bit, b4=toggle for period_count, b5=index cleared mode equ 0x08 ;0=digital, 1=analog, 2=demo PERIOD_CNT equ 0x09 ;incremented every other interrupt PERIOD equ 0x0A ;stable period after hysteresis calc. COUNTER equ 0x0B ;used to slow time set period_dup equ 0x0C ;copy of period_count safe from interrupt MODE_TIMER equ 0x0D ;for demo mode, counts zsecs until next mode I_CNT equ 0x0E ;Nth counter for incrementing PERIOD_CNT at interrupt DEV equ 0x0F ;*****BANK 0------------- ;----unique to digital--- cblock 0x10 ;-----put in upper 16 bytes (these will be in bank 0)---------- dot_index ;which column is being displayed digit_index ;which digit is being displayed hours ;in display format, not hex(01-12) minutes ;00 to 59 bigtick_dbl ;incremented each interrupt bigtick_hi bigtick_lo scratch ;scratch value tick ;used by delay COUNTER2 ;used as secondary counter to slow time set ADJUST ;fine adjust on timing. See time adjustment notes or spreadsheet ;corrects for observed crystal error to get most accurate time ;----common-------------- mode_debounce ;counters used to control response to mode switch sensor mode_debounce1 endc ;*****BANK 1------------ ;----unique to analog--- cblock 0x10 ;-----put in upper 16 bytes (these will be in bank 1)---------- DIVISOR1 ;these are to count # of interrupts DIVISOR2 ;required to increment ZSEC, decrement DSEC DSEC ;There are 256 DSECs in a minute (1 rev of hands) ZSEC ;When this rolls over, decrement DMIN DMIN ;There are 256 DMINs in an hour (1 rev of hands) ZMIN ;When this rolls over, decrement DHOUR DHOUR ;There are 256 DHOURs in 12 hours (1 rev of hands) mulcnd ; 8 bit multiplicand H_byte ; High byte of the 16 bit result L_byte ; Low byte of the 16 bit result - (unused result) TEMP ; part of routine for setting hands when period=0 HOLDFLAGS ;flags to determine on/off status of hands sec_on_cnt ;counters for number of interrupts since hands were turned on min_on_cnt hour_on_cnt endc ;----ANALOG-------------- #define divisor1_val d'24' ; #define divisor2_val d'216' ; #define zsec_val d'196' ;min hand moves 1/60 fast as sec hand #define zmin_val d'244' ;hour hand moves 1/12 fast as min hand ;-------------------ADJUST AS REQUIRED FOR ACCURACY-make sure to change the corresponding ;-------------------operation to add or subtract as required----------------------------- #define nths_adj_div2 d'125' ;these can be adjusted to correct #define nths_adj_zsec d'16' ;for observed crystal error in analog mode #define nths_adj_zmin d'5' ;time is kept similarly to AN590 ;---------------------------------------------------------------------------------------- #define sec_flag HOLDFLAGS,0 ;Flags that determine if a previously lit hand should stay #define min_flag HOLDFLAGS,1 ;on during the current interrupt. This allows hands to be #define hour_flag HOLDFLAGS,2 ;on longer, appearing brighter and wider...... #define hand_on_cnt_val d'8' ;How many interrupts to keep each hand lit #define sec_on_cnt_val d'1' ;use less for second hand to make it thinner ;-----COMMON------------- #define in_bit PORTA,0 ;using phototransistor connected to ground, externally pulled-up #define time_set PORTA,3 ;Hall-effect, externally pulled-up #define mode_switch PORTA,2 ;Hall-effect, externally pulled-up #define prev_flag flags,0 ;whether or not index sense was detected on prev iteration #define mode_bit flags,3 ;applies to mode 3 (demo) 1=analog, 0=digital #define debounce_val d'50' ;determines how sensitive the mode switching is #define debounce_val2 d'20' ;determines how sensitive the mode switching is from analog display #define DEV_val d'2' ;allowable deviation in PERIOD calculation ;-----DIGITAL------ #define index_cleared flags,5 ;set by "check_index", notifies "display_now" that index was detected ;************PAGE 0******************************** org 0x00 ;interrupt vector ;---------------------------------------------- ;---INTERRUPT ROUTINE-------------------------- Int BANKX 0 ;set to bank 0 to read digital variables ;-------------------------------------- ; Keep digital time-------------------- ; 2343750 interrupts every minute. Increment the bigtick each time. incf bigtick_lo,f btfsc STATUS,Z incf bigtick_hi,f btfsc STATUS,Z incfsz bigtick_dbl,f goto Bigtick_out ;-------- ; here? bigtick has rolled over to zero and one minute has passed. ; reload bigtick and set a flag for the main counter ;-------- movlw 0xdc ;these timings for no prescale movwf bigtick_dbl ;and 10Mhz crystal movlw 0x3c ;not corrected for observed error movwf bigtick_hi movlw 0xba movwf bigtick_lo bsf flags,1 ;notify Keep_time incfsz ADJUST,1 ;make correction every 256 minutes goto Bigtick_out movlw d'0' ;****adjust for accuracy here addwf bigtick_lo,f ;****add or subtact as required Bigtick_out ;-------------------------------- ;analog main time keeping code ;-------------------------------- BANKX 1 ;all analog variables are in bank 1 incfsz DIVISOR1,1 goto exit movlw divisor1_val ;reset DIVISOR1 every time it rolls over movwf DIVISOR1 incfsz DIVISOR2,1 goto exit movlw divisor2_val ;reset DIVISOR2 each time it rolls movwf DIVISOR2 movlw nths_adj_div2 ;adj-roll over earlier (add when sign is negative in time calculation spreadsheet) addwf DIVISOR1,1 ;****MANUALLY CHANGE THIS TO ADD OR SUBTRACT AS REQUIRED decf DSEC,1 ;decrement: reverses direction of display. get here 256 times/minute decfsz MODE_TIMER,1 ;toggle the mode_bit. Determines analog or digital when in demo mode goto no_mode movlw d'25' ;25 ZSECs is about about 6 seconds (25 * 60/256 = 5.859375) movwf MODE_TIMER ;reload it movlw b'00001000' xorwf flags,1 ;mode flag (bit 3) . toggle it. no_mode incfsz ZSEC,1 goto exit movlw zsec_val ;reset ZSEC when it rolls movwf ZSEC movlw nths_adj_zsec subwf DIVISOR1,1 ;****zsec, MANUALLY CHANGE THIS TO ADD OR SUBTRACT AS REQUIRED decf DMIN,1 incfsz ZMIN,1 goto exit movlw zmin_val ;reset ZMIN when it rolls movwf ZMIN movlw nths_adj_zmin subwf DIVISOR1,1 ;****zmin, MANUALLY CHANGE THIS TO ADD OR SUBTRACT AS REQUIRED decf DHOUR,1 exit BANKX 0 ;back to digital bank ;---------NOW take action depending on mode it is in----------- test_mode movf mode,f btfsc STATUS,Z goto i_digital ;if mode=0 movlw d'1' xorwf mode,w btfsc STATUS,Z goto i_analog ;if mode = 1 btfss mode_bit ;mode=2, (demo) goto i_digital ;if mode=2 and bit clear, do digital ;else analog ;-Analog mode-------------- i_analog PAGEX 3 call Check_index ;calling check_index from here rather than in main loop PAGEX 0 ;is a big help in reducing wobble BANKX 1 movlw b'11111111' ;make all outputs high movwf PORTB ;to turn off all the LEDs movf PERIOD,W ;some junk is here to fix problem movwf TEMP ;where hands turn off when PERIOD_CNT is 0 movlw d'2' subwf TEMP,1 ;TEMP=PERIOD-2 ;-start setting hands on the clock based on time in the registers ;seconds-------- movf DSEC,W movwf mulcnd call mpy_F ;do the math->PERIOD x time/256 = H_byte movf H_byte,W ;if H_byte>PERIOD-2 and subwf TEMP,W btfsc STATUS,C goto ng movf PERIOD_CNT,1 ;if PERIOD_CNT=0 turn on LED btfsc STATUS,Z goto sec_on ng movf PERIOD_CNT,W ;compare result of the calculation to PERIOD_CNT xorwf H_byte,W btfss STATUS,Z ;turn on LED if PERIOD_CNT matches calculated value goto not_sec_on sec_on movlw b'00000000' ;this is the pattern for this hand andwf PORTB,1 ;turn it on bsf sec_flag ;set the flag that controls whether or not hand will light on next interrupt clrf sec_on_cnt goto i_min not_sec_on btfss sec_flag ;no math match, but turn on if it it has not timed out yet goto i_min movlw b'00000000' ;this is the pattern for this hand andwf PORTB,1 ;turn it on incf sec_on_cnt,1 movlw sec_on_cnt_val xorwf sec_on_cnt,W btfsc STATUS,Z bcf sec_flag ;clear flag so it won't go on at next interrupt ;minutes-------- i_min movf DMIN,W ;most everything is the same as for seconds movwf mulcnd call mpy_F movf H_byte,W subwf TEMP,W btfsc STATUS,C goto ngm movf PERIOD_CNT,1 btfsc STATUS,Z goto min_on ngm movf PERIOD_CNT,W xorwf H_byte,W btfss STATUS,Z goto not_min_on min_on movlw b'01100000' ;this is the pattern for this hand andwf PORTB,1 ;turn it on bsf min_flag clrf min_on_cnt goto i_hour not_min_on btfss min_flag goto i_hour movlw b'01100000' ;this is the pattern for this hand andwf PORTB,1 ;turn it on incf min_on_cnt,1 movlw hand_on_cnt_val xorwf min_on_cnt,W btfsc STATUS,Z bcf min_flag ;hours------------------------- i_hour movf DHOUR,W ;everything is the same as for minutes movwf mulcnd call mpy_F movf H_byte,W subwf TEMP,W btfsc STATUS,C goto ngh movf PERIOD_CNT,1 btfsc STATUS,Z goto hour_on ngh movf PERIOD_CNT,W xorwf H_byte,W btfss STATUS,Z goto not_hour_on hour_on movlw b'01111000' andwf PORTB,1 bsf hour_flag clrf hour_on_cnt goto end_int not_hour_on btfss hour_flag goto end_int movlw b'01111000' andwf PORTB,1 incf hour_on_cnt,1 movlw hand_on_cnt_val xorwf hour_on_cnt,W btfsc STATUS,Z bcf hour_flag ;-----digital------ i_digital ;don't need to do anything ;------------------ end_int ;increment the counter. Increment the PERIOD_CNT only every Nth interrupt decfsz I_CNT,1 ;if set to 1 then it will increment this interrupt RETI incf PERIOD_CNT,1 movlw d'7' movwf I_CNT ;increment PERIOD_CNT only every Nth ;interrupt. Since hand position can only ;be determined to the nearest interrupt, ;this produces less hand jitter than using ;tmr0 prescale (otherwise period_cnt will overflow at 10Mhz ;and this RPM) go_there RETI ;return from interrupt ;******************************************************************* ;Time, whether sec, min, or hour is kept as a value between 0 to 255, ;and is maintained in DSEC, DMIN and DHOUR ;To scale the time in order to compare to the current value of PERIOD_CNT, ;multiply time*PERIOD and divide by 256, which is just the high ;byte of time*PERIOD result ; ( Fast Version : Straight Line Code ) ; Before calling the subroutine " mpy_F ", the multiplier is PERIOD ; multiplicand is " mulcnd " . The 16 bit result is stored in locations ; H_byte & L_byte. ;******************************************************************* ;**** Define a macro for adding & right shifting ** mult MACRO bit ; Begin macro btfsc PERIOD,bit addwf H_byte,1 rrf H_byte,1 rrf L_byte,1 ENDM ; End of macro ; ***************************** Begin Multiplier Routine mpy_F clrf H_byte clrf L_byte movf mulcnd,W ; move the multiplicand to W reg. bcf STATUS,C ; Clear the carry bit in the status Reg. mult 0 mult 1 mult 2 mult 3 mult 4 mult 5 mult 6 mult 7 retlw 0 ;---------needs a start that is on page 0, top half..... org 0x0FF ;0x100 - 1 ;last location in page 0 top half Start PAGEX 1 goto Start2 ;the real start is on page 1 ;************ PAGE 1**************************************** org 0x200 ;start of page 1 ;--initialize all RAM-digital and analog, ports, and options--------------------- init ;***digital***** movlw 0x12 ;why do clocks always start movwf hours ;at 12:00 ? clrf minutes clrf dot_index clrf digit_index movlw 0xDC movwf bigtick_dbl movlw d'5' movwf COUNTER2 ;****common***** clrf mode ;we will start in mode=0, digital movlw debounce_val ;load debouce counter movwf mode_debounce movlw DEV_val movwf DEV ;****analog******* BANKX 1 ;These are all in bank 1 movlw divisor1_val ;initialize DIVISOR1 movwf DIVISOR1 movlw divisor2_val ;initialize DIVISOR2 movwf DIVISOR2 movlw zsec_val ;and other timekeeping movwf ZSEC ;counters movlw zmin_val movwf ZMIN movlw d'63' ;1/4 of a revolution of hands movwf DHOUR ;ensures that hands start at 12:00 position movwf DSEC movwf DMIN BANKX 0 ;--Ports--- MODE 0x0f ;0x0f is direction, 1=input movlw b'00000000' ;all are output tris PORTB movlw b'00001101' ;porta 0 is index sensor tris PORTA ;porta 3 is timeset, porta 2 is mode switch ;---Timer --- clrf TMR0 ;clear timer movlw b'10011000' ;set up options. no RTCC prescale option ;send w to option. generate warning. retlw 0 ;------------------- ;set_analog for adjusting time ;------------------- Set_analog btfss time_set ;input uses pull-up- normally set goto do_set retlw 0 ;exit if no magnet near do_set decfsz COUNTER,1 ;COUNTER used to take action only every 256 loops retlw 0 ;this slows down time setting movlw d'63' ;reset seconds hand to 12:00 position movwf DSEC ; decf DMIN,1 ;adjust time one minute incfsz ZMIN,1 ;this one goes the other way retlw 0 ;if ZMIN rolls, reset it and decrement DHOUR movlw zmin_val movwf ZMIN decf DHOUR,1 retlw 0 ;**************************************** ;---Digital Code--subs below here ;**************************************** ;-------- ; CHARACTER LOOKUP TABLE ; set=LED off, clear=LED on ;-flipped digits upside down and mirrored Char_tbl addwf PCL,f dt 0x41 ,0x3E ,0x3E ,0x3E, 0x41 dt 0x7F ,0x7E ,0x0 ,0x5E, 0x7F dt 0x4E ,0x36 ,0x3A ,0x3C, 0x5E dt 0x39 ,0x16 ,0x2E ,0x3E, 0x3D dt 0x7B ,0x0 ,0x5B ,0x6B, 0x73 dt 0x31 ,0x2E ,0x2E ,0x2E, 0xD dt 0x79 ,0x36 ,0x36 ,0x56, 0x61 dt 0x1F ,0x2F ,0x37 ,0x38, 0x3F dt 0x49 ,0x36 ,0x36 ,0x36, 0x49 dt 0x43 ,0x35 ,0x36 ,0x36, 0x4F dt 0x7F ,0x7F ,0x49 ,0x49, 0x7F Char_tbl_end ;-------- ; for digital mode. ; change LED pattern based on state of digit_index and dot_index ;-------- Display_now ;******do a delay 1st if this is right after index is detected btfss index_cleared ;check_index sets this flag when index is detected goto not_first bcf index_cleared ; ;Do one delay 1st. To get colon at the 12:00 position ;we make delay=1/64 of a revolution. Since display is ;30 columns wide, putting one delay 1st ensures that ;the colon is always centered at 12:00 movf PERIOD,W ;load W for delay call Delay ;width of digits with this delay clrf dot_index clrf digit_index not_first movlw 0x05 xorwf dot_index,w ;test for end of digit movlw 0xFF ;pattern for blank column btfsc STATUS,Z goto D_lookup_3 ;it needs a blank bcf STATUS,C ;clear carry before a rotate rlf digit_index,w ;double the index because each addwf PCL,f ;takes two instructions D_1min movf minutes,w ;DZ-reversed order of display goto D_lookup ;since my motor is counterclockwise D_10min swapf minutes,w goto D_lookup D_colon movlw 0x0A goto D_lookup D_1hr movf hours,w goto D_lookup D_10hr swapf hours,w goto D_lookup D_nothing retlw 0 D_lookup andlw b'00001111' ;strip off hi bits movwf scratch ;multiply this by 5 for lookup addwf scratch,f ;table base position addwf scratch,f ;is this cheating? addwf scratch,f ;I think not. addwf scratch,f ;I think it is conserving energy! btfss STATUS,Z ;test for zero goto D_lookup_2 ;not a zero movlw 0x04 ;-DZ changes for counterclockwise- 10 hours is now digit 5 xorwf digit_index,w ;-if digit 5 is 0, display blank movlw 0xFF ;this makes a blank LED pattern btfsc STATUS,Z ;test if it is 10 hrs digit goto D_lookup_3 ;it's a trailing zero D_lookup_2 movf dot_index,w ;get column addwf scratch,w ;add it to digit base call Char_tbl ;get the dot pattern for this column iorlw b'10000000' ;set bit 7 (LED OFF), since that is only for inner LEDs in analog mode D_lookup_3 movwf PORTB ;send it to the LEDs movf PERIOD,W ; call Delay ;width of digits with this delay incf dot_index,f ;increment to the next column movlw 0x06 ;6 columns is a digit plus space xorwf dot_index,w ;next digit test btfss STATUS,Z retlw 0 ;not a new digit clrf dot_index ;new digit time incf digit_index,f retlw 0 ;Display_now done. ;-------- ; a short delay routine ;# of cycles in a revolution is PERIOD x 256 x (8), so 1/64th is ; ((256*8)/64)*PERIOD, or 32 x PERIOD (tick) ; ;However, note that as this is being executed, interrupts are occuring, so ;it is not so precise. Therefore we are not doing the full 32*PERIOD cycles ;-------- Delay movwf tick Delay_loop goto $+1 goto $+1 goto $+1 goto $+1 goto $+1 goto $+1 ;each goto $+1 is a 3-cycle delay goto $+1 decfsz tick,f goto Delay_loop retlw 0 ;-------- ; test for magnet and adjust time if needed ;-------- Set_digital btfsc time_set ;input uses pull-up- normally set retlw 0 ;exit if no magnet near decfsz COUNTER,1 ;COUNTER used to take action only every 256 loops retlw 0 ;this slows down time setting decfsz COUNTER2,1 ;COUNTER2 slows things even more retlw 0 movlw d'8' ;adjust to suit for setting speed movwf COUNTER2 ;reset COUNTER2 when it rolls call Inc_mins ;got to here, now adjust time retlw 0 ;-------- ; increment one hour ;-------- Inc_hours movlw 0x12 xorwf hours,w btfsc STATUS,Z goto Inc_hours_12 movlw 0x07 ;this part gets a little sloppy addwf hours,w movlw 0x07 btfss STATUS,DC movlw 1 addwf hours,f retlw 0 Inc_hours_12 movlw 0x01 movwf hours retlw 0 ;-------- ; increment the time based on flags,1 as sent by interrupt routine ; Inc_mins also used by time setting routine ;-------- Keep_time btfss flags,1 ;the minutes flag retlw 0 ;not this time bcf flags,1 ;clear the minutes flag Inc_mins movlw 0x07 ;start incrementing time addwf minutes,w ;add 7 minutes into w btfsc STATUS,DC ;did adding 7 cause digit carry? goto Sixty_mins ;then test for an hour change incf minutes,1 ;otherwise add 1 for real retlw 0 ;and go back Sixty_mins movwf minutes ;save the minutes movlw 0x60 ;test for 60 xorwf minutes,w ;are minutes at 60? btfss STATUS,Z retlw 0 ;no? go back clrf minutes ;otherwise zero minutes goto Inc_hours ;and increment hours ;-------------------- ; Program starts here ;-------------------- Start2 call init ;set variables to nice values and do some other setup things circle call Keep_time ;for digital only, but needs to keep running regardless PAGEX 2 call check_mode PAGEX 1 movf mode,f btfsc STATUS,Z goto digital ;if mode=0 movlw d'1' xorwf mode,w btfsc STATUS,Z goto analog ;if mode = 1, else mode=2 btfss mode_bit goto digital ;if mode=2 and bit clear, do digital ;else analog analog bcf PORTA,1 ;turn on the outer LED for ring effect BANKX 1 call Set_analog BANKX 0 goto circle digital bsf PORTA,1 ;turn OFF the outer LED (no ring effect) PAGEX 3 call Check_index PAGEX 1 call Display_now call Set_digital goto circle ;*********PAGE 2********** org 0x400 ;Page 2 ;-------------------- ; check_mode reads status of the mode switching sensor to increment the mode ;-------------------- check_mode btfsc mode_switch retlw 0 decfsz mode_debounce1,1 ; used to take action only every 256 loops retlw 0 ; this slows down mode switching decfsz mode_debounce,1 ; slows things even more retlw 0 incf mode,1 ;increment_mode movlw d'3' ;resetting to 0 if not 0, 1 or 2 subwf mode,w btfsc STATUS,C clrf mode movlw debounce_val movwf mode_debounce retlw 0 ;**********PAGE 3******************** org 0x600 ; Page 3 ;-------------------------------------- ;Check_index- common to all modes ;-------------------------------------- Check_index btfsc in_bit ;we detect the low-to-high transition goto bit_high bcf prev_flag goto contin ;could return from here, but works better to do the period calculation more often bit_high btfsc prev_flag retlw 0 bsf index_cleared ;clear flag that informs digital's "display_now" to start at the beginning bsf prev_flag movf PERIOD_CNT,w ;make a working copy movwf period_dup ;called period dup clrf PERIOD_CNT ;a fresh start for next rotation movlw 1 movwf I_CNT ;cause PERIOD_CNT to be incremented on this interrupt ; calculate a period that does not dither or jitter ; period will not be changed unless new period is really different contin movf PERIOD,W subwf period_dup,W ;find difference btfss STATUS,C ;carry flag set means no borrow goto Calc_neg ;must be other way subwf DEV,W ;allowable deviation = 3 btfss STATUS,C ;borrow won't skip incf PERIOD,1 ;new value much larger than calc retlw 0 Calc_neg addwf DEV,W ;allowable deviation = 3 btfss STATUS,C ;carry will skip decf PERIOD,1 ;no carry means it must be change movf period_dup,W movwf PERIOD retlw 0 ;----------------------- ;----RESET-------------- ORG 0x07FF reset goto Start ;page bits not set, so start must be on page 0, top half end