;********************************************************************
; PWM generator with encoder control
; *******************************************************************
; http://ifrimv.altervista.org
; *******************************************************************

	list      p=12f629      ; list directive to define processor
	#include <p12f629.inc>  ; processor specific variable definitions
;	errorlevel  -302        ; suppress message 302 from list file
	__CONFIG   0x31C4	;_CP_OFF & _CPD_OFF & _BODEN_ON & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT 
	cblock     0x20

	encoder_old	;var chk_encoder 	
	encoder_new	;
	encoder_cont

	status_flag	;b0=1 -> on
			;b1=1 -> start | stop
	sw_count
	sw_old		;var sw 	
	sw_new		;
	start_count

	t0val
	pwm_rgb
	Light_val

     	endc

;***** Declaring the hardware *****
;Port	Dir	Default	PullUp	AN	Function	
;GP5	OUT	0	x	-	PWM-OUT
;GP4	IN	0	ON	-	ENC-SW
;GP3	IN	0	x	-	ENC-A /(MCLR)
;GP2	IN	0	x	-	ENC-B
;GP1	IN	0	x	-	(PGC)
;GP0	IN	0	x	-	(PGD)

c_B_val		equ 	d'64'	; start with 1/2 brightnes 
c_ON_speed	equ	d'150'	;c_ON_speed x timer0 x c_B_val = ON time  
c_OFF_speed	equ	d'50'	;c_OFF_speed x timer0 x c_B_val = OFF time
encoder_port 	equ	GPIO
sw_port		equ 	GPIO
enc_pin		equ	b'00001100'
sw_pin		equ	b'00010000'
     	org 	0x000
	nop
	goto	main
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
	org 	0x004
	bcf	INTCON,GIE		; interrupt disable
;Timer 0 interrupt			;1x2*(255-205) us = 100us	(205=t0val)	
	movfw	t0val			;reload
	addwf	TMR0,F			; timer value
	bcf	INTCON,T0IF		;

	btfsc	status_flag,0		;Off?
	goto	start_pwm		;no 
	btfss	status_flag,1		;stop?
	goto	end_encoder		;no -> skip pwm + encoder

start_pwm	;-----------------------;
	incf	pwm_rgb,F		;
	btfss	pwm_rgb,7		;limit(128)?
	goto	test_pwm_value	;

	clrf	pwm_rgb	
	bsf	GPIO,5			;Led ON
	goto	end_pwm			;skip next

test_pwm_value
	movfw	pwm_rgb			;test if Light_val > pwm_rgb 
	subwf	Light_val,W 		;	
	btfss	STATUS,C		;
	bcf	GPIO,5			;led off
end_pwm	;-------------------------------;

;start/stop-----------------------------;
	btfss	status_flag,1
	goto	chk_encoder

	btfss	status_flag,0		;on?
	goto	end_start		;no -> stop
;start
	decfsz	start_count,F
	goto	end_encoder	

	movlw	c_ON_speed		;
	movwf	start_count		;reload counter

	incf	Light_val,F
	movlw	c_B_val			;d'64'
	xorwf	Light_val,W
	btfss	STATUS,Z
	goto	end_encoder

	bcf	status_flag,1		;ON!!!!!!!!!!!!
	goto	end_encoder
end_start
;stop
	decfsz	start_count,F	
	goto	end_encoder		;skip next

	movlw	c_OFF_speed		;reload
	movwf	start_count		;counter
	decfsz	Light_val,F			;reduce 
	goto	end_encoder		;brightnes

	bcf	status_flag,1		;OFF!!!!!!!!!!!!!
	bcf	GPIO,5			;led off
	goto	end_encoder		;skip next
end_stop
;---------------------------------------;

chk_encoder 	;-----------------------; 
	movfw	encoder_port
	andlw	enc_pin			; Strip off all but the encoder bits.
	movwf	encoder_new	
	xorwf	encoder_old,W		; Is new = old?
	btfsc	STATUS,Z
	goto	err_chk_encoder		; If so, return 
	
	decfsz	encoder_cont,F		; debounce counter
	goto	end_encoder

	bcf 	STATUS,C	
	rlf	encoder_old,F		; Move old to the left to align old.0 with new.1.
	movfw	encoder_new
	xorwf	encoder_old,F
	btfss	encoder_old,3
	goto	isr_e_dw
isr_e_up
	movfw	Light_val	
	xorlw	d'127'
	btfss	STATUS,Z
	incf	Light_val,F
	goto	isr_e_ud
isr_e_dw
	movfw	Light_val
	xorlw	d'1'
	btfss	STATUS,Z
	decf	Light_val,F
isr_e_ud
	movfw	encoder_new
	movwf	encoder_old
err_chk_encoder
	movlw	d'10'
	movwf	encoder_cont
end_encoder
;---------------------------; end chk_encoder

;test switch				; ----------------------- ;
	movfw	sw_port
	andlw	sw_pin			; Strip off all but the switch bits.
	movwf	sw_new	
	xorwf	sw_old,W		; Is new = old?
	btfsc	STATUS,Z
	goto	err_test_sw		; If so, return 
	
	decfsz	sw_count,F		; debounce counter
	goto	end_switch	

	movfw	sw_new			; backup 
	movwf	sw_old			;

	btfss	STATUS,Z		; 1->0
	goto	err_test_sw		; no	
	
	movlw	0x02
	btfss	status_flag,0		; ON?
	movlw	0x03			; no-> do ON
	movwf	status_flag
	clrf	start_count
err_test_sw
	movlw	d'250'
	movwf	sw_count
end_switch				;-----------------------;	
		
;--------------- end isr timer 0
	retfie 
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

main
	call	INIT_gen
; var init -----------------------------;
	movlw	d'205'
	movwf	t0val			;<-

	clrf	Light_val		;<-
	clrf	status_flag		;<-
	movlw	d'250'
	movwf	sw_count		;<-
	
	movfw	sw_port			;
	andlw	sw_pin			;
	movwf	sw_old			;<-

	movfw	encoder_port
	andlw	enc_pin			; Strip off all but the encoder bits.
	movwf	encoder_old		;<-

	bsf	INTCON,GIE		;interrupt enable
	bsf	INTCON,T0IE		;enable interrup timer0
;---------------------------------------;
MainLoop
	nop
    	goto    MainLoop
;---------------------------------------;

;-------------------------------;
INIT_gen
	clrf	GPIO		; 
    	bsf	STATUS,RP0     	; select Register Bank 1

	movlw	b'00000000'	; set prescaler 1/2(0x00) 
	movwf	OPTION_REG	; 
	movlw	b'00010000'	; set pull up on / for GP4 
	movwf	WPU		;
     	movlw   b'00011111'	; set GP2,4 and GP5 output pin 
        movwf   TRISIO		;
	
    	bcf	STATUS,RP0     	; select Register Bank 0

	movlw	b'00000111'	; comparator 
	movwf	CMCON		;  OFF
	movlw	b'00110000'	; timer1 off, prescaler 1:8
	movwf	T1CON

	return
;-------------------------------;
	end