Batteri-laddar-styrning med PIC16F688

Berätta om dina pågående projekt.
Användarvisningsbild
baron3d
EF Sponsor
Inlägg: 1339
Blev medlem: 1 oktober 2005, 23:58:43
Ort: Torestorp

Batteri-laddar-styrning med PIC16F688

Inlägg av baron3d »

Hej alla

Tycker det är dags för att delge er mitt senaste hobby projekt: Logik till en hemmabyggd bilbatteriladdare. Laddaren gjorde jag för c:a 30 år sedan.
Efter mycket funderingar bestämde jag mig för en PIC16F688. Bra för jag har en del, dåligt för att den går inte att debugga. :evil: Jag skulle valt en 20-pin i stället. Vilket jag ångrar av flera anledningar.

Jag är mycket nöjd över hur laddaren beter sig och har väl en del idéer om modifieringar.
Så här är den i nuläget.
front.jpg
ovan.jpg
sch.gif

Kod: Markera allt

Inkoppling:
------------------------------------------------------------------
>Ladaren stängs av.
>Batteriet kopplas in.
>Lysdioder indikerar:
	Grön: rätt inkopplat
	Röd:  fel inkopplat

>Välj tid med Tids-omkopplaren.
	Ner=3tim=grön, mitten=6tim=gul, upp=10tim=röd

>Sätt på laddaren med lämplig strömstyrka.

Tid: Gul indikerar att tiden är klar.
Spänning: Fast Gul indikerar att laddningen är klar
Spänning: Blinkade Gul indikerar att batteriets spänning är för låg



Programmering:
------------------------------------------------------------------
>Laddaren skall vara avstängd.
>PRG hålls nertryckt.
>Laddaren sätts på.
>PRG släpps.


>Laddaren kopplas till en variabel spänningskälla.

De gula lysdioderna indikerar:

	Spänning                 tids led  spännins led
	----------------         --------  ------------
	Över "Laddning klar"       På          På
	mellan                     På            Av
	under "Laddning startar"     Av        På
	under "för låg"              Av          Av

Laddning klar, c:a 13.8V:
----------------------
>Tids-omkopplaren ställs i sitt övre läge.
>Spänningen ställs in.
>PRG trycks ner tills dess att "PÅ" indikatorn släcks.


Laddning startar, c:a 12.8V:
----------------------
>Tids-omkopplaren ställs i mitt läge.
>Spänningen ställs in.
>PRG trycks ner tills dess att "PÅ" indikatorn släcks.


Batteriet har för låg spänning, c:a 10.0V:
----------------------
>Tids-omkopplaren ställs i sitt undre läge.
>Spänningen ställs in.
>PRG trycks ner tills dess att "PÅ" indikatorn släcks.


>Laddaren stängs av.

Kod: Markera allt

// main.c
// PIC16F688 project: Laddare_2

#include "main.h"
#include "eeprom.h"

// Port bit pin base_fn x_fn     funktion
//	---- --- --- ------  ----		--------------------------
// PORTA 0	13	ICSPDAT				---ICSP---
// PORTA 1	12	ICSPCLK				---ICSP---
// PORTA 2	11				A/D 2		a-in	spänning
// PORTA 3	 4	Reset					---ICSP---  sw-reset
// PORTA 4	 3	(XTAL)	(A/D 3)	in		sw-tid-a
// PORTA 5	 2	(XTAL)				in		sw-tid-b 
// PORTC 0	10				(A/D 4)	in		sw-prog
// PORTC 1	 9				(A/D 5)	ut		relay + led-green
// PORTC 2	 8							ut		---
// PORTC 3	 7							ut		led-yellow time
// PORTC 4	 6				(TX)		ut		led-yellow voltage
// PORTC 5	 5				(RX)		ut		led green blink (On)

//#define SW_PROG_IN      RC0
//#define OK_BAT_LED_OUT  RC2
#define VON_LED_OUT     RC5
//#define TIMEOUT_LED_OUT RC3
//#define VOLTAGE_LED_OUT RC4
//#define RELAY_LED_OUT   RC1

#define SW_TIME_LONG_IN    (RA4==1)
#define SW_TIME_SHORT_IN   (RA5==1)

#define SW_PROGR_IN        (RC0==1)

#define RELAY_LED_ON_OUT    RC1=1
#define RELAY_LED_OFF_OUT   RC1=0
#define TIMEOUT_LED_ON_OUT  RC3=0
#define TIMEOUT_LED_OFF_OUT RC3=1
#define VOLTAGE_LED_ON_OUT  RC4=0
#define VOLTAGE_LED_OFF_OUT RC4=1
#define VON_LED_ON_OUT      RC5=0
#define VON_LED_OFF_OUT     RC5=1

#define EE_HI_LIMIT_ADR		0
#define EE_LOW_LIMIT_ADR	2
#define EE_LOW_BAT_ADR		4

typedef char sint8;
typedef unsigned char uint8;
	
typedef int sint16;
typedef unsigned int uint16;

typedef union {
	uint16 u;
	sint16 s;
	struct {
		uint8 l;
		uint8 h;
	};
} word ;		


uint8  cnt_u8 = 0;
uint8  sec_u8 = 0;
uint8  min_u8 = 0;
uint8  tim_u8 = 0;

uint8  out_ctrl_u8 = 0;

uint8  cnt2_u8 = 0;
uint16 res_u16 = 0;
uint16 resL_u16 = 0;
//uint16 resH_u16 = 0;
uint16 result_u16 = 0;
uint16 result_L_u16 = 0;

// 10.0V = 9344
uint16 lim_H_u16 = 12700;
uint16 lim_L_u16 = 11900;
uint16 lim_Low_u16 = 8000;
uint16 lim_too_H_u16 = 13150;

uint16 s_u16;

uint8  key_u8 = 0;
 
typedef enum  {oo_Off=0, oo_On} OnOff_e;

OnOff_e out_oo = oo_Off;
uint8  timer_u8 = 0;

uint8  tim_timer_u8 = 10;

word r_w;

#define M_FACTOR 16
#define OFFTIMER 5
#define ONTIMER  2
#define OFFTIMER2 10


int main(void) {
		
	CMCON0 = 0b00000111; // Comparator off	
	OSCCON = 0b01110001;	// 8Mhz
	TRISA  = 0b11111111;	// set all port A bits to be input
	TRISC  = 0b00000001;	// set bits 1-5 to be output and bit0 to input
	PORTC  = 0b00000000;	// write a value to the portC
	
	ANSEL  = 0b00000100;	// ANS2
	ADCON0 = 0b10001001;
	ADCON1 = 0b00100000;	// 8MHz
	T1CON  = 0b00110101; // 16bit timer /8 
	
	s_u16 = EEPROM_get_int(EE_HI_LIMIT_ADR);
	if( (s_u16 == 0) || (s_u16 == 0xffff) ) {
		EEPROM_put_int(EE_HI_LIMIT_ADR, lim_H_u16);
	}
	else {
		lim_H_u16 = s_u16;
	}	
	
	s_u16 = EEPROM_get_int(EE_LOW_LIMIT_ADR);
	if( (s_u16 == 0) || (s_u16 == 0xffff) ) {
		EEPROM_put_int(EE_LOW_LIMIT_ADR, lim_L_u16);
	}
	else {
		lim_L_u16 = s_u16;
	}		
	
	s_u16 = EEPROM_get_int(EE_LOW_BAT_ADR);
	if( (s_u16 == 0) || (s_u16 == 0xffff) ) {
		EEPROM_put_int(EE_LOW_BAT_ADR, lim_Low_u16);
	}
	else {
		lim_Low_u16 = s_u16;
	}
	
	//	lim_too_H_u16 = lim_H_u16 * 1.03516
//	r_w.u = lim_too_H_u16 = lim_H_u16;
//	lim_too_H_u16 += lim_H_u16 >> 5;
//	lim_too_H_u16 += (uint16)r_w.h;

	//	lim_too_H_u16 = lim_H_u16 * 1.07
	lim_too_H_u16 = lim_H_u16;
	s_u16 = lim_H_u16 >> 4;
	lim_too_H_u16 += s_u16;	// + lim_H_u16 / 16
	lim_too_H_u16 += s_u16 >> 3;;	// + lim_H_u16 / 128
	
	// programmering
	if(SW_PROGR_IN) {
		while(SW_PROGR_IN) {
			CLRWDT();
		}	
		
		// programmering loop
		while(1) {
			CLRWDT();
			
			GO_DONE = 1; // Starta ad omvandling			
			while(GO_DONE); // vänta tills klar
	
			r_w.h = ADRESH;
			r_w.l = ADRESL;
			
			//  *** calc sum of 16 values and calculate min val *** 
			res_u16 += r_w.u;
			cnt2_u8++;		
			if( cnt2_u8 >= M_FACTOR ) {
				// res = r_w*16
				cnt2_u8 = 0;
				result_u16 = res_u16;			
				res_u16 = 0;
			}			
			
			TIMEOUT_LED_ON_OUT;
			VOLTAGE_LED_OFF_OUT;
			
			if( result_u16 > lim_H_u16) {					
				TIMEOUT_LED_ON_OUT;
				VOLTAGE_LED_ON_OUT;
			}	
			if( result_u16 < lim_L_u16) {
				TIMEOUT_LED_OFF_OUT;
				VOLTAGE_LED_ON_OUT;
			}					
			if( result_u16 < lim_Low_u16) {
				TIMEOUT_LED_OFF_OUT;
				VOLTAGE_LED_OFF_OUT;
			}	
						
			// *** sw-prog to set cutoff voltage *** 
			if(key_u8) {
				out_oo = oo_Off;
				timer_u8 = OFFTIMER;
				
				if(SW_PROGR_IN) {
					if(key_u8 < 250) {					
						key_u8++;
					}	
					else {
						VON_LED_OFF_OUT;
					}
				}
				else {	
					if(key_u8 >= 250) {				
						if(SW_TIME_LONG_IN) {
							lim_H_u16 = result_u16;
							EEPROM_put_int(EE_HI_LIMIT_ADR, lim_H_u16);
						}	
						else if(SW_TIME_SHORT_IN) {
							lim_Low_u16 = result_u16;
							EEPROM_put_int(EE_LOW_BAT_ADR, lim_Low_u16);
						}	
						else {
							lim_L_u16 = result_u16;
							EEPROM_put_int(EE_LOW_LIMIT_ADR, lim_L_u16);
						}						
					}	
					key_u8 = 0;
				}				
			}
			else {
				if(SW_PROGR_IN) {
					key_u8 = 1;				
				}	
				VON_LED_ON_OUT;			
			}						
		}	// end while(1) programmering		
	}	// end if(SW_PROGR)
	
	
	//	Charge loop 
	while(1) {
		CLRWDT();
				
		GO_DONE = 1; // Starta ad omvandling
		
		tim_timer_u8 = 6;
		if(SW_TIME_LONG_IN ) tim_timer_u8 = 10;
		if(SW_TIME_SHORT_IN) tim_timer_u8 = 3;
		
		while(GO_DONE); // vänta tills klar

		r_w.h = ADRESH;
		r_w.l = ADRESL;
		
		//  *** calc sum of 16 values and calcultate min val *** 
		res_u16 += r_w.u;
		cnt2_u8++;		
		if( cnt2_u8 >= M_FACTOR ) {
			// res = r_w*16
			cnt2_u8 = 0;
			if(res_u16 < resL_u16) resL_u16 = res_u16;
			//if(res_u16 > resH_u16) resH_u16 = res_u16;
			result_u16 = res_u16;			
			res_u16 = 0;
		}	
	 	
	 	if(TMR1IF) {	 	// 0,52s 
		 	TMR1IF = 0;
			cnt_u8++;
			VON_LED_OUT = ~VON_LED_OUT;	//	led green blink
		}
		
		if(cnt_u8 > 1) {
			cnt_u8 = 0;
			sec_u8++;		
			
			if(timer_u8 == 0) {			
				if( out_ctrl_u8 == 1) {
					out_oo = oo_Off;
					timer_u8 = OFFTIMER;
				}	
				if( out_ctrl_u8 == 2) {
					out_oo = oo_On;							
					timer_u8 = ONTIMER;
				}
			}
			result_L_u16 = resL_u16;	
			resL_u16 = 65535;
		}
		
		out_ctrl_u8 = 0;
		if( result_L_u16 > lim_H_u16) {					
			VOLTAGE_LED_ON_OUT;	//	led-yellow, voltage high
			out_ctrl_u8 = 1;
		}	
		if( result_L_u16 < lim_L_u16) {
			VOLTAGE_LED_OFF_OUT;	//	led-yellow, voltage normal	
			out_ctrl_u8 = 2;
		}		
		
		//  *** under voltage *** 
		if( result_u16 < lim_Low_u16) {
			// flash led-yellow, voltage too low
			if(cnt_u8 & 1) {
				VOLTAGE_LED_OFF_OUT;
			}	
			else {
				VOLTAGE_LED_ON_OUT;
			}	
			out_oo = oo_Off;
			timer_u8 = 1;
			sec_u8   = 45;
		}
		
		//  *** over voltage *** 
		if( result_L_u16 > lim_too_H_u16) {
			// flash led-yellow, voltage too high
			if(cnt_u8 & 1) {
				VOLTAGE_LED_OFF_OUT;
			}	
			else {
				VOLTAGE_LED_ON_OUT; 
			}	
			out_oo = oo_Off;
			timer_u8 = OFFTIMER2;
		}
				
		//  *** process time *** 
		if(sec_u8 > 59) {
			sec_u8 = 0;
	 		min_u8++;
	 		
			if(timer_u8) {
				timer_u8--;
			}					 		
	 	}	
		if(min_u8 > 59) {
			min_u8 = 0;
	 		tim_u8++;
	 	}	
	 	
	 	if(tim_u8 >= tim_timer_u8) {
			tim_u8 = tim_timer_u8;
			// time out
			out_oo = oo_Off;	
			TIMEOUT_LED_ON_OUT;	//	led-yellow time
		}
		else {
			TIMEOUT_LED_OFF_OUT;	//	led-yellow time			
		}		
			
		//  *** set/clear output relay *** 		
		if( out_oo == oo_On) {
			RELAY_LED_ON_OUT;
		}
		else {
			RELAY_LED_OFF_OUT;
		}
		
	} // end while(1) Charge loop
	return 0;
}
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.