; ----------------------------------- ; Drehzahlmesser.asm ; ; Steuerprogramm für optischen Drehzahlmesser ; ; Misst über einen Fototransistor die Drehzahl z.B. eines Modellbaumotors ; Kontaktlos, optische Abtastung ; Messung erfolgt durch Auswertung der Zeit zwischen zwei Impulsen via capture Modul mit einer Auflösung von 2,66us ; Einstellbare Anzahl der Impulse pro Umdrehung von 1 bis 4, um z.B. auch mit 2-, 3- oder 4-Blatt ; Luftschrauben ohne Umrechnung zu funktionieren. ; automatische Bereichsumschaltung 0..9999 und 10.000 bis 37.500 ; Handheld-Gehäuse, batteriebetrieben, 4-stelliges 7-segm. Display ; ; (c) Stephan Asmus 06/2019 ; info@sasmus.de ; ; Das Programm oder Teile davon dürfen für private, nicht-kommerzielle ; Anwendungen weiterverwendet werden. ; Der ursprüngliche Autor ist dabei zu erwähnen ; ----------------------------------- ; PIC 16F690 ; ----------------------------------- ; Log: ; 27.06.2019 Start, outline, display & key working ; 30.06.2019 ready, 1st release ; ; ; Used Controller: PIC 16F690 ; Pins & Ports: ; ; Port C: ; 0: Segment g ; 1: Segment f ; 2: Segment e ; 3: Segment a ; Port B: ; 4: Segment d ; 5: Segment c ; 6: Segment b ; 7: Dots ; ; ; RA2: Driver Display 1 ; RC4: Driver Display 2 ; RC6: Driver Display 3 ; RC7: Driver Display 4 ; ; RA3: Switch ; CCP1/RC5: Sensor input ; ; see schematic for more Details ; ; Fosc=12MHz ceramic oscillator LIST P=PIC16F690 #include errorlevel -302 ;No bank select warnings errorlevel -306 ;No page select warnings __config (_HS_OSC & _WDT_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _BOD_OFF & _IESO_OFF & _FCMEN_OFF) ;---------------------------------------------------------------- ;variables w_tmp EQU 0x20 ; used for context saving Register "W" status_tmp EQU 0x21 ; used for context saving Register "Status" pclath_tmp equ 0x22 ; used for context saving Register "PCLATH" pclath_save equ 0x23 ; used to save pclath within computed gotos cblock 0x24 d1 ;Delay-Variable 1 d2 ;Delay-Variable 2 d3 ;Delay-Variable 3 xhi ;for math routines xlo yhi ylo f0 ;used by conversion routines & add24 f1 f2 g0 g1 g2 digit1 ;digits after conversion to BCD digit2 digit3 digit4 digit5 digit6 digit7 digit8 bitcnt ;used by conversion routine digcnt ppu ;pulses per rotation const0 ;holds constant (dividend) for calculating rpm const1 const2 const3 divid0 ;dividend for calculating rpm divid1 divid2 divid3 divis0 ;divisor for calculation rpm divis1 remdrL ;used by division routine remdrH old00 ;old values (used for interpolating) old01 old02 old10 old11 old12 old20 old21 old22 disp1 ; holds 4 Display positions (active on display): left disp2 disp3 disp4 ;right position ;Position of Display (0..3) capture_l ;used to save captured data capture_h tickcounter_l ;counter für ISR loop tickcounter_h keydata ;holds pressed key flags ;holds diverse flags (see definitions) eprom_adr ;eeprom Adress tmp eprom_dat ;eeprom data tmp endc ;---------------------------------------------------------------- ;constants & definitions #define Key PORTA,3 ;Key #define f_high flags,0 ;indicates that frequency is too high #define f_low flags,1 ;indicates that frequency is too low #define config_changed flags,2 ;indicates if config has to be saved to eeprom #define new_value flags,3 ;indicates that a new valid value for rpm arrived ;---------------------------------------------------------------- ;macro definitions ;---------------------------------------------------------------- ;set to Register Bank 0 SET_BANK0 MACRO bcf STATUS, RP0 bcf STATUS, RP1 ENDM ;set to Register Bank 1 SET_BANK1 MACRO bsf STATUS, RP0 bcf STATUS, RP1 ENDM ;set to Register Bank 2 SET_BANK2 MACRO bcf STATUS, RP0 bsf STATUS, RP1 ENDM ;strout Macro to output string on display strout macro stringaddr movlw high stringaddr movwf PCLATH call stringaddr movwf disp1 call stringaddr+1 movwf disp2 call stringaddr+2 movwf disp3 call stringaddr+3 movwf disp4 movlw high $ movwf PCLATH endm ; ********************************************************************** ;Program Start ; ********************************************************************** org 0 goto INIT ORG 0x004 ; interrupt vector location movwf w_tmp ; save off current W register contents swapf STATUS,W ; move status register into W register clrf STATUS ; select Bank 0 movwf status_tmp ; save off contents of STATUS register movf PCLATH,w movwf pclath_tmp clrf PCLATH btfsc PIR1,CCP1IF ;If capture module caused the interrupt... call CCP1_ISR btfsc PIR1,TMR1IF ;If timer 1 overflow... call Timer1_ISR btfsc INTCON,T0IF ; If Timer 0 caused the interrupt, handle it. call Timer0_ISR ; movf pclath_tmp,w movwf PCLATH swapf status_tmp,w ; retrieve copy of STATUS register movwf STATUS ; restore pre-isr STATUS register contents swapf w_tmp,f swapf w_tmp,w ; restore pre-isr W register contents retfie ; return from interrupt ; ********************************************* ; Timer 1 Interrupt handler. ; Timer 1 has overflowed ; ********************************************* Timer1_ISR bsf f_low ;indicate that frequency is too low to measure bcf new_value ;clear other flags bcf f_high clrf TMR1L ;clear timer 1 clrf TMR1H bcf PIR1,TMR1IF ;clear interrupt flag return ; ********************************************* ; CCP1 Interrupt handler. ; CCP1 captured new data ; ********************************************* CCP1_ISR btfss f_low ;if last status was f_low, then ignore this capture to suppress false values bsf new_value ;indicate new value bcf f_high ;clear flag f_high (not checked yet) btfsc f_low ;ignore if previously low goto ccp1_end clrf TMR1L ;clear timer 1 clrf TMR1H movf CCPR1L,w ;save capture data movwf capture_l movf CCPR1H,w movwf capture_h ;now check if frequency is too high movf ppu,w ;get current ppu xorlw d'1' ;check if ppu is 1 skpz goto ccp1_1 movf capture_h,w movwf xhi movf capture_l,w movwf xlo movlw 0x58 movwf ylo movlw 0x02 movwf yhi call compare_unsigned_16 skpnc bsf f_high goto ccp1_end ccp1_1 xorlw d'1'^d'2' ;check if ppu is 2 skpz goto ccp1_2 movf capture_h,w movwf xhi movf capture_l,w movwf xlo movlw 0x2c movwf ylo movlw 0x01 movwf yhi call compare_unsigned_16 skpnc bsf f_high goto ccp1_end ccp1_2 xorlw d'2'^d'3' ;check if ppu is 3 skpz goto ccp1_3 movf capture_h,w movwf xhi movf capture_l,w movwf xlo movlw 0xc8 movwf ylo movlw 0x00 movwf yhi call compare_unsigned_16 skpnc bsf f_high goto ccp1_end ccp1_3 movf capture_h,w movwf xhi movf capture_l,w movwf xlo movlw 0x96 movwf ylo movlw 0x00 movwf yhi call compare_unsigned_16 skpnc bsf f_high ccp1_end btfsc f_high ;f_high set after checks? bcf new_value ;yes, clear flag again (cause it is wrong now) bcf PIR1,CCP1IF ;clear Interrupt-Flag bcf f_low ;clear low flag return ; ********************************************* ; Timer 0 Interrupt handler. ; Timer 0 has overflowed ; ********************************************* Timer0_ISR incf position,f ;next dislay position movlw 0x04 ;already 5? xorwf position,w btfsc STATUS,Z clrf position ;yes, then start at 0 movf position,w xorlw 0x00 skpnz goto is_1 xorlw 0x01^0x00 skpnz goto is_2 xorlw 0x02^0x01 skpnz goto is_3 goto is_4 is_1 bcf PORTC,7 ;that was the last one switched on movf disp1,w movwf PORTB ;and set Port (RB4..RB7) andlw 0x0f ;mask for Rc0..RC3 movwf PORTC ;and set Port bsf PORTA,2 ;switch on transistor goto disp_loaded is_2 bcf PORTA,2 ;that was the last one switched on movf disp2,w movwf PORTB ;and set Port (RB4..RB7) andlw 0x0f ;mask for Rc0..RC3 movwf PORTC ;and set Port bsf PORTC,4 ;switch on transistor goto disp_loaded is_3 bcf PORTC,4 ;that was the last one switched on movf disp3,w movwf PORTB ;and set Port (RB4..RB7) andlw 0x0f ;mask for Rc0..RC3 movwf PORTC ;and set Port bsf PORTC,6 ;switch on transistor goto disp_loaded is_4 bcf PORTC,6 ;that was the last one switched on movf disp4,w movwf PORTB ;and set Port (RB4..RB7) andlw 0x0f ;mask for Rc0..RC3 movwf PORTC ;and set Port bsf PORTC,7 ;switch on transistor disp_loaded incf tickcounter_l,f ;increment low-counter (256 ticks ca. 700msec) skpz ;overflow? goto tmr0end ;no, then end incf tickcounter_h,f ;yes, then increment high-couner (1Tick ca. 700ms) movf tickcounter_h,w xorlw 0x0A ;10 secs over? skpz goto tmr0end ;no, then end ;else... clrf tickcounter_h ;clear counter tmr0end BCF INTCON,T0IF ; Clear Timer0 flag and continue. return ;------------------------------------------------------------------ ;initializes Processor ;------------------------------------------------------------------ INIT SET_BANK1 ;select Register Page 1 clrf TRISA ;Port A all output (RA3 always input) clrf TRISB ;Port B all output clrf TRISC ;Port C all output ;except RC5/CCP1: bsf TRISC,5 ;as an input (CCP1) SET_BANK2 ;configure analog I/O clrf ANSEL ;all digital I/O clrf ANSELH SET_BANK0 ;initialise Timer 0 ;we are in Bank 0... clrwdt ;Routine from Datasheet Microchip clrf TMR0 bsf STATUS, RP0 ;Switch to BANK 1 movlw b'11000100' ;Pullup disable, Prescaler to TMR0, Prescaler 1:32 movwf OPTION_REG SET_BANK0 ;initialise Timer1 movlw b'00110001' ;Prescale 1:8, internal clock, enable timer movwf T1CON clrf TMR1L clrf TMR1H ;initialise capture module movlw b'00000101' ;capture mode, every rising edge movwf CCP1CON ;----now set reasonable values to variables clrf position clrf disp1 clrf disp2 clrf disp3 clrf disp4 clrf tickcounter_l clrf tickcounter_h clrf flags call load_prefs call set_const ;--- SET_BANK1 clrf PIE1 ;all disable bsf PIE1,CCP1IE ;enable CCP1 bsf PIE1,TMR1IE ;enable TMR1 SET_BANK0 clrf TMR0 clrf INTCON ;initialize Interrupts bsf INTCON,T0IE ;enable Timer0 interrupts clrf PIR1 ;clear pending peripheral interrupt flags bsf INTCON,PEIE ;enable peripheral interrupts bsf INTCON,GIE ;enable global interrupts ;now timer 0 & 1 fires ;############################################################################# ;here to start main routine################################################### ;############################################################################# main call keycheck ;key pressed? skpnz ;yes, then handle menu etc goto main1 ;no, then go on call handle_menu ;else goto menu and handle it call waitforrelease ;wait for key release btfsc config_changed ;do we have a new config? call save_prefs ;yes, save it to eeprom call set_const main1 btfss f_low ;indicate message if Flag on goto main2 strout msg_low main2 btfss f_high ;indicate message if Flag on goto main3 strout msg_high main3 btfss new_value ;new valus captured? goto main4 ;no bcf new_value ;clear it movf const0,w ;load constant for division... movwf divid0 movf const1,w movwf divid1 movf const2,w movwf divid2 movf const3,w movwf divid3 movf capture_l,w ;load capture to divisor movwf divis0 movf capture_h,w movwf divis1 call div32by16 ;divide ;now calculate average of last 3 + current value call calculate_average movf g0,w ;prepare conversion to BCD (average in g0:2 movwf f0 movf g1,w movwf f1 movf g2,w movwf f2 call bin2bcd ;convert it movf digit5,w ;>9999? (digit 5 in use?) skpz ;no, then use ones goto main_10er ;else use 10th main_1er movlw high numbers ;send to display movwf PCLATH movf digit4,w call numbers movwf disp1 movf digit3,w call numbers movwf disp2 movf digit2,w call numbers movwf disp3 movf digit1,w call numbers movwf disp4 movlw high $ movwf PCLATH goto main4 main_10er movf digit1,w sublw 4 btfsc STATUS,C ;if clear, then w>=5--> need to round up goto main_10er_1 ;c not clear: w<5, no need to roud up movf digit2,w ;now round up...add carry on ones addlw 0x01 xorlw 0x0A ;overflow to 10? btfsc STATUS,Z bsf STATUS,C ;yes... then remember this xorlw 0x0A btfsc STATUS,C ;if overflow than set digit to 0 movlw 0x00 movwf digit2 btfss STATUS,C ;if set then we need to add 1 to next digit goto main_10er_1 ;else, if clear: nothing more to add bcf STATUS,C movf digit3,w ;add carry on tens addlw 0x01 xorlw 0x0A btfsc STATUS,Z bsf STATUS,C xorlw 0x0A btfsc STATUS,C movlw 0x00 movwf digit3 btfss STATUS,C ;if set then we need to add 1 to next digit goto main_10er_1 ;else, if clear: nothing more to add bcf STATUS,C movf digit4,w ;add carry on hundreds addlw 0x01 xorlw 0x0A btfsc STATUS,Z bsf STATUS,C xorlw 0x0A btfsc STATUS,C movlw 0x00 movwf digit4 btfss STATUS,C ;if set then we need to add 1 to next digit goto main_10er_1 ;else, if clear: nothing more to add bcf STATUS,C movf digit5,w ;add carry on thousands addlw 0x01 xorlw 0x0A btfsc STATUS,Z bsf STATUS,C xorlw 0x0A btfsc STATUS,C movlw 0x00 movwf digit5 main_10er_1 movlw high numbers ;send to display movwf PCLATH movf digit5,w call numbers movwf disp1 movf digit4,w call numbers movwf disp2 bsf disp2,7 ;switch Point on (2nd. digit) movf digit3,w call numbers movwf disp3 movf digit2,w call numbers movwf disp4 movlw high $ movwf PCLATH main4 call Delay100ms ;to make display more stable call Delay100ms goto main ;------------------------------------------------------------------------ ;handle_menu (only function is to change the pulses per rotation) ;------------------------------------------------------------------------ handle_menu strout msg_ppu ;text and current value of ppu to display movlw high numbers movwf PCLATH movf ppu,w call numbers movwf disp1 movlw high $ movwf PCLATH call waitforrelease ;wait for user to leave key call Delay100ms ;debounce hm_1 clrf tickcounter_h ;5 secs to handle input hm_2 movf tickcounter_h,w xorlw d'5' ;already 5? skpnz ;skip if not 5 goto hm_end ;otherwise end ckecking call keycheck ;key pressed? skpnz ;skip if key pressed goto hm_2 ;no key, keep checking movf ppu,w ;get current ppu addlw d'1' ;increase it xorlw d'5' ;already 5? skpnz ;skip if not 5 movlw d'4' ;else set to 4 xorlw d'5' ;which results in the old value if not previously 5, else results in 1 (previously 4) movwf ppu ;save ppu movlw high numbers ;display movwf PCLATH movf ppu,w call numbers movwf disp1 movlw high $ movwf PCLATH bsf config_changed ; we have a new config call waitforrelease ;wait for key release call Delay100ms ;debounce goto hm_1 ;and new 5 secs hm_end return ;then leave menu ;-------------------------------------------------------------------- ;calculate average ;last 3 values and current one ;saves values to old0 ... old2 afterwards for next calculation ;-------------------------------------------------------------------- calculate_average movf divid0,w ;add current value movwf f0 movf divid1,w movwf f1 movf divid2,w movwf f2 movf old00,w ;add to old0 movwf g0 movf old01,w movwf g1 movf old02,w movwf g2 call add24 movf old10,w ;add to old1 movwf f0 movf old11,w movwf f1 movf old12,w movwf f2 call add24 movf old20,w ;add to old2 movwf f0 movf old21,w movwf f1 movf old22,w movwf f2 call add24 bcf STATUS,C ;divide by 4 rrf g2,f rrf g1,f rrf g0,f bcf STATUS,C rrf g2,f rrf g1,f rrf g0,f movf old10,w ;save old values to new position -3 movwf old00 movf old11,w movwf old01 movf old12,w movwf old02 movf old20,w ;save old values to new position -2 movwf old10 movf old21,w movwf old11 movf old22,w movwf old12 movf divid0,w ;save old values to new position -1 movwf old20 movf divid1,w movwf old21 movf divid2,w movwf old22 return ;-------------------------------------------------------------------- ;Math routines ;-------------------------------------------------------------------- ;compare unsigned 16 ;x=y --> Z=1 ;y C=0 ;x<=y --> C=1 ;-------------------------------------------------------------------- compare_unsigned_16 movf xhi,w subwf yhi,w ;y-x skpz ;are they equal? return ;no, then ready ;otherwise compare low movf xlo,w subwf ylo,w ;y-x return ;-------------------------------------------------------------------- ;add24 ;f0:2 + g0:2 ;result in g0:2 ;-------------------------------------------------------------------- add24 movfw f0 ; addwf g0,F ;LS byte movfw f1 ;middle byte skpnc incfsz f1,W addwf g1,F ; movfw f2 ;MS byte skpnc incfsz f2,W addwf g2,F ; return ;-------------------------------------------------------------------- ;divide 32 bits by 16 by Peter Hemsley ;dividend: dividend0...dividend3 ;divisor: divisor0..divisor1 ;-------------------------------------------------------------------- div32by16 movlw d'32' ; 32-bit divide by 16-bit movwf bitcnt clrf remdrH ; Clear remainder clrf remdrL dvloop clrc ; Set quotient bit to 0 ; Shift left dividend and quotient rlf divid0 ; lsb rlf divid1 rlf divid2 rlf divid3 ; lsb into carry rlf remdrL ; and then into partial remainder rlf remdrH skpnc ; Check for overflow goto subd movfw divis1 ; Compare partial remainder and divisor subwf remdrH,w skpz goto testgt ; Not equal so test if remdrH is greater movfw divis0 ; High bytes are equal, compare low bytes subwf remdrL,w testgt skpc ; Carry set if remdr >= divis goto remrlt subd movfw divis0 ; Subtract divisor from partial remainder subwf remdrL skpc ; Test for borrow decf remdrH ; Subtract borrow movfw divis1 subwf remdrH bsf divid0,0 ; Set quotient bit to 1 ; Quotient replaces dividend which is lost remrlt decfsz bitcnt goto dvloop return ;-------------------------------------------------------------------- ;Conversion routines ;-------------------------------------------------------------------- ;-------------------------------------------------------------------- ; Binary to BCD ; input:f0,f1,f2 ; output:digit1..digit8 ; From Peter Hemsley ;-------------------------------------------------------------------- bin2bcd clrf digit1 clrf digit2 clrf digit3 clrf digit4 clrf digit5 clrf digit6 clrf digit7 clrf digit8 movlw d'24' ;24 bits to do movwf bitcnt bitlp rlf f0 ;Shift msb into carry rlf f1 rlf f2 movlw digit1 movwf FSR ;Pointer to digits movlw d'8' ;8 digits to do movwf digcnt adjlp rlf INDF ;Shift digit 1 bit left movlw -d'10' addwf INDF,w ;Check and adjust for decimal overflow skpnc movwf INDF incf FSR ;Next digit decfsz digcnt goto adjlp decfsz bitcnt ;Next bit goto bitlp return ;--------------------------------------------------------------- ;load Prefs ;loads Preferences from internal eeprom if valid config is saved ;in eeprom. Set to default values otherwise ;--------------------------------------------------------------- load_prefs clrf eprom_adr ;read pos 0 =valid-check call eprom_read xorlw 0x55 skpz ;go on if config is valid goto load_prefs_def ;set to defaults otherwise ;config is valid, now load them call read_it movwf ppu goto load_prefs_end load_prefs_def ;set default to prefs movlw 0x01 ;1 pulse per rotation movwf ppu goto load_prefs_end read_it incf eprom_adr,f ;next call eprom_read return load_prefs_end return ;--------------------------------------------------------------- ;save_Prefs ; save Preferences to internal eeprom ;--------------------------------------------------------------- save_prefs clrf eprom_adr ;begin saving at pos 0 movlw 0x55 ;valid config marker movwf eprom_dat call eprom_write movf ppu,w call save_it goto save_prefs_end save_it movwf eprom_dat incf eprom_adr,f call eprom_write return save_prefs_end return ;--------------------------------------------------------------- ;EEPROM handling routines ;--------------------------------------------------------------- ;eprom read: Address in eprom_adr, return value in w ;--------------------------------------------------------------- eprom_read bcf PIR2, EEIF ;clear interrupt flag (necessary?) movf eprom_adr,w ;Set adress of read banksel EEADR movwf EEADR banksel EECON1 bcf EECON1,EEPGD ;we want to read data mem bsf EECON1,RD ;init read banksel EEDATA movf EEDATA,w bcf STATUS,RP0 ;back to bank 0 (our standard) bcf STATUS,RP1 return ;------------------------------------------------------------------------- ;eprom write Address in eprom_adr, data in eprom_dat returns when finished ;------------------------------------------------------------------------- eprom_write bcf PIR2, EEIF ;clear interrupt (to be sure) movf eprom_adr,w ;load Adress banksel EEADR movwf EEADR banksel 0x00 movf eprom_dat,w ;load value banksel EEDATA movwf EEDATA banksel EECON1 bcf EECON1,EEPGD ;we want to write data mem bsf EECON1,WREN ;enable write bcf INTCON,GIE ;we don't want interrupts now btfsc INTCON,GIE ;make sure it is really cleared goto $-2 movlw 0x55 ;see datasheet, required sequence movwf EECON2 movlw 0xaa movwf EECON2 bsf EECON1,WR ;set write bit to begin write bsf INTCON,GIE ;re-enable global interrupts banksel 0x00 ;back to Bank0 (our default) btfss PIR2,EEIF ;wait for flag to be set (polling) goto $-1 bcf PIR2,EEIF ;clear it, write complete banksel EECON1 bcf EECON1,WREN ;clear write enable banksel 0x00 return ;--------------------------------------------------------------- ;key handling ;returns status of keys in w ;0= nothing pressed ;8= key pressed ;--------------------------------------------------------------- ;doesn't wait for anything, just checks current status keycheck movf PORTA,w andlw b'00001000' ;mask bit 3 xorlw b'00001000' ;inverse movwf keydata return ;waits for key to be pressed getkey call keycheck skpnz ;if no key pressed goto getkey ;check again return ;otherwise return to caller ;waits for release of any key waitforrelease call Delay10ms ;debounce call keycheck movf keydata,w skpz ;if zero then enough goto waitforrelease call Delay10ms ;debounce return ;-------------------------------------------------------------------- ;sets correct dividend for given ppu ;-------------------------------------------------------------------- set_const movf ppu,w ;get current ppu xorlw d'1' ;check if ppu is 1 skpz goto sd_1 movlw 0xA0 movwf const0 movlw 0x52 movwf const1 movlw 0x57 movwf const2 movlw 0x01 movwf const3 goto sd_end sd_1 xorlw d'1'^d'2' ;check if ppu is 2 skpz goto sd_2 movlw 0x50 movwf const0 movlw 0xA9 movwf const1 movlw 0xAB movwf const2 movlw 0x00 movwf const3 goto sd_end sd_2 xorlw d'2'^d'3' ;check if ppu is 3 skpz goto sd_3 movlw 0xE0 movwf const0 movlw 0x70 movwf const1 movlw 0x72 movwf const2 movlw 0x00 movwf const3 goto sd_end sd_3 ;we get here if ppu is 4 movlw 0xA8 movwf const0 movlw 0xD4 movwf const1 movlw 0x55 movwf const2 movlw 0x00 movwf const3 sd_end return ;-------------------------------------------------------------------- ;Delay-Subroutines (for fosc=12 MHz!!!) ;-------------------------------------------------------------------- Delay10ms ;Delays ca.10ms movlw 0x6F movwf d1 movlw 0x18 movwf d2 Delay10ms_1 decfsz d1, f goto $+2 decfsz d2, f goto Delay10ms_1 goto $+1 return ;----- Delay100ms ;Delays ca.100ms movlw 0x5F movwf d1 movlw 0xEB movwf d2 Delay100ms_1 decfsz d1, f goto $+2 decfsz d2, f goto Delay100ms_1 goto $+1 return ;######################################################################## org 0x800 ;define next in memory Page 1 (so we have space in Page 0) ;######################################################################## ;--------------------------------------------------------- ;Definitions for Display ;Table is short enough to ensure that no rollover from 0xff to 0x00 happens ;within this table - otherwise the code above has to be modified numbers addwf PCL,f dt 0x7e,0x60,0x5d,0x79,0x63,0x3b,0x3f,0x68,0x7f,0x7b msg_low dt 0x00,0x00,0x16,0x7e msg_high dt 0x00,0x00,0x67,0x60 msg_ppu dt 0x00,0x4f,0x4f,0x76 end