Project

General

Profile

Statistics
| Revision:

root / branches / autonomous_recharging / code / projects / autonomous_recharging / archs / Charging.c @ 356

History | View | Annotate | Download (13.9 KB)

1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <avr/sleep.h>
4
#include "i2c.h"
5

    
6
#define TRICKLE
7

    
8

    
9
//These are in ADC steps; if any values change in the charging
10
//circuitry these will have to be recalculated
11
#ifndef TRICKLE
12
        #define FAST_I 450//660 //660 fries the 5A fuse!!
13
#else
14
        #define FAST_I 20 //Works => 1.3A
15
#endif
16

    
17
#define TEST_CURR 550
18

    
19
#define MAX_V 1020//990 //7.75V
20

    
21

    
22
#define MAX_T 300
23
#define MIN_T 730
24
//range is 0 to 45 C
25
//cal tests:
26
//room temp - 25
27
//value ~500, varies from battery to battery, but is consistent on one battery
28
//freezer 737
29
//heat gun at a distance 461
30

    
31
//change in one minute
32
#define MAX_DT 30
33
#define MAX_DV 30
34

    
35

    
36
//The following times are in seconds
37
#define MAX_FAST_TIME 5400
38
#define MAX_TRICKLE_TIME 600
39

    
40
//debug pins
41
#define debug_time PA3
42
#define debug_curr PA4
43
#define debug_volt PA5
44
#define debug_temp PA6
45
#define debug_12in PA7
46

    
47
//be sure admux also sets the MUX5 bit which is in ADCSRB
48
#define ADMUX_I
49
#define ADMUX_V
50
#define ADMUX_T
51

    
52
#define ROBOT_TX PB1
53
#define ROBOT_RX PB2
54
#define PWM PB3
55
#define DETECT_12V PB6
56

    
57
#define LED1 PB4 //Green
58
#define LED2 PB5 //Red
59

    
60

    
61
//LED States:
62
//Red - Fast Charging
63
//Green - Trickle Charging
64
//Both steady - done charging
65
//Both Blinking - Error
66

    
67
#define INT_COUNT 2 //interrupts per second
68
#define AVG_COUNT 64 //number of times to count current
69

    
70
//To enable the PWM write :         TCCR1B = (_Bv(CS10));//enable PWM
71

    
72
uint8_t interrupt_count = INT_COUNT;
73

    
74
volatile uint32_t abs_time=1; // start at one second so it doesnt do the minute checks right away
75
volatile uint8_t new_second=0; //only used as a boolean
76

    
77
volatile uint8_t error=0;
78
volatile uint8_t status;
79

    
80
volatile uint8_t steady_current = 0;
81

    
82
//DT must be triggered twice in a row
83
volatile uint8_t last_DT = 0;
84
//same for DV
85
volatile uint8_t last_DV = 0;
86

    
87
#define FAST_CHARGE 1
88
#define TRICKLE_CHARGE 2
89

    
90

    
91

    
92
void wait(int ops)
93
{
94
        int i = 0;
95
        while(i<ops)
96
                i++;
97
}
98

    
99

    
100

    
101
int avg_ADC(void)
102
{
103
        int av;
104
        char i;
105

    
106
        //Calculate a average out of the next 8 A/D conversions
107
    for(av=0,i=8;i;--i)
108
    {
109
        ADCSRA |= _BV(ADSC);                      // start new A/D conversion
110
        while (!(ADCSRA & (_BV(ADIF))))        // wait until ADC is ready
111
            ;      
112
        av = av+ADC;
113
    }
114
    av = av/8;
115
        
116
        //ADCSRA &= ~_BV(ADEN);
117

    
118
        return av;
119
        
120
}
121

    
122
int get_voltage(void)
123
{
124
        ADMUX = _BV(MUX0);
125
        
126
        ADCSRB &= ~_BV(MUX5);
127
        
128
        return avg_ADC();
129
}
130

    
131
int get_current(void)
132
{
133
        ADMUX = _BV(MUX1);
134
        
135
        ADCSRB |= _BV(MUX5);
136
        
137
        return avg_ADC();
138
}
139

    
140
int get_temperature(void)
141
{
142
        ADMUX = _BV(MUX1);
143
        
144
        ADCSRB &= ~_BV(MUX5);
145
        
146
        return avg_ADC();
147
}
148

    
149
int get_avg_voltage(void)
150
{
151
        int count=0;
152
        uint32_t sum=0;
153
                
154
                //OCR1B =120;
155
        while(count < AVG_COUNT)
156
        {
157
                sum += get_voltage();
158
                count++;
159
        }
160

    
161
        return sum/AVG_COUNT;
162
}
163

    
164
int get_avg_current(void)
165
{
166
        int count=0;
167
        uint32_t sum=0;
168
                
169
                //OCR1B =120;
170
        while(count < AVG_COUNT)
171
        {
172
                sum += get_current();
173
                count++;
174
        }
175

    
176
        return sum/AVG_COUNT;
177
}
178

    
179
int get_avg_temperature(void)
180
{
181
        int count=0;
182
        uint32_t sum=0;
183
                
184
                //OCR1B =120;
185
        while(count < AVG_COUNT)
186
        {
187
                sum += get_temperature();
188
                count++;
189
        }
190

    
191
        return sum/AVG_COUNT;
192
}
193

    
194

    
195
uint8_t supply_voltage(void)
196
{
197
        return PINB & _BV(DETECT_12V);
198
}
199

    
200
void clear_err(void)
201
{
202
        error=0;
203
        PORTB &= ~(_BV(LED1)|_BV(LED2));
204
        
205
        if(status==FAST_CHARGE)
206
                PORTB |= _BV(LED2);
207
                
208
        if(status==TRICKLE_CHARGE)
209
                PORTB |= _BV(LED1);
210
}
211
        
212
void wait_8th(void)
213
{
214
        uint8_t start = abs_time % 8;
215
        
216
        while(abs_time % 8 == start)
217
        {
218
                /*if(supply_voltage())
219
                        PORTB |= _BV(LED1);
220
                else
221
                        PORTB &= ~_BV(LED1);
222
                if(get_voltage()>100)
223
                        PORTB |= _BV(LED2);
224
                else
225
                        PORTB &= ~_BV(LED2);*/
226
        }
227
}
228

    
229
void send_err(void)
230
{
231
        OCR1B=0;//turn off the PWM to be safe
232

    
233
        PORTB &= ~(_BV(LED1)|_BV(LED2));
234
        if(status!=0)//leave last error if there was one
235
                PORTA &= ~(_BV(debug_time)|_BV(debug_curr)|_BV(debug_volt)|_BV(debug_temp)|_BV(debug_12in)); 
236
        error=1;
237
        status=0;
238
}
239

    
240
void send_done(void)
241
{
242
        char tempData;
243
        //Finished, leave
244
        tempData = 'F';
245
        i2c_putpacket(0x01, &tempData, 1);
246
        
247
        PORTA &= ~(_BV(debug_time)|_BV(debug_curr)|_BV(debug_volt)|_BV(debug_temp)|_BV(debug_12in)); 
248
        
249
}
250

    
251
void setup(void)
252
{
253
        DDRA = (_BV(debug_time)|_BV(debug_curr)|_BV(debug_volt)|_BV(debug_temp)|_BV(debug_12in));
254
        PORTA = 0x00;
255
        DDRB = (_BV(ROBOT_TX)|_BV(PWM)|_BV(LED1)|_BV(LED2)); //confiure output pins
256
        PORTB = 0x00;
257
        
258
        ADCSRA = (_BV(ADEN)|_BV(ADPS2)|_BV(ADPS1)); //start ADC with a division factor of 64
259
        
260
        TCCR0B = (_BV(CS01)); //set timer 0 for realtime mode
261
        TCCR0A = (_BV(TCW0));
262
        TIMSK = (_BV(TOIE0)); //enable overflow interrupts
263
        
264
        TCCR1A = (_BV(COM1B1)|_BV(PWM1B)|_BV(COM1A1)|_BV(PWM1A)); //clear timer 1 on compare, set at 0x00. Fast PWM mode
265
        TCCR1B |= _BV(CS12)|_BV(CS10); //leave timer on and set compare to 0 to make output off        
266
        OCR1B = 0;
267
        OCR1A = 0;
268
        
269
        sei();
270
}
271

    
272
int regulate_current(int i)
273
{
274
        if(status==0)
275
        {
276
                OCR1B = 0;
277
                return 0;
278
        }
279
                
280
        PORTA ^= _BV(debug_curr);
281
        
282
        int curr=0;
283
        int count=0;
284
        int diff=0;
285
        uint32_t sum=0;
286
                
287
                //OCR1B =120;
288
        while(count < AVG_COUNT)
289
        {
290
                sum += get_current();
291
                count++;
292
        }
293

    
294
        curr = sum/AVG_COUNT;
295
        //OCR1A = curr >> 2;
296
        
297
        
298
         //old linear regulation
299
         /*
300
        if(OCR1B <255 && curr < i)
301
                        OCR1B++;
302
        else if(OCR1B >0 && curr > i)
303
                        OCR1B--;
304
        
305
        return curr;
306
        */
307
        
308
        
309
        //cool control law stuff
310
        diff=curr-i;
311
        
312
        OCR1B = diff/4 + curr/4; //K*Ierr + Kguess
313
        
314
        
315
        
316
        //1024/255
317
        /*if(OCR1B <255 && curr<i)
318
                OCR1B += (i-curr)/4;
319
        else if(OCR1B >0 && curr > i)
320
                OCR1B -= (curr-i)/4;*/
321
        //differential regulation (sort of)
322
        /*diff = i-curr;
323
        
324
        if(diff<8)
325
                steady_current=1;
326
        else
327
                steady_current=0;
328
        
329
        OCR1B += diff/4;*/
330
        
331
}
332

    
333
void check_voltage(void)
334
{
335
        int volt = get_avg_voltage();
336
        
337
        
338
        if(volt > MAX_V)
339
        {
340
                OCR1A = 128;
341
                send_err();
342
                PORTA |= _BV(debug_volt);
343
                status = 0;
344
        }
345
}
346

    
347
void check_temperature(void)
348
{
349
        int temp = get_avg_temperature();
350
        
351
        //temp readings are reversed
352
        if(temp < MAX_T || temp > MIN_T)
353
        {
354
                OCR1A = 192;
355
                send_err();
356
                PORTA |= _BV(debug_temp);
357
                status=0;
358
        }
359
}
360

    
361

    
362
//takes a 7-bit ionteger and displays it on the 7 LEDs with the Green being the MSB
363
void LED_out(int i)
364
{
365
        if(i & 64)
366
                PORTB |= _BV(LED1);
367
        else
368
                PORTB &= ~_BV(LED1);
369
                
370
        if(i & 32)
371
                PORTB |= _BV(LED2);
372
        else
373
                PORTB &= ~_BV(LED2);
374
                
375
        if(i & 16)
376
                PORTA |= _BV(PA3);
377
        else
378
                PORTA &= ~_BV(PA3);
379
        
380
        if(i & 8)
381
                PORTA |= _BV(PA4);
382
        else
383
                PORTA &= ~_BV(PA4);
384
                
385
        if(i & 4)
386
                PORTA |= _BV(PA5);
387
        else
388
                PORTA &= ~_BV(PA5);
389
        
390
        if(i & 2)
391
                PORTA |= _BV(PA6);
392
        else
393
                PORTA &= ~_BV(PA6);
394
                
395
        if(i & 1)
396
                PORTA |= _BV(PA7);
397
        else
398
                PORTA &= ~_BV(PA7);
399
}
400
        
401

    
402
void test_board(void)
403
{
404
        setup();
405
        abs_time = 0;
406
        status = 1;
407
        char tempData[5];
408
        i2c_init();
409
        int volt;
410
        int temp;
411
        int curr;
412
        int meas_count;
413
        int mod=0;
414
        sei();
415
        OCR1B = 0;
416
        while(1)
417
        {
418
                mod=abs_time%4;
419
                while(abs_time%4==mod);
420
                
421
                /*if((abs_time>>3)%3==0)
422
                        OCR1B=21;
423
                else if((abs_time>>3)%3==1)
424
                        OCR1B=57;
425
                else
426
                        OCR1B=85;*/
427
                
428
                tempData[0] = 'C';
429
                tempData[1] = abs_time>>8;
430
                tempData[2] = abs_time&0xFF;
431
                i2c_putpacket(0x01, tempData, 3);
432
                
433
                mod=abs_time%4;
434
                while(abs_time%4==mod)
435
                {
436
                        if(supply_voltage())
437
                        {
438
                                //curr = regulate_current(500);
439
                                curr = get_avg_current();
440
                                OCR1B = 100;
441
                        }
442
                        else
443
                        {
444
                                curr = 0;
445
                                OCR1B = 0;
446
                        }
447
                }
448
                
449

    
450
                tempData[0] = 'P';
451
                tempData[1] = 0;
452
                tempData[2] = OCR1B;
453
                i2c_putpacket(0x01, tempData, 3);
454
                tempData[0] = 'I';
455
                tempData[1] = curr>>8;
456
                tempData[2] = curr&0xFF;
457
                i2c_putpacket(0x01, tempData, 3);
458
                curr=6666;
459
                
460
                mod=abs_time%4;
461
                while(abs_time%4==mod)
462
                {
463
                        volt = get_avg_voltage();
464
                }
465

    
466
                tempData[0] = 'V';
467
                tempData[1] = volt>>8;
468
                tempData[2] = volt&0xFF;
469
                i2c_putpacket(0x01, tempData, 3);
470

    
471
                volt=6666;
472
                
473
                mod=abs_time%4;
474
                while(abs_time%4==mod)
475
                {
476
                        temp = get_avg_temperature();
477
                        
478
                }
479
                
480
                tempData[0] = 'T';
481
                tempData[1] = temp>>8;
482
                tempData[2] = temp&0xFF;
483
                i2c_putpacket(0x01, tempData, 3);
484

    
485
                temp=6666;
486
        }
487
        int c=0,oc;
488
        oc=get_avg_temperature();
489
        //this will read the temperature and output it to the LEDS.
490
        //to read the value, enter the LEDs as binary, with the bottom green as the MSB.
491
        //after two second the LEDS will toggle to the next 7 bits
492
        /*while(1)
493
        {
494
                c=oc-get_avg_temperature();
495
                oc+=c;
496
                
497
                if(c<0)
498
                        c=-c;
499
                
500
                if(c<5)
501
                        break;
502
        }*/
503
/*
504
        while(1)
505
        {
506
                LED_out(oc>>7);
507
                for(c=0;c<16;c++)
508
                        wait_8th();
509
                LED_out(oc);
510
                for(c=0;c<16;c++)
511
                        wait_8th();
512
        }*/
513
        
514
        
515
        /*PORTB |= (_BV(LED1)|_BV(LED2));
516
        
517
        while(1)
518
        {
519
                PORTA ^= _BV(debug_time);
520
                wait_8th();
521
                c=get_current()-FAST_I;
522
                if(c<0)
523
                        c=-c;
524
                if(c<4)
525
                        PORTA |= _BV(debug_curr);
526
                else
527
                        PORTA &= ~_BV(debug_curr);
528
                wait_8th();
529
                if(get_avg_voltage() > 50)
530
                        PORTA |= _BV(debug_volt);
531
                else
532
                        PORTA &= ~_BV(debug_volt);
533
                wait_8th();
534
                if(get_avg_temperature() > MAX_T)
535
                        PORTA |= _BV(debug_temp);
536
                else
537
                        PORTA &= ~_BV(debug_temp);
538
                wait_8th();
539
                if(supply_voltage())
540
                        PORTA |= _BV(debug_12in);
541
                else
542
                        PORTA &= ~_BV(debug_12in);
543
                wait_8th();
544
        }*/
545
        
546
}
547

    
548

    
549
int main(void)
550
{
551
        test_board();
552
        new_second=0;
553
        char tempData[5];        //For i2c communication
554
        //test_board();
555
        char noVoltagePrintFlag = 0;
556
  
557
        setup();
558
        i2c_init();
559
        
560
        /*GIMSK = (_BV(PCIE0)); //enable PCINT interrupts
561
        PCMSK1 = (_BV(PCINT10)); //enable pin change interrupt on ROBOT_RX
562
        MCUCR = (_BV(SE)|_BV(SM1));// (power-down mode)
563
        */
564
        
565
        OCR1B=0;
566
        
567
        sei();
568
        
569
        tempData[0] = 'S';
570
        tempData[1] = 'S';
571
        tempData[2] = 'S';
572
        tempData[3] = 'S';
573
        tempData[4] = 'S';
574
        i2c_putpacket(0x01, tempData, 5);        
575
        
576
        int temp=0;
577
        int last_temp = get_avg_temperature();
578
        
579
        int volt=0;
580
        int last_volt = get_avg_voltage();
581
        
582
        
583
        while(1)
584
        {
585
                /*GIMSK = (_BV(PCIE0)); //enable PCINT interrupts
586
                sleep_cpu();*/
587
                
588
                PORTB=0;//clear outputs
589
                
590
                GIMSK = 0;
591
                
592
                error=0;
593
                
594
                OCR1B = 0;
595
                
596
                //wait for 12v source
597
                
598
                while(!supply_voltage()) {
599
                        if (!noVoltagePrintFlag) {
600
                                tempData[0] = 'N';
601
                                tempData[1] = 'N';
602
                                tempData[2] = 'N';
603
                                tempData[3] = 'N';
604
                                tempData[4] = 'N';
605
                                i2c_putpacket(0x01, tempData, 5);
606
                                noVoltagePrintFlag = 1;
607
                        }
608
                }
609
                
610
                noVoltagePrintFlag = 0;
611
                
612
                //Contact 
613
                tempData[0] = 'C';
614
                tempData[1] = 'C';
615
                tempData[2] = 'C';
616
                tempData[3] = 'C';
617
                tempData[4] = 'C';
618
                i2c_putpacket(0x01, tempData, 5);
619
                
620
                PORTA |= _BV(debug_12in);
621
                
622
                abs_time=1;
623

    
624
                //--------------FAST CHARGE-----------------------
625
                //split seconds into eights as following:
626
                //1: abs_volt
627
                //2: reg
628
                //3: abs_temp
629
                //4: reg
630
                //5: abs_volt
631
                //6: reg
632
                //7: abs_temp
633
                //between seconds: abs time and minute checks, which takes an extra 8th
634
                status = FAST_CHARGE;
635
                
636
                PORTB |= _BV(LED2);
637
                
638
                while(status == FAST_CHARGE)
639
                {
640
                        
641
                        if(!supply_voltage())
642
                        {
643
                                
644
                                
645
                                send_err();
646
                                //Lost Contact
647
                                tempData[0] = 'N';
648
                                tempData[1] = 'N';
649
                                tempData[2] = 'N';
650
                                tempData[3] = 'N';
651
                                tempData[4] = 'N';
652
                                i2c_putpacket(0x01, tempData, 5);
653
                                
654
                                PORTA &= ~_BV(debug_12in);
655
                                while(!supply_voltage());
656
                                
657
                                //Contact again
658
                                tempData[0] = 'C';
659
                                tempData[1] = 'C';
660
                                tempData[2] = 'C';
661
                                tempData[3] = 'C';
662
                                tempData[4] = 'C';
663
                                i2c_putpacket(0x01, tempData, 5);
664
                                
665
                                PORTA |= _BV(debug_12in);
666
                                clear_err();
667
                        }
668
                        
669
                        check_voltage();
670
                        wait_8th();
671
                        regulate_current(FAST_I);
672
                        wait_8th();
673
                        check_temperature();
674
                        wait_8th();
675
                        regulate_current(FAST_I);
676
                        wait_8th();
677
                        check_voltage();
678
                        wait_8th();
679
                        regulate_current(FAST_I);
680
                        wait_8th();
681
                        check_temperature();
682
                        wait_8th();
683
                        
684
#ifdef TRICKLE
685
                        
686
                        if(abs_time > 9600) //90 minute time limit
687
                        {
688
                                OCR1A = 32;
689
                                send_done();
690
                                PORTA |= _BV(debug_time);
691
                                break;
692
                        }
693

    
694
#else
695

    
696
                        if(abs_time > 43200) //90 minute time limit
697
                        {
698
                                OCR1A = 32;
699
                                send_err();
700
                                PORTA |= _BV(debug_time);
701
                                break;
702
                        }
703
                        
704
                        //minute checks
705
                        if( (abs_time >> 3)%55 == 0/* && steady_current*/)
706
                        {
707
                                PORTA ^= _BV(debug_time);
708
                                
709
                                temp = get_avg_temperature();
710
                                wait_8th(); //to avoid interference
711
                                volt = get_avg_voltage(); 
712
                                
713
                                OCR1A = volt >> 2;
714
                                
715
                                //seems to be some random drops when connected to a power supply
716
                                //may need a fudge factor but maybe not becuase voltage should be climbing during charge
717
                                if(volt < last_volt - MAX_DV)
718
                                {
719
          PORTA |= _BV(debug_volt);
720
          if(last_DV)
721
          {
722
            OCR1A = 64;
723
            
724
            send_done();
725
            PORTA |= _BV(debug_volt);
726
            status = TRICKLE_CHARGE;
727
          }
728
          else
729
            last_DV=1;
730
          
731
                                }
732
        else
733
        {
734
          last_DV=0;
735
          PORTA &= ~_BV(debug_volt);
736
         }
737
                                
738
                                
739
                                if(temp < last_temp - MAX_DT)
740
                                {
741
          PORTA |= _BV(debug_temp);
742
          if(last_DT)
743
          {       
744
            OCR1A = 128;
745
            
746
            send_done();
747
            PORTA |= _BV(debug_temp);
748
            status = TRICKLE_CHARGE;
749
          }
750
          else
751
            last_DT=1;
752
                                }
753
        else
754
        {
755
          last_DT=0;
756
          PORTA &= ~_BV(debug_temp);
757
        }
758
                                
759
                                last_volt = volt;
760
                                last_temp = temp;
761
                        }
762
#endif
763

    
764
                }
765
                if (error) {
766
                        //We have an error...let's bail out of this ship captain!
767
                        tempData[0] = 'F';
768
                        tempData[1] = 'F';
769
                        tempData[2] = 'F';
770
                        tempData[3] = 'F';
771
                        tempData[4] = 'F';
772
                        i2c_putpacket(0x01, tempData, 5);
773
                }
774
                
775
                //PORTB ^= _BV(LED2);
776
                
777
        }
778

    
779
        
780
        return 1;
781
}
782

    
783
ISR(TIMER0_OVF_vect)
784
{
785
        if(error)
786
                PORTB ^= (_BV(LED1)|_BV(LED2));
787

    
788
        interrupt_count--;
789
        if(interrupt_count==0)
790
        {
791
                abs_time++;
792
                new_second=1;
793
                        
794
                interrupt_count=INT_COUNT;
795
        }
796
}
797

    
798
ISR(PCINT_vect){;} //so the interrupt doesnt go to the reset vector