Project

General

Profile

Statistics
| Revision:

root / trunk / code / projects / autonomous_recharging / archs / ConstantCharging.c @ 80

History | View | Annotate | Download (12.5 KB)

1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <avr/sleep.h>
4
#include "i2c.h"
5
#include "ring_buffer.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 0
26

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

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

    
40

    
41
//The following times are in seconds
42
#define MAX_FAST_TIME 5400
43
#define MAX_TRICKLE_TIME 600
44

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

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

    
57
#define ROBOT_TX PB1
58
#define ROBOT_RX PB2
59
#define PWM PB3
60
#define DETECT_12V PB6
61

    
62
#define LED1 PB4 //Green
63
#define LED2 PB5 //Red
64

    
65

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

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

    
75
//To enable the PWM write :         TCCR1B = (_Bv(CS10));//enable PWM
76

    
77
uint8_t interrupt_count = INT_COUNT;
78

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

    
82
volatile uint8_t error=0;
83
volatile uint8_t status;
84

    
85
volatile uint8_t steady_current = 0;
86

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

    
92
#define FAST_CHARGE 1
93
#define TRICKLE_CHARGE 2
94

    
95
RING_BUFFER_NEW(ring_buffer, 12, int, buffer);
96

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

    
104

    
105

    
106
int avg_ADC(void)
107
{
108
        int av;
109
        char i;
110

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

    
123
        return av;
124
        
125
}
126

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

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

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

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

    
166
        return sum/AVG_COUNT;
167
}
168

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

    
181
        return sum/AVG_COUNT;
182
}
183

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

    
196
        return sum/AVG_COUNT;
197
}
198

    
199

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

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

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

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

    
245
void send_done(void)
246
{
247
        char tempData;
248
        //Finished, leave
249
        tempData = 'F';
250
        i2c_putpacket(0x01, &tempData, 1);
251
        
252
        PORTA &= ~(_BV(debug_time)|_BV(debug_curr)|_BV(debug_volt)|_BV(debug_temp)|_BV(debug_12in)); 
253
        
254
}
255

    
256
void setup(void)
257
{
258
      DDRA = _BV(PA3);
259
#ifdef debug
260
        //DDRA = (_BV(debug_time)|_BV(debug_curr)|_BV(debug_volt)|_BV(debug_temp)|_BV(debug_12in));
261
#endif
262
        PORTA = 0x00;
263
        DDRB = (_BV(ROBOT_TX)|_BV(PWM)|_BV(LED1)|_BV(LED2)); //confiure output pins
264
        PORTB = 0x00;
265
        
266
        ADCSRA = (_BV(ADEN)|_BV(ADPS2)|_BV(ADPS1)); //start ADC with a division factor of 64
267
        
268
        TCCR0B = (_BV(CS01)); //set timer 0 for realtime mode
269
        TCCR0A = (_BV(TCW0));
270
        TIMSK = (_BV(TOIE0)); //enable overflow interrupts
271
        
272
        TCCR1A = (_BV(COM1B1)|_BV(PWM1B)|_BV(COM1A1)|_BV(PWM1A)); //clear timer 1 on compare, set at 0x00. Fast PWM mode
273
        TCCR1B |= _BV(CS12)|_BV(CS10); //leave timer on and set compare to 0 to make output off        
274
        OCR1B = 0;
275
        OCR1A = 0;
276
        
277
        
278
        RING_BUFFER_CLEAR(buffer);
279
        RING_BUFFER_INIT(buffer, 12);
280
        for(int i=0;i<10;i++)
281
                RING_BUFFER_ADD(buffer, 0);
282
        
283
        sei();
284
}
285

    
286

    
287

    
288

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

    
328
//get the difference of the current value minues the value 10 entires ago
329
int ring_buffer_d10(int y)
330
{        
331
        int x;
332
        RING_BUFFER_REMOVE(buffer, x);
333
                
334
        RING_BUFFER_ADD(buffer, y);
335
        return y-x;
336
}
337

    
338

    
339
uint8_t read_homing()
340
{
341
    uint8_t ret = PINA & _BV(HOMING_PIN);
342
    if(ret)
343
        PORTA |= _BV(PA3);
344
    else
345
        PORTA &= ~_BV(PA3);
346
    return ret;
347
}
348

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

    
381
void trickle_charge(void)
382
{
383

    
384
        abs_time = 0;
385
        status = 0;
386
        char tempData[5];
387
        char data[2];
388
        data[0]='D';
389
        int volt = 0;
390
        int temp = 0;
391
        int curr = 0;
392
        int meas_count = 0;
393
        int mod=0;
394
        sei();
395
        OCR1B = 0;
396
        
397
        while(status!=2)
398
        {
399
                mod=abs_time%4;
400
                
401
                if(supply_voltage())
402
                  while(abs_time%4==mod);
403
                
404
    /* TIME TERMINATION */
405
                if(abs_time>500) //12000=25 minutes
406
                {
407
                        //SEND_DONE
408
                        OCR1B=0;
409
                        break;
410
                }
411
                
412
#if DEBUG                
413
                tempData[0] = 'C';
414
                tempData[1] = abs_time>>8;
415
                tempData[2] = abs_time&0xFF;
416
                i2c_putpacket(0x01, tempData, 3);
417
#endif
418
                
419
                mod=abs_time%4;
420
                while(abs_time%4==mod)
421
                {
422
      /* CONTACT */
423
                        if(supply_voltage())
424
                        {
425
                                //curr = regulate_current(500);
426
                                curr = get_avg_current();
427
                                
428
                                if(status==0)
429
                                {
430
                                        status=1;
431
                                        data[1]='a';
432
                                        i2c_putpacket(0x01, data, 2);
433
                                        data[1]=I2C_MSG_BATTERY_CHARGING;
434
                                        i2c_putpacket(0x01, data, 2);
435
                                }
436
                                
437
        /* Trickle Charge */
438
                                if(status==1)
439
                                        OCR1B = 50;
440
                        }
441
      /* NO CONTACT */
442
                        else
443
                        {
444
                                if(status==1)
445
                                {
446
                                        status=0;
447
                                        data[1]=I2C_MSG_CONTACT_ERROR;
448
                                        i2c_putpacket(0x01, data, 2);
449
                                }
450
                                else
451
                                {
452
          get_delay(); //reject the first reading
453
                                        data[0]=I2C_MSG_HOMING;
454
                                        data[1]=get_delay();
455
          i2c_putpacket(0x01, data, 2);
456
          
457
          data[0]='D';
458
                                }
459
                                curr = 0;
460
                                OCR1B = 0;
461
                        }
462
                }
463
                
464
#if DEBUG
465
                tempData[0] = 'P';
466
                tempData[1] = 0;
467
                tempData[2] = OCR1B;
468
                i2c_putpacket(0x01, tempData, 3);
469
                tempData[0] = 'I';
470
                tempData[1] = curr>>8;
471
                tempData[2] = curr&0xFF;
472
                i2c_putpacket(0x01, tempData, 3);
473
#endif
474
                curr=6666;
475
                
476
    /* Absolute Voltage Termination */
477
                if(supply_voltage())
478
                  {
479
                mod=abs_time%4;
480
                while(abs_time%4==mod)
481
                {
482
                        volt = get_avg_voltage();
483
                }
484
                
485
                if(volt>1010)
486
                {
487
                        //SEND ERROR
488
                        status=0;
489
                }
490
    
491
#if DEBUG
492
                tempData[0] = 'V';
493
                tempData[1] = volt>>8;
494
                tempData[2] = volt&0xFF;
495
                i2c_putpacket(0x01, tempData, 3);
496
#endif
497
                volt=6666;
498
                
499
    /* Absolute Temperature Termination */
500
                mod=abs_time%4;
501
                while(abs_time%4==mod)
502
                {
503
                        temp = get_avg_temperature();
504
                }
505
                
506
                if(temp<250)
507
                {
508
                        //SEND ERROR
509
                        status=0;
510
                }
511

    
512
#if DEBUG
513
                tempData[0] = 'T';
514
                tempData[1] = temp>>8;
515
                tempData[2] = temp&0xFF;
516
                i2c_putpacket(0x01, tempData, 3);
517
#endif
518
                  }
519

    
520
                temp=6666;
521
        }
522
        
523
        data[1]=I2C_MSG_BATTERY_FULL;
524
        i2c_putpacket(0x01, data, 2);
525

    
526
}
527

    
528
int main(void)
529
{
530
        new_second=0;
531
        char tempData[5];        //For i2c communication
532
        //test_board();
533
  
534
        setup();
535
        i2c_init();
536
        
537
        
538
        /*GIMSK = (_BV(PCIE0)); //enable PCINT interrupts
539
        PCMSK1 = (_BV(PCINT10)); //enable pin change interrupt on ROBOT_RX
540
        MCUCR = (_BV(SE)|_BV(SM1));// (power-down mode)
541
        */
542
        
543
        OCR1B=0;
544
        
545
        sei();
546
  
547
  //test delay_ms
548
  PORTB|=_BV(LED2);
549
  PORTB|=_BV(LED1);
550
  delay_ms(1000);
551
  PORTB&=~_BV(LED2);
552
  PORTB&=~_BV(LED1);
553
        
554
        //*******************************
555
        while(1)
556
                trickle_charge();
557
        
558
        /*GIMSK = (_BV(PCIE0)); //enable PCINT interrupts
559
        sleep_cpu();*/
560
        
561
        PORTB=0;//clear outputs
562
        
563
        GIMSK = 0;
564
        
565
        error=0;
566
                
567
        i2c_init();
568
        int volt=0, last_volt=0, same_volt=0;
569
        int temp=0, dt;
570
        int curr=0;
571
        int meas_count;
572
        int mod=0;
573
        
574
        status=FAST_CHARGE;
575
        
576
        while(1)
577
        {
578
                mod=abs_time%4;
579
                while(abs_time%4==mod);
580
                
581
                /*if((abs_time>>3)%3==0)
582
                        OCR1B=21;
583
                else if((abs_time>>3)%3==1)
584
                        OCR1B=57;
585
                else
586
                        OCR1B=85;*/
587
                
588
                tempData[0] = 'C';
589
                tempData[1] = abs_time>>8;
590
                tempData[2] = abs_time&0xFF;
591
                i2c_putpacket(0x01, tempData, 3);
592
                
593
                mod=abs_time%4;
594
                while(abs_time%4==mod)
595
                {
596
      /* CONTACT */
597
                        if(supply_voltage())
598
                        {
599
                                //curr = regulate_current(500);
600
                                curr = get_avg_current();
601
                                
602
                                if(status==FAST_CHARGE)
603
                                        OCR1B=50;
604
                        }
605
      /* NO CONTACT */
606
                        else
607
                        {
608
                                curr = 0;
609
                                OCR1B = 0;
610
                        }
611
                }
612
                
613

    
614
                tempData[0] = 'P';
615
                tempData[1] = 0;
616
                tempData[2] = OCR1B;
617
                i2c_putpacket(0x01, tempData, 3);
618
                tempData[0] = 'I';
619
                tempData[1] = curr>>8;
620
                tempData[2] = curr&0xFF;
621
                i2c_putpacket(0x01, tempData, 3);
622
                curr=6666;
623
                
624
                mod=abs_time%4;
625
                while(abs_time%4==mod)
626
                {
627
                        volt = get_avg_voltage();
628
                }
629
                
630
    //Same volt - Last volt upkeep
631
                if(volt==last_volt && supply_voltage())
632
                                same_volt++;
633
    else
634
    {
635
      last_volt = volt;
636
      same_volt=0;
637
    }
638

    
639
                        
640
                tempData[0] = 'v';
641
                tempData[1] = same_volt>>8;
642
                tempData[2] = same_volt&0xFF;
643
                i2c_putpacket(0x01, tempData, 3);
644
                
645
    /* Voltage Dip Termination */
646
                if(volt<last_volt && same_volt>=VOLT_PLATEAU)
647
                {
648
                        OCR1B=0;
649
                        status=0;
650
                }
651

    
652
                tempData[0] = 'V';
653
                tempData[1] = volt>>8;
654
                tempData[2] = volt&0xFF;
655
                i2c_putpacket(0x01, tempData, 3);
656

    
657
                volt=6666;
658
                
659
    //Temp ring buffer upkeep
660
                mod=abs_time%4;
661
                while(abs_time%4==mod)
662
                {
663
                        temp = get_avg_temperature();                        
664
                }
665
                
666
                dt=ring_buffer_d10(temp);
667
                
668
                tempData[0] = 't';
669
                tempData[1] = dt>>8;
670
                tempData[2] = dt&0xFF;
671
                i2c_putpacket(0x01, tempData, 3);
672
                
673
    /* Temperature Rise Termination */
674
                if(dt < MAX_DT && temp < MAX_DT_ABS)
675
                {
676
                        status=0;
677
                        OCR1B=0;
678
                }
679
                
680
                tempData[0] = 'T';
681
                tempData[1] = temp>>8;
682
                tempData[2] = temp&0xFF;
683
                i2c_putpacket(0x01, tempData, 3);
684

    
685
                temp=6666;
686
        }
687

    
688
        
689
        return 1;
690
}
691

    
692
ISR(TIMER0_OVF_vect)
693
{
694
        if(error)
695
                PORTB ^= (_BV(LED1)|_BV(LED2));
696

    
697
        interrupt_count--;
698
        if(interrupt_count==0)
699
        {
700
                abs_time++;
701
                new_second=1;
702
                        
703
                interrupt_count=INT_COUNT;
704
        }
705
}
706

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