Statistics
| Revision:

root / branches / autonomous_recharging / code / projects / autonomous_recharging / archs / ConstantCharging.c @ 955

History | View | Annotate | Download (13.6 KB)

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

    
7

    
8
// for i2c_byte coming from charge board
9
//I2C Message Codes
10
#define I2C_MSG_ACKNOWLEDGE       'A'
11
#define I2C_MSG_BATTERY_CHARGING  'C'
12
#define I2C_MSG_DATA              'D'
13
#define I2C_MSG_CONTACT_ERROR     'E'
14
#define I2C_MSG_BATTERY_FULL      'F'
15
#define I2C_MSG_NO_CONTACT        'N'
16
#define I2C_MSG_REQUEST_DATA      'R'
17
#define I2C_MSG_GO_TO_SLEEP       'Y'
18
#define I2C_MSG_ENTERING_SLEEP    'Z'
19
#define I2C_MSG_HOMING            'H'
20

    
21

    
22
#define SW0 PA6
23
#define HOMING_PIN PA7
24

    
25
#define DEBUG 1 //enable I2C outputs of form time, OCR, current, voltage, temp
26
#define USE_I2C 1
27

    
28

    
29
#define MAX_T 300
30
#define MIN_T 730
31
//range is 0 to 45 C
32
//cal tests:
33
//room temp - 25
34
//value ~500, varies from battery to battery, but is consistent on one battery
35
//freezer 737
36
//heat gun at a distance 461
37

    
38
#define MAX_DT -4 //this is the LOWEST ACCEPTABLE ADC value
39
#define MAX_DT_ABS 400
40
#define VOLT_PLATEAU 50
41

    
42

    
43
//The following times are in seconds
44
#define MAX_FAST_TIME 5400
45
#define MAX_TRICKLE_TIME 600
46

    
47
//debug pins
48
#define debug_time PA3
49
#define debug_curr PA4
50
#define debug_volt PA5
51
#define debug_temp PA6
52
#define debug_12in PA7
53

    
54
//be sure admux also sets the MUX5 bit which is in ADCSRB
55
#define ADMUX_I
56
#define ADMUX_V
57
#define ADMUX_T
58

    
59
#define ROBOT_TX PB1
60
#define ROBOT_RX PB2
61
#define PWM PB3
62
#define DETECT_12V PB6
63

    
64
#define LED1 PB4 //Green
65
#define LED2 PB5 //Red
66

    
67

    
68
//LED States:
69
//Red - Fast Charging
70
//Green - Trickle Charging
71
//Both steady - done charging
72
//Both Blinking - Error
73

    
74
#define INT_COUNT 2 //interrupts per second
75
#define AVG_COUNT 64 //number of times to count current
76

    
77
//To enable the PWM write :         TCCR1B = (_Bv(CS10));//enable PWM
78

    
79
uint8_t interrupt_count = INT_COUNT;
80

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

    
84
volatile uint8_t error=0;
85
volatile uint8_t status;
86

    
87
volatile uint8_t steady_current = 0;
88

    
89
//DT must be triggered twice in a row
90
volatile uint8_t last_DT = 0;
91
//same for DV
92
volatile uint8_t last_DV = 0;
93

    
94
#define FAST_CHARGE 1
95
#define TRICKLE_CHARGE 2
96

    
97
RING_BUFFER_NEW(ring_buffer, 12, int, buffer);
98

    
99
void wait(int ops)
100
{
101
        int i = 0;
102
        while(i<ops)
103
                i++;
104
}
105

    
106

    
107

    
108
int avg_ADC(void)
109
{
110
        int av;
111
        char i;
112

    
113
        //Calculate a average out of the next 8 A/D conversions
114
    for(av=0,i=8;i;--i)
115
    {
116
        ADCSRA |= _BV(ADSC);                      // start new A/D conversion
117
        while (!(ADCSRA & (_BV(ADIF))))        // wait until ADC is ready
118
            ;      
119
        av = av+ADC;
120
    }
121
    av = av/8;
122
        
123
        //ADCSRA &= ~_BV(ADEN);
124

    
125
        return av;
126
        
127
}
128

    
129
int get_voltage(void)
130
{
131
        ADMUX = _BV(MUX0);
132
        
133
        ADCSRB &= ~_BV(MUX5);
134
        
135
        return avg_ADC();
136
}
137

    
138
int get_current(void)
139
{
140
        ADMUX = _BV(MUX1);
141
        
142
        ADCSRB |= _BV(MUX5);
143
        
144
        return avg_ADC();
145
}
146

    
147
int get_temperature(void)
148
{
149
        ADMUX = _BV(MUX1);
150
        
151
        ADCSRB &= ~_BV(MUX5);
152
        
153
        return avg_ADC();
154
}
155

    
156
int get_avg_voltage(void)
157
{
158
        int count=0;
159
        uint32_t sum=0;
160
                
161
                //OCR1B =120;
162
        while(count < AVG_COUNT)
163
        {
164
                sum += get_voltage();
165
                count++;
166
        }
167

    
168
        return sum/AVG_COUNT;
169
}
170

    
171
int get_avg_current(void)
172
{
173
        int count=0;
174
        uint32_t sum=0;
175
                
176
                //OCR1B =120;
177
        while(count < AVG_COUNT)
178
        {
179
                sum += get_current();
180
                count++;
181
        }
182

    
183
        return sum/AVG_COUNT;
184
}
185

    
186
int get_avg_temperature(void)
187
{
188
        int count=0;
189
        uint32_t sum=0;
190
                
191
                //OCR1B =120;
192
        while(count < AVG_COUNT)
193
        {
194
                sum += get_temperature();
195
                count++;
196
        }
197

    
198
        return sum/AVG_COUNT;
199
}
200

    
201

    
202
uint8_t supply_voltage(void)
203
{
204
        return PINB & _BV(DETECT_12V);
205
}
206

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

    
236
void send_err(void)
237
{
238
        OCR1B=0;//turn off the PWM to be safe
239

    
240
        PORTB &= ~(_BV(LED1)|_BV(LED2));
241
        if(status!=0)//leave last error if there was one
242
                PORTA &= ~(_BV(debug_time)|_BV(debug_curr)|_BV(debug_volt)|_BV(debug_temp)|_BV(debug_12in)); 
243
        error=1;
244
        status=0;
245
}
246

    
247
void send_done(void)
248
{
249

    
250
#if USE_I2C
251
        char tempData;
252
        //Finished, leave
253
        tempData = 'F';
254
        i2c_putpacket(0x01, &tempData, 1);
255
#endif
256
        
257
        PORTA &= ~(_BV(debug_time)|_BV(debug_curr)|_BV(debug_volt)|_BV(debug_temp)|_BV(debug_12in)); 
258
        
259
}
260

    
261
void setup(void)
262
{
263
      DDRA = _BV(PA3);
264
#if DEBUG
265
        //DDRA = (_BV(debug_time)|_BV(debug_curr)|_BV(debug_volt)|_BV(debug_temp)|_BV(debug_12in));
266
#endif
267
        PORTA = 0x00;
268
        DDRB = (_BV(ROBOT_TX)|_BV(PWM)|_BV(LED1)|_BV(LED2)); //confiure output pins
269
        PORTB &= ~(_BV(LED1) | _BV(LED2)); //clear LEDs without messing everything else up!
270
        
271
        ADCSRA = (_BV(ADEN)|_BV(ADPS2)|_BV(ADPS1)); //start ADC with a division factor of 64
272
        
273
        TCCR0B = (_BV(CS01)); //set timer 0 for realtime mode
274
        TCCR0A = (_BV(TCW0));
275
        TIMSK = (_BV(TOIE0)); //enable overflow interrupts
276
        
277
        TCCR1A = (_BV(COM1B1)|_BV(PWM1B)|_BV(COM1A1)|_BV(PWM1A)); //clear timer 1 on compare, set at 0x00. Fast PWM mode
278
        TCCR1B |= _BV(CS10); //leave timer on and set compare to 0 to make output off        
279
        
280
        //hack stuff so it will run in continuous mode
281
        //TIMSK |= _BV(TOIE1); //enable overflow interrupt for timer 1
282
        
283
        OCR1B = 0;
284
        OCR1A = 0;
285
        
286
        
287
        RING_BUFFER_CLEAR(buffer);
288
        RING_BUFFER_INIT(buffer, 12);
289
        for(int i=0;i<10;i++)
290
                RING_BUFFER_ADD(buffer, 0);
291
        
292
        sei();
293
}
294

    
295

    
296

    
297

    
298
//takes a 7-bit ionteger and displays it on the 7 LEDs with the Green being the MSB
299
void LED_out(int i)
300
{
301
        if(i & 64)
302
                PORTB |= _BV(LED1);
303
        else
304
                PORTB &= ~_BV(LED1);
305
                
306
        if(i & 32)
307
                PORTB |= _BV(LED2);
308
        else
309
                PORTB &= ~_BV(LED2);
310
                
311
        if(i & 16)
312
                PORTA |= _BV(PA3);
313
        else
314
                PORTA &= ~_BV(PA3);
315
        
316
        if(i & 8)
317
                PORTA |= _BV(PA4);
318
        else
319
                PORTA &= ~_BV(PA4);
320
                
321
        if(i & 4)
322
                PORTA |= _BV(PA5);
323
        else
324
                PORTA &= ~_BV(PA5);
325
        
326
        if(i & 2)
327
                PORTA |= _BV(PA6);
328
        else
329
                PORTA &= ~_BV(PA6);
330
                
331
        if(i & 1)
332
                PORTA |= _BV(PA7);
333
        else
334
                PORTA &= ~_BV(debug_12in);
335
}
336

    
337
//get the difference of the current value minues the value 10 entires ago
338
int ring_buffer_d10(int y)
339
{        
340
        int x;
341
        RING_BUFFER_REMOVE(buffer, x);
342
                
343
        RING_BUFFER_ADD(buffer, y);
344
        return y-x;
345
}
346

    
347

    
348
uint8_t read_homing(void)
349
{
350
    uint8_t ret = PINA & _BV(HOMING_PIN);
351
    if(ret)
352
        PORTA |= _BV(PA3);
353
    else
354
        PORTA &= ~_BV(PA3);
355
    return ret;
356
}
357

    
358
//copied from scheduler/seeking.c
359
uint8_t get_delay(void)
360
{
361
    uint8_t count = 0;
362
    
363
        PORTB|=_BV(LED2);
364
    while(read_homing())
365
    {
366
        delay_ms(1);
367
        count++;
368
        if (count >= 100)
369
            return 1;
370
    } //wait a beacon cycle to make sure we aren't starting the count in the middle of one
371
        PORTB&=~_BV(LED2);
372
    count = 0;
373
    PORTB|=_BV(LED1);
374
    while(!read_homing())
375
    {
376
        delay_ms(1);
377
        count++;
378
        if(count==255)
379
          return 2;
380
    }
381
    PORTB&=~_BV(LED1);
382
        
383
  /*RECH_PUTS("\n\rCount: ");
384
        RECH_PUTI(count);
385
        RECH_PUTC('.');*/
386
        
387
    return count;
388
}
389

    
390
void trickle_charge(void)
391
{
392

    
393
        abs_time = 0;
394
        status = 0;
395
        char tempData[5];
396
        char data[2];
397
        data[0]='D';
398
        int volt = 0;
399
        int temp = 0;
400
        int curr = 0;
401
        int meas_count = 0;
402
        int mod=0;
403
        OCR1B = 0;
404
        
405
        PORTB &= ~(_BV(LED1)|_BV(LED2));
406

    
407
        
408
        while(status!=2)
409
        {
410
                mod=abs_time%4;
411
                
412
                PORTB ^= _BV(LED2);
413
                
414
                if(supply_voltage())
415
                  while(abs_time%4==mod);
416
                
417
    /* TIME TERMINATION */
418
                if(abs_time>12000) //12000=25 minutes
419
                {
420
                        //SEND_DONE
421
                        OCR1B=0;
422
                        break;
423
                }
424
                
425
#if DEBUG                
426
                tempData[0] = 'C';
427
                tempData[1] = abs_time>>8;
428
                tempData[2] = abs_time&0xFF;
429
        delay_ms(50);
430
                i2c_putpacket(0x01, tempData, 3);
431
        delay_ms(50);
432
#endif
433
                
434
                mod=abs_time%4;
435
                while(abs_time%4==mod)
436
                {
437
      /* CONTACT */
438
                        if(supply_voltage())
439
                        {
440
                                PORTB |= _BV(LED1);
441
                                //curr = regulate_current(500);
442
                                curr = get_avg_current();
443
                                
444
                                if(status==0)
445
                                {
446
                                        status=1;
447
#if USE_I2C
448
                                        data[1]='a';
449
                                        i2c_putpacket(0x01, data, 2);
450
                                        data[1]=I2C_MSG_BATTERY_CHARGING;
451
                                        i2c_putpacket(0x01, data, 2);
452
#endif
453
                                }
454
                                
455
        /* Trickle Charge */
456
                                if(status==1)
457
                                        OCR1B = 100;
458
                        }
459
      /* NO CONTACT */
460
                        else
461
                        {
462
                                PORTB &= ~_BV(LED1);
463
                                if(status==1)
464
                                {
465
                                        status=0;
466
#if USE_I2C
467
                                        data[1]=I2C_MSG_CONTACT_ERROR;
468
                                        i2c_putpacket(0x01, data, 2);
469
#endif
470
                                }
471
                                else
472
                                {
473
          /*get_delay(); //reject the first reading //homing import stuff, uncomment this!!!!!!
474
                                        data[0]=I2C_MSG_HOMING;
475
                                        data[1]=get_delay();
476
          i2c_putpacket(0x01, data, 2);*/
477
          
478
          data[0]='D';
479
                                }
480
                                curr = 0;
481
                                OCR1B = 0;
482
                        }
483
                }
484
                
485
#if DEBUG
486
                tempData[0] = 'P';
487
                tempData[1] = 0;
488
                tempData[2] = OCR1B;
489
        delay_ms(50);
490
                i2c_putpacket(0x01, tempData, 3);
491
        delay_ms(50);
492
                tempData[0] = 'I';
493
                tempData[1] = curr>>8;
494
                tempData[2] = curr&0xFF;
495
        delay_ms(50);
496
                i2c_putpacket(0x01, tempData, 3);
497
        delay_ms(50);
498
#endif
499
                curr=6666;
500
                
501
    /* Absolute Voltage Termination */
502
                mod=abs_time%4;
503
                while(abs_time%4==mod)
504
                {
505
                        volt = get_avg_voltage();
506
                }
507
                
508
                if(volt>1010)
509
                {
510
                        //SEND ERROR
511
                        status=0;
512
                }
513
    
514
#if DEBUG
515
                tempData[0] = 'V';
516
                tempData[1] = volt>>8;
517
                tempData[2] = volt&0xFF;
518
        delay_ms(50);
519
                i2c_putpacket(0x01, tempData, 3);
520
        delay_ms(50);
521
#endif
522
                volt=6666;
523
                
524
    /* Absolute Temperature Termination */
525
                mod=abs_time%4;
526
                while(abs_time%4==mod)
527
                {
528
                        temp = get_avg_temperature();
529
                }
530
                
531
                if(temp<250)
532
                {
533
                        //SEND ERROR
534
                        status=0;
535
                }
536

    
537
#if DEBUG
538
                tempData[0] = 'T';
539
                tempData[1] = temp>>8;
540
                tempData[2] = temp&0xFF;
541
        delay_ms(50);
542
                i2c_putpacket(0x01, tempData, 3);
543
        delay_ms(50);
544
#endif
545

    
546
                temp=6666;
547
        }
548
#if USE_I2C
549
        data[1]=I2C_MSG_BATTERY_FULL;
550
        i2c_putpacket(0x01, data, 2);
551
#endif
552
}
553

    
554
int main(void)
555
{
556
        new_second=0;
557
        char tempData[5];        //For i2c communication
558
  
559
        setup();
560

    
561
i2c_init();
562
PORTB|=_BV(LED2);
563
PORTB|=_BV(LED1);
564

    
565

    
566
while(1)
567
{
568
        delay_ms(500);
569
        i2c_putpacket(0x01,'I', 1);
570
        delay_ms(500);
571
}
572

    
573
#if USE_I2C
574
        delay_ms(500);
575
        i2c_init();
576
        i2c_putpacket(0x01,"I2C init'd on ARCHS\r\n", 21);
577
        delay_ms(500);
578
#else
579
    #if DEBUG
580
        i2c_init();
581
    #endif
582
#endif
583
        
584
        
585
        /*GIMSK = (_BV(PCIE0)); //enable PCINT interrupts
586
        PCMSK1 = (_BV(PCINT10)); //enable pin change interrupt on ROBOT_RX
587
        MCUCR = (_BV(SE)|_BV(SM1));// (power-down mode)
588
        */
589
        
590
        OCR1B=0;
591
        
592
        sei();
593
  
594
  //test delay_ms
595
  PORTB|=_BV(LED2);
596
  PORTB|=_BV(LED1);
597
  delay_ms(1000);
598
  PORTB&=~_BV(LED2);
599
  PORTB&=~_BV(LED1);
600
        
601
        //*******************************
602
        while(1)
603
                trickle_charge();
604
        
605
        /*GIMSK = (_BV(PCIE0)); //enable PCINT interrupts
606
        sleep_cpu();*/
607
        
608
        PORTB=0;//clear outputs
609
        
610
        GIMSK = 0;
611
        
612
        error=0;
613
                
614
        i2c_init();
615
        int volt=0, last_volt=0, same_volt=0;
616
        int temp=0, dt;
617
        int curr=0;
618
        int meas_count;
619
        int mod=0;
620
        
621
        status=FAST_CHARGE;
622
        
623
        while(1)
624
        {
625
                mod=abs_time%4;
626
                while(abs_time%4==mod);
627
                
628
                /*if((abs_time>>3)%3==0)
629
                        OCR1B=21;
630
                else if((abs_time>>3)%3==1)
631
                        OCR1B=57;
632
                else
633
                        OCR1B=85;*/
634
                
635
                tempData[0] = 'C';
636
                tempData[1] = abs_time>>8;
637
                tempData[2] = abs_time&0xFF;
638
                i2c_putpacket(0x01, tempData, 3);
639
                
640
                mod=abs_time%4;
641
                while(abs_time%4==mod)
642
                {
643
      /* CONTACT */
644
                        if(supply_voltage())
645
                        {
646
                                //curr = regulate_current(500);
647
                                curr = get_avg_current();
648
                                
649
                                if(status==FAST_CHARGE)
650
                                        OCR1B=50;
651
                        }
652
      /* NO CONTACT */
653
                        else
654
                        {
655
                                curr = 0;
656
                                OCR1B = 0;
657
                        }
658
                }
659
                
660

    
661
                tempData[0] = 'P';
662
                tempData[1] = 0;
663
                tempData[2] = OCR1B;
664
                i2c_putpacket(0x01, tempData, 3);
665
                tempData[0] = 'I';
666
                tempData[1] = curr>>8;
667
                tempData[2] = curr&0xFF;
668
                i2c_putpacket(0x01, tempData, 3);
669
                curr=6666;
670
                
671
                mod=abs_time%4;
672
                while(abs_time%4==mod)
673
                {
674
                        volt = get_avg_voltage();
675
                }
676
                
677
    //Same volt - Last volt upkeep
678
                if(volt==last_volt && supply_voltage())
679
                                same_volt++;
680
    else
681
    {
682
      last_volt = volt;
683
      same_volt=0;
684
    }
685

    
686
                        
687
                tempData[0] = 'v';
688
                tempData[1] = same_volt>>8;
689
                tempData[2] = same_volt&0xFF;
690
                i2c_putpacket(0x01, tempData, 3);
691
                
692
    /* Voltage Dip Termination */
693
                if(volt<last_volt && same_volt>=VOLT_PLATEAU)
694
                {
695
                        OCR1B=0;
696
                        status=0;
697
                }
698

    
699
                tempData[0] = 'V';
700
                tempData[1] = volt>>8;
701
                tempData[2] = volt&0xFF;
702
                i2c_putpacket(0x01, tempData, 3);
703

    
704
                volt=6666;
705
                
706
    //Temp ring buffer upkeep
707
                mod=abs_time%4;
708
                while(abs_time%4==mod)
709
                {
710
                        temp = get_avg_temperature();                        
711
                }
712
                
713
                dt=ring_buffer_d10(temp);
714
                
715
                tempData[0] = 't';
716
                tempData[1] = dt>>8;
717
                tempData[2] = dt&0xFF;
718
                i2c_putpacket(0x01, tempData, 3);
719
                
720
    /* Temperature Rise Termination */
721
                if(dt < MAX_DT && temp < MAX_DT_ABS)
722
                {
723
                        status=0;
724
                        OCR1B=0;
725
                }
726
                
727
                tempData[0] = 'T';
728
                tempData[1] = temp>>8;
729
                tempData[2] = temp&0xFF;
730
                i2c_putpacket(0x01, tempData, 3);
731

    
732
                temp=6666;
733
        }
734

    
735
        
736
        return 1;
737
}
738

    
739
ISR(TIMER0_OVF_vect)
740
{
741
        if(error)
742
                PORTB ^= (_BV(LED1)|_BV(LED2));
743

    
744
        interrupt_count--;
745
        if(interrupt_count==0)
746
        {
747
                abs_time++;
748
                new_second=1;
749
                        
750
                interrupt_count=INT_COUNT;
751
        }
752
}
753

    
754
ISR(TIMER1_OVF_vect)
755
{
756
        wait(2); //wait a bit so we know the ouput gets set (which happens at timer = 0)
757
        
758
        TCNT1 = 0;//156; // start out at 156. Now OCR1B - 156 = duty cycle
759
}
760

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