; Lessn13c.asm
;
;  Roulette Wheel
;
;  WB8RCR - 16-Mar-04
;
;=====================================================================

		processor	pic16f84a
		include		"p16f84a.inc"
		__config	_XT_OSC & _WDT_OFF & _PWRTE_ON
		list		b=4,n=70

;=====================================================================
;	Manifest Constants
;=====================================================================
PB1		equ			H'04'		; PORTA pin for PB1
HZ2TIME	equ			D'49'		; Clock ticks for 20/sec
HZ8TIME	equ			D'12'		; Clock ticks for 80/sec
HZVMAX	equ			D'10'		; Max rate for n/sec

;=====================================================================
;	File register use
;=====================================================================
		cblock		H'20'
			Hz2Cnt				; 20 times per second counter
			HzVCnt				; variable times per second counter
			Hz8Cnt				; 80 times per second counter
			Outputs				; Output storage
			Inputs				; Input storage
			LEDstate			; Which LED on?
			LEDrate				; Rate of flashing
		endc

		goto		start

;=====================================================================
;  Subroutines
;=====================================================================
SendOut
		movf		Outputs,W		; Pick up the output word
		movwf		PORTB			; And send it to the world
		return

;=====================================================================
;  Time domains
;=====================================================================

;---------------------------------------------------------------------
;	80 times per second code
;---------------------------------------------------------------------
Hz8
	; Get inputs
		movf		PORTA,W
		movwf		Inputs

	; Check button state
		btfsc		Inputs,PB1		; Is button up?
		return						; Button up, do nothing
	; Button is down
		movlw		HZVMAX			; Set rate to
		movwf		LEDrate			; fastest flashing
		return

;---------------------------------------------------------------------
;	20 times per second code
;---------------------------------------------------------------------
Hz2
	; Check whether rate already slowest
		movf		LEDrate,W		; Pick up rate and xor with
		xorlw		0xff			; ff so Z set if equal
		btfsc		STATUS,Z		; Is rate slowest?
		return						; Yes, do nothing
	; Make LEDs slower
		incf		LEDrate,F		; Bump it down by one
		return

;---------------------------------------------------------------------
;	Variable times per second code
;---------------------------------------------------------------------
HzV
		rlf			LEDstate,F		; Move the 1 over a bit
		btfss		LEDstate,4		; Did it roll off the end?
		goto		SetLEDs			; No, continue on
		movlw		B'00000010'		; Yes, reset to bit 1 on
		movwf		LEDstate		; and store it away
SetLEDs
		movlw		B'1110001'		; Initially turn on LEDs (actually
		andwf		Outputs,F		; overkill since no other IO)
		movf		LEDstate,W		; Pick up LED state
		xorlw		H'0e'			; Flip because active low
		iorwf		Outputs,F		; Set it in the outputs
		call		SendOut			; Go do output
		return

;=====================================================================
;  Mailine begins here -- Initialization
;=====================================================================
start

;---------------------------------------------------------------------
;	Set up timer 
;---------------------------------------------------------------------
		errorlevel	-302
		banksel		INTCON
		bcf			INTCON,T0IE		; Mask timer interrupt
	; Normally, we would have simply loaded a constant, but the
	; code below makes it explicit what we are doing
		banksel		OPTION_REG
		bcf			OPTION_REG,T0CS	; Select timer
		bcf			OPTION_REG,PSA	; Prescaler to timer
		bcf			OPTION_REG,PS2	; \
		bcf			OPTION_REG,PS1	;  >- 1:4 prescale
		bsf			OPTION_REG,PS0	; /
;---------------------------------------------------------------------
;	Set up I/O 
;---------------------------------------------------------------------
		banksel		TRISB
		clrw						; 
		movwf		TRISB			; Make all port B output
		banksel		PORTA
		errorlevel	+302

;---------------------------------------------------------------------
;	Initialize memory
;---------------------------------------------------------------------
		movlw		B'00001110'		; Initially set all LEDs
		movwf		Outputs			; to off
		movwf		PORTB

		movlw		HZ2TIME			; Initialize 20 times
		movwf		Hz2Cnt			; per second counter
		movlw		HZ8TIME			; and eighty times per
		movwf		Hz8Cnt			; second counter

		movlw		B'00000010'		; Initialize the LED
		movwf		LEDstate		; states
		movlw		H'd0'			; and the speed of LED
		movwf		LEDrate			; movement

;=====================================================================
; Main program loop here
;=====================================================================
main
		btfss		INTCON,T0IF		; Did timer overflow?
		goto		main			; No, hang around some more
		bcf			INTCON,T0IF		; reset overflow flag

;---------------------------------------------------------------------
;	Check for eighty times per second
;---------------------------------------------------------------------
		decfsz		Hz8Cnt,F		; Count down until Hz8
		goto		$+4				; Not time yet
		movlw		HZ8TIME			; Reset the counter so
		movwf		Hz8Cnt			; it's available next time
		call		Hz8				; Go do 80X per second code

;---------------------------------------------------------------------
;	Check for twenty times per second
;---------------------------------------------------------------------
		decfsz		Hz2Cnt,F		; Count down until Hz2
		goto		$+4				; Not time yet
		movlw		HZ2TIME			; Reset the counter so
		movwf		Hz2Cnt			; it's available next time
		call		Hz2				; Go do 20X per second code

;---------------------------------------------------------------------
;	Check for variable times per second
;---------------------------------------------------------------------
	; Special case, if LEDrate = 0xff quit doing this
		movf		LEDrate,W		; Pick up rate, if it's
		xorlw		H'ff'			; ff we want to not run
		btfsc		STATUS,Z		; this time domain
		goto		main

		decfsz		HzVCnt,F		; Count down until HzV
		goto		$+4				; Not time yet
		movf		LEDrate,W		; Reset the counter so
		movwf		HzVCnt			; it's available next time
		call		HzV				; N times per second code

		goto		main
		end
