Rev Author Line No. Line
1352 miho 1 //**********************************************************************
2 // INFO BATTERY PACK
3 //**********************************************************************
4 // (c) OK1XGL 2008
5 // verze 1.0 - uvodni verze
6 // 1.1 - referencni teplota pro samovybijeni se uklada pri zadani doby mereni samovybijeni
7 //
8 //
9  
10 #include "ibp2.h"
11  
12  
13 // nastavi orientaci a klidovy stav portu
14 //
15 void init_ports (void) {
16 set_tris_a (0b00101011);
17 output_a (0b000000000);
18  
19 set_tris_b (0b11010000);
20 output_b (0b00100000);
21 port_b_pullups (FALSE);
22 }
23  
24  
25 //////////////////////////////////////////////////
26 //
27 // iterrupty
28 // cele preruseni zabere 33+xx+30 cyklu
29 //
30 //////////////////////////////////////////////////
31  
32 // periodicky casovac
33 //
34 #INT_TIMER1
35 void tmr1_int (void) {
36 // natahovani casovace
37 set_timer1 (S_TICK_TIME);
38 s_tick = 1;
39  
40 if (l_timer == 0) {
41 l_timer = L_TICK_TIME;
42 l_tick = 1;
43 blink = ~blink;
44 if (blink)
45 slow_blink = ~slow_blink;
46 }
47 else
48 l_timer--;
49 }
50  
51  
52  
53 ///////////////////////////////////////////////////
54 //
55 // FUNKCE PRO PRACI S TEPLOMEREM
56 //
57 //////////////////////////////////////////////////
58  
59 // testuje pritomnost teplomeru, pri pritomnosti vraci 1
60 // zabere 1060 taktu
61 //
62 int8 TM_present() {
63 int1 present;
64  
65 output_low (TM_PIN);
66 output_fixed (TM_PIN);
67 delay_us (500);
68 disable_interrupts (GLOBAL);
69 output_float (TM_PIN);
70 if(!input (TM_PIN)) {
71 enable_interrupts (GLOBAL);
72 return (0);
73 }
74 delay_us (65);
75 present = input(TM_PIN);
76 enable_interrupts (GLOBAL);
77 delay_us (440);
78 if (present)
79 return (0);
80 else
81 return (1);
82 }
83  
84  
85 // precte bajt z teplomeru
86 //
87 int8 TM_read_byte() {
88 int8 i,data;
89  
90 for(i = 0; i < 8; ++i) {
91 disable_interrupts (GLOBAL);
92 output_low (TM_PIN);
93 output_fixed (TM_PIN);
94 delay_us (2);
95 output_float (TM_PIN);
96 delay_us (8);
97 shift_right (&data,1,input(TM_PIN));
98 enable_interrupts (GLOBAL);
99 delay_us (55);
100 }
101 return (data);
102 }
103  
104  
105 // zapise bajt do teplomeru
106 //
107 void TM_write_byte(int8 data) {
108 int8 i;
109  
110 for (i = 0 ; i < 8; ++i) {
111 disable_interrupts (GLOBAL);
112 output_low (TM_PIN);
113 output_fixed (TM_PIN);
114 delay_us (5);
115 if (shift_right (&data,1,0))
116 output_float (TM_PIN);
117 delay_us (60);
118 output_float (TM_PIN);
119 delay_us (2);
120 enable_interrupts (GLOBAL);
121 }
122 }
123  
124  
125 // vraci 0 pri ukonceni mereni
126 // vraci 1 pri rozpracovanem mereni
127 // zabere max 1100 taktu na 1 cyklus
128 // potrebuje 10 volani pro zmereni teploty
129 //
130 int8 measure_temp () {
131 static int8 phase;
132 static int8 tmp;
133 int8 tmp2;
134  
135 switch (phase) {
136 case 0:
137 if (! TM_present ()) { // over pritomnost teplomeru
138 phase = 0;
139 TB_val = TB_DEFAULT;
140 return (0); // teplomer neni pritomen, dal nelze pokracovat
141 }
142 break;
143  
144 case 1:
145 TM_write_byte (0xcc); // preskoc na dalsi sadu prikazu
146 break;
147  
148 case 2:
149 TM_write_byte (0x44); // prikaz spust mereni teploty
150 output_high (TM_PIN); // zapni tvrdy pullup
151 output_fixed (TM_PIN); //
152 break;
153  
154 case 3:
155 case 4:
156 case 5: // cekej nejmene 750 ms
157 break;
158  
159 case 6:
160 output_float (TM_PIN); // vyppni tvrdy pullup
161 output_low (TM_PIN); //
162 if (! TM_present ()) { // over pritomnost teplomeru
163 phase = 0;
164 TB_val = TB_DEFAULT;
165 return (0); // teplomer neni pritomen, dal nelze pokracovat
166 }
167 break;
168  
169 case 7:
170 TM_write_byte (0xcc); // preskoc na dalsi sadu prikazu
171 break;
172  
173 case 8:
174 TM_write_byte (0xbe); // prikaz precti zmerenou teplotu
175 break;
176  
177 case 9:
178 tmp = TM_read_byte () >> 4; // precti LSB bajt s teplotou a zahod destiny stupne
179 break;
180  
181 case 10:
182 tmp |= TM_read_byte () << 4; // precti MSB bajt s teplotou a sloz s LSB
183 tmp2 = tmp & 0x7F; //
184 if (tmp2 < 80) { // teplota je v moznem rozsahu (nahrada kontroly CRC - bylo by casove prilis dlouhe)
185 if (tmp & 0x80)
186 TB_val = 0; // zapornou teplotu povazujeme za nulovou
187 else
188 TB_val = tmp2;
189 }
190 phase = 0;
191 return (0);
192 break;
193  
194 default:
195 phase = 0;
196 TB_val = TB_DEFAULT;
197 return (0);
198 }
199 phase++;
200 return (1);
201 }
202  
203  
204  
205 //////////////////////////////////////////////////////
206 //
207 // FUNNKCE PRO MERENI NAPETI A PROUDU
208 //
209 //////////////////////////////////////////////////////
210  
211 // meri velikost proudu z/do baterie a prumeruje z 8 mereni
212 // zabere max 1760 taktu (1760 us)
213 //
214 int16 measure_IB (void) {
215 int16 out;
216  
217 set_adc_channel (IB_CAN);
218 delay_us (100);
219 out = read_adc (ADC_START_AND_READ);
220 delay_us (100);
221 out += read_adc (ADC_START_AND_READ);
222 delay_us (100);
223 out += read_adc (ADC_START_AND_READ);
224 delay_us (100);
225 out += read_adc (ADC_START_AND_READ);
226 delay_us (100);
227 out += read_adc (ADC_START_AND_READ);
228 delay_us (100);
229 out += read_adc (ADC_START_AND_READ);
230 delay_us (100);
231 out += read_adc (ADC_START_AND_READ);
232 delay_us (100);
233 out += read_adc (ADC_START_AND_READ);
234 out = out >> 3;
235 return (out);
236 }
237  
238  
239 // meri velikost napeti baterie a provadi klouzavy prumer z 8 mereni
240 // zabere max 320 taktu (320 us)
241 //
242 int16 measure_VB (void) {
243 static int16 smpl [8];
244 static int8 i;
245 int16 out;
246  
247 if (i >= 8-1)
248 i = 0;
249 else
250 i++;
251  
252 set_adc_channel (VB_CAN);
253 delay_us (100);
254 smpl [i] = read_adc (ADC_START_AND_READ);
255  
256 out = smpl [0] + smpl [1] + smpl [2] + smpl [3] +
257 smpl [4] + smpl [5] + smpl [6] + smpl [7];
258 out = out >> 3;
259 return (out);
260 }
261  
262  
263 // meri velikost vstupniho napeti zdroje pro nabijeni
264 // zabere max 200 taktu (200 us)
265 //
266 int16 measure_VS (void) {
267 int16 out;
268  
269 set_adc_channel (VS_CAN);
270 delay_us (100);
271 out = read_adc (ADC_START_AND_READ);
272 return (out);
273 }
274  
275  
276 // meri vystupni napeti OZ pro mereni proudu pri nulovem odberu - pro kompenzaci ofsetu OZ
277 //
278 int16 measure_offset (void) {
279 int16 out;
280 int8 i;
281  
282 // vypni vsechny spotrebice
283 init_ports ();
284 disable_interrupts (GLOBAL);
285 ADIE = 1;
286 PEIE = 1;
287 delay_ms (500);
288  
289 // mer napeti OZ a vypocti prumer z 8 mereni
290 set_adc_channel (IB_CAN);
291 delay_us (100);
292 out = 0;
293 for (i = 0; i < 8; i++) {
294 read_adc (ADC_START_ONLY);
295 sleep ();
296 out += read_adc (ADC_READ_ONLY);
297 delay_us (100);
298 restart_wdt ();
299 }
300 out = out >> 3;
301  
302 ADIE = 0;
303 PEIE = 0;
304 enable_interrupts (GLOBAL);
305 return (out);
306 }
307  
308  
309 /////////////////////////////////////////////////
310 //
311 // FUNKCE PRO PRACI S LED
312 //
313 /////////////////////////////////////////////////
314  
315 // rozsviti vsechny led
316 //
317 void leds_all_on () {
318 output_high (LED4_R);
319 output_high (LED3_Y);
320 output_high (LED2_Y);
321 output_high (LED1_G);
322 }
323  
324  
325 // zhasne vsechny led
326 //
327 void leds_all_off () {
328 output_low (LED4_R);
329 output_low (LED3_Y);
330 output_low (LED2_Y);
331 output_low (LED1_G);
332 }
333  
334  
335 // signalizuje kapacitu baterie pri nabijeni
336 // vraci cislo odpovidajici stavu nabiti
337 // zabere max 40 cyklu
338 //
339 int8 leds_chrg (void) {
340 if (B_cap >= B_cap_4_4) {
341 leds_all_on ();
342 return (4); // baterie plne nabita
343 }
344  
345 if (B_cap > B_cap_3_4) {
346 output_high (LED4_R);
347 output_high (LED3_Y);
348 output_high (LED2_Y);
349 if (slow_blink)
350 output_high (LED1_G);
351 else
352 output_low (LED1_G);
353 return (3);
354 }
355  
356 if (B_cap > B_cap_2_4) {
357 output_high (LED4_R);
358 output_high (LED3_Y);
359 if (slow_blink)
360 output_high (LED2_Y);
361 else
362 output_low (LED2_Y);
363 output_low (LED1_G);
364 return (2);
365 }
366  
367 if (B_cap > B_cap_1_4) {
368 output_high (LED4_R);
369 if (slow_blink)
370 output_high (LED3_Y);
371 else
372 output_low (LED3_Y);
373 output_low (LED2_Y);
374 output_low (LED1_G);
375 return (1);
376 }
377  
378 if (slow_blink)
379 output_high (LED4_R);
380 else
381 output_low (LED4_R);
382 output_low (LED3_Y);
383 output_low (LED2_Y);
384 output_low (LED1_G);
385 return (0);
386 }
387  
388  
389 // signalizuje chybu
390 //
391 void leds_err () {
392 output_low (LED1_G);
393 output_low (LED4_R);
394 if (blink) {
395 output_high (LED2_Y);
396 output_high (LED3_Y);
397 }
398 else {
399 output_low (LED2_Y);
400 output_low (LED3_Y);
401 }
402 }
403  
404  
405 // signalizuje neznamou aktualni kapacitu baterie
406 //
407 void leds_invalid_cap () {
408 output_low (LED2_Y);
409 output_low (LED3_Y);
410 if (blink) {
411 output_high (LED1_G);
412 output_high (LED4_R);
413 }
414 else {
415 output_low (LED1_G);
416 output_low (LED4_R);
417 }
418 }
419  
420  
421 // signalizuje zbyvajici kapacitu baterie pri vybijeni
422 //
423 void leds_dis () {
424 if (B_cap < B_cap_1_4) {
425 output_low (LED1_G);
426 output_low (LED2_Y);
427 output_low (LED3_Y);
428 output_high (LED4_R);
429 return;
430 }
431  
432 if (B_cap < B_cap_2_4) {
433 output_low (LED1_G);
434 output_low (LED2_Y);
435 output_high (LED3_Y);
436 output_low (LED4_R);
437 return;
438 }
439  
440 if (B_cap < B_cap_3_4) {
441 output_low (LED1_G);
442 output_high (LED2_Y);
443 output_low (LED3_Y);
444 output_low (LED4_R);
445 return;
446 }
447  
448 output_high (LED1_G);
449 output_low (LED2_Y);
450 output_low (LED3_Y);
451 output_low (LED4_R);
452 }
453  
454  
455 // signalizuje temer vybitou baterii
456 //
457 void leds_VB_low () {
458 output_low (LED1_G);
459 output_low (LED2_Y);
460 output_low (LED3_Y);
461 if (slow_blink)
462 output_high (LED4_R);
463 else
464 output_low (LED4_R);
465 }
466  
467  
468 // zobrazi cislo v rozsahu 0 - 9 v binarnim kodu na ledkach
469 //
470 void num_to_leds (int8 num) {
471  
472 switch (num) {
473 case 0:
474 output_low (LED4_R); // nejnizsi bit
475 output_low (LED3_Y);
476 output_low (LED2_Y);
477 output_low (LED1_G); // nejvyssi bit
478 break;
479 case 1:
480 output_high (LED4_R); // nejnizsi bit
481 output_low (LED3_Y);
482 output_low (LED2_Y);
483 output_low (LED1_G); // nejvyssi bit
484 break;
485 case 2:
486 output_low (LED4_R); // nejnizsi bit
487 output_high (LED3_Y);
488 output_low (LED2_Y);
489 output_low (LED1_G); // nejvyssi bit
490 break;
491 case 3:
492 output_high (LED4_R); // nejnizsi bit
493 output_high (LED3_Y);
494 output_low (LED2_Y);
495 output_low (LED1_G); // nejvyssi bit
496 break;
497 case 4:
498 output_low (LED4_R); // nejnizsi bit
499 output_low (LED3_Y);
500 output_high (LED2_Y);
501 output_low (LED1_G); // nejvyssi bit
502 break;
503 case 5:
504 output_high (LED4_R); // nejnizsi bit
505 output_low (LED3_Y);
506 output_high (LED2_Y);
507 output_low (LED1_G); // nejvyssi bit
508 break;
509 case 6:
510 output_low (LED4_R); // nejnizsi bit
511 output_high (LED3_Y);
512 output_high (LED2_Y);
513 output_low (LED1_G); // nejvyssi bit
514 break;
515 case 7:
516 output_high (LED4_R); // nejnizsi bit
517 output_high (LED3_Y);
518 output_high (LED2_Y);
519 output_low (LED1_G); // nejvyssi bit
520 break;
521 case 8:
522 output_low (LED4_R); // nejnizsi bit
523 output_low (LED3_Y);
524 output_low (LED2_Y);
525 output_high (LED1_G); // nejvyssi bit
526 break;
527 case 9:
528 output_high (LED4_R); // nejnizsi bit
529 output_low (LED3_Y);
530 output_low (LED2_Y);
531 output_high (LED1_G); // nejvyssi bit
532 break;
533 default:
534 output_low (LED4_R); // nejnizsi bit
535 output_low (LED3_Y);
536 output_low (LED2_Y);
537 output_low (LED1_G); // nejvyssi bit
538 }
539 }
540  
541  
542 ///////////////////////////////////////////////////////
543 //
544 // FUNKCE PRO CTENI TLACITEK A KONTAKTU
545 //
546 ///////////////////////////////////////////////////////
547  
548 // je pripojena zatez?
549 // vraci 1 pri pripojene zatezi
550 //
551 int1 is_load () {
552 int1 load;
553 port_b_pullups (TRUE);
554 delay_us (100);
555 load = input (LOAD_ON); // precti stav kontaktu pripojeni zateze
556 port_b_pullups (FALSE);
557 return (load);
558 }
559  
560  
561 // cte stav nastavovacich tlacitek
562 // vraci masky stisknutych tlacitek, 0 = klidovy stav
563 //
564 int8 read_keys () {
565 static int1 up_key_old;
566 static int1 set_key_old;
567 static int8 keys;
568 int1 key_state;
569  
570 key_state = input (UP);
571 if (key_state != up_key_old)
572 up_key_old = key_state;
573 else
574 if (! key_state)
575 keys |= UP_MASK;
576 else
577 keys &= ~UP_MASK;
578  
579 key_state = input (SET);
580 if (key_state != set_key_old)
581 set_key_old = key_state;
582 else
583 if (! key_state)
584 keys |= SET_MASK;
585 else
586 keys &= ~SET_MASK;
587 return (keys);
588 }
589  
590  
591 ///////////////////////////////////////////////////
592 //
593 // VYKONNE FUNKCE
594 //
595 ///////////////////////////////////////////////////
596  
597 // vybijeni baterie
598 //
599 void do_discharge () {
600 int16 IB_val;
601 int16 I_zero;
602 int16 VB_val;
603 int16 dec_cap;
604 int1 load, load_old;
605 int1 err;
606  
607 #ifdef DEBUG
608 int16 max,min;
609 int16 cnt;
610 #endif
611  
612 // signalizuj neduveryhodnost zbyvajici kapacity baterie
613 if (invalid_cap) {
614 blink = 1;
615 leds_invalid_cap ();
616 delay_ms (500);
617 leds_all_off ();
618 }
619  
620 // nastaveni AD prevodniku: reference je 2.5V posun mereni proudu o 2,51V => cim vetsi prout, tim nizzsi cislo z prevodniku
621 setup_adc_ports (sAN0 | sAN1 | sAN2 | sAN3 | sAN5 | VSS_VREF);
622 setup_vref (VREF_HIGH | VREF_A2 | 8); // na A2 vystup reference 2.51V
623 delay_ms (1);
624  
625 I_zero = measure_offset (); // precti klidovou hodnotu, tedy offset OZ - nulovy odebirany proud
626  
627 output_high (BATT_ON);
628 leds_dis (); // signalizuj zbyvajici kapacitu bateie
629  
630 err = 0;
631 blink = 1;
632 l_tick = 0;
633 s_tick = 0;
634  
635 // jeden pruchod smycku zabere max 2000 taktu
636 for(;;) {
637 restart_wdt ();
638 if (s_tick) {
639 s_tick = 0;
640 IB_val = measure_IB (); // mer proud odebirany z baterie
641 if (IB_val == 0 ) {
642 // proudove pretizeni
643 output_low (BATT_ON); // odpoj baterii
644 err = 1; // signalizuj chybu
645 }
646 dec_cap = I_zero - IB_val; // zbav se ofsetu OZ
647 if (B_cap > dec_cap)
648 B_cap = B_cap - dec_cap; // uprav zbyvajici kapacitu baterie
649  
650 if (! err)
651 VB_val = measure_VB (); // napeti baterie je mozne merit jen pokud neni odpojena
652  
653 #ifdef DEBUG
654 if (IB_val > max)
655 max = IB_val;
656 if (IB_val < min)
657 min = IB_val;
658 cnt++;
659 #endif
660 }
661  
662 if (l_tick) {
663 l_tick = 0;
664 if (! is_load ()) {
665 return; // koncime, zatez odpojena
666 }
667  
668 if (VB_val < VB_MIN) {
669 // baterie zcela vybita
670 B_cap = 0; // nastav prazdnou kapacitu
671 invalid_cap = 0; // aktualni kapacita baterie je nyni znama
672 return;
673 }
674  
675 if (err) {
676 leds_err (); // signalizuj chybu
677 }
678 else {
679 if (VB_val < VB_LOW) {
680 leds_VB_low (); // signalizuj temer vybitou baterii
681 }
682 else {
683 leds_dis (); // signalizuj zbyvajici kapacitu bateie
684 }
685 }
686  
687 #ifdef DEBUG
688 printf ("cnt:%lu z:%lu max:%ld delta:%u dec:%lu\n\r",cnt,I_zero,max,(int8)(max-min),dec_cap);
689 max = 0;
690 min = 1024;
691 cnt = 0;
692 #endif
693 }
694 }
695 }
696  
697  
698 // proces nabijeni baterie
699 //
700 void do_charge () {
701 int1 chrg;
702 int1 err;
703 int16 I_zero;
704 int16 IB_val;
705 int16 inc_cap;
706 int32 fast_chrg;
707 int8 pwm;
708 int16 duty;
709  
710 #ifdef DEBUG
711 int16 max,min;
712 int16 vs_val;
713 #endif
714  
715 // vypocti mez do ktere budeme nabijet vyssim proudem
716 // fast_chrg = (B_cap_4_4 - B_cap) / 64;
717 fast_chrg = (B_cap_4_4 - B_cap) / 72;
718 fast_chrg *= chrg_eff;
719 fast_chrg += B_cap;
720 #ifdef DEBUG
721 // printf ("%lu %u %lu %lu\n\r\n\r",B_cap_4_4, chrg_eff,B_cap, fast_chrg);
722 #endif
723  
724 err = 0;
725 s_tick = 0;
726 l_tick = 0;
727 pwm = 0;
728 chrg = 0;
729  
730 // nastaveni AD prevodniku, reference je VDD = 5V , zadny posun napeti pri mereni proudu => cim vyssi proud, tim vyssi cislo z prevodniku
731 setup_adc_ports (sAN0 | sAN1 | sAN2 | sAN3 | sAN5 | VSS_VDD);
732 setup_vref (VREF_LOW | VREF_A2 | 2); // na A2 vystup reference 0.416V
733 delay_ms (1);
734 I_zero = measure_offset (); // precti klidovou hodnotu, tedy ofset OZ - nulovy nabijeci proud
735  
736 if (invalid_cap == 0 &&
737 TB_val < TB_MAX &&
738 TB_VAL > TB_MIN) {
739 // kapacita baterie je znama a teplota baterie je v mezich
740 output_high (BATT_ON); // pripoj baterii
741 output_high (CHRG_ON); // pripoj zdroj nabijeni
742 delay_ms (500); // cekej na ustaleni menice
743 chrg = 1;
744 }
745  
746 if (measure_VS () < VS_MIN) { // kontrola napeti zatizeneho menice
747 // napajeci zdroj je prilis mekky
748 err = 1; // signalizuj chybu
749 chrg = 0; // ukonci nabijeni
750 output_low (CHRG_ON); // odpoj zdroj nabijeni
751 output_low (BATT_ON); // odpoj baterii
752 delay_ms (300); // cekej na ustaleni menice
753 }
754  
755 // jeden pruchod smyckou zabere max 3000 taktu
756 for (;;) {
757 restart_wdt ();
758 if (s_tick) {
759 s_tick = 0;
760 IB_val = measure_IB (); // mer proud dodavany do baterie 1760 taktu
761 if (IB_val > I_zero) // zbav se ofsetu OZ
762 IB_val -= I_zero;
763 else
764 IB_val = 0;
765 // nasledujici sekvence zabere max 300 taktu
766 if (chrg) {
767 if (IB_val == 0) { // tece vubec nejaky nabijeci proud ?
768 // NE netece
769 err = 1; // signalizuj chybu
770 chrg = 0; // ukonci nabijeni
771 output_low (CHRG_ON);
772 output_low (BATT_ON);
773 }
774 else {
775 // ANO tece
776 inc_cap = IB_val * chrg_eff; // uprav koeficientem ucinnosti nabijeni
777 inc_cap = inc_cap >> (6-1); // zbav se vynasobeni 64x a vynasob dvema, protoze krok proudu pri nabijeni je dvojnasobny proti vybijeni
778 B_cap = B_cap + inc_cap; // uprav kapacitu baterie
779 }
780 }
781 #ifdef DEBUG
782 if (IB_val > max)
783 max = IB_val;
784 if (IB_val < min)
785 min = IB_val;
786 #endif
787 }
788  
789 if (l_tick) {
790 l_tick = 0;
791  
792 measure_temp (); // mer teplotu baterie - 1100 taktu
793  
794 if (measure_VS () < VS_MIN)
795 return; // koncime, napajeci zdroj byl odpojen
796  
797 if (is_load ())
798 return; // koncime, je pripojena zatez
799  
800 if (invalid_cap)
801 leds_invalid_cap (); // signalizace nezname aktualni kapacity baterie - nutno nejdive baterii vybit
802 else
803 if (err)
804 leds_err (); // signalizace chyby
805 else {
806 // signalizace nabiti baterie
807 if ( leds_chrg () == 4 || TB_val > TB_MAX) {
808 // baterie je plne nabita
809 output_low (CHRG_ON);
810 output_low (BATT_ON);
811 chrg = 0;
812 B_cap = B_cap_4_4;
813 }
814 else {
815 if (B_cap > fast_chrg)
816 duty = chrg_01C; // temer nabito dale nabijime 0.1C
817 else
818 duty = chrg_02C; // nabijeni proudem max. 0.2C
819  
820 if (pwm == 0) {
821 output_high (CHRG_ON);
822 chrg = 1;
823 }
824 else {
825 if (pwm >= duty / IB_val) { // 400 taktu
826 output_low (CHRG_ON);
827 chrg = 0;
828 }
829 }
830 pwm++;
831 }
832 }
833  
834 #ifdef DEBUG
835 restart_wdt ();
836 // printf ("z:%lu h:%ld add:%lu cap:%lu T:%u\n\r",I_zero,max,inc_cap,B_cap,TB_val);
837 // printf ("pwm:%u z:%lu max:%lu d:%lu\n\r",pwm,I_zero,max,max-min);
838 // printf ("%lu %lu\n\r",B_cap, fast_chrg);
839 printf ("z:%lu max:%lu delta:%u inc:%lu\n\r",I_zero,max,(int8)(max-min),inc_cap);
840  
841 max = 0;
842 min = 1024;
843 #endif
844 }
845 }
846 }
847  
848  
849 // upravi kapacitu baterie dle samovybijeni
850 // zabere max. 2000 cyklu
851 //
852 void selfdischarge (int8 day_cnt) {
853 int8 k2;
854 int16 temp;
855 int32 dec_cap;
856  
857 // realizuje upravu koeficientu samovybijeni podle teploty k2 = k * Z * delta_TB
858 // zmena Z je 1.05 na stupen
859 if (TB_avr24 > TB_ref)
860 temp = (3 * (TB_avr24 - TB_ref)) + 64;
861 else {
862 temp = 3 * (TB_ref - TB_avr24);
863 if (temp > 64)
864 temp = 0;
865 else
866 temp = 64 - temp;
867 }
868 temp = (temp * k) / 64;
869 k2 = (int8)temp;
870  
871 // v prvnich 5 dnech je samovybijeni strmejsi
872 if (day_cnt < 5)
873 k2 = k2 * 2;
874 dec_cap = k2 * CAP_BATT;
875 if (B_cap > dec_cap)
876 B_cap -=dec_cap;
877 #ifdef DEBUG
878 // printf ("k:%u k2:%u dec_cap:%lu cap:%lu ",k,k2,dec_cap,B_cap);
879 #endif
880 }
881  
882  
883 //////////////////////////////////////////////////////
884 //
885 // PRIPRAVNE A NASTAVOVACI FUNKCE
886 //
887 //////////////////////////////////////////////////////
888  
889 // pripravi promenne pro beh programu
890 //
891 void prepare_var () {
892 int16 B_cap;
893 int8 tmp8;
894 int16 tmp16;
895 int32 tmp32;
896 float tmpf;
897  
898 // priprav meze pro signalizaci stavu vybiti baterie
899 B_cap = read_eeprom (B_CAP_L_ADDR);
900 B_cap *= 100;
901 tmp16 = read_eeprom (B_CAP_H_ADDR);
902 tmp16 *= 1000;
903 B_cap += tmp16; // kapacita baterie v mAh
904  
905 B_cap_4_4 = B_cap * CAP_BATT;
906 // B_cap_4_4 = 100 * CAP_BATT;
907 B_cap_2_4 = B_cap_4_4 / 2;
908 B_cap_1_4 = B_cap_2_4 / 2;
909 B_cap_3_4 = B_cap_2_4 + B_cap_1_4;
910  
911 // priprav omezeni nabijecich proudu
912 tmpf = B_cap / 10;
913 tmpf *= 256;
914 tmpf /= 4.88;
915 chrg_01C = (int16)tmpf;
916 chrg_02C = chrg_01C * 2;
917  
918 // priprav koeficient ucinnosti nabijeni
919 // eff = 1+(( read_eeprom (EFF_ADDR) * 5) / 100.0); // koeficient s jednickou
920 // eff -= 0.1;
921 // eff = 64 / eff; // ucinnost nabijeni (0-1) nasovena 64
922 // chrg_eff = (int8)(eff); // ucinnost nabijeni vhodna pro celociselnou aritmetiku
923  
924 chrg_eff = CHRG_EFF_TAB [read_eeprom (EFF_ADDR)]; // toto je vyhodnejsi varianta
925  
926 // priprav koeficient samovybijeni
927 tmp8 = read_eeprom (LOSS_CAP_H_ADDR) * 10 + read_eeprom (LOSS_CAP_L_ADDR); // ztracena kapacita v procentech
928 tmp32 = B_cap;
929 tmp32 *= tmp8;
930 tmp16 = tmp32 / 100; // ztracena kapacita v mAh
931 tmp8 = read_eeprom (LOSS_DAY_H_ADDR) * 10 + read_eeprom (LOSS_DAY_L_ADDR); // pocet dni, za kterou se kapacita ztratila
932 k = tmp16 / tmp8; // strmost poklesu samovybijeni v mAh / den
933  
934 TB_ref = read_eeprom (TB_REF_ADDR); // teplota, pri ktere k samovybijeni dochazelo
935  
936 #ifdef DEBUG
937 // printf ("chrg_eff:%lu ",B_cap);
938 // printf ("chrg_eff:%u ",chrg_eff);
939 // printf ("k:%u ",k);
940 #endif
941 }
942  
943  
944 // pripravi konstantu pro odmereni 1 hod pomoci wdt
945 //
946 prepare_hour_time () {
947 int32 hour_time_cor;
948  
949 // vypocti potrebny pocet tiku wdt pro odmereni jedne hodiny
950 hour_time_cor = 400 - hour_time;
951 hour_time_cor *= HOUR_TIME_WDT;
952 hour_time_cor /= hour_time;
953 hour_time = HOUR_TIME_WDT + (int16)hour_time_cor;
954 }
955  
956  
957 // priprav vse pro minimalizaci spotreby ve spanku
958 //
959 void prepare_sleep () {
960 leds_all_off ();
961 output_low (BATT_ON);
962 output_low (CHRG_ON);
963 setup_vref (FALSE);
964 }
965  
966  
967 // nastavi parametry programu
968 //
969 void do_set_par () {
970 int8 par_num; // cislo parametru
971 int8 par_val; // hodnota parametru
972 int8 key_timer; // pro osetreni zakmitu nastavovacich tlacitek
973 int8 keys; // stav nastavovacich tlacitek
974 int1 set_par; // jsme v rezimu nastavovani hodnoty parametru
975 int1 wait_release; // cekame na uvolneni tlacitka
976  
977 leds_all_on (); // oznam, ze jsme v nastavovacim rezimu
978 delay_ms (1000);
979  
980 par_num = 0;
981 s_tick = 0;
982 l_tick = 0;
983 key_timer = 0;
984 wait_release = 0;
985 set_par = 0;
986 num_to_leds (par_num); // zobraz zvoleny parametr
987  
988 for (;;) {
989 restart_wdt ();
990 if (s_tick) {
991 s_tick = 0;
992 if (key_timer != 0)
993 key_timer--;
994 else {
995 key_timer = 5;
996 keys = read_keys (); // precti stav tlacitek
997 if (keys & SET_MASK) {
998 // tlacitko SET je stisknuto - rezim vyberu parametru
999 if (set_par) {
1000 if (par_val != read_eeprom (par_num)) { // prechazime z rezimu nastaveni parametru, uloz zvoleny parametr
1001 write_eeprom (par_num, par_val); // uloz jen pokud byl zmenen
1002 if (par_num == LOSS_DAY_H_ADDR ||
1003 par_num == LOSS_DAY_L_ADDR)
1004 write_eeprom (TB_REF_ADDR,TB_avr24); // pokud byla zmenena hodnota ztracene kapacity samovybijenim, uloz TB_avr24 jako refrerencni
1005 }
1006 num_to_leds (par_num); // zobraz zpatky zvoleny parametr
1007 set_par = 0;
1008 }
1009 else {
1010 // vybirame parametr
1011 if (keys & UP_MASK) {
1012 if (! wait_release) {
1013 if (par_num < 6)
1014 par_num++;
1015 else
1016 par_num = 0;
1017 num_to_leds (par_num); // zobrazeni vybraneho parametru
1018 wait_release = 1; // cekame na uvolneni tlacitka UP
1019 }
1020 }
1021 else
1022 wait_release = 0; // tlacitko UP bylo uvolneno
1023 }
1024 }
1025 else {
1026 // tlacitko SET je uvolneno - rezim nastaveni parametru
1027 if (! set_par) {
1028 par_val = read_eeprom (par_num); // prechazime z rezimu vyberu parametru, vyzvedni zvoleny parametr
1029 num_to_leds (par_val); // zobraz hodotu parametru
1030 set_par = 1;
1031 }
1032 else {
1033 // nastavujeme parametr
1034 if (keys & UP_MASK) {
1035 if (! wait_release) {
1036 if (par_val < PAR_MAX_TAB [par_num])
1037 par_val++;
1038 else
1039 par_val = 0;
1040 num_to_leds (par_val); // zobraz hodnotu parametru
1041 wait_release = 1; // cekame na uvolneni tlacitka UP
1042 }
1043 }
1044 else
1045 wait_release = 0;
1046 }
1047 }
1048 }
1049 }
1050  
1051 if (l_tick) {
1052 l_tick = 0;
1053 if (measure_VS () < VS_MIN)
1054 break; // koncime, napajeci zdroj odpojen
1055 }
1056 }
1057 prepare_var (); // konec nastavovani, aktualizuj promenne programu
1058 }
1059  
1060  
1061  
1062 ///////////////////////////////////////////////////
1063 // HLAVNI FUNKCE
1064 ///////////////////////////////////////////////////
1065  
1066 main () {
1067 int1 load_old;
1068 int1 load;
1069 int1 no_load;
1070 int1 start_TB; // spust mrereni teploty baterie
1071 int16 wdt_timer; // pro odmereni hodiny pomoci wdt
1072 int8 hour_timer; // pro odmerovani hodin
1073 int8 day_timer; // pro odmerovani dni od nabiti
1074 int16 TB_avr_tmp; // pro vypocet prumerne teploty
1075  
1076  
1077 #ifdef DEBUG
1078 int16 c;
1079 int16 inc_cap,IB_val,I_zero;
1080 int8 val;
1081 #endif
1082  
1083 init_ports ();
1084  
1085 if (restart_cause () != WDT_TIMEOUT) {
1086 // mereni skutecne doby behu wdt proved pro vseshny resety krome wdt
1087 setup_oscillator (OSC_4MHZ | OSC_NORMAL);
1088 delay_ms (100);
1089 setup_timer_1 (T1_INTERNAL | T1_DIV_BY_1);
1090 setup_wdt (WDT_288MS);
1091 hour_time = 0;
1092 set_timer1 (~1000);
1093 restart_wdt ();
1094 for (;;) {
1095 if (TMR1IF) {
1096 hour_time++;
1097 TMR1IF = 0;
1098 set_timer1 (~1000);
1099 }
1100 }
1101 }
1102  
1103 setup_oscillator (OSC_4MHZ | OSC_NORMAL);
1104 setup_timer_0 (RTCC_INTERNAL| RTCC_DIV_1);
1105 setup_wdt (WDT_288MS);
1106 setup_timer_1 (T1_INTERNAL | T1_DIV_BY_1);
1107 set_timer1 (S_TICK_TIME);
1108 setup_spi (FALSE);
1109 setup_comparator (NC_NC_NC_NC);
1110 setup_vref (FALSE);
1111 setup_ccp1 (CCP_OFF);
1112 setup_adc (ADC_CLOCK_INTERNAL); // doba prevodu cca 48 uS
1113 setup_adc_ports (sAN0 | sAN1 | sAN2 | sAN3 | sAN5 | VSS_VDD);
1114  
1115 enable_interrupts (INT_TIMER1);
1116 enable_interrupts (GLOBAL);
1117  
1118 prepare_var (); // priprav promenne pro beh programu z udaju o vlastnostech baterie
1119 prepare_hour_time ();
1120  
1121  
1122 //////////////////////////////////////////////////
1123  
1124 // uvodni bliknuti ledkou
1125 output_high (LED1_G);
1126 delay_ms (250);
1127 output_low (LED1_G);
1128  
1129  
1130 /*
1131 #ifdef DEBUG
1132 output_high (BATT_ON);
1133 printf ("Ahoj %lu\n\r",hour_time);
1134  
1135 for (;;) {
1136 restart_wdt ();
1137 if (is_load ())
1138 break; // napajeci zdroj byl pripojen
1139 delay_ms (100);
1140 }
1141  
1142 B_cap = B_cap_2_4;
1143 invalid_cap = 0;
1144  
1145 set_timer1 (0);
1146 // zde se meri doba trvani funkci nebo vybraneho kodu
1147 // selfdischarge (0); //OK
1148 do_discharge ();
1149  
1150 c = get_timer1 ();
1151 // printf ("T:%lu %lu %u \n\r",c,B_cap,chrg_eff);
1152  
1153 printf ("T:%lu\n\r",c);
1154 output_low (BATT_ON);
1155 delay_ms (250);
1156 for (;;)
1157 restart_wdt ();
1158 #endif
1159 */
1160  
1161 #ifdef DEBUG
1162 invalid_cap = 0;
1163 // B_cap = B_cap_3_4;
1164 B_cap = B_cap_2_4;
1165 #else
1166 invalid_cap = 1; // nezname zbyvajici kapacitu baterie
1167 B_cap = 0; // povazujeme ji za vybitou
1168 #endif
1169  
1170 TB_avr24 = TB_DEFAULT;
1171 TB_avr_tmp = 0;
1172 wdt_timer = 0;
1173 hour_timer = 0;
1174 day_timer = 0;
1175 start_TB = 1;
1176 no_load = 0;
1177  
1178 // hlavni programova smycka
1179 for (;;) {
1180 restart_wdt ();
1181 prepare_sleep ();
1182 sleep ();
1183 setup_adc_ports (sAN0 | sAN1 | sAN2 | sAN3 | sAN5 | VSS_VDD);
1184 load = is_load (); // precti stav kontaktu pripojeni zateze
1185 if (load != load_old)
1186 load_old = load; // stav kontaktu neni platny
1187 else {
1188 if (load) {
1189 if (! no_load) {
1190 do_discharge (); // zatez pripojena, vybijime - ma vyssi prioritu
1191 no_load = 1; // dalsi vybijeni je mozne az po odpojeni zateze
1192 wdt_timer = 0;
1193 }
1194 }
1195 else {
1196 no_load = 0; // zatez byl odpojena
1197 if (measure_VS () > VS_MIN) { // ma zdroj pro nabijeni dostatecne napeti?
1198 if (input (SET))
1199 do_charge (); // zatez odpojena a pripojen zdroj pro nabijeni, nabijime - ma nizsi pioritu
1200 else
1201 do_set_par (); // prechazime do rezimu pro nastavovani parametru programu
1202 TB_avr_tmp = 0;
1203 wdt_timer = 0;
1204 hour_timer = 0;
1205 day_timer = 0;
1206 }
1207 }
1208 }
1209  
1210 // reseni samovybijeni
1211 if (wdt_timer < hour_time)
1212 wdt_timer++;
1213 else {
1214 // uplynula hodina
1215 start_TB = 1; // odstartuj mereni teploty
1216 wdt_timer = 0; // natahni odmerovani hodiny
1217 if (hour_timer < 23)
1218 hour_timer++;
1219 else {
1220 // uplynul den
1221 TB_avr24 = TB_avr_tmp / 24; // vypocti prumernou teplotu za den
1222 if (day_timer < 90)
1223 day_timer++;
1224 else
1225 invalid_cap = 1; // po 90 dnech uz neverime kapacite baterie
1226 selfdischarge (day_timer); // uprav kapacitu baterie s ohledem na samovybijeni
1227 #ifdef DEBUG
1228 // printf ("TB:%u\n\r",TB_avr24);
1229 #endif
1230 TB_avr_tmp = 0;
1231 hour_timer = 0;
1232 }
1233 }
1234  
1235 // realizace mereni teploty - je v mnoha krocich
1236 if (start_TB) {
1237 if (measure_temp () == 0) {
1238 #ifdef DEBUG
1239 // printf("T:%u ",TB_val);
1240 #endif
1241 TB_avr_tmp += TB_val; // pocitame prumer teploty
1242 start_TB = 0;
1243 }
1244 }
1245 }
1246  
1247 }