//
// Battery charger
// with PIC12F675
// 2011.5.7 (c)h_fujiwara_1995

#include "12F675.H"
#device ADC=10
#fuses INTRC_IO,NOWDT,PROTECT,NOMCLR,BROWNOUT,PUT
#use delay(internal=4MHz)

//  RA0 AN0 Battery2(Positive side)
//  RA1 AN1 Battery1(Negative side)
//  RA2 AN2 Current
//  RA3 N.C (MCLR)
//  RA4 OUT CHARGE FET-GATE
//  RA5 OUT LED

#use fast_io(A)

int16 get_ad()
{
	int1	done; int16	value;
	read_adc(ADC_START_ONLY); done = adc_done();
	while(!done) done=adc_done();
	value=read_adc(ADC_READ_ONLY); return(value); 
}

int16	get_ad64(int ch)
{
	int16	v; int i;

	set_adc_channel(ch);
	delay_us(50);
	v=0; for(i=0;i<64;i++) v+=get_ad();
	v= v >> 6;
	return(v);
}

#define	FETPORT	PIN_A4
#define	LEDPORT	PIN_A5

// charge mode

#define	NOBATTERY	0
#define	PRECHARGE	1
#define	CHARGING	2
#define	FINISHCHG	3

#define		MAXTIMECHG			(144*60*10)
#define		PRECHARGETIME		(5*60*10)
#define		MINCURRENT			(15)
#define		NOBATTERYVOLTAGE	(700)

main()
{
	int16 curr,battery,maxbattery;
	int	mode,i;
	int32	timercount;

	// initialize
	set_tris_a(0x0f);
	output_low(LEDPORT);
	output_low(FETPORT);
	setup_adc(ADC_CLOCK_DIV_8);
	setup_adc_ports(sAN0 | sAN1 | sAN2);
	mode=NOBATTERY;
	maxbattery=0;
	
	while(1){
		switch(mode){
		case	NOBATTERY:
			timercount=0;
			maxbattery=0;
			output_high(FETPORT);	// test charge
			delay_ms(100);
			curr=get_ad64(2);		// check current
			battery= get_ad64(0) - get_ad64(1);
			if(curr>MINCURRENT) mode=PRECHARGE; else {output_low(FETPORT);delay_ms(900);}
			break;
		case	PRECHARGE:
			output_high(FETPORT);
			timercount++;
			if(timercount>=PRECHARGETIME){mode=CHARGING; break;} 	// after precharging, run to charge
			curr=get_ad64(2);
			if(curr<MINCURRENT) mode=NOBATTERY;
			break;
		case	CHARGING:
			output_high(FETPORT);
			timercount++;
			curr=get_ad64(2);
			battery= get_ad64(0) - get_ad64(1);
			if(curr<MINCURRENT){mode=NOBATTERY; break;}					// maybe removed battery
			if(battery>=NOBATTERYVOLTAGE){mode=NOBATTERY;break;}			// removed battery
			if(timercount > MAXTIMECHG){mode=FINISHCHG; break;}// timer over
			if(battery>maxbattery) maxbattery=battery;
			if(battery<(maxbattery-1)) mode=FINISHCHG;			// delta peak detection
			break;
		case	FINISHCHG:
			timercount=0;
			maxbattery=0;
			output_low(FETPORT);
			delay_ms(2000);
			battery= get_ad64(0) - get_ad64(1);
			if(battery>=NOBATTERYVOLTAGE) mode=NOBATTERY;					// removed battery
			break;
		default:
			mode=NOBATTERY;
			break;
		}

		delay_ms(100);		// loop interval 

		switch(mode){
		case	NOBATTERY:
			output_low(LEDPORT);break;
		case	PRECHARGE:
			output_high(LEDPORT);break;
		case	CHARGING:
			if(timercount&2) output_high(LEDPORT); else output_low(LEDPORT);
			break;
		case	FINISHCHG:
			output_high(LEDPORT);break;
		default:break;
		}
	}
}