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