JU Bat Blinker Development Docs: game_2.asm

Gadget Sourcecode: game_2.asm


#define SIM             0

#define USE_16F628      0
#define USE_16F630      1   ; turn off TEST_VCOMPARE or run out of mem
#define USE_16F84A      0   ; NOT SUPPORTED!!

#define DO_VCHECK       1
#define TEST_VCOMPARE   0
#define CHECK_SYNC      1

#define NO_SLEEP_IF_HELD    0

#if USE_16F630
        LIST P=16F630
        include <p16f630.inc>
        __CONFIG    0x24
#endif
#if USE_16F628
        LIST P=16F628   ;f=inhx8m
        include <p16f628.inc>
        __CONFIG    0x3f38
#endif
#if USE_16F84A
        ;
        ; 16F84 IS NO LONGER SUPPORTED!!
        ;
        LIST P=16F84A   ;f=inhx8m
        include <p16f84a.inc>
        __CONFIG    0x3ff1
#endif

    RADIX   DEC

;#################################
; SETUP FOR DIFFERENT PROCESSORS
;#################################

;
; PIC 16F630
;
#if USE_16F630

#define RED_LEDS        PORTC

#define b_led_red0      PORTC,0
#define b_led_red1      PORTC,1
#define b_led_red2      PORTC,2
#define b_led_red4      PORTC,3
#define b_led_red3      PORTC,4

#define RED0            0x01
#define RED1            0x02
#define RED2            0x04
#define RED3            0x10
#define RED4            0x08

#define RED_END         0x80
#define END_BIT         7

#define b_led_green0    PORTA,4
#define b_led_green1    PORTA,5

#define b_gravity       PORTA,2

TRISVAL_A   equ         0x06    ; Port tristate and initial values
TRISVAL_C   equ         0x00

FB          equ         0x20        ; first free byte

#define b_por           PCON,NOT_POR
#define b_rp0           STATUS,RP0
#define b_rapu          OPTION_REG,NOT_GPPU
#define b_intedg        OPTION_REG,INTEDG
#define b_int0if        INTCON,INTF
#define b_int0ie        INTCON,INTE
#define b_gie           INTCON,GIE
#define b_c1out         CMCON,COUT
#define b_wpua2         WPUA,2
#endif

;
; PIC 16F628
;
#if USE_16F628

#define RED_LEDS        PORTB

#define b_led_red4      PORTB,1
#define b_led_red3      PORTB,2
#define b_led_red2      PORTB,3
#define b_led_red1      PORTB,4
#define b_led_red0      PORTB,5

#define RED4            0x02
#define RED3            0x04
#define RED2            0x08
#define RED1            0x10
#define RED0            0x20

#define RED_END         0x80        ; end bit
#define END_BIT         7

#define b_led_green0    PORTA,7
#define b_led_green1    PORTA,6

#define b_gravity       PORTB,0


TRISVAL_A   equ         0x01    ; Port tristate and initial values
TRISVAL_B   equ         0x01

FB          equ         0x20    ; first free byte

#define b_por           PCON,NOT_POR
#define b_oscf          PCON,OSCF
#define b_rp0           STATUS,RP0
#define b_rp1           STATUS,RP1
#define b_irp           STATUS,IRP
#define b_rbpu          OPTION_REG,NOT_RBPU
#define b_intedg        OPTION_REG,INTEDG
#define b_int0if        INTCON,INTF
#define b_int0ie        INTCON,INTE
#define b_gie           INTCON,GIE
#define b_c1out         CMCON,C1OUT
#endif

;#################################
; CONSTANTS
;#################################

WAIT_100        equ     65      ; delay 100ms = 65*1540
GRAV_LOOPS      equ     10      ; spins before sleeping
START_LOOPS     equ     100     ; initial loops before sleeping
SYNC_LOOK_CNT   equ     3       ; # times to look for sync none found


VOLT_MIN        equ     4       ; start at this range
VOLT_CNT        equ     4       ; check this many ranges

;#################################
; VARIABLES
;#################################


;
; bit variables
;
#define b_check_sync    v_bits0,0
#define b_got_intr      v_bits0,1
#define b_check_v       v_bits0,2
#define b_test_vcmp     v_bits0,3


;
; byte variables
;


v_bits0         equ     FB+0    ; bits
v_current_msg   equ     FB+1    ; message currently being

v_cnt1          equ     FB+2    ; wait counter ls digit
v_cnt2          equ     FB+3    ; wait counter ms digit


v_volt          equ     FB+5
v_volt_cnt      equ     FB+6

v_loops         equ     FB+7    ; spins before we sleep

v_cptr          equ     FB+8    ; column pointer
v_curval        equ     FB+9    ; value of current column (input)
v_redval        equ     FB+10   ; value of current column (output)

v_sync_cnt      equ     FB+11   ; times to check sync


;#################################
; BEGIN CODE
;#################################

;#################################
; VECTORS
;#################################

;
; reset vector
;
        org     0

    goto    init

;
; interrupt vector
;
        org     4

    bsf     b_got_intr      ; indicate interrupt occurred
    bcf     b_int0if
    retfie

;#################################
; red/green function jump tables
;#################################
red:
    clrf    PCLATH
    movf    v_volt,w
    addwf   PCL,f

    goto    red14
    goto    red14
    goto    red12
    goto    red12
    goto    red1


    ;
    ; w contains duration (w * 960usec)
    ;
green:
    movwf   v_cnt2

    clrf    PCLATH
    movf    v_volt,w
    addwf   PCL,f       ; jump to green func based on voltage

    goto    green50
    goto    green50
    goto    green35
    goto    green35
    goto    green1

;#################################
; autogenerated subroutines
;#################################
    include <swords.inc>

;#################################
; off mode - turn off after last msg
;#################################
turn_off:
    clrf    v_current_msg
    decf    v_current_msg,f

off_loop:
    clrf    INTCON      ; interrupts off
    sleep


;#################################
; init routine
;#################################
init:
    clrf    STATUS
    clrf    INTCON      ; interrupts off

#if USE_16F630

    clrf    PORTA
    clrf    PORTC

    ;
    ; BANK 1
    ;
    bsf     b_rp0

    movlw   TRISVAL_A
    movwf   TRISA
    movlw   TRISVAL_C
    movwf   TRISC

    bcf     b_rapu      ; turn on pullup for PORTA
    ;bsf    b_wpua2     ; turn on pullup for A2 (on by default)
    bcf     b_intedg    ; interrupt on falling edge

    movf    OSCCAL,w
    call    0x3ff       ; get osc calibration value in w
    movwf   OSCCAL      ; calibrate the oscillator

    bcf     b_rp0
    ;
    ; BANK 0
    ;
#endif



#if USE_16F628

    clrf    PORTA
    clrf    PORTB

    ;
    ; BANK 1
    ;
    bsf     b_rp0

    movlw   TRISVAL_A
    movwf   TRISA
    movlw   TRISVAL_B
    movwf   TRISB


    bcf     b_rbpu      ; turn on pullup for PORTB
    bcf     b_intedg    ; interrupt on falling edge

    bcf     b_rp0
    ;
    ; BANK 0
    ;

#endif

    clrf    v_bits0     ; clear bit variables
    clrf    v_sync_cnt  ; do not check for sync (until sync is seen)
    bcf     b_int0if    ; clear sync
    bsf     b_check_v   ; check voltage next dot

#if TEST_VCOMPARE
    btfss   b_gravity
    bsf     b_test_vcmp ; test voltage compare if gravity switch
                        ; pressed during reset
#endif

;#################################
; Debounce wait
;#################################
;
; wait a bit for MCLR switch debouncing
; (if bouncing, reset will occur here again)
;

debounce:
    call    wait_100

;#################################
; NEXT MESSAGE
;#################################

next_message:
    ;
    ; increment to next message
    ;
    incf    v_current_msg,f
    movf    v_current_msg,w
    addlw   LOW -PHRASE_CNT
    btfsc   STATUS,C
    goto    turn_off

    ;
    ; initial loop count value
    ;
    movlw   START_LOOPS
    movwf   v_loops

    ;
    ; display current message
    ;
    movf    v_current_msg,w

    ;
    ; go to phrase jump table in swords.inc
    ;
    goto    jump

;#################################
; WAIT_500 - wait for 500 ms (1/2 sec)
;#################################
wait_500:
    call    wait_100
    call    wait_200

    ; fall thru to wait_200

;#################################
; WAIT_200 - wait for 100 ms (1/10 sec)
;#################################
wait_200:
    call    wait_100

    ; fall thru to wait_100

;#################################
; WAIT_100 - wait for 100 ms (1/10 sec)
;#################################
wait_100:
    movlw   WAIT_100

    ; fall thru to wait

;#################################
; WAIT - wait for a short time
;#################################
;
; wait loop. Wait for:
;       W * 772 cycles = W * 772 usec
;
; if b_check_sync is 1 then exit when b_int0if is set
;
; w contains time to wait:
;   if b_check_sync == 0
;        cycles = usec = w * 1540
;
;   if b_check_sync == 1
;        cycles = usec = w * 1796
;
wait:
    movwf   v_cnt2

#if !SIM
wait_loop2:
    clrf    v_cnt1  
wait_loop1:
    btfss   b_check_sync    ; check sync?
    goto    wait_cont

    btfsc   b_int0if        ; exit if sync occurred
    return

wait_cont:
    decfsz  v_cnt1,f
    goto    wait_loop1

    decfsz  v_cnt2,f
    goto    wait_loop2
#endif

    return


;#################################
; go to sleep
;#################################

;
; setup to wake up if interrupt occurs
; if b_int0if is set then sleep will not occur
;
do_sleep:
    bcf     b_got_intr  ; this gets set if interrupt occurs
    bsf     b_int0ie    ; enable gravity interrupt
    bsf     b_gie       ; enable interrupts

    btfss   b_got_intr
    sleep

    ;
    ; wakeup by interrupt goes here
    ;
    clrf    INTCON      ; disable interrupts
    return              ; continue displaying message

;#################################
; DRAW GREEN DOT & OPTIONALLY CHECK VOLTAGE
;#################################

dot:

#if DO_VCHECK
    ;
    ; turn on both green LEDs
    ;
    bsf     b_led_green0
    bsf     b_led_green1

    ;
    ; need to check voltage?
    ;
    btfss   b_check_v
    goto    dot_wait

    ;
    ; next time do not check voltage
    ;
    bcf     b_check_v

    ;
    ; check voltage
    ;
#if USE_16F630
    movlw   0x04        ; set up voltage compare
    movwf   CMCON
#endif
#if USE_16F628
    movlw   0x02        ; set up voltage compare
    movwf   CMCON
#endif

    movlw   VOLT_CNT
    movwf   v_volt_cnt  ; check this many levels
    movlw   VOLT_MIN
    movwf   v_volt      ; starting with this level


#if TEST_VCOMPARE
    btfss   b_test_vcmp
    goto    tvc_skip1

    movlw   16          ; try all 16 levels
    movwf   v_volt_cnt
    clrf    v_volt      ; starting with 0


    movlw   0x80        ; enable voltage reference
    iorwf   v_volt,w
    bsf     b_rp0
    movwf   VRCON
    bcf     b_rp0
                        ; allow user to measure voltage with meter
    call    wait_500
    call    wait_500
    call    wait_500
    call    wait_500
    call    wait_500
    call    wait_500
    call    wait_500
    call    wait_500

tvc_skip1:
#endif

vtst_loop1:
    movlw   0x80        ; enable voltage reference
    iorwf   v_volt,w    ; check this voltage
    bsf     b_rp0
    movwf   VRCON
    bcf     b_rp0

    movlw   2
    call    wait        ; wait for it to settle 


    btfsc   b_c1out     ; exit loop if Vref > Vled
    goto    vtst_done
    
    incf    v_volt,f
    decfsz  v_volt_cnt,f
    goto    vtst_loop1

vtst_done:
    bsf     b_rp0
    clrf    VRCON       ; turn off voltage reference
    bcf     b_rp0

#if TEST_VCOMPARE
    btfss   b_test_vcmp
    goto    tvc_skip2


    bcf     b_led_green0    ; green off
    bcf     b_led_green1

#if USE_16F630
    movf    v_volt,w        ; indicate voltage reading on red LEDs
#endif
#if USE_16F628
    rlf     v_volt,w        ; indicate voltage reading on red LEDs
#endif
    movwf   RED_LEDS

    call    wait_500        ; display for 1sec
    call    wait_500

    clrf    RED_LEDS        ; red off

    ;
    ; clamp to min=VOLT_MIN
    ;
    movf    v_volt,w
    addlw   LOW -VOLT_MIN
    movlw   VOLT_MIN
    btfss   STATUS,C
    movwf   v_volt


    ;
    ; clamp to max=VOLT_MIN+VOLT_CNT-1
    ;
    movf    v_volt,w
    addlw   LOW -(VOLT_MIN+VOLT_CNT)
    movlw   VOLT_MIN+VOLT_CNT
    btfsc   STATUS,C
    movwf   v_volt

tvc_skip2:
#endif

    movlw   LOW -VOLT_MIN
    addwf   v_volt,f        ; range from 0 to VOLT_CNT-1

#else  ; DO_VCHECK
    clrf    v_volt
#endif ; DO_VCHECK


dot_wait:
    movlw   208             ; 208 * 960usec = 200ms
    call    green           ; about 200ms of green per dot

    call    wait_100        ; about 300ms blank between dots
    goto    wait_200

;#################################
; DRAW CHARACTER (incl gap)
;#################################
;
; pointer to start of char in W
;
putc:
    movwf   v_cptr

putc_loop:
    call    jump            ; get dot values
    movwf   v_curval        ; save to check if last column
    movwf   v_redval        ; save to specify which LEDs to light
    call    red

    incf    v_cptr,f
    movf    v_cptr,w

    btfss   v_curval,END_BIT
    goto    putc_loop

    goto    gap

;#################################
; DRAW SPACE BETWEEN WORDS
;#################################
lspace:
    call    gap
    call    gap

    ; fall thru to gap function

;#################################
; DRAW GAP BETWEEN CHARACTERS
;#################################
gap:
    clrf    v_redval    ; all LED off
    call    red         ; draw with no leds set
    goto    red         ; and again (2 columns per gap)


;#################################
; DRAW SPIN MODE COLUMN OF RED LEDs
;#################################
;
; v_redval should hold red LED values
;
; time = 933 usec
;

;
; 25% duty cycle
;
#define RED14_TIME  154
red14:
    movlw   RED14_TIME
    movwf   v_cnt1

    movf    v_redval,w

red14_loop:
    movwf   RED_LEDS
    nop
    clrf    RED_LEDS

#if !SIM
    decfsz  v_cnt1,f
    goto    red14_loop
#endif

    goto    red_end


;
; 50% duty cycle
;
#define RED12_TIME  116
red12:
    movlw   RED12_TIME
    movwf   v_cnt1

    movf    v_redval,w

red12_loop:
    movwf   RED_LEDS
    nop
    nop
    nop
    clrf    RED_LEDS

#if !SIM
    decfsz  v_cnt1,f
    goto    red12_loop
#endif

    goto    red_end


;
; 100% duty cycle (always on)
;
#define RED1_TIME   186
red1:
    movlw   RED1_TIME
    movwf   v_cnt1

red1_loop:
    movf    v_redval,w
    movwf   RED_LEDS

#if !SIM
    decfsz  v_cnt1,f
    goto    red1_loop
#endif

red_end:
    clrf    RED_LEDS
    movlw   0x00        ; zero w for next character

    return

;#################################
; DRAW LAST RED COLUMN IN CHARACTER
;#################################
;
; w should hold red LED values
;
red_last:
    call    red     ; last column in character
    goto    gap     ; gap following character
    
;#################################
; DRAW GREEN LINE
;#################################

;
; time = v_cnt2 * 935usec
;


;
; 3/5 duty cycle
;
#define GREEN35_TIME    116
green35:
green35_loop2
    movlw   GREEN35_TIME
    movwf   v_cnt1

green35_loop1:
    bsf     b_led_green0
    bsf     b_led_green1
    nop
    bcf     b_led_green0
    bcf     b_led_green1

#if !SIM
    decfsz  v_cnt1,f
    goto    green35_loop1

    decfsz  v_cnt2,f
    goto    green35_loop2
#endif

    return

;
; 50% duty cycle
;
#define GREEN12_TIME    93
green12:
green12_loop2
    movlw   GREEN12_TIME
    movwf   v_cnt1

green12_loop1:
    bsf     b_led_green0
    bsf     b_led_green1
    nop
    nop
    nop
    bcf     b_led_green0
    bcf     b_led_green1

#if !SIM
    decfsz  v_cnt1,f
    goto    green12_loop1

    decfsz  v_cnt2,f
    goto    green12_loop2
#endif

    return

;
; 100% duty cycle (always on)
;
#define GREEN1_TIME 187
green1:
green1_loop2
    movlw   GREEN1_TIME
    movwf   v_cnt1

green1_loop1:
    bsf     b_led_green0
    bsf     b_led_green1

#if !SIM
    decfsz  v_cnt1,f
    goto    green12_loop1

    decfsz  v_cnt2,f
    goto    green12_loop2
#endif

    bcf     b_led_green0
    bcf     b_led_green1

    return


;#################################
; START LOOP
;#################################
;
; Call this at start of phrase.
;
;     - draw green line
;     - check for timeout (sleep)
;
start_loop:

;#################################
; Check for sync (gravity switch)
;#################################
check_switch:

#if NO_SLEEP_IF_HELD
    ;
    ; check for switch being held in - never sleep while that is
    ; true
    ;
    movlw   GRAV_LOOPS
    btfss   b_gravity   ; gravity switch held in?
    movwf   v_loops     ; yes - do not sleep for a while
#endif

    ;
    ; whenever we see a sync, check for sync the next N loops
    ;    (N = SYNC_LOOK_CNT)
    ;

    ;
    ; check for switch toggling - if it toggles then look for sync
    ;
    movlw   SYNC_LOOK_CNT
    btfsc   b_int0if    ; got sync?
    movwf   v_sync_cnt  ; check sync next N times

    ;
    ; looking for sync?
    ;
    movf    v_sync_cnt,f
    btfsc   STATUS,Z
    goto    sync_skip       ; skip looking for sync - we dont see it

    decf    v_sync_cnt,f    ; if no sync for a while then skip it

    movlw   GRAV_LOOPS      ; do not sleep while looking for sync
    movwf   v_loops

    ;
    ; wait until we get a sync pulse
    ;
sync_wait:
    bcf     b_int0if    ; clear sync

#if CHECK_SYNC
    bsf     b_check_sync
    call    wait_500        ; wait 1/2 sec or until sync occurs
    bcf     b_check_sync

    ;
    ; NOTE: we do not clear sync (b_int0if) - next loop it will
    ; be seen and will cause v_sync_cnt to be set again.
    ; So as long as we keep getting sync, we will keep looking
    ; for sync
    ;
#endif  ; CHECK_SYNC

sync_skip:

;#################################
; Draw green line
;#################################
    movlw   50      ; 50 * 920usec = 46msec
    call    green

;#################################
; Check for timeout
;#################################

dec_time:
    decf    v_loops,f
    btfsc   STATUS,Z
    call    do_sleep

start_loop_done:
    movlw   0x00        ; zero W for character functions
    return

    org     0x3ff
    return
    
;#################################
; END
;#################################

    END



This file Copyright (C) 2004 by Nathan (Acorn) Pooley
Go to Bat Blinker Development page
Go to Bat Blinker page
Go to JU Gadgets page
Go to Justice Unlimited homepage
Go to Acorn's personal webpage
Contact Acorn
See comments from others
Post your own comments
File created by do_doc at Wed Aug 4 20:16:01 2004