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. 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.
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;
}