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