; JOY_STIK.ASM ; Calibration routine - start w/fire button ; Two joystick channels ; Third toggle w/fire button ; Jumper select two speed serial (2400/9600) ; 16x16, 32x16 math ; Output formatted for SSC2 ; Delta compression ; PIC 16F84 micro @ 4 Mhz ; Copyright 2001 Mike Berg ; Free for non commercial use ; 06/06/01 ;------------------------------------------------------------ LIST P=PIC16F84 include "P16F84.INC" __CONFIG _XT_OSC & _CP_OFF & _PWRTE_ON & _WDT_OFF ;------------------------------------------------------------- ; Port Set-up ; 0 1 2 3 4 5 6 7 bit ; port A I/O I/O Out Out I/O X X X ; B Out Out In Out Out Out Out In ;------------------------------------------------------------ ORG 0 ; start code goto main ;------------------------------------------------------------ cblock 0x0c ACCa_hi ;math registers ACCa_lo ;ACCa, b, c, d, e ACCb_hi ACCb_lo ACCc_hi ACCc_lo ACCd_hi ACCd_lo ACCe_hi ACCe_lo calA_hi ;calc factor(s) calA_lo ;stored here calB_hi calB_lo axis_x ;post calc data axis_x_mirror axis_y ;post calc data axis_y_mirror flip_flop ;toggled output flip_flop_mirror flags ;port select digit ;aux counter bit_count ;serial bit counter serial_reg ;serial byte bit_length ;(24h) serial speed endc cblock 0x2a maxA_hi maxA_lo minA_hi minA_lo maxB_hi maxB_lo minB_hi minB_lo endc ;------------------------------------------------------------ #define MODE_CHECK PORTB,0 ;lo to calbrate #define SYNC_LED PORTB,1 ;in sync LED #define S_SPEED PORTB,2 ;set = 2k4, clear = 9k6 #define SERIAL_OUT PORTB,7 ;async serial out #define P_FLAG flags,0 ;x or y axis #define X_FLAG flags,5 ;new x data #define Y_FLAG flags,6 ;new y data #define F_FLAG flags,7 ;fire status ;------------------------------------------------------------ DISCHARGE equ b'00000011' ;porta disch cfg AXIS_1 equ b'00010010' ;read axis 1 AXIS_2 equ b'00010001' ;read axis 2 SSC_FLAG equ h'ff' ;SSC2 start flag ;------------------------------------------------------------ main clrwdt bsf STATUS,RP0 ;bank 1 movlw b'00010000' ;A:0-3 outputs movwf TRISA ;set up port A I/O movlw b'00000101' ;B:0,2 inputs movwf TRISB ;set up port B I/O movlw b'10010001' movwf OPTION_REG ;TMR0/4 bcf STATUS,RP0 ;bank 0 clrf INTCON ;int setup clrf PORTA bcf SERIAL_OUT ;stop bit bcf SYNC_LED ;LED off movlw d'25' btfsc S_SPEED ;jumper on, 9600 movlw d'104' ;jumper off, 2400 movwf bit_length ;speed select clrf flags call deb_delay ;------------------------------------------------------------ btfss MODE_CHECK goto stick_cal ; test_ee clrf EEADR ;set to start call eemem_read movfw EEDATA xorlw 0xaa bnz slo_flash incf EEADR,F call eemem_read movfw EEDATA xorlw 0xf0 bnz slo_flash incf EEADR,F movlw 0x2a movwf FSR ;start of MIN/MAX ee_read_loop call eemem_read movfw EEDATA movwf INDF ;fill buffers incf FSR,F incf EEADR,W sublw 0x09 bnc calc_factor incf EEADR,F goto ee_read_loop ; ; calc_factor call x_calc ;calc master divisor movlw d'127' movwf flip_flop_mirror ; ohms bcf SYNC_LED ;LED off bcf P_FLAG ;x axis call meas_r ;result in ACCa_hi,lo movfw ACCa_hi ;more than max ? subwf maxA_hi,W bnc loadx_max ;hi byte < max bnz below_x ;hi byte > max, test min movfw ACCa_lo ;hi byte = max, check lo subwf maxA_lo,W bnc loadx_max ;hi, lo byte < max bz loadx_max ;hi, lo byte = max below_x ;less than min ? movfw ACCa_hi subwf minA_hi,W bnc x_as_is ;hi byte < min, use data bnz loadx_min ;hi byte > min, use stored movfw ACCa_lo ;hi byte = min, check lo subwf minA_lo,W bnc x_as_is ;lo byte < min, use data loadx_min ;lo byte => min, hold at min movfw minA_hi ;hold at stored min movwf ACCa_hi movfw minA_lo movwf ACCa_lo goto x_as_is loadx_max movfw maxA_hi ;hold at stored max movwf ACCa_hi movfw maxA_lo movwf ACCa_lo ; x_as_is movfw ACCa_lo ;prep for math movwf ACCb_lo movfw ACCa_hi movwf ACCb_hi movfw minA_hi movwf ACCa_hi movfw minA_lo movwf ACCa_lo call subtract_16 ;modified result ; clrf ACCc_lo clrf ACCc_hi movfw calA_hi movwf ACCa_hi movfw calA_lo movwf ACCa_lo call divide_32_16 ;1 byte result movfw ACCb_hi movwf axis_x ;store x axis xorlw SSC_FLAG skpnz decf axis_x,F ;hold at 254 ; bsf P_FLAG ;y axis call meas_r ;result in ACCa_hi,lo movfw ACCa_hi ;more than max ? subwf maxB_hi,W bnc loady_max ;hi byte < max, hold at max bnz below_y ;hi byte > max, check min movfw ACCa_lo ;hi byte = max, check lo subwf maxB_lo,W bnc loady_max ;lo byte < max, hold at max bz loady_max ;hi, lo = max, hold at max below_y ;less than min ? movfw ACCa_hi subwf minB_hi,W bnc y_as_is ;hi byte < min, use data bnz loady_min ;hi byte > min, use stored movfw ACCa_lo ;hi byte = min, check lo subwf minB_lo,W bnc y_as_is ;lo byte < min, use data loady_min movfw minB_hi ;lo byte => min, hold at min movwf ACCa_hi movfw minB_lo movwf ACCa_lo goto y_as_is loady_max movfw maxB_hi movwf ACCa_hi movfw maxB_lo movwf ACCa_lo ;hold at max y_as_is movfw ACCa_lo ;prep for math movwf ACCb_lo movfw ACCa_hi movwf ACCb_hi movfw minB_hi movwf ACCa_hi movfw minB_lo movwf ACCa_lo call subtract_16 ;modified result ; clrf ACCc_lo clrf ACCc_hi movfw calB_hi movwf ACCa_hi movfw calB_lo movwf ACCa_lo call divide_32_16 ;1 byte result movfw ACCb_hi movwf axis_y ;store y axis xorlw SSC_FLAG skpnz decf axis_y,F ;hold at 254 ; movlw d'254' movwf flip_flop btfsc MODE_CHECK ;fire button ? clrf flip_flop movlw 0x01 andwf flags,F ;clear delta flags ; movfw axis_x subwf axis_x_mirror,W ;test x axis bz delta_y addlw 0x01 bz delta_y xorlw 0x02 bz delta_y bsf X_FLAG movfw axis_x movwf axis_x_mirror delta_y movfw axis_y subwf axis_y_mirror,W ;test y axis bz delta_f addlw 0x01 bz delta_f xorlw 0x02 bz delta_f bsf Y_FLAG movfw axis_y movwf axis_y_mirror delta_f movfw flip_flop xorwf flip_flop_mirror,W ;test fire button bz check_out bsf F_FLAG movfw flip_flop movwf flip_flop_mirror check_out movlw b'11100000' andwf flags,W bz ohms ;no flags set bsf SYNC_LED ;LED on btfss X_FLAG goto y_load movlw SSC_FLAG movwf serial_reg call serial_tx ;send flag clrf serial_reg call serial_tx ;send channel (0) movfw axis_x movwf serial_reg call serial_tx ;send x axis y_load btfss Y_FLAG goto f_load movlw SSC_FLAG movwf serial_reg call serial_tx ;flag movlw 0x01 movwf serial_reg call serial_tx ;channel movfw axis_y movwf serial_reg call serial_tx ;send y axis f_load btfss F_FLAG goto ohms movlw SSC_FLAG movwf serial_reg call serial_tx ;send flag movlw 0x02 movwf serial_reg call serial_tx ;send channel movfw flip_flop movwf serial_reg xorlw 0xff skpnz decf serial_reg,F ;hold at 254 call serial_tx ;send position goto ohms ; ;------------------------------------------------------------ stick_cal movlw 0xff ;preset registers movwf minA_hi ;255 movwf minA_lo movwf minB_hi movwf minB_lo clrf maxA_hi ;0 clrf maxA_lo clrf maxB_hi clrf maxB_lo btfss MODE_CHECK goto $-1 ;wait for button off call deb_delay ;debounce find_min_max btfss MODE_CHECK goto store_this ;check for done ; bcf P_FLAG ;x axis call meas_r ;yes, get resistance movfw ACCa_hi ;test for low subwf minA_hi,W ;compare bnc test_for_hi_A ;new < min_hi bnz store_new_lo_A ;new > min_hi, keep movfw ACCa_lo ;new = min_hi, test lo subwf minA_lo,W ;compare bnc test_for_hi_A skpz goto store_new_lo_A test_for_hi_A movfw ACCa_hi subwf maxA_hi,W bnc store_new_hi_A ;new < max_hi bnz setup_B ;new > max_hi movfw ACCa_lo ;new = max_hi, test lo subwf maxA_lo,W skpnc goto setup_B store_new_hi_A movfw ACCa_hi movwf maxA_hi movfw ACCa_lo movwf maxA_lo goto setup_B store_new_lo_A movfw ACCa_hi movwf minA_hi movfw ACCa_lo movwf minA_lo setup_B bsf P_FLAG ;y axis call meas_r ;get resistance movfw ACCa_hi ;test for low subwf minB_hi,W ;compare bnc test_for_hi_B ;new < min_hi bnz store_new_lo_B ;new > min_hi, keep movfw ACCa_lo ;new = min_hi, test lo subwf minB_lo,W ;compare bnc test_for_hi_B skpz goto store_new_lo_B test_for_hi_B movfw ACCa_hi subwf maxB_hi,W bnc store_new_hi_B ;new < max_hi bnz find_min_max ;new > max_hi movfw ACCa_lo ;new = max_hi, test lo subwf maxB_lo,W skpnc goto find_min_max store_new_hi_B movfw ACCa_hi movwf maxB_hi movfw ACCa_lo movwf maxB_lo goto find_min_max store_new_lo_B movfw ACCa_hi movwf minB_hi movfw ACCa_lo movwf minB_lo goto find_min_max ;------------------------------------------------------------ store_this call deb_delay btfsc MODE_CHECK ;still lo ? goto find_min_max ;no clrf EEADR ;yes, store in EEPROM movlw 0xaa movwf EEDATA call eemem_write incf EEADR,F movlw 0xf0 movwf EEDATA call eemem_write movlw 0x2a movwf FSR incf EEADR,F store_this_loop movfw INDF movwf EEDATA call eemem_write incf FSR,F incf EEADR,W sublw 0x09 bnc slo_flash ;done incf EEADR,F goto store_this_loop ; ; Slow LED flash - stays here slo_flash bcf INTCON,T0IF ;clear flag bsf STATUS,RP0 ;bank 1 movlw b'10010111' movwf OPTION_REG ;TMR0/256 bcf STATUS,RP0 ;bank 0 LED_loop btfss INTCON,T0IF goto LED_loop bcf INTCON,T0IF incf bit_count,F btfsc bit_count,2 goto $+3 bcf SYNC_LED goto $+2 bsf SYNC_LED goto LED_loop ;------------------------------------------------------------ ; Subroutines Area ;------------------------------------------------------------ ; Assumes address in EEADR ; Assumes data in EEDATA eemem_read bsf STATUS,RP0 ;bank 1 bsf EECON1,RD bcf STATUS,RP0 ;bank 0 return ; eemem_write bsf STATUS,RP0 ;bank 1 bcf EECON1,EEIF ;clear flag bsf EECON1,WREN ;write enable movlw 0x55 movwf EECON2 movlw 0xaa movwf EECON2 bsf EECON1,WR nop btfss EECON1,EEIF goto $-2 bcf EECON1,WREN ;write disable bcf STATUS,RP0 ;bank 0 return ;------------------------------------------------------------ ; Measures resistance result in ACCa_hi,lo meas_r call dschrg btfss P_FLAG goto do_axis_2 movlw AXIS_1 call cfg_port_a bsf PORTA,0 ;A:0 hi thru X call m_time ;resistor bcf PORTA,0 ;A:0 lo return do_axis_2 movlw AXIS_2 call cfg_port_a bsf PORTA,1 ;A:1 hi thru Y call m_time ;resistor bcf PORTA,1 ;A:1 lo return ; cfg_port_a bsf STATUS,RP0 ;bank 1 movwf TRISA bcf STATUS,RP0 ;bank 0 return ; dschrg movlw DISCHARGE call cfg_port_a clrf PORTA ;outputs low movlw 0xff movwf bit_count decfsz bit_count,F goto $-1 ;wait 256 uS return ; m_time clrf ACCa_lo clrf ACCa_hi t_loop incfsz ACCa_lo,F ;(1)(2) goto end_chk ;(1)(2) incfsz ACCa_hi,F ;(1) goto end_chk ;(2) return ;< 390 mS end_chk btfss PORTA,4 ;(1)(2) goto t_loop ;(2) return ;----------------------------------------------------------- ; stored max - stored min / 254 ; Returns with calA,B_hi, calA,B_lo (x_factor) ; ACCb_hi,lo - ACCa_hi,lo = ACCb_hi,lo x_calc movlw 0x2a ;start of max/min movwf FSR movfw INDF movwf ACCb_hi ;max_hi incf FSR,F movfw INDF movwf ACCb_lo ;max_lo incf FSR,F movfw INDF movwf ACCa_hi ;min_hi incf FSR,F movfw INDF movwf ACCa_lo ;min_lo call subtract_16 ;results in ACCb_hi,lo ; movlw 0xfe movwf ACCa_lo clrf ACCa_hi call divide_16 ;/254 movfw ACCb_lo movwf calA_hi ;store MSB movfw ACCc_lo ;calc remainder movwf ACCb_lo clrf ACCb_hi clrf ACCc_lo clrf ACCc_hi movlw 0xfe movwf ACCa_lo clrf ACCa_hi call divide_32_16 movfw ACCb_hi movwf calA_lo ;store LSB ; incf FSR,F ;Y axis begin movfw INDF movwf ACCb_hi ;max_hi incf FSR,F movfw INDF movwf ACCb_lo ;max_lo incf FSR,F movfw INDF movwf ACCa_hi ;min_hi incf FSR,F movfw INDF movwf ACCa_lo ;min_lo call subtract_16 ;results in ACCb_hi,lo ; movlw 0xfe movwf ACCa_lo clrf ACCa_hi call divide_16 ;/254 movfw ACCb_lo movwf calB_hi ;store B MSB movfw ACCc_lo ;calc remainder movwf ACCb_lo clrf ACCb_hi clrf ACCc_lo clrf ACCc_hi movlw 0xfe movwf ACCa_lo clrf ACCa_hi call divide_32_16 movfw ACCb_hi movwf calB_lo ;store B LSB return ;------------------------------------------------------------ ; Math routines ;************************************************************ ; 16 x 16 Add and Subtract ; ACCb_hi,lo - ACCa_hi,lo result ACCb_hi,lo subtract_16 comf ACCa_lo,F incf ACCa_lo,F skpnz decf ACCa_hi,F comf ACCa_hi,F ; ; ACCa_hi,lo + ACCb_hi,lo result ACCb_hi,lo add_16 movfw ACCa_lo addwf ACCb_lo,F skpnc incf ACCb_hi,F movfw ACCa_hi addwf ACCb_hi,F bnc hold_at_1 movfw ACCb_lo bnz sub_16_end movfw ACCb_hi bnz sub_16_end hold_at_1 clrf ACCb_hi movlw 0x01 movwf ACCb_lo sub_16_end return ;------------------------------------------------------------ ; 16 x 16 divide ; ACCb_hi,lo / ACCa_hi,lo ; result in ACCb_hi,lo ; remainder in ACCc_hi,lo divide_16 movlw 0x10 movwf bit_count movfw ACCb_hi movwf ACCd_hi movfw ACCb_lo movwf ACCd_lo clrf ACCb_hi clrf ACCb_lo clrf ACCc_hi clrf ACCc_lo div_loop clrc rlf ACCd_lo,F rlf ACCd_hi,F rlf ACCc_lo,F rlf ACCc_hi,F movfw ACCa_hi subwf ACCc_hi,W skpz goto no_chk movfw ACCa_lo subwf ACCc_lo,W no_chk skpc goto no_go movfw ACCa_lo subwf ACCc_lo,F skpc decf ACCc_hi,F movfw ACCa_hi subwf ACCc_hi,F setc no_go rlf ACCb_lo,F rlf ACCb_hi,F decfsz bit_count,F goto div_loop return ;------------------------------------------------------------ ; 32 bit / 16 bit ; ACCb_hi,lo ACCc_hi,lo / ACCa_hi,lo ; Results ACCb_hi,lo divide_32_16 movfw ACCb_hi movwf ACCd_hi movfw ACCb_lo movwf ACCd_lo movfw ACCc_hi movwf ACCe_hi movfw ACCc_lo movwf ACCe_lo clrf ACCb_hi clrf ACCb_lo clrf ACCc_hi clrf ACCc_lo movlw 0x20 ;32 loops movwf bit_count d_loop rlf ACCe_lo,F rlf ACCe_hi,F rlf ACCd_lo,F rlf ACCd_hi,F rlf ACCc_lo,F rlf ACCc_hi,F movfw ACCa_hi subwf ACCc_hi,W skpz goto no_chk_32 movfw ACCa_lo subwf ACCc_lo,W no_chk_32 skpc goto no_go_32 movfw ACCa_lo subwf ACCc_lo,F skpc decf ACCc_hi,F movfw ACCa_hi subwf ACCc_hi,F setc no_go_32 rlf ACCb_lo,F rlf ACCb_hi,F decfsz bit_count,F goto d_loop return ;------------------------------------------------------------ ; 9600,8,N,1 serial out routine serial_tx movlw 0x08 ;init shift counter movwf bit_count btfss INTCON,T0IF goto $-1 clrf TMR0 ;insure it's zero bsf SERIAL_OUT ;start bit set movfw bit_length subwf TMR0,F ;104 uS bcf INTCON,T0IF ;clear flag comf serial_reg,F ;invert data clrc serial_out_loop btfss INTCON,T0IF goto $-1 rrf serial_reg,F ;rotate bit 0 into carry skpnc ;test carry flag goto $+3 ;carry = 1 bcf SERIAL_OUT ;bit is clear, output 0 goto $+2 bsf SERIAL_OUT ;bit is set, output 1 movfw bit_length ;104 uS subwf TMR0,F bcf INTCON,T0IF ;clear flag decfsz bit_count,F ;shifted 8? goto serial_out_loop ;no btfss INTCON,T0IF goto $-1 bcf SERIAL_OUT ;yes, output stopbit movfw bit_length ;104 uS subwf TMR0,F bcf INTCON,T0IF return ;done ;------------------------------------------------------------ deb_delay clrf digit ;(1) clrf bit_count ;(1) incfsz bit_count,F ;(1)(2) goto $-1 ;(2) incfsz digit,F ;(1)(2) goto $-3 ;(2) return ;------------------------------------------------------------ end ;------------------------------------------------------------