Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (12.5 KB)

1 80 bneuman
#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