/Designs/HAM Constructions/IBP20/SW/V_1_1/ibp2.c
0,0 → 1,1247
//**********************************************************************
// INFO BATTERY PACK
//**********************************************************************
// (c) OK1XGL 2008
// verze 1.0 - uvodni verze
// 1.1 - referencni teplota pro samovybijeni se uklada pri zadani doby mereni samovybijeni
//
//
 
#include "ibp2.h"
 
 
// nastavi orientaci a klidovy stav portu
//
void init_ports (void) {
set_tris_a (0b00101011);
output_a (0b000000000);
 
set_tris_b (0b11010000);
output_b (0b00100000);
port_b_pullups (FALSE);
}
 
 
//////////////////////////////////////////////////
//
// iterrupty
// cele preruseni zabere 33+xx+30 cyklu
//
//////////////////////////////////////////////////
 
// periodicky casovac
//
#INT_TIMER1
void tmr1_int (void) {
// natahovani casovace
set_timer1 (S_TICK_TIME);
s_tick = 1;
 
if (l_timer == 0) {
l_timer = L_TICK_TIME;
l_tick = 1;
blink = ~blink;
if (blink)
slow_blink = ~slow_blink;
}
else
l_timer--;
}
 
 
 
///////////////////////////////////////////////////
//
// FUNKCE PRO PRACI S TEPLOMEREM
//
//////////////////////////////////////////////////
 
// testuje pritomnost teplomeru, pri pritomnosti vraci 1
// zabere 1060 taktu
//
int8 TM_present() {
int1 present;
 
output_low (TM_PIN);
output_fixed (TM_PIN);
delay_us (500);
disable_interrupts (GLOBAL);
output_float (TM_PIN);
if(!input (TM_PIN)) {
enable_interrupts (GLOBAL);
return (0);
}
delay_us (65);
present = input(TM_PIN);
enable_interrupts (GLOBAL);
delay_us (440);
if (present)
return (0);
else
return (1);
}
 
 
// precte bajt z teplomeru
//
int8 TM_read_byte() {
int8 i,data;
 
for(i = 0; i < 8; ++i) {
disable_interrupts (GLOBAL);
output_low (TM_PIN);
output_fixed (TM_PIN);
delay_us (2);
output_float (TM_PIN);
delay_us (8);
shift_right (&data,1,input(TM_PIN));
enable_interrupts (GLOBAL);
delay_us (55);
}
return (data);
}
 
 
// zapise bajt do teplomeru
//
void TM_write_byte(int8 data) {
int8 i;
 
for (i = 0 ; i < 8; ++i) {
disable_interrupts (GLOBAL);
output_low (TM_PIN);
output_fixed (TM_PIN);
delay_us (5);
if (shift_right (&data,1,0))
output_float (TM_PIN);
delay_us (60);
output_float (TM_PIN);
delay_us (2);
enable_interrupts (GLOBAL);
}
}
 
 
// vraci 0 pri ukonceni mereni
// vraci 1 pri rozpracovanem mereni
// zabere max 1100 taktu na 1 cyklus
// potrebuje 10 volani pro zmereni teploty
//
int8 measure_temp () {
static int8 phase;
static int8 tmp;
int8 tmp2;
 
switch (phase) {
case 0:
if (! TM_present ()) { // over pritomnost teplomeru
phase = 0;
TB_val = TB_DEFAULT;
return (0); // teplomer neni pritomen, dal nelze pokracovat
}
break;
 
case 1:
TM_write_byte (0xcc); // preskoc na dalsi sadu prikazu
break;
 
case 2:
TM_write_byte (0x44); // prikaz spust mereni teploty
output_high (TM_PIN); // zapni tvrdy pullup
output_fixed (TM_PIN); //
break;
 
case 3:
case 4:
case 5: // cekej nejmene 750 ms
break;
 
case 6:
output_float (TM_PIN); // vyppni tvrdy pullup
output_low (TM_PIN); //
if (! TM_present ()) { // over pritomnost teplomeru
phase = 0;
TB_val = TB_DEFAULT;
return (0); // teplomer neni pritomen, dal nelze pokracovat
}
break;
 
case 7:
TM_write_byte (0xcc); // preskoc na dalsi sadu prikazu
break;
 
case 8:
TM_write_byte (0xbe); // prikaz precti zmerenou teplotu
break;
 
case 9:
tmp = TM_read_byte () >> 4; // precti LSB bajt s teplotou a zahod destiny stupne
break;
 
case 10:
tmp |= TM_read_byte () << 4; // precti MSB bajt s teplotou a sloz s LSB
tmp2 = tmp & 0x7F; //
if (tmp2 < 80) { // teplota je v moznem rozsahu (nahrada kontroly CRC - bylo by casove prilis dlouhe)
if (tmp & 0x80)
TB_val = 0; // zapornou teplotu povazujeme za nulovou
else
TB_val = tmp2;
}
phase = 0;
return (0);
break;
 
default:
phase = 0;
TB_val = TB_DEFAULT;
return (0);
}
phase++;
return (1);
}
 
 
 
//////////////////////////////////////////////////////
//
// FUNNKCE PRO MERENI NAPETI A PROUDU
//
//////////////////////////////////////////////////////
 
// meri velikost proudu z/do baterie a prumeruje z 8 mereni
// zabere max 1760 taktu (1760 us)
//
int16 measure_IB (void) {
int16 out;
 
set_adc_channel (IB_CAN);
delay_us (100);
out = read_adc (ADC_START_AND_READ);
delay_us (100);
out += read_adc (ADC_START_AND_READ);
delay_us (100);
out += read_adc (ADC_START_AND_READ);
delay_us (100);
out += read_adc (ADC_START_AND_READ);
delay_us (100);
out += read_adc (ADC_START_AND_READ);
delay_us (100);
out += read_adc (ADC_START_AND_READ);
delay_us (100);
out += read_adc (ADC_START_AND_READ);
delay_us (100);
out += read_adc (ADC_START_AND_READ);
out = out >> 3;
return (out);
}
 
 
// meri velikost napeti baterie a provadi klouzavy prumer z 8 mereni
// zabere max 320 taktu (320 us)
//
int16 measure_VB (void) {
static int16 smpl [8];
static int8 i;
int16 out;
 
if (i >= 8-1)
i = 0;
else
i++;
 
set_adc_channel (VB_CAN);
delay_us (100);
smpl [i] = read_adc (ADC_START_AND_READ);
 
out = smpl [0] + smpl [1] + smpl [2] + smpl [3] +
smpl [4] + smpl [5] + smpl [6] + smpl [7];
out = out >> 3;
return (out);
}
 
 
// meri velikost vstupniho napeti zdroje pro nabijeni
// zabere max 200 taktu (200 us)
//
int16 measure_VS (void) {
int16 out;
 
set_adc_channel (VS_CAN);
delay_us (100);
out = read_adc (ADC_START_AND_READ);
return (out);
}
 
 
// meri vystupni napeti OZ pro mereni proudu pri nulovem odberu - pro kompenzaci ofsetu OZ
//
int16 measure_offset (void) {
int16 out;
int8 i;
 
// vypni vsechny spotrebice
init_ports ();
disable_interrupts (GLOBAL);
ADIE = 1;
PEIE = 1;
delay_ms (500);
 
// mer napeti OZ a vypocti prumer z 8 mereni
set_adc_channel (IB_CAN);
delay_us (100);
out = 0;
for (i = 0; i < 8; i++) {
read_adc (ADC_START_ONLY);
sleep ();
out += read_adc (ADC_READ_ONLY);
delay_us (100);
restart_wdt ();
}
out = out >> 3;
 
ADIE = 0;
PEIE = 0;
enable_interrupts (GLOBAL);
return (out);
}
 
 
/////////////////////////////////////////////////
//
// FUNKCE PRO PRACI S LED
//
/////////////////////////////////////////////////
 
// rozsviti vsechny led
//
void leds_all_on () {
output_high (LED4_R);
output_high (LED3_Y);
output_high (LED2_Y);
output_high (LED1_G);
}
 
 
// zhasne vsechny led
//
void leds_all_off () {
output_low (LED4_R);
output_low (LED3_Y);
output_low (LED2_Y);
output_low (LED1_G);
}
 
 
// signalizuje kapacitu baterie pri nabijeni
// vraci cislo odpovidajici stavu nabiti
// zabere max 40 cyklu
//
int8 leds_chrg (void) {
if (B_cap >= B_cap_4_4) {
leds_all_on ();
return (4); // baterie plne nabita
}
 
if (B_cap > B_cap_3_4) {
output_high (LED4_R);
output_high (LED3_Y);
output_high (LED2_Y);
if (slow_blink)
output_high (LED1_G);
else
output_low (LED1_G);
return (3);
}
 
if (B_cap > B_cap_2_4) {
output_high (LED4_R);
output_high (LED3_Y);
if (slow_blink)
output_high (LED2_Y);
else
output_low (LED2_Y);
output_low (LED1_G);
return (2);
}
 
if (B_cap > B_cap_1_4) {
output_high (LED4_R);
if (slow_blink)
output_high (LED3_Y);
else
output_low (LED3_Y);
output_low (LED2_Y);
output_low (LED1_G);
return (1);
}
 
if (slow_blink)
output_high (LED4_R);
else
output_low (LED4_R);
output_low (LED3_Y);
output_low (LED2_Y);
output_low (LED1_G);
return (0);
}
 
 
// signalizuje chybu
//
void leds_err () {
output_low (LED1_G);
output_low (LED4_R);
if (blink) {
output_high (LED2_Y);
output_high (LED3_Y);
}
else {
output_low (LED2_Y);
output_low (LED3_Y);
}
}
 
 
// signalizuje neznamou aktualni kapacitu baterie
//
void leds_invalid_cap () {
output_low (LED2_Y);
output_low (LED3_Y);
if (blink) {
output_high (LED1_G);
output_high (LED4_R);
}
else {
output_low (LED1_G);
output_low (LED4_R);
}
}
 
 
// signalizuje zbyvajici kapacitu baterie pri vybijeni
//
void leds_dis () {
if (B_cap < B_cap_1_4) {
output_low (LED1_G);
output_low (LED2_Y);
output_low (LED3_Y);
output_high (LED4_R);
return;
}
 
if (B_cap < B_cap_2_4) {
output_low (LED1_G);
output_low (LED2_Y);
output_high (LED3_Y);
output_low (LED4_R);
return;
}
 
if (B_cap < B_cap_3_4) {
output_low (LED1_G);
output_high (LED2_Y);
output_low (LED3_Y);
output_low (LED4_R);
return;
}
 
output_high (LED1_G);
output_low (LED2_Y);
output_low (LED3_Y);
output_low (LED4_R);
}
 
 
// signalizuje temer vybitou baterii
//
void leds_VB_low () {
output_low (LED1_G);
output_low (LED2_Y);
output_low (LED3_Y);
if (slow_blink)
output_high (LED4_R);
else
output_low (LED4_R);
}
 
 
// zobrazi cislo v rozsahu 0 - 9 v binarnim kodu na ledkach
//
void num_to_leds (int8 num) {
 
switch (num) {
case 0:
output_low (LED4_R); // nejnizsi bit
output_low (LED3_Y);
output_low (LED2_Y);
output_low (LED1_G); // nejvyssi bit
break;
case 1:
output_high (LED4_R); // nejnizsi bit
output_low (LED3_Y);
output_low (LED2_Y);
output_low (LED1_G); // nejvyssi bit
break;
case 2:
output_low (LED4_R); // nejnizsi bit
output_high (LED3_Y);
output_low (LED2_Y);
output_low (LED1_G); // nejvyssi bit
break;
case 3:
output_high (LED4_R); // nejnizsi bit
output_high (LED3_Y);
output_low (LED2_Y);
output_low (LED1_G); // nejvyssi bit
break;
case 4:
output_low (LED4_R); // nejnizsi bit
output_low (LED3_Y);
output_high (LED2_Y);
output_low (LED1_G); // nejvyssi bit
break;
case 5:
output_high (LED4_R); // nejnizsi bit
output_low (LED3_Y);
output_high (LED2_Y);
output_low (LED1_G); // nejvyssi bit
break;
case 6:
output_low (LED4_R); // nejnizsi bit
output_high (LED3_Y);
output_high (LED2_Y);
output_low (LED1_G); // nejvyssi bit
break;
case 7:
output_high (LED4_R); // nejnizsi bit
output_high (LED3_Y);
output_high (LED2_Y);
output_low (LED1_G); // nejvyssi bit
break;
case 8:
output_low (LED4_R); // nejnizsi bit
output_low (LED3_Y);
output_low (LED2_Y);
output_high (LED1_G); // nejvyssi bit
break;
case 9:
output_high (LED4_R); // nejnizsi bit
output_low (LED3_Y);
output_low (LED2_Y);
output_high (LED1_G); // nejvyssi bit
break;
default:
output_low (LED4_R); // nejnizsi bit
output_low (LED3_Y);
output_low (LED2_Y);
output_low (LED1_G); // nejvyssi bit
}
}
 
 
///////////////////////////////////////////////////////
//
// FUNKCE PRO CTENI TLACITEK A KONTAKTU
//
///////////////////////////////////////////////////////
 
// je pripojena zatez?
// vraci 1 pri pripojene zatezi
//
int1 is_load () {
int1 load;
port_b_pullups (TRUE);
delay_us (100);
load = input (LOAD_ON); // precti stav kontaktu pripojeni zateze
port_b_pullups (FALSE);
return (load);
}
 
 
// cte stav nastavovacich tlacitek
// vraci masky stisknutych tlacitek, 0 = klidovy stav
//
int8 read_keys () {
static int1 up_key_old;
static int1 set_key_old;
static int8 keys;
int1 key_state;
 
key_state = input (UP);
if (key_state != up_key_old)
up_key_old = key_state;
else
if (! key_state)
keys |= UP_MASK;
else
keys &= ~UP_MASK;
 
key_state = input (SET);
if (key_state != set_key_old)
set_key_old = key_state;
else
if (! key_state)
keys |= SET_MASK;
else
keys &= ~SET_MASK;
return (keys);
}
 
 
///////////////////////////////////////////////////
//
// VYKONNE FUNKCE
//
///////////////////////////////////////////////////
 
// vybijeni baterie
//
void do_discharge () {
int16 IB_val;
int16 I_zero;
int16 VB_val;
int16 dec_cap;
int1 load, load_old;
int1 err;
 
#ifdef DEBUG
int16 max,min;
int16 cnt;
#endif
 
// signalizuj neduveryhodnost zbyvajici kapacity baterie
if (invalid_cap) {
blink = 1;
leds_invalid_cap ();
delay_ms (500);
leds_all_off ();
}
 
// nastaveni AD prevodniku: reference je 2.5V posun mereni proudu o 2,51V => cim vetsi prout, tim nizzsi cislo z prevodniku
setup_adc_ports (sAN0 | sAN1 | sAN2 | sAN3 | sAN5 | VSS_VREF);
setup_vref (VREF_HIGH | VREF_A2 | 8); // na A2 vystup reference 2.51V
delay_ms (1);
 
I_zero = measure_offset (); // precti klidovou hodnotu, tedy offset OZ - nulovy odebirany proud
 
output_high (BATT_ON);
leds_dis (); // signalizuj zbyvajici kapacitu bateie
 
err = 0;
blink = 1;
l_tick = 0;
s_tick = 0;
 
// jeden pruchod smycku zabere max 2000 taktu
for(;;) {
restart_wdt ();
if (s_tick) {
s_tick = 0;
IB_val = measure_IB (); // mer proud odebirany z baterie
if (IB_val == 0 ) {
// proudove pretizeni
output_low (BATT_ON); // odpoj baterii
err = 1; // signalizuj chybu
}
dec_cap = I_zero - IB_val; // zbav se ofsetu OZ
if (B_cap > dec_cap)
B_cap = B_cap - dec_cap; // uprav zbyvajici kapacitu baterie
 
if (! err)
VB_val = measure_VB (); // napeti baterie je mozne merit jen pokud neni odpojena
 
#ifdef DEBUG
if (IB_val > max)
max = IB_val;
if (IB_val < min)
min = IB_val;
cnt++;
#endif
}
 
if (l_tick) {
l_tick = 0;
if (! is_load ()) {
return; // koncime, zatez odpojena
}
 
if (VB_val < VB_MIN) {
// baterie zcela vybita
B_cap = 0; // nastav prazdnou kapacitu
invalid_cap = 0; // aktualni kapacita baterie je nyni znama
return;
}
 
if (err) {
leds_err (); // signalizuj chybu
}
else {
if (VB_val < VB_LOW) {
leds_VB_low (); // signalizuj temer vybitou baterii
}
else {
leds_dis (); // signalizuj zbyvajici kapacitu bateie
}
}
 
#ifdef DEBUG
printf ("cnt:%lu z:%lu max:%ld delta:%u dec:%lu\n\r",cnt,I_zero,max,(int8)(max-min),dec_cap);
max = 0;
min = 1024;
cnt = 0;
#endif
}
}
}
 
 
// proces nabijeni baterie
//
void do_charge () {
int1 chrg;
int1 err;
int16 I_zero;
int16 IB_val;
int16 inc_cap;
int32 fast_chrg;
int8 pwm;
int16 duty;
 
#ifdef DEBUG
int16 max,min;
int16 vs_val;
#endif
 
// vypocti mez do ktere budeme nabijet vyssim proudem
// fast_chrg = (B_cap_4_4 - B_cap) / 64;
fast_chrg = (B_cap_4_4 - B_cap) / 72;
fast_chrg *= chrg_eff;
fast_chrg += B_cap;
#ifdef DEBUG
// printf ("%lu %u %lu %lu\n\r\n\r",B_cap_4_4, chrg_eff,B_cap, fast_chrg);
#endif
 
err = 0;
s_tick = 0;
l_tick = 0;
pwm = 0;
chrg = 0;
 
// nastaveni AD prevodniku, reference je VDD = 5V , zadny posun napeti pri mereni proudu => cim vyssi proud, tim vyssi cislo z prevodniku
setup_adc_ports (sAN0 | sAN1 | sAN2 | sAN3 | sAN5 | VSS_VDD);
setup_vref (VREF_LOW | VREF_A2 | 2); // na A2 vystup reference 0.416V
delay_ms (1);
I_zero = measure_offset (); // precti klidovou hodnotu, tedy ofset OZ - nulovy nabijeci proud
 
if (invalid_cap == 0 &&
TB_val < TB_MAX &&
TB_VAL > TB_MIN) {
// kapacita baterie je znama a teplota baterie je v mezich
output_high (BATT_ON); // pripoj baterii
output_high (CHRG_ON); // pripoj zdroj nabijeni
delay_ms (500); // cekej na ustaleni menice
chrg = 1;
}
 
if (measure_VS () < VS_MIN) { // kontrola napeti zatizeneho menice
// napajeci zdroj je prilis mekky
err = 1; // signalizuj chybu
chrg = 0; // ukonci nabijeni
output_low (CHRG_ON); // odpoj zdroj nabijeni
output_low (BATT_ON); // odpoj baterii
delay_ms (300); // cekej na ustaleni menice
}
 
// jeden pruchod smyckou zabere max 3000 taktu
for (;;) {
restart_wdt ();
if (s_tick) {
s_tick = 0;
IB_val = measure_IB (); // mer proud dodavany do baterie 1760 taktu
if (IB_val > I_zero) // zbav se ofsetu OZ
IB_val -= I_zero;
else
IB_val = 0;
// nasledujici sekvence zabere max 300 taktu
if (chrg) {
if (IB_val == 0) { // tece vubec nejaky nabijeci proud ?
// NE netece
err = 1; // signalizuj chybu
chrg = 0; // ukonci nabijeni
output_low (CHRG_ON);
output_low (BATT_ON);
}
else {
// ANO tece
inc_cap = IB_val * chrg_eff; // uprav koeficientem ucinnosti nabijeni
inc_cap = inc_cap >> (6-1); // zbav se vynasobeni 64x a vynasob dvema, protoze krok proudu pri nabijeni je dvojnasobny proti vybijeni
B_cap = B_cap + inc_cap; // uprav kapacitu baterie
}
}
#ifdef DEBUG
if (IB_val > max)
max = IB_val;
if (IB_val < min)
min = IB_val;
#endif
}
 
if (l_tick) {
l_tick = 0;
 
measure_temp (); // mer teplotu baterie - 1100 taktu
 
if (measure_VS () < VS_MIN)
return; // koncime, napajeci zdroj byl odpojen
 
if (is_load ())
return; // koncime, je pripojena zatez
 
if (invalid_cap)
leds_invalid_cap (); // signalizace nezname aktualni kapacity baterie - nutno nejdive baterii vybit
else
if (err)
leds_err (); // signalizace chyby
else {
// signalizace nabiti baterie
if ( leds_chrg () == 4 || TB_val > TB_MAX) {
// baterie je plne nabita
output_low (CHRG_ON);
output_low (BATT_ON);
chrg = 0;
B_cap = B_cap_4_4;
}
else {
if (B_cap > fast_chrg)
duty = chrg_01C; // temer nabito dale nabijime 0.1C
else
duty = chrg_02C; // nabijeni proudem max. 0.2C
 
if (pwm == 0) {
output_high (CHRG_ON);
chrg = 1;
}
else {
if (pwm >= duty / IB_val) { // 400 taktu
output_low (CHRG_ON);
chrg = 0;
}
}
pwm++;
}
}
 
#ifdef DEBUG
restart_wdt ();
// printf ("z:%lu h:%ld add:%lu cap:%lu T:%u\n\r",I_zero,max,inc_cap,B_cap,TB_val);
// printf ("pwm:%u z:%lu max:%lu d:%lu\n\r",pwm,I_zero,max,max-min);
// printf ("%lu %lu\n\r",B_cap, fast_chrg);
printf ("z:%lu max:%lu delta:%u inc:%lu\n\r",I_zero,max,(int8)(max-min),inc_cap);
 
max = 0;
min = 1024;
#endif
}
}
}
 
 
// upravi kapacitu baterie dle samovybijeni
// zabere max. 2000 cyklu
//
void selfdischarge (int8 day_cnt) {
int8 k2;
int16 temp;
int32 dec_cap;
 
// realizuje upravu koeficientu samovybijeni podle teploty k2 = k * Z * delta_TB
// zmena Z je 1.05 na stupen
if (TB_avr24 > TB_ref)
temp = (3 * (TB_avr24 - TB_ref)) + 64;
else {
temp = 3 * (TB_ref - TB_avr24);
if (temp > 64)
temp = 0;
else
temp = 64 - temp;
}
temp = (temp * k) / 64;
k2 = (int8)temp;
 
// v prvnich 5 dnech je samovybijeni strmejsi
if (day_cnt < 5)
k2 = k2 * 2;
dec_cap = k2 * CAP_BATT;
if (B_cap > dec_cap)
B_cap -=dec_cap;
#ifdef DEBUG
// printf ("k:%u k2:%u dec_cap:%lu cap:%lu ",k,k2,dec_cap,B_cap);
#endif
}
 
 
//////////////////////////////////////////////////////
//
// PRIPRAVNE A NASTAVOVACI FUNKCE
//
//////////////////////////////////////////////////////
 
// pripravi promenne pro beh programu
//
void prepare_var () {
int16 B_cap;
int8 tmp8;
int16 tmp16;
int32 tmp32;
float tmpf;
 
// priprav meze pro signalizaci stavu vybiti baterie
B_cap = read_eeprom (B_CAP_L_ADDR);
B_cap *= 100;
tmp16 = read_eeprom (B_CAP_H_ADDR);
tmp16 *= 1000;
B_cap += tmp16; // kapacita baterie v mAh
 
B_cap_4_4 = B_cap * CAP_BATT;
// B_cap_4_4 = 100 * CAP_BATT;
B_cap_2_4 = B_cap_4_4 / 2;
B_cap_1_4 = B_cap_2_4 / 2;
B_cap_3_4 = B_cap_2_4 + B_cap_1_4;
 
// priprav omezeni nabijecich proudu
tmpf = B_cap / 10;
tmpf *= 256;
tmpf /= 4.88;
chrg_01C = (int16)tmpf;
chrg_02C = chrg_01C * 2;
 
// priprav koeficient ucinnosti nabijeni
// eff = 1+(( read_eeprom (EFF_ADDR) * 5) / 100.0); // koeficient s jednickou
// eff -= 0.1;
// eff = 64 / eff; // ucinnost nabijeni (0-1) nasovena 64
// chrg_eff = (int8)(eff); // ucinnost nabijeni vhodna pro celociselnou aritmetiku
 
chrg_eff = CHRG_EFF_TAB [read_eeprom (EFF_ADDR)]; // toto je vyhodnejsi varianta
 
// priprav koeficient samovybijeni
tmp8 = read_eeprom (LOSS_CAP_H_ADDR) * 10 + read_eeprom (LOSS_CAP_L_ADDR); // ztracena kapacita v procentech
tmp32 = B_cap;
tmp32 *= tmp8;
tmp16 = tmp32 / 100; // ztracena kapacita v mAh
tmp8 = read_eeprom (LOSS_DAY_H_ADDR) * 10 + read_eeprom (LOSS_DAY_L_ADDR); // pocet dni, za kterou se kapacita ztratila
k = tmp16 / tmp8; // strmost poklesu samovybijeni v mAh / den
 
TB_ref = read_eeprom (TB_REF_ADDR); // teplota, pri ktere k samovybijeni dochazelo
 
#ifdef DEBUG
// printf ("chrg_eff:%lu ",B_cap);
// printf ("chrg_eff:%u ",chrg_eff);
// printf ("k:%u ",k);
#endif
}
 
 
// pripravi konstantu pro odmereni 1 hod pomoci wdt
//
prepare_hour_time () {
int32 hour_time_cor;
 
// vypocti potrebny pocet tiku wdt pro odmereni jedne hodiny
hour_time_cor = 400 - hour_time;
hour_time_cor *= HOUR_TIME_WDT;
hour_time_cor /= hour_time;
hour_time = HOUR_TIME_WDT + (int16)hour_time_cor;
}
 
 
// priprav vse pro minimalizaci spotreby ve spanku
//
void prepare_sleep () {
leds_all_off ();
output_low (BATT_ON);
output_low (CHRG_ON);
setup_vref (FALSE);
}
 
 
// nastavi parametry programu
//
void do_set_par () {
int8 par_num; // cislo parametru
int8 par_val; // hodnota parametru
int8 key_timer; // pro osetreni zakmitu nastavovacich tlacitek
int8 keys; // stav nastavovacich tlacitek
int1 set_par; // jsme v rezimu nastavovani hodnoty parametru
int1 wait_release; // cekame na uvolneni tlacitka
 
leds_all_on (); // oznam, ze jsme v nastavovacim rezimu
delay_ms (1000);
 
par_num = 0;
s_tick = 0;
l_tick = 0;
key_timer = 0;
wait_release = 0;
set_par = 0;
num_to_leds (par_num); // zobraz zvoleny parametr
 
for (;;) {
restart_wdt ();
if (s_tick) {
s_tick = 0;
if (key_timer != 0)
key_timer--;
else {
key_timer = 5;
keys = read_keys (); // precti stav tlacitek
if (keys & SET_MASK) {
// tlacitko SET je stisknuto - rezim vyberu parametru
if (set_par) {
if (par_val != read_eeprom (par_num)) { // prechazime z rezimu nastaveni parametru, uloz zvoleny parametr
write_eeprom (par_num, par_val); // uloz jen pokud byl zmenen
if (par_num == LOSS_DAY_H_ADDR ||
par_num == LOSS_DAY_L_ADDR)
write_eeprom (TB_REF_ADDR,TB_avr24); // pokud byla zmenena hodnota ztracene kapacity samovybijenim, uloz TB_avr24 jako refrerencni
}
num_to_leds (par_num); // zobraz zpatky zvoleny parametr
set_par = 0;
}
else {
// vybirame parametr
if (keys & UP_MASK) {
if (! wait_release) {
if (par_num < 6)
par_num++;
else
par_num = 0;
num_to_leds (par_num); // zobrazeni vybraneho parametru
wait_release = 1; // cekame na uvolneni tlacitka UP
}
}
else
wait_release = 0; // tlacitko UP bylo uvolneno
}
}
else {
// tlacitko SET je uvolneno - rezim nastaveni parametru
if (! set_par) {
par_val = read_eeprom (par_num); // prechazime z rezimu vyberu parametru, vyzvedni zvoleny parametr
num_to_leds (par_val); // zobraz hodotu parametru
set_par = 1;
}
else {
// nastavujeme parametr
if (keys & UP_MASK) {
if (! wait_release) {
if (par_val < PAR_MAX_TAB [par_num])
par_val++;
else
par_val = 0;
num_to_leds (par_val); // zobraz hodnotu parametru
wait_release = 1; // cekame na uvolneni tlacitka UP
}
}
else
wait_release = 0;
}
}
}
}
 
if (l_tick) {
l_tick = 0;
if (measure_VS () < VS_MIN)
break; // koncime, napajeci zdroj odpojen
}
}
prepare_var (); // konec nastavovani, aktualizuj promenne programu
}
 
 
 
///////////////////////////////////////////////////
// HLAVNI FUNKCE
///////////////////////////////////////////////////
 
main () {
int1 load_old;
int1 load;
int1 no_load;
int1 start_TB; // spust mrereni teploty baterie
int16 wdt_timer; // pro odmereni hodiny pomoci wdt
int8 hour_timer; // pro odmerovani hodin
int8 day_timer; // pro odmerovani dni od nabiti
int16 TB_avr_tmp; // pro vypocet prumerne teploty
 
 
#ifdef DEBUG
int16 c;
int16 inc_cap,IB_val,I_zero;
int8 val;
#endif
 
init_ports ();
 
if (restart_cause () != WDT_TIMEOUT) {
// mereni skutecne doby behu wdt proved pro vseshny resety krome wdt
setup_oscillator (OSC_4MHZ | OSC_NORMAL);
delay_ms (100);
setup_timer_1 (T1_INTERNAL | T1_DIV_BY_1);
setup_wdt (WDT_288MS);
hour_time = 0;
set_timer1 (~1000);
restart_wdt ();
for (;;) {
if (TMR1IF) {
hour_time++;
TMR1IF = 0;
set_timer1 (~1000);
}
}
}
 
setup_oscillator (OSC_4MHZ | OSC_NORMAL);
setup_timer_0 (RTCC_INTERNAL| RTCC_DIV_1);
setup_wdt (WDT_288MS);
setup_timer_1 (T1_INTERNAL | T1_DIV_BY_1);
set_timer1 (S_TICK_TIME);
setup_spi (FALSE);
setup_comparator (NC_NC_NC_NC);
setup_vref (FALSE);
setup_ccp1 (CCP_OFF);
setup_adc (ADC_CLOCK_INTERNAL); // doba prevodu cca 48 uS
setup_adc_ports (sAN0 | sAN1 | sAN2 | sAN3 | sAN5 | VSS_VDD);
 
enable_interrupts (INT_TIMER1);
enable_interrupts (GLOBAL);
 
prepare_var (); // priprav promenne pro beh programu z udaju o vlastnostech baterie
prepare_hour_time ();
 
 
//////////////////////////////////////////////////
 
// uvodni bliknuti ledkou
output_high (LED1_G);
delay_ms (250);
output_low (LED1_G);
 
 
/*
#ifdef DEBUG
output_high (BATT_ON);
printf ("Ahoj %lu\n\r",hour_time);
 
for (;;) {
restart_wdt ();
if (is_load ())
break; // napajeci zdroj byl pripojen
delay_ms (100);
}
 
B_cap = B_cap_2_4;
invalid_cap = 0;
 
set_timer1 (0);
// zde se meri doba trvani funkci nebo vybraneho kodu
// selfdischarge (0); //OK
do_discharge ();
 
c = get_timer1 ();
// printf ("T:%lu %lu %u \n\r",c,B_cap,chrg_eff);
 
printf ("T:%lu\n\r",c);
output_low (BATT_ON);
delay_ms (250);
for (;;)
restart_wdt ();
#endif
*/
 
#ifdef DEBUG
invalid_cap = 0;
// B_cap = B_cap_3_4;
B_cap = B_cap_2_4;
#else
invalid_cap = 1; // nezname zbyvajici kapacitu baterie
B_cap = 0; // povazujeme ji za vybitou
#endif
 
TB_avr24 = TB_DEFAULT;
TB_avr_tmp = 0;
wdt_timer = 0;
hour_timer = 0;
day_timer = 0;
start_TB = 1;
no_load = 0;
 
// hlavni programova smycka
for (;;) {
restart_wdt ();
prepare_sleep ();
sleep ();
setup_adc_ports (sAN0 | sAN1 | sAN2 | sAN3 | sAN5 | VSS_VDD);
load = is_load (); // precti stav kontaktu pripojeni zateze
if (load != load_old)
load_old = load; // stav kontaktu neni platny
else {
if (load) {
if (! no_load) {
do_discharge (); // zatez pripojena, vybijime - ma vyssi prioritu
no_load = 1; // dalsi vybijeni je mozne az po odpojeni zateze
wdt_timer = 0;
}
}
else {
no_load = 0; // zatez byl odpojena
if (measure_VS () > VS_MIN) { // ma zdroj pro nabijeni dostatecne napeti?
if (input (SET))
do_charge (); // zatez odpojena a pripojen zdroj pro nabijeni, nabijime - ma nizsi pioritu
else
do_set_par (); // prechazime do rezimu pro nastavovani parametru programu
TB_avr_tmp = 0;
wdt_timer = 0;
hour_timer = 0;
day_timer = 0;
}
}
}
 
// reseni samovybijeni
if (wdt_timer < hour_time)
wdt_timer++;
else {
// uplynula hodina
start_TB = 1; // odstartuj mereni teploty
wdt_timer = 0; // natahni odmerovani hodiny
if (hour_timer < 23)
hour_timer++;
else {
// uplynul den
TB_avr24 = TB_avr_tmp / 24; // vypocti prumernou teplotu za den
if (day_timer < 90)
day_timer++;
else
invalid_cap = 1; // po 90 dnech uz neverime kapacite baterie
selfdischarge (day_timer); // uprav kapacitu baterie s ohledem na samovybijeni
#ifdef DEBUG
// printf ("TB:%u\n\r",TB_avr24);
#endif
TB_avr_tmp = 0;
hour_timer = 0;
}
}
 
// realizace mereni teploty - je v mnoha krocich
if (start_TB) {
if (measure_temp () == 0) {
#ifdef DEBUG
// printf("T:%u ",TB_val);
#endif
TB_avr_tmp += TB_val; // pocitame prumer teploty
start_TB = 0;
}
}
}
 
}