Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (14.1 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 250//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
    error = 0;
270
        
271
        sei();
272
}
273

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

    
297
        curr = sum/AVG_COUNT;
298
        //OCR1A = curr >> 2;
299
        
300
        
301
         //old linear regulation
302
         /*
303
        if(OCR1B <255 && curr < i)
304
                        OCR1B++;
305
        else if(OCR1B >0 && curr > i)
306
                        OCR1B--;
307
        
308
        return curr;*/
309
        
310
        
311
        
312
        //cool control law stuff
313
        diff=i-curr;
314
        
315
        //OCR1B = diff/4 + curr/4; //K*Ierr + Kguess
316
    newcurr += diff/4;
317
    
318
    if(newcurr>255){
319
        OCR1B = 255;
320
    }else if(newcurr>0){
321
        OCR1B = newcurr;
322
    }else { //negative
323
        OCR1B = 1;
324
    }
325
        
326
        
327
        
328
        //1024/255
329
        /*if(OCR1B <255 && curr<i)
330
                OCR1B += (i-curr)/4;
331
        else if(OCR1B >0 && curr > i)
332
                OCR1B -= (curr-i)/4;*/
333
        //differential regulation (sort of)
334
        /*diff = i-curr;
335
        
336
        if(diff<8)
337
                steady_current=1;
338
        else
339
                steady_current=0;
340
        
341
        OCR1B += diff/4;*/
342
    
343
    return curr;
344
        
345
}
346

    
347
void check_voltage(void)
348
{
349
        int volt = get_avg_voltage();
350
        
351
        
352
        if(volt > MAX_V)
353
        {
354
                OCR1A = 128;
355
                send_err();
356
                PORTA |= _BV(debug_volt);
357
                status = 0;
358
        }
359
}
360

    
361
void check_temperature(void)
362
{
363
        int temp = get_avg_temperature();
364
        
365
        //temp readings are reversed
366
        if(temp < MAX_T || temp > MIN_T)
367
        {
368
                OCR1A = 192;
369
                send_err();
370
                PORTA |= _BV(debug_temp);
371
                status=0;
372
        }
373
}
374

    
375

    
376
//takes a 7-bit ionteger and displays it on the 7 LEDs with the Green being the MSB
377
void LED_out(int i)
378
{
379
        if(i & 64)
380
                PORTB |= _BV(LED1);
381
        else
382
                PORTB &= ~_BV(LED1);
383
                
384
        if(i & 32)
385
                PORTB |= _BV(LED2);
386
        else
387
                PORTB &= ~_BV(LED2);
388
                
389
        if(i & 16)
390
                PORTA |= _BV(PA3);
391
        else
392
                PORTA &= ~_BV(PA3);
393
        
394
        if(i & 8)
395
                PORTA |= _BV(PA4);
396
        else
397
                PORTA &= ~_BV(PA4);
398
                
399
        if(i & 4)
400
                PORTA |= _BV(PA5);
401
        else
402
                PORTA &= ~_BV(PA5);
403
        
404
        if(i & 2)
405
                PORTA |= _BV(PA6);
406
        else
407
                PORTA &= ~_BV(PA6);
408
                
409
        if(i & 1)
410
                PORTA |= _BV(PA7);
411
        else
412
                PORTA &= ~_BV(PA7);
413
}
414
        
415

    
416
void test_board(void)
417
{
418
        setup();
419
        abs_time = 0;
420
        status = 1;
421
        char tempData[5];
422
        i2c_init();
423
        int volt;
424
        int temp;
425
        int curr;
426
        int meas_count;
427
        int mod=0;
428
        sei();
429
        OCR1B = 0;
430
        while(1)
431
        {
432
                mod=abs_time%4;
433
                while(abs_time%4==mod);
434
                
435
                /*if((abs_time>>3)%3==0)
436
                        OCR1B=21;
437
                else if((abs_time>>3)%3==1)
438
                        OCR1B=57;
439
                else
440
                        OCR1B=85;*/
441
                
442
                tempData[0] = 'C';
443
                tempData[1] = abs_time>>8;
444
                tempData[2] = abs_time&0xFF;
445
                i2c_putpacket(0x01, tempData, 3);
446
                
447
                mod=abs_time%4;
448
                while(abs_time%4==mod);
449
                //{
450
                        if(supply_voltage())
451
                        {
452
                                curr = regulate_current(FAST_I);
453
                                //curr = get_avg_current();
454
                                //OCR1B = 100;
455
                        }
456
                        else
457
                        {
458
                                curr = 0;
459
                                OCR1B = 0;
460
                        }
461
                //}
462
                
463

    
464
                tempData[0] = 'P';
465
                tempData[1] = 0;
466
                tempData[2] = OCR1B;
467
                i2c_putpacket(0x01, tempData, 3);
468
                tempData[0] = 'I';
469
                tempData[1] = curr>>8;
470
                tempData[2] = curr&0xFF;
471
                i2c_putpacket(0x01, tempData, 3);
472
                curr=6666;
473
                
474
                mod=abs_time%4;
475
                //while(abs_time%4==mod)
476
                {
477
                        volt = get_avg_voltage();
478
                }
479

    
480
                tempData[0] = 'V';
481
                tempData[1] = volt>>8;
482
                tempData[2] = volt&0xFF;
483
                i2c_putpacket(0x01, tempData, 3);
484

    
485
                volt=6666;
486
                
487
                mod=abs_time%4;
488
                //while(abs_time%4==mod)
489
                {
490
                        temp = get_avg_temperature();
491
                        
492
                }
493
                
494
                tempData[0] = 'T';
495
                tempData[1] = temp>>8;
496
                tempData[2] = temp&0xFF;
497
                i2c_putpacket(0x01, tempData, 3);
498

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

    
562

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

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

    
708
#else
709

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

    
778
                }
779
                if (error) {
780
                        //We have an error...let's bail out of this ship captain!
781
                        tempData[0] = 'F';
782
                        tempData[1] = 'F';
783
                        tempData[2] = 'F';
784
                        tempData[3] = 'F';
785
                        tempData[4] = 'F';
786
                        i2c_putpacket(0x01, tempData, 5);
787
                }
788
                
789
                //PORTB ^= _BV(LED2);
790
                
791
        }
792

    
793
        
794
        return 1;
795
}
796

    
797
ISR(TIMER0_OVF_vect)
798
{
799
        if(error)
800
                PORTB ^= (_BV(LED1)|_BV(LED2));
801

    
802
        interrupt_count--;
803
        if(interrupt_count==0)
804
        {
805
                abs_time++;
806
                new_second=1;
807
                        
808
                interrupt_count=INT_COUNT;
809
        }
810
}
811

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