; *******************************************************************
; pulse generator
; *******************************************************************
;
; 2008 Copyright by Frank Buss
; *******************************************************************

			LIST	P=12F508

#include "P12F508.INC"

; internal reset
; code protect off
; watchdog off
; internal oscillator (Fosc = 4 MHz)
			__CONFIG _MCLRE_OFF & _CP_OFF & _WDT_OFF & _IntRC_OSC

			org 0

; port bits
SW1			EQU D'0'
SW2			EQU D'1'
SW3			EQU D'2'
SW4			EQU D'4'
IN_MASK		EQU ((1 << SW1)|(1 << SW2)|(1 << SW3)|(1 << SW4))
PULSE_OUT	EQU D'5'

DELAY1		EQU D'2'
DELAY2		EQU D'5'
DELAY3		EQU D'10'
DELAY4		EQU D'25'

; variables
TIMER_VALUE	EQU H'08'
SEC125		EQU H'09'
WAIT125		EQU H'0a'
DELAY_BIT	EQU H'0b'
SEC_COUNTER	EQU H'0c'
MIN_COUNTER	EQU H'0d'


; program start

; init
			movwf	OSCCAL		; on reset, W contains the calibration value
			clrf	STATUS
			movlw	D'0'		; set levels low
			movwf	GPIO		;  for GPIO (PORTB)

; wake-up on port change disabled,
; pullups disabled
; timer clock source: internal, Fosc/4
; prescalar to timer: 1:64, timer runs at 15625 Hz
			clrwdt
			movlw	H'85'
			option

			movlw	1
			movwf	SEC_COUNTER
			movwf	MIN_COUNTER
			movwf	SEC125
			movwf	DELAY_BIT

; set tris to test keys
START		movlw	IN_MASK	 ; set switch GPIOs to input
			tris	GPIO

; enable LED5 on last second in last minute
			movlw	1 << PULSE_OUT
			movf	SEC_COUNTER, F
			btfss	STATUS, Z
			goto	SET_LED
			movf	MIN_COUNTER, F
			btfsc	STATUS, Z
			movlw	0
SET_LED		movwf	GPIO

; wait 1/15625 s
			call	WAIT

; test keys and update delay bit variable, if a key was pressed
			movf	GPIO, W
			andlw	IN_MASK
			xorlw	IN_MASK
			btfss	STATUS, Z
			movwf	DELAY_BIT

; set LED1-4 to last pressed button
			movf	DELAY_BIT, W
			xorlw	IN_MASK
			tris	GPIO

; test 1/125 counter
			decf	SEC125, F
			btfss	STATUS, Z
			goto	NEXT

; 125 counter is zero, reload
			movlw	D'125'
			movwf	SEC125

; test second counter
			movlw	D'1'
			subwf	SEC_COUNTER, F
			btfsc	STATUS, C
			goto	NEXT

; reload second counter
			movlw	D'59'
			movwf	SEC_COUNTER

; test minute counter
			movlw	D'1'
			subwf	MIN_COUNTER, F
			btfsc	STATUS, C
			goto	NEXT

; reload minute counter
			btfsc	DELAY_BIT, SW1
			movlw	DELAY1 - 1
			btfsc	DELAY_BIT, SW2
			movlw	DELAY2 - 1
			btfsc	DELAY_BIT, SW3
			movlw	DELAY3 - 1
			btfsc	DELAY_BIT, SW4
			movlw	DELAY4 - 1
			movwf	MIN_COUNTER

; wait 1/15625 s * 124
NEXT		movlw	D'125'
			movwf	WAIT125
WAIT_REST	call	WAIT
			decf	WAIT125, F
			btfsc	STATUS, Z
			goto	START
			goto	WAIT_REST

; wait 1/15625 s
WAIT		movf	TMR0, W
			movwf	TIMER_VALUE
WAIT2		movf	TIMER_VALUE, W
			subwf	TMR0, W
			btfsc	STATUS, Z
			goto	WAIT2
			retlw	0

			end
