; developed on PICkit2 44pin demo board with 16F887


; 16F887 demo board wiring
#ifdef __16F887

#include <p16F887.inc>
	__CONFIG    _CONFIG1, _LVP_OFF & _FCMEN_OFF & _IESO_OFF & _BOR_OFF & _CPD_OFF & _CP_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT
	__CONFIG    _CONFIG2, _WRT_OFF & _BOR21V

#define	USER_RAM	0x20
#define	SHARED_RAM	0x70

#define	Output	PORTD
#define	OUTBIT	PORTD,7
#define	Input	PORTB
#define	INPBIT	PORTB,0
#define	Display	PORTD

initports	MACRO
	banksel	ANSEL
	movlw	0xFF
	movwf	ANSEL
	banksel	ANSELH
	movlw	0x00
	movwf	ANSELH

	banksel	TRISA
	movlw	0xFF
	movwf	TRISA
	movlw	0x01
	movwf	TRISB
	clrf	TRISD
	ENDM

inittmr0	MACRO
	banksel	OPTION_REG
	movlw	B'10001000'		; PS on WDT, min prescale (/1)
	movwf	OPTION_REG
	ENDM

initirq		MACRO
	banksel	INTCON
	movlw	B'10100000'		; enable Timer 0 and global interrupts
	movwf	INTCON
	ENDM

#endif



; 12F675 board wiring
#ifdef __12F675

#include <p12F675.inc>
	__CONFIG    _BODEN_OFF & _CPD_OFF & _CP_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT


#define	USER_RAM	0x20
#define	SHARED_RAM	0x50

#define	Output	GPIO
#define	OUTBIT	GPIO,2
#define	Input	GPIO
#define	INPBIT	GPIO,4
#define	Display	0x5f

initports	MACRO
	banksel	ANSEL
	movlw	0x00
	movwf	ANSEL

	banksel	CMCON
	MOVLW	07h
	MOVWF	CMCON

	banksel	TRISIO
	MOVLW	B'00010000'
	MOVWF	TRISIO

	banksel	WPU
	movlw	0xFF
	movwf	WPU
	ENDM

inittmr0	MACRO
	banksel	OPTION_REG
	movlw	B'00001000'		; PS on WDT, min prescale (/1), pullups
	movwf	OPTION_REG
	ENDM

initirq		MACRO
	banksel	INTCON
	movlw	B'10100000'		; enable Timer 0 and global interrupts
	movwf	INTCON
	ENDM

#endif



#define	PWMC_MASK	B'00011111'
#define	PWMD_MASK	B'00011111'

; keyboard timings
#define	TIM		D'50'
#define	FIRST	D'25'
#define	REST	D'6'

     cblock     USER_RAM
Delay1               ; Assign an address to label Delay1
Delay2     
T0Semaphore
tcnt
pwmc
pwmd
kbd
okbd
kbdcnt
bitvars
     endc

     
#define	KBD_SHORT	bitvars,0	; signal for short keypress
#define	PWM_DIR		bitvars,1	; pwm modifying direction
#define	PWM_EN		bitvars,2	; pwm output enable (on/off function)



; Flag Definitions
     cblock 	SHARED_RAM     ; put these up in unbanked RAM
W_Save
STATUS_Save
     endc
     
     org 0
     goto      Start

     org 4
ISR:   
	movwf	W_Save
	movf	STATUS,w
	movwf	STATUS_Save
	
	banksel	INTCON
	btfsc	INTCON,T0IF
	goto	ServiceTimer0
	goto	ExitISR          
     
ServiceTimer0:
	bcf		INTCON,T0IF

	banksel	pwmd
	movf	pwmd,w
	banksel	Display
	movwf	Display

	banksel	bitvars
	btfsc	PWM_EN
	goto	dopwm

	banksel	Output
	bcf		OUTBIT
	goto	key

dopwm
	banksel	pwmc
	incf	pwmc,w
	andlw	PWMC_MASK
	movwf	pwmc

	subwf	pwmd,w
	btfss	STATUS,C
	goto	noc
	banksel	Output
	bsf		OUTBIT
	goto	key
noc
	banksel	Output
	bcf		OUTBIT

key
	banksel	tcnt
	decfsz	tcnt,f
	goto	kbdend

	movlw	TIM
	movwf	tcnt

	clrw
	banksel	Input
	btfss	INPBIT
	addlw	1

	banksel	kbd
	movwf	kbd

	xorwf	okbd,w
	btfsc	STATUS,Z
	goto	up_or_down

; key is just pressed or released 
	movf	kbd,f
	btfss	STATUS,Z
	goto	pressed

; key is just released
	banksel	bitvars
	btfsc	KBD_SHORT
	goto	short

; long keypress is just released
; toggle pwm modify direction
	banksel	bitvars
	btfsc	PWM_DIR
	goto	pwmdir1

	bsf		PWM_DIR
	goto	kbdend

pwmdir1
	bcf		PWM_DIR
	goto	kbdend

short
; short keypress is just released
; toggle pwm enable bit
	banksel	bitvars
	btfsc	PWM_EN
	goto	pwmen1

	bsf		PWM_EN
	goto	kbdend

pwmen1
	bcf		PWM_EN
	goto	kbdend

pressed
; key is just pressed
	banksel	bitvars
	bsf		KBD_SHORT

	banksel	kbdcnt
	movlw	FIRST
	movwf	kbdcnt

	goto	kbdend

; key is in up or down state
up_or_down
	banksel	kbd
	movf	kbd,f
	btfss	STATUS,Z
	goto	down

; key is in up state
	goto	kbdend

down
; key is in down state
	decf	kbdcnt,f
	btfss	STATUS,Z
	goto	kbdend

; long press
	banksel	bitvars
	bcf		KBD_SHORT
	bsf		PWM_EN
	movlw	REST
	movwf	kbdcnt

	movf	pwmd,w
	btfss	PWM_DIR
	xorlw	PWMD_MASK
	btfsc	STATUS,Z
	goto	kbdend

	movlw	1
	btfsc	PWM_DIR
	movlw	-1
	addwf	pwmd,w
	andlw	PWMD_MASK
	movwf	pwmd

	goto	kbdend


kbdend
	banksel	kbd
	movf	kbd,w
	movwf	okbd

ExitISR:
	movf	STATUS_Save,w
	movwf	STATUS
	swapf	W_Save,f
	swapf	W_Save,w
	retfie
     



; main program
     
Start:
	banksel	pwmc
	clrf	pwmc
	clrf	tcnt
	movlw	0
;	movlw	PWMD_MASK
	movwf	pwmd

	banksel	kbd
	clrf	kbd
	clrf	okbd

	banksel	bitvars
	bcf		KBD_SHORT
	bcf		PWM_DIR
;	bsf		PWM_DIR
	bcf		PWM_EN

	initports

;	banksel	Output
;	bsf		OUTBIT

;sss
;	goto	sss

	inittmr0

	movlw	0xFF
	banksel	Display
	movwf	Display

	initirq

MainLoop:
	goto	MainLoop
     

; Delay Subroutine.  Enter delays Wreg * 771uS + 5 uS including call and return
Delay:
     movwf     Delay2              ;
DelayLoop:
     decfsz    Delay1,f            ; Waste time.  
     goto      DelayLoop           ; The Inner loop takes 3 instructions per loop * 256 loopss = 768 instructions
     decfsz    Delay2,f            ; The outer loop takes and additional 3 instructions per lap * 256 loops
     goto      DelayLoop           ; (768+3) * 256 = 197376 instructions / 1M instructions per second = 0.197 sec.
                                   ; call it two-tenths of a second.
     return
     
     end
     
