; ***************************************************************
; * Copyright (c) 2001, Embed Inc (http://www.embedinc.com) *
; * *
; * Permission to copy this file is granted as long as this *
; * copyright notice is included in its entirety at the *
; * beginning of the file, whether the file is copied in whole *
; * or in part and regardless of whether other information is *
; * added to the copy. *
; * *
; * The contents of this file may be used in any way, *
; * commercial or otherwise. This file is provided "as is", *
; * and Embed Inc makes no claims of suitability for a *
; * particular purpose nor assumes any liability resulting from *
; * its use. *
; ***************************************************************
;
; Module controlling the LED "eyes". These eyes can shift left and right
; to four different positions, and occasionally go off for a short time
; to simulate blinking.
;
include "hal.inc"
extern rand_max ;set REG0 to random number in range 0 thru REG1
extern rand ;set REG0 to a random byte value
extern_flags ;declare global flag bits EXTERN
;
;***********************************************************************
;
; Configuration constants.
;
lbank equ 0 ;register bank for the local state of this module
blnkmin equ 60 ;min time between blinks, 100mS units
blnkmax equ 80 ;max time between blinks, 100mS units
shftmin equ 3 ;min time between shifting eyes, 100mS units
shftmax equ 20 ;max time between shifting eyes, 100mS units
;
; Derived constants.
;
lbankadr equ bankadr(lbank) ;address within local state register bank
;
;***********************************************************************
;
; Global state. All this state is assumed to be in the GBANK register
; bank by other modules.
;
.bank#v(gbank) udata
;
;***********************************************************************
;
; Local state.
;
if lbank != gbank
.bank#v(lbank) udata
endif
eyes res 1 ;"eyes" enable value, always exactly two bits 1
cntblnk res 1 ;100mS ticks until next blink
cntshft res 1 ;100mS ticks until next eyes shift
.eyes code
;
;***********************************************************************
;
; Subroutine EYES_INIT
;
; Initialize the hardware and software state managed by this module.
;
glbsub eyes_init, noregs
;
; Initialize the local state.
;
dbankif lbankadr
movlw b'01000100' ;init the eyes value
movwf eyes
movlw (blnkmin + blnkmax) / 2 ;init time until next blink
movwf cntblnk
movlw (shftmin + shftmax) / 2 ;init time until next eyes shift
movwf cntshft
;
; Initialize the hardware.
;
dbankif lbankadr
comf eyes, w ;get the value to write to the output port
dbankif portb
movwf portb ;light the LEDs indicated by the EYES value
leaverest
;
;***********************************************************************
;
; Subroutine EYES_OFF
;
; OFF mode was just entered. Update the eyes handling accordingly.
;
glbsub eyes_off, noregs
dbankif portb
movlw h'FF' ;shut off all the eye lights
movwf portb
leaverest
;
;***********************************************************************
;
; Subroutine EYES_100MS
;
; This routine is called once every 100mS. This routine updates the
; eyes LEDs if appropriate.
;
glbsub eyes_100ms, regf0 | regf1
;
; Check for OFF mode, in which case there is nothing to do.
;
dbankif gbankadr
btfsc flag_off ;not in OFF mode ?
goto leave_100ms ;in OFF mode, eye lights are disabled
;
; Decide whether to blink this 100mS time slice. If so, FLAG_BLINK will
; be set, which will cause all the LEDs to be unlit later.
;
dbankif gbankadr
bcf flag_blink ;init flag to indicate eyes not blinking
dbankif lbankadr
decfsz cntblnk ;blink timer just expired, time to do a blink ?
goto done_blink ;not time to do another blink yet
dbankif gbankadr
bsf flag_blink ;indicate we will now be blinking
;
; Update the blink timer to the number of 100mS ticks until the
; next blink.
;
movlw blnkmax - blnkmin ;make number of valid blink times in range
movwf reg1 ;pass random number max limit
gcall rand_max ;get random number in REG0 that is at or below REG1
movf reg0, w ;get the 0 - N random number into W
addlw blnkmin ;make randomly chosen blink time
dbankif lbankadr
movwf cntblnk ;set new ticks until next blink
done_blink unbank
;
; Decide whether to shift the eyes this time slice. If so, update EYES
; to the shifted value and reset CNTSHFT to the number of ticks until
; the next time to shift the eyes.
;
dbankif lbankadr
decfsz cntshft ;count one less tick until time to shift the eyes
goto done_shift ;not time yet to shift the eyes
;
; It is time to shift the eyes.
;
; Reload CNTSHFT to the number of 100mS ticks until the next
; eyes shift.
;
movlw shftmax - shftmin ;make number of valid shift times in range
movwf reg1 ;pass random number max limit
gcall rand_max ;get random number in REG0 that is at or below REG1
movf reg0, w ;get the 0 - N random number into W
addlw shftmin ;make randomly chosen shift time
dbankif lbankadr
movwf cntshft ;set new ticks until next shift
;
; A random choice will be made to shift the eyes
; left or right unless the eyes are already fully left or right.
; In those cases, the eyes will be shifted in the only direction
; possible.
;
dbankif lbankadr
btfsc eyes, 7 ;could shift left ?
goto shift_right ;no, shifting right is the only choice
btfsc eyes, 0 ;could shift right ?
goto shift_left ;no, shifting left is the only choice
;
; The eyes could be shifted either direction. Get a random number
; to decide.
;
gcall rand ;get a random byte value in REG0
btfss reg0, 0 ;shift left ?
goto shift_right ;shift right
shift_left unbank ;shift the eyes left one position
dbankif lbankadr
bcf status, c ;set bit value to shift in
rlf eyes ;shift the eyes left one position
goto done_shift
shift_right unbank ;shift the eyes right one position
dbankif lbankadr
bcf status, c ;set bit value to shift in
rrf eyes ;shift the eyes right one position
done_shift unbank ;all done shifting the eyes
;
; Write the current eyes state to the hardware. Note that all LEDs should
; be unlit when FLAG_BLINK is set.
;
dbankif lbankadr
comf eyes, w ;get hardware value for the indicated eyes lit
dbankif gbankadr
btfsc flag_blink ;not blinking right now ?
movlw h'FF' ;blinking, get hardware value for all LEDs off
dbankif portb
movwf portb ;write the new eyes LED bits to the hardware port
leave_100ms unbank ;common exit point
leaverest
end