	;/////////////////////////////////////////////////////////////////////////////////
	;                      R O F
	;		
	;     M A D E  B Y  B R U N O  F A S C E N D I N I
	;     bipus24hs@hotmail.com
	;/////////////////////////////////////////////////////////////////////////////////
	
	;/////////////////////////////////////////////////////////////////////////////////
	; Project Name:
	; Date created: 02/01/2011 (mm/dd/yyyy)
	; Description: 
	;
	;
	;
	;
	;/////////////////////////////////////////////////////////////////////////////////
	
		LIST P=16F1823
		#include <p16F1823.inc>

		__CONFIG	_CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_ON & _CPD_ON & _BOREN_OFF & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF
		__CONFIG	_CONFIG2, _WRT_ALL & _PLLEN_ON & _STVREN_ON & _BORV_19 & _LVP_OFF
	
		ERRORLEVEL -302

	;/////////////////////////////////////////////////////////////////////////////////
	;   R A M
	;/////////////////////////////////////////////////////////////////////////////////
	
		CBLOCK	0x20
			PWM1
			PWM_BUTTON1R
			PWM_BUTTON1G
			PWM_BUTTON1B

			PWM_BUTTON2R
			PWM_BUTTON2G
			PWM_BUTTON2B

			PWM_BUTTON3R
			PWM_BUTTON3G
			PWM_BUTTON3B
	
			VALUE1
			VALUE2
			VALUE3
	
			PWM_COUNTER  		;Temporal Variable
			PORT_AUX  			;Temporal Variable
			ADC_STAGE			;ADC stage control
			ADC_LOOPS

			MAX_MINUTESL
			MAX_MINUTESH

			USED_MINUTESL
			USED_MINUTESH
			AUX_MINUTES

			BUFFER_TMP
			BUFFER_SUML
			BUFFER_SUMH	
			BUFFER_SUMTEMPL
			BUFFER_SUMTEMPH	
			BUFFER_START
		ENDC

#DEFINE		SAMPLES			.32
#DEFINE		BUFFER_END 		BUFFER_START + SAMPLES - .1
	
	;/////////////////////////////////////////////////////////////////////////////////
	;   D E F I N I T I O N S
	;/////////////////////////////////////////////////////////////////////////////////
	
	#DEFINE	ADC_CONVERTING	ADC_STAGE,0	;indicates if a conversion is running
	#DEFINE	ADC_RELAX_LOOPS		    0	;pause between conversions
	#DEFINE	BUTTON1			PORTA,  0	;ADC inout 0
	#DEFINE	BUTTON2			PORTA,  0	;ADC inout 1
	#DEFINE	BUTTON3			PORTA,  2	;ADC inout 2
	#DEFINE	PWM1_OUT		LATC,   5	;ACTUAL PWM VALUE
	
	
	#DEFINE	EEPROM_MINUTESL			0
	#DEFINE	EEPROM_MINUTESH			1

	#DEFINE	EEPROM_MINUTESMAXL		2
	#DEFINE	EEPROM_MINUTESMAXH		3

	;max minutes ON
	#DEFINE	MAXL					0xA0
	#DEFINE	MAXH					0x05

	#DEFINE	BUTTON1_MINR			.255
	#DEFINE	BUTTON1_MING			.255
	#DEFINE	BUTTON1_MINB			.255

	#DEFINE	BUTTON2_MINR			.255
	#DEFINE	BUTTON2_MING			.255
	#DEFINE	BUTTON2_MINB			.255

	#DEFINE	BUTTON3_MINR			.255
	#DEFINE	BUTTON3_MING			.255
	#DEFINE	BUTTON3_MINB			.255

	#DEFINE	BUTTON1_MAXR			.255
	#DEFINE	BUTTON1_MAXG			.0
	#DEFINE	BUTTON1_MAXB			.255

	#DEFINE	BUTTON2_MAXR			.255
	#DEFINE	BUTTON2_MAXG			.0
	#DEFINE	BUTTON2_MAXB			.255

	#DEFINE	BUTTON3_MAXR			.0
	#DEFINE	BUTTON3_MAXG			.0
	#DEFINE	BUTTON3_MAXB			.0


	;/////////////////////////////////////////////////////////////////////////////////
	; E E P R O M
	;/////////////////////////////////////////////////////////////////////////////////
		ORG		0xF000
		DE		0, 0, MAXL, MAXH

	;/////////////////////////////////////////////////////////////////////////////////
	;   R O M
	;/////////////////////////////////////////////////////////////////////////////////
		ORG 	0x000
		goto	CONFIG_INIT
	
		ORG		0x004
ISR
		retfie
	
CONFIG_INIT
		banksel	PORTA				;Bank 0
		clrf 	PORTA				;Clear latches
		clrf	PORTC
	
		banksel	TRISA
	
		movlw 	b'00000111'
		movwf	TRISA				;A0,A1,A2 as input.
		movlw	b'00000000'
		movwf	TRISC				;C as output

		movlw	b'01100110'			
		movwf	OPTION_REG			;Weak pull ups ON, TMR0 external clock, prescaler asigned to TMR0, prescaler value = 1:256 ( (32768 / 4) / 64 = 128 ticks per second)

		banksel	ADCON0
		;ADC Config
		movlw	b'00000001'			;ADFM Left Justified, VCFG Vdd, channel 0,module ON.
		movwf	ADCON0
		
		banksel	ANSELA
		movlw	b'00000111'			;A0,A1,A2 as analog inputs
		movwf	ANSELA

		banksel	ANSELC
		movlw	b'00000000'			;A0,A1,A2 as analog inputs
		movwf	ANSELC

		banksel	T1CON
	
		;TIMER1 CONFIG!
		movlw	b'00110101'			;TIMER1 ON, FOSC/4, 1:8 preescaler
		movwf	T1CON

		bcf		PIR1,TMR1IF			;clear TIMER1 interrupt flag

		clrf	AUX_MINUTES			;set aux minutes to zero

		clrf	PWM1				;clear PWM1 value!
	
		clrf	ADC_STAGE			;initialize adc stage
		bcf		ADC_CONVERTING		;indicate that we are not converting anything
		
		movlw	.1					;initialize PWM_COUNTER
		movwf	PWM_COUNTER
	
BEGIN
		movlw	0x20				;FIRST RAM POSITION
		movwf	FSR0L
		clrf	FSR0H
		
NEXT_CLEAR_RAM
		clrf	INDF0
	
		incf	FSR0L,F				
		movlw	0x60				;LAST RAM + 1
		xorwf	FSR0L,W
		btfss	STATUS,Z
		goto	NEXT_CLEAR_RAM

		movlw	BUFFER_START
		movwf	FSR0L				;initialize buffer pointer

		movlw	BUTTON1_MINR
		movwf	PWM_BUTTON1R
		movlw	BUTTON1_MING
		movwf	PWM_BUTTON1G
		movlw	BUTTON1_MINB
		movwf	PWM_BUTTON1B

		movlw	BUTTON2_MINR
		movwf	PWM_BUTTON2R
		movlw	BUTTON2_MING
		movwf	PWM_BUTTON2G
		movlw	BUTTON2_MINB
		movwf	PWM_BUTTON2B

		movlw	BUTTON3_MINR
		movwf	PWM_BUTTON3R
		movlw	BUTTON3_MING
		movwf	PWM_BUTTON3G
		movlw	BUTTON3_MINB
		movwf	PWM_BUTTON3B

		call	RESTORE_MINUTES		;load previous minutes saved

LOOP
	
	;-----------------------------------------
	;PWM GENERATION SUB-ROUTINE
	;-----------------------------------------
CHECK_PWM		
		movf	PWM_COUNTER,W
		subwf	PWM1,W
		rlf		PORT_AUX,F

		movf	PWM_COUNTER,W
		subwf	PWM_BUTTON3G,W
		rlf		PORT_AUX,F

		movf	PWM_COUNTER,W
		subwf	PWM_BUTTON3R,W
		rlf		PORT_AUX,F

		movf	PWM_COUNTER,W
		subwf	PWM_BUTTON1B,W
		rlf		PORT_AUX,F

		movf	PWM_COUNTER,W
		subwf	PWM_BUTTON1G,W
		rlf		PORT_AUX,F

		movf	PWM_COUNTER,W
		subwf	PWM_BUTTON1R,W
		rlf		PORT_AUX,W

		movwf	LATC



		clrf	PORT_AUX
		
		movf	PWM_COUNTER,W
		subwf	PWM_BUTTON2B,W
		btfsc	STATUS,C
		bsf		PORT_AUX,5

		movf	PWM_COUNTER,W
		subwf	PWM_BUTTON2G,W
		btfsc	STATUS,C
		bsf		PORT_AUX,4

		movf	PWM_COUNTER,W
		subwf	PWM_BUTTON2R,W
		btfsc	STATUS,C
		bsf		PORT_AUX,3

		movf	PORT_AUX,W
		movwf	LATA
		
PWM_READY
		incfsz	PWM_COUNTER,F
		goto	LOOP

		incf	PWM_COUNTER,F
	
		call	CHECK_ADC
		call	CHECK_MINUTES

		goto	LOOP



	
	;-----------------------------------------
	;ADC CONVERSION SUB-ROUTINE
	;-----------------------------------------
	
CHECK_ADC
		btfss	ADC_CONVERTING
		goto	ADC_WAITING
	
ADC_IS_CONVERTING
		btfsc	ADCON0, GO_NOT_DONE
		return

		movf	INDF0,W
		subwf	BUFFER_SUML,F
		btfss	STATUS,C
		decf	BUFFER_SUMH,F

		movf	ADRESH,W			;store readed value into buffer
		movwf	INDF0

		addwf	BUFFER_SUML,F
		btfsc	STATUS,C
		incf	BUFFER_SUMH,F	

		movf	BUFFER_SUML,W
		movwf	BUFFER_SUMTEMPL
		movf	BUFFER_SUMH,W
		movwf	BUFFER_SUMTEMPH

BUFFER_DIVISION_BY_2	MACRO
		bcf		STATUS,C
		rrf		BUFFER_SUMTEMPH,F
		rrf		BUFFER_SUMTEMPL,F
	ENDM
		
		BUFFER_DIVISION_BY_2
		BUFFER_DIVISION_BY_2
		BUFFER_DIVISION_BY_2
		BUFFER_DIVISION_BY_2
		BUFFER_DIVISION_BY_2
		
		movf	BUFFER_SUMTEMPL,W
		movwf	PWM1
		btfsc	STATUS,Z
		incf	PWM1,F			;PWM1 must be never zero!

		btfsc	BUTTON3			;if key is power off, shut down lights
		clrf	PWM1

		movf	USED_MINUTESH,W	
		subwf	MAX_MINUTESH,W
		btfss	STATUS,C
		clrf	PWM1

		btfss	STATUS,Z
		goto	OK_CHECKMIN

		movf	USED_MINUTESL,W
		subwf	MAX_MINUTESL,W
		btfss	STATUS,C
		clrf	PWM1

		btfsc	STATUS,Z
		clrf	PWM1

OK_CHECKMIN
		;movlw	.64
		;movwf	PWM1

		;movf	PWM1,W
		;movwf	PWM_BUTTON1G

		;comf	PWM1,W
		;movwf	PWM_BUTTON2G

		incf	FSR0L,F			;next buffer element
		movf	FSR0L,W
		xorlw	BUFFER_END + .1
		movlw	BUFFER_START
		btfsc	STATUS,Z
		movwf	FSR0L
	
		bcf		ADC_CONVERTING
		clrf	ADC_LOOPS
		return
	
ADC_WAITING
		movlw	ADC_RELAX_LOOPS
		xorwf	ADC_LOOPS,W
		btfsc	STATUS,Z
		goto	START_ADC_CONVERSION	
		
		incf	ADC_LOOPS,F
		return
	
START_ADC_CONVERSION
		bsf		ADCON0, GO			;start conversion
		bsf		ADC_CONVERTING		;indicate that we're converting a value	
		return
	
	

CHECK_MINUTES
		btfss	PIR1,TMR1IF
		return

		bcf		PIR1,TMR1IF
	
		movlw	0x0B		;timer each 500ms
		movwf	TMR1H
		movlw	0xDC
		movwf	TMR1L

		incf	AUX_MINUTES,F
		movf	AUX_MINUTES,W
		xorlw	.119
		btfss	STATUS,Z
		return

		clrf	AUX_MINUTES

		incfsz	USED_MINUTESL,F
		goto	OK_INC
	
		incf	USED_MINUTESH,F
		btfsc	STATUS,Z
		decf	USED_MINUTESH,F		;do not allow overflow

WRITE_HIGH
		movlw	EEPROM_MINUTESH
		banksel	EEADR
		movwf	EEADR
		banksel	USED_MINUTESH
		movf	USED_MINUTESH,W
		banksel	EEDAT
		movwf	EEDAT
		banksel	0

		call	WRITE_EEPROM
OK_INC

WRITE_LOW
		banksel	EECON1
		btfsc	EECON1,WR
		goto	$-1
		
		banksel	0

		movlw	EEPROM_MINUTESL
		banksel	EEADR
		movwf	EEADR
		banksel	USED_MINUTESL
		movf	USED_MINUTESL,W
		banksel	EEDAT
		movwf	EEDAT
		banksel	0

		call	WRITE_EEPROM

CHECK_READY		return

RESTORE_MINUTES
	movlw	EEPROM_MINUTESMAXL
	call	READ_EEPROM
	movwf	MAX_MINUTESL
	movlw	EEPROM_MINUTESMAXH
	call	READ_EEPROM
	movwf	MAX_MINUTESH

	movlw	EEPROM_MINUTESL
	call	READ_EEPROM
	movwf	USED_MINUTESL
	movlw	EEPROM_MINUTESH
	call	READ_EEPROM
	movwf	USED_MINUTESH
	return

READ_EEPROM
		banksel	EECON1
		btfsc	EECON1,WR	;wait for previous write to end
		goto	$-1

		movwf 	EEADR	 	;Address to read
		bsf 	EECON1,RD 	;EE Read
		movf 	EEDAT,W 	;Move data to W			
		banksel	0
		return

WRITE_EEPROM
		banksel	EECON1
		btfsc	EECON1,WR	;wait for previous write to end
		goto	$-1

		bsf 	EECON1,WREN ;Enable write
		bcf 	INTCON,GIE 	;Disable INTs
		movlw 	0x55 		;Unlock write
		movwf 	EECON2 		;
		movlw 	0xAA 		;
		movwf 	EECON2		;
		bsf 	EECON1,WR 	;Start the write
		bsf 	INTCON,GIE 	;Enable INTS		
		banksel	0
		return

		END