;*************************************************************** ;*************************************************************** ;**** SHARPINT.asm 2-11-99 Ted Griebling ;**** Assembly code written for 69hc12b32 ;**** ;**** An example program using IRINT: an interrupt driven ;**** subroutine that communicates with a Sharp GP2D02 ;**** IR range-finding sensor. The subroutine continuously ;**** updates an eight bit variable with the latest sensor ;**** data. The refresh rate has been as fast as 20Hz. The time ;**** to read a byte increases as the detected object gets closer. ;**** The slowest refresh rate measured so far was ~18.5Hz. ;**** ;**** Due to the similarity between the HC12 and HC11 u-processors, ;**** I expect it to be simple matter to port the IRINT subroutine ;**** with few modifications, mostly timing. ;**** ;*************************************************************** ;*************************************************************** opt nol #include equates.asm opt l ;**** Constants IROUTB equ $01 ;Output bit to IR sensor is bit 1 of... IROUTP equ PORTA ;Port A, later configured as output IRINB equ $01 ;Input from IR sensor is bit 1 of... IRINP equ PORTB ;Port B, later configured as input ;**** Ram Equates, variables ;**** IRINT Variables org RAMSTART IRINT rmb 3 ;IR Interrupt Pseudo-vector ir_step rmb 1 ;IR interrupt sequence step ir_bit rmb 1 ;bit counter ir_datw rmb 1 ;working ir data ir_data rmb 1 ;ir sensor data org EEPROMSTART ;*************************************************************** ;**** Initialize INIT: lds #$0bff ;Initialize the stack pointer clr COPCTL ;kill the COP ;*************************************************************** ;**** Initialize PWM channels ldaa #$01 staa PWPOL ;PWM Channel 0: clock=A, polarity=1 clr PWSCAL0 ;PWM prescale register0 is zero clr PWSCNT0 ;PWM prescale counter0 is zero clr PWCNT0 ;PWM Channel 0 counter is zero ldaa #220 ;Approximate max sensor value... staa PWPER0 ; is stored as PWM Channel 0 period ldaa #2 ;a number... staa PWDTY0 ; is stored as initial Duty cycle ;*************************************************************** ;**** Initialize I-O movb #$ff DDRA ;all of PortA is output clr DDRB ;all of PortB is input bset PUCR $02 ;enable PortB pull up resistors bset PWEN $01 ;PortP, bit0 is PWMchannel0 output ;*************************************************************** ;**** Initialize IR subroutine bsr IRINT_INIT ;*************************************************************** ;**** MAIN program, A loop that repeatedly loads ir_data and ;**** stores it as the Duty cycle for PWM Channel 0 ;*************************************************************** MAIN: ldab ir_data subb #1 ;because desired duty = PWDTYx + 1 (for left) stab PWDTY0 ;store value as PWM channel 0 Duty Cycle bra MAIN ;do it all again ;*************************************************************** ;*************************************************************** ;**** IRINT_INIT - IR Interrupt Initialization ;**** ;**** Initialize the pseudovector by storing "JMP" object ;**** code to the first byte of IRINT. The second two IRINT bytes ;**** are continously redefined to point to the different steps of ;**** the IR sensor interrupt sequence. ;*********************** ;**** initialize vector IRINT_INIT: ldaa #$06 ;jmp (extended) object code staa IRINT ;pseudo vector ldd #IRSTEP0 ;load the first step location: #IRSTEP0 std IRINT+1 ;store as destination for first interrupt bset IROUTP IROUTB ;set IROUTPort,IROUTBbit high ;**** Initialize timer functions bset TSCR $80 ;enable timer bset TIOS $01 ;Timer channel 0 is output compare ldd #16000 ;initial wait is 2000usec addd TCNTH ;start timekeeping from current time std TC0H ;store the next time to timer channel 0 ;**** Turn on interrupt cli ;clear the interrupt mask bit bset TFLG1 $01 ;clear timer channel 0 interrupt flag bset TMSK1 $01 ;enable timer channel 0 interrupts rts ;return from subroutine ;*************************************************************** ;*************************************************************** ;**** IRINT, IR Interrupt Steps ;**** ;**** Each step, after doing something unique, ;**** - loads the next step location in X ;**** - loads number of clock counts until next step in D ;**** - returns from interrupt ;**** ;*************************************************************** ;**** Set the control line high and initialize variables IRSTEP0: bclr IROUTP IROUTB ;set IROUTPort,IROUTBbit low ldaa #8 ;eight bits of sensor data to read staa ir_bit ;reset the ir_bit counter ; clr ir_datw ;working ir data (not really needed ldx #IRSTEP1 ;next step is IRSTEP1 bra IREXIT ;2000usec wait time is defined in IREXIT ;*********************** ;**** Every 2000usec check if sensor input has gone high IRSTEP1: brset IRINP IRINB IRSTEP2 ;Wait for IRINPort,IRDATBit high ldx #IRSTEP1 ;jump here again if IRINBit is still low bra IREXIT ;2000usec time is defined in IREXIT ;*********************** ;**** Set control line high and wait 100usec IRSTEP2: bset IROUTP IROUTB ;set IROUTPort,IROUTBit high ldd #800 ;100usec wait time after IROUTBit goes high ldx #IRSTEP3 ;next step is IRSTEP3 bra IRBITEXIT ;exit ;*********************** ;**** Set control line low and wait another 100usec IRSTEP3: bclr IROUTP IROUTB ;set IROUTPort,IROUTBit low ldd #800 ;100usec wait time after IROUTBit goes low ldx #IRSTEP4 ;next step is IRSTEP4 bra IRBITEXIT ;exit ;*********************** ;**** Read a bit from the IR sensor input. IRSTEP4: brclr IRINP IRINB IR_BIT_LOW ;test IRINPort,IRINBit IR_BIT_HI: sec ;if IRINBit is high, set the carry bit bra ROTATE ;skip the other case IR_BIT_LOW: clc ;If IRINBit is low, clear the carry bit ROTATE: rol ir_datw ;rotate the bit into ir_datw dec ir_bit ;decrement the bit counter beq IR_BIT_DONE ;branch if bit counter=0 bra IRSTEP2 ;otherwise do the last two steps again ;*********************** ;**** Eight bits have been read, set control line high and save data. IR_BIT_DONE: bset IROUTP IROUTB ;set IROUTPort,IROUTBbit high ldaa ir_datw ;load the finished IR data staa ir_data ;save as a variable used by the main prog. ldx #IRSTEP0 ;load the first step (fall through to next line) ;*********************** ;**** The 2000usec wait is common to most steps. IREXIT: ldd #16000 ;2000usec (fall through to next line) ;*********************** ;**** Store the next wait period and the next step to run. IRBITEXIT: addd TC0H ;add the current counter value to D std TC0H ;store the next time to interrupt stx IRINT+1 ;store the next step in routine bset TFLG1 $01 ;clear the interrupt flag rti ;return from interrupt ;*************************************************************** ;*************************************************************** ;**** Vectors org RESET fdb INIT org TC0 ;Timer channel 0 interrupt vector fdb IRINT ;IRINT pseudo vector