Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (13.2 KB)

1 80 bneuman
#include <avr/io.h>
2 355 bneuman
#include <avr/io.h>
3 80 bneuman
#include <avr/interrupt.h>
4
#include <avr/sleep.h>
5 355 bneuman
#include "ring_buffer.h"
6 80 bneuman
#include "i2c.h"
7
8
9
// for i2c_byte coming from charge board
10
//I2C Message Codes
11
#define I2C_MSG_ACKNOWLEDGE       'A'
12
#define I2C_MSG_BATTERY_CHARGING  'C'
13
#define I2C_MSG_DATA              'D'
14
#define I2C_MSG_CONTACT_ERROR     'E'
15
#define I2C_MSG_BATTERY_FULL      'F'
16
#define I2C_MSG_NO_CONTACT        'N'
17
#define I2C_MSG_REQUEST_DATA      'R'
18
#define I2C_MSG_GO_TO_SLEEP       'Y'
19
#define I2C_MSG_ENTERING_SLEEP    'Z'
20
#define I2C_MSG_HOMING            'H'
21
22
23
#define SW0 PA6
24
#define HOMING_PIN PA7
25
26 403 bneuman
#define DEBUG 1
27 355 bneuman
#define USE_I2C 1
28 80 bneuman
29 355 bneuman
30 80 bneuman
#define MAX_T 300
31
#define MIN_T 730
32
//range is 0 to 45 C
33
//cal tests:
34
//room temp - 25
35
//value ~500, varies from battery to battery, but is consistent on one battery
36
//freezer 737
37
//heat gun at a distance 461
38
39
#define MAX_DT -4 //this is the LOWEST ACCEPTABLE ADC value
40
#define MAX_DT_ABS 400
41
#define VOLT_PLATEAU 50
42
43
44
//The following times are in seconds
45
#define MAX_FAST_TIME 5400
46
#define MAX_TRICKLE_TIME 600
47
48
//debug pins
49
#define debug_time PA3
50
#define debug_curr PA4
51
#define debug_volt PA5
52
#define debug_temp PA6
53
#define debug_12in PA7
54
55
//be sure admux also sets the MUX5 bit which is in ADCSRB
56
#define ADMUX_I
57
#define ADMUX_V
58
#define ADMUX_T
59
60
#define ROBOT_TX PB1
61
#define ROBOT_RX PB2
62
#define PWM PB3
63
#define DETECT_12V PB6
64
65
#define LED1 PB4 //Green
66
#define LED2 PB5 //Red
67
68
69
//LED States:
70
//Red - Fast Charging
71
//Green - Trickle Charging
72
//Both steady - done charging
73
//Both Blinking - Error
74
75
#define INT_COUNT 2 //interrupts per second
76
#define AVG_COUNT 64 //number of times to count current
77
78
//To enable the PWM write :         TCCR1B = (_Bv(CS10));//enable PWM
79
80
uint8_t interrupt_count = INT_COUNT;
81
82
volatile uint32_t abs_time=1; // start at one second so it doesnt do the minute checks right away
83
volatile uint8_t new_second=0; //only used as a boolean
84
85
volatile uint8_t error=0;
86
volatile uint8_t status;
87
88
volatile uint8_t steady_current = 0;
89
90
//DT must be triggered twice in a row
91
volatile uint8_t last_DT = 0;
92
//same for DV
93
volatile uint8_t last_DV = 0;
94
95
#define FAST_CHARGE 1
96
#define TRICKLE_CHARGE 2
97
98
RING_BUFFER_NEW(ring_buffer, 12, int, buffer);
99
100
void wait(int ops)
101
{
102
        int i = 0;
103
        while(i<ops)
104
                i++;
105
}
106
107
108
109
int avg_ADC(void)
110
{
111
        int av;
112
        char i;
113
114
        //Calculate a average out of the next 8 A/D conversions
115
    for(av=0,i=8;i;--i)
116
    {
117
        ADCSRA |= _BV(ADSC);                      // start new A/D conversion
118
        while (!(ADCSRA & (_BV(ADIF))))        // wait until ADC is ready
119
            ;
120
        av = av+ADC;
121
    }
122
    av = av/8;
123
124
        //ADCSRA &= ~_BV(ADEN);
125
126
        return av;
127
128
}
129
130
int get_voltage(void)
131
{
132
        ADMUX = _BV(MUX0);
133
134
        ADCSRB &= ~_BV(MUX5);
135
136
        return avg_ADC();
137
}
138
139
int get_current(void)
140
{
141
        ADMUX = _BV(MUX1);
142
143
        ADCSRB |= _BV(MUX5);
144
145
        return avg_ADC();
146
}
147
148
int get_temperature(void)
149
{
150
        ADMUX = _BV(MUX1);
151
152
        ADCSRB &= ~_BV(MUX5);
153
154
        return avg_ADC();
155
}
156
157
int get_avg_voltage(void)
158
{
159
        int count=0;
160
        uint32_t sum=0;
161
162
                //OCR1B =120;
163
        while(count < AVG_COUNT)
164
        {
165
                sum += get_voltage();
166
                count++;
167
        }
168
169
        return sum/AVG_COUNT;
170
}
171
172
int get_avg_current(void)
173
{
174
        int count=0;
175
        uint32_t sum=0;
176
177
                //OCR1B =120;
178
        while(count < AVG_COUNT)
179
        {
180
                sum += get_current();
181
                count++;
182
        }
183
184
        return sum/AVG_COUNT;
185
}
186
187
int get_avg_temperature(void)
188
{
189
        int count=0;
190
        uint32_t sum=0;
191
192
                //OCR1B =120;
193
        while(count < AVG_COUNT)
194
        {
195
                sum += get_temperature();
196
                count++;
197
        }
198
199
        return sum/AVG_COUNT;
200
}
201
202
203
uint8_t supply_voltage(void)
204
{
205
        return PINB & _BV(DETECT_12V);
206
}
207
208
void clear_err(void)
209
{
210
        error=0;
211
        PORTB &= ~(_BV(LED1)|_BV(LED2));
212
213
        if(status==FAST_CHARGE)
214
                PORTB |= _BV(LED2);
215
216
        if(status==TRICKLE_CHARGE)
217
                PORTB |= _BV(LED1);
218
}
219
220
void wait_8th(void)
221
{
222
        uint8_t start = abs_time % 8;
223
224
        while(abs_time % 8 == start)
225
        {
226
                /*if(supply_voltage())
227
                        PORTB |= _BV(LED1);
228
                else
229
                        PORTB &= ~_BV(LED1);
230
                if(get_voltage()>100)
231
                        PORTB |= _BV(LED2);
232
                else
233
                        PORTB &= ~_BV(LED2);*/
234
        }
235
}
236
237
void send_err(void)
238
{
239
        OCR1B=0;//turn off the PWM to be safe
240
241
        PORTB &= ~(_BV(LED1)|_BV(LED2));
242
        if(status!=0)//leave last error if there was one
243
                PORTA &= ~(_BV(debug_time)|_BV(debug_curr)|_BV(debug_volt)|_BV(debug_temp)|_BV(debug_12in));
244
        error=1;
245
        status=0;
246
}
247
248
void send_done(void)
249
{
250 355 bneuman
251 403 bneuman
#if USE_I2C
252 80 bneuman
        char tempData;
253
        //Finished, leave
254
        tempData = 'F';
255
        i2c_putpacket(0x01, &tempData, 1);
256 355 bneuman
#endif
257 80 bneuman
258
        PORTA &= ~(_BV(debug_time)|_BV(debug_curr)|_BV(debug_volt)|_BV(debug_temp)|_BV(debug_12in));
259
260
}
261
262
void setup(void)
263
{
264
      DDRA = _BV(PA3);
265 355 bneuman
#if DEBUG
266 80 bneuman
        //DDRA = (_BV(debug_time)|_BV(debug_curr)|_BV(debug_volt)|_BV(debug_temp)|_BV(debug_12in));
267
#endif
268
        PORTA = 0x00;
269
        DDRB = (_BV(ROBOT_TX)|_BV(PWM)|_BV(LED1)|_BV(LED2)); //confiure output pins
270 403 bneuman
        PORTB &= ~(_BV(LED1) | _BV(LED2)); //clear LEDs without messing everything else up!
271 80 bneuman
272
        ADCSRA = (_BV(ADEN)|_BV(ADPS2)|_BV(ADPS1)); //start ADC with a division factor of 64
273
274
        TCCR0B = (_BV(CS01)); //set timer 0 for realtime mode
275
        TCCR0A = (_BV(TCW0));
276
        TIMSK = (_BV(TOIE0)); //enable overflow interrupts
277
278
        TCCR1A = (_BV(COM1B1)|_BV(PWM1B)|_BV(COM1A1)|_BV(PWM1A)); //clear timer 1 on compare, set at 0x00. Fast PWM mode
279 266 bneuman
        TCCR1B |= _BV(CS10); //leave timer on and set compare to 0 to make output off
280 264 bneuman
281
        //hack stuff so it will run in continuous mode
282
        TIMSK |= _BV(TOIE1); //enable overflow interrupt for timer 1
283
284 80 bneuman
        OCR1B = 0;
285
        OCR1A = 0;
286
287
288
        RING_BUFFER_CLEAR(buffer);
289
        RING_BUFFER_INIT(buffer, 12);
290
        for(int i=0;i<10;i++)
291
                RING_BUFFER_ADD(buffer, 0);
292
293
        sei();
294
}
295
296
297
298
299
//takes a 7-bit ionteger and displays it on the 7 LEDs with the Green being the MSB
300
void LED_out(int i)
301
{
302
        if(i & 64)
303
                PORTB |= _BV(LED1);
304
        else
305
                PORTB &= ~_BV(LED1);
306
307
        if(i & 32)
308
                PORTB |= _BV(LED2);
309
        else
310
                PORTB &= ~_BV(LED2);
311
312
        if(i & 16)
313
                PORTA |= _BV(PA3);
314
        else
315
                PORTA &= ~_BV(PA3);
316
317
        if(i & 8)
318
                PORTA |= _BV(PA4);
319
        else
320
                PORTA &= ~_BV(PA4);
321
322
        if(i & 4)
323
                PORTA |= _BV(PA5);
324
        else
325
                PORTA &= ~_BV(PA5);
326
327
        if(i & 2)
328
                PORTA |= _BV(PA6);
329
        else
330
                PORTA &= ~_BV(PA6);
331
332
        if(i & 1)
333
                PORTA |= _BV(PA7);
334
        else
335
                PORTA &= ~_BV(debug_12in);
336
}
337
338
//get the difference of the current value minues the value 10 entires ago
339
int ring_buffer_d10(int y)
340
{
341
        int x;
342
        RING_BUFFER_REMOVE(buffer, x);
343
344
        RING_BUFFER_ADD(buffer, y);
345
        return y-x;
346
}
347
348
349 403 bneuman
uint8_t read_homing(void)
350 80 bneuman
{
351
    uint8_t ret = PINA & _BV(HOMING_PIN);
352
    if(ret)
353
        PORTA |= _BV(PA3);
354
    else
355
        PORTA &= ~_BV(PA3);
356
    return ret;
357
}
358
359
//copied from scheduler/seeking.c
360
uint8_t get_delay(void)
361
{
362
    uint8_t count = 0;
363
364
        PORTB|=_BV(LED2);
365
    while(read_homing())
366
    {
367
        delay_ms(1);
368
        count++;
369
        if (count >= 100)
370
            return 1;
371
    } //wait a beacon cycle to make sure we aren't starting the count in the middle of one
372
        PORTB&=~_BV(LED2);
373
    count = 0;
374
    PORTB|=_BV(LED1);
375
    while(!read_homing())
376
    {
377
        delay_ms(1);
378
        count++;
379
        if(count==255)
380
          return 2;
381
    }
382
    PORTB&=~_BV(LED1);
383
384
  /*RECH_PUTS("\n\rCount: ");
385
        RECH_PUTI(count);
386
        RECH_PUTC('.');*/
387
388
    return count;
389
}
390
391
void trickle_charge(void)
392
{
393
394
        abs_time = 0;
395
        status = 0;
396
        char tempData[5];
397
        char data[2];
398
        data[0]='D';
399
        int volt = 0;
400
        int temp = 0;
401
        int curr = 0;
402
        int meas_count = 0;
403
        int mod=0;
404
        OCR1B = 0;
405
406 266 bneuman
        PORTB &= ~(_BV(LED1)|_BV(LED2));
407
408
409 80 bneuman
        while(status!=2)
410
        {
411
                mod=abs_time%4;
412
413 266 bneuman
                PORTB ^= _BV(LED2);
414
415 80 bneuman
                if(supply_voltage())
416
                  while(abs_time%4==mod);
417
418
    /* TIME TERMINATION */
419 266 bneuman
                if(abs_time>12000) //12000=25 minutes
420 80 bneuman
                {
421
                        //SEND_DONE
422
                        OCR1B=0;
423
                        break;
424
                }
425
426
#if DEBUG
427
                tempData[0] = 'C';
428
                tempData[1] = abs_time>>8;
429
                tempData[2] = abs_time&0xFF;
430
                i2c_putpacket(0x01, tempData, 3);
431
#endif
432
433
                mod=abs_time%4;
434
                while(abs_time%4==mod)
435
                {
436
      /* CONTACT */
437
                        if(supply_voltage())
438
                        {
439 266 bneuman
                                PORTB |= _BV(LED1);
440 80 bneuman
                                //curr = regulate_current(500);
441 355 bneuman
                                curr = get_avg_current();
442 80 bneuman
443
                                if(status==0)
444
                                {
445
                                        status=1;
446 403 bneuman
#if USE_I2C
447 80 bneuman
                                        data[1]='a';
448
                                        i2c_putpacket(0x01, data, 2);
449
                                        data[1]=I2C_MSG_BATTERY_CHARGING;
450
                                        i2c_putpacket(0x01, data, 2);
451 355 bneuman
#endif
452 80 bneuman
                                }
453
454
        /* Trickle Charge */
455
                                if(status==1)
456 355 bneuman
                                        OCR1B = 128;
457 80 bneuman
                        }
458
      /* NO CONTACT */
459
                        else
460
                        {
461 266 bneuman
                                PORTB &= ~_BV(LED1);
462 80 bneuman
                                if(status==1)
463
                                {
464
                                        status=0;
465 403 bneuman
#if USE_I2C
466 80 bneuman
                                        data[1]=I2C_MSG_CONTACT_ERROR;
467
                                        i2c_putpacket(0x01, data, 2);
468 355 bneuman
#endif
469 80 bneuman
                                }
470
                                else
471
                                {
472 266 bneuman
          /*get_delay(); //reject the first reading //homing import stuff, uncomment this!!!!!!
473 80 bneuman
                                        data[0]=I2C_MSG_HOMING;
474
                                        data[1]=get_delay();
475 266 bneuman
          i2c_putpacket(0x01, data, 2);*/
476 80 bneuman
477
          data[0]='D';
478
                                }
479
                                curr = 0;
480
                                OCR1B = 0;
481
                        }
482
                }
483
484
#if DEBUG
485
                tempData[0] = 'P';
486
                tempData[1] = 0;
487
                tempData[2] = OCR1B;
488
                i2c_putpacket(0x01, tempData, 3);
489
                tempData[0] = 'I';
490
                tempData[1] = curr>>8;
491
                tempData[2] = curr&0xFF;
492
                i2c_putpacket(0x01, tempData, 3);
493
#endif
494
                curr=6666;
495
496
    /* Absolute Voltage Termination */
497
                if(supply_voltage())
498
                  {
499
                mod=abs_time%4;
500
                while(abs_time%4==mod)
501
                {
502
                        volt = get_avg_voltage();
503
                }
504
505
                if(volt>1010)
506
                {
507
                        //SEND ERROR
508
                        status=0;
509
                }
510
511
#if DEBUG
512
                tempData[0] = 'V';
513
                tempData[1] = volt>>8;
514
                tempData[2] = volt&0xFF;
515
                i2c_putpacket(0x01, tempData, 3);
516
#endif
517
                volt=6666;
518
519
    /* Absolute Temperature Termination */
520
                mod=abs_time%4;
521
                while(abs_time%4==mod)
522
                {
523
                        temp = get_avg_temperature();
524
                }
525
526
                if(temp<250)
527
                {
528
                        //SEND ERROR
529
                        status=0;
530
                }
531
532
#if DEBUG
533
                tempData[0] = 'T';
534
                tempData[1] = temp>>8;
535
                tempData[2] = temp&0xFF;
536
                i2c_putpacket(0x01, tempData, 3);
537
#endif
538
                  }
539
540
                temp=6666;
541
        }
542 403 bneuman
#if USE_I2C
543 80 bneuman
        data[1]=I2C_MSG_BATTERY_FULL;
544
        i2c_putpacket(0x01, data, 2);
545 355 bneuman
#endif
546 80 bneuman
}
547
548
int main(void)
549
{
550
        new_second=0;
551
        char tempData[5];        //For i2c communication
552
553
        setup();
554 355 bneuman
555 403 bneuman
#if USE_I2C
556
        delay_ms(500);
557 80 bneuman
        i2c_init();
558 355 bneuman
        i2c_putpacket(0x01,"I2C init'd on ARCHS\r\n", 21);
559 403 bneuman
        delay_ms(500);
560 355 bneuman
#endif
561 80 bneuman
562
563
        /*GIMSK = (_BV(PCIE0)); //enable PCINT interrupts
564
        PCMSK1 = (_BV(PCINT10)); //enable pin change interrupt on ROBOT_RX
565
        MCUCR = (_BV(SE)|_BV(SM1));// (power-down mode)
566
        */
567
568
        OCR1B=0;
569
570
        sei();
571
572
  //test delay_ms
573
  PORTB|=_BV(LED2);
574
  PORTB|=_BV(LED1);
575
  delay_ms(1000);
576
  PORTB&=~_BV(LED2);
577
  PORTB&=~_BV(LED1);
578
579
        //*******************************
580
        while(1)
581
                trickle_charge();
582
583
        /*GIMSK = (_BV(PCIE0)); //enable PCINT interrupts
584
        sleep_cpu();*/
585
586
        PORTB=0;//clear outputs
587
588
        GIMSK = 0;
589
590
        error=0;
591
592
        i2c_init();
593
        int volt=0, last_volt=0, same_volt=0;
594
        int temp=0, dt;
595
        int curr=0;
596
        int meas_count;
597
        int mod=0;
598
599
        status=FAST_CHARGE;
600
601
        while(1)
602
        {
603
                mod=abs_time%4;
604
                while(abs_time%4==mod);
605
606
                /*if((abs_time>>3)%3==0)
607
                        OCR1B=21;
608
                else if((abs_time>>3)%3==1)
609
                        OCR1B=57;
610
                else
611
                        OCR1B=85;*/
612
613
                tempData[0] = 'C';
614
                tempData[1] = abs_time>>8;
615
                tempData[2] = abs_time&0xFF;
616
                i2c_putpacket(0x01, tempData, 3);
617
618
                mod=abs_time%4;
619
                while(abs_time%4==mod)
620
                {
621
      /* CONTACT */
622
                        if(supply_voltage())
623
                        {
624
                                //curr = regulate_current(500);
625
                                curr = get_avg_current();
626
627
                                if(status==FAST_CHARGE)
628
                                        OCR1B=50;
629
                        }
630
      /* NO CONTACT */
631
                        else
632
                        {
633
                                curr = 0;
634
                                OCR1B = 0;
635
                        }
636
                }
637
638
639
                tempData[0] = 'P';
640
                tempData[1] = 0;
641
                tempData[2] = OCR1B;
642
                i2c_putpacket(0x01, tempData, 3);
643
                tempData[0] = 'I';
644
                tempData[1] = curr>>8;
645
                tempData[2] = curr&0xFF;
646
                i2c_putpacket(0x01, tempData, 3);
647
                curr=6666;
648
649
                mod=abs_time%4;
650
                while(abs_time%4==mod)
651
                {
652
                        volt = get_avg_voltage();
653
                }
654
655
    //Same volt - Last volt upkeep
656
                if(volt==last_volt && supply_voltage())
657
                                same_volt++;
658
    else
659
    {
660
      last_volt = volt;
661
      same_volt=0;
662
    }
663
664
665
                tempData[0] = 'v';
666
                tempData[1] = same_volt>>8;
667
                tempData[2] = same_volt&0xFF;
668
                i2c_putpacket(0x01, tempData, 3);
669
670
    /* Voltage Dip Termination */
671
                if(volt<last_volt && same_volt>=VOLT_PLATEAU)
672
                {
673
                        OCR1B=0;
674
                        status=0;
675
                }
676
677
                tempData[0] = 'V';
678
                tempData[1] = volt>>8;
679
                tempData[2] = volt&0xFF;
680
                i2c_putpacket(0x01, tempData, 3);
681
682
                volt=6666;
683
684
    //Temp ring buffer upkeep
685
                mod=abs_time%4;
686
                while(abs_time%4==mod)
687
                {
688
                        temp = get_avg_temperature();
689
                }
690
691
                dt=ring_buffer_d10(temp);
692
693
                tempData[0] = 't';
694
                tempData[1] = dt>>8;
695
                tempData[2] = dt&0xFF;
696
                i2c_putpacket(0x01, tempData, 3);
697
698
    /* Temperature Rise Termination */
699
                if(dt < MAX_DT && temp < MAX_DT_ABS)
700
                {
701
                        status=0;
702
                        OCR1B=0;
703
                }
704
705
                tempData[0] = 'T';
706
                tempData[1] = temp>>8;
707
                tempData[2] = temp&0xFF;
708
                i2c_putpacket(0x01, tempData, 3);
709
710
                temp=6666;
711
        }
712
713
714
        return 1;
715
}
716
717
ISR(TIMER0_OVF_vect)
718
{
719
        if(error)
720
                PORTB ^= (_BV(LED1)|_BV(LED2));
721
722
        interrupt_count--;
723
        if(interrupt_count==0)
724
        {
725
                abs_time++;
726
                new_second=1;
727
728
                interrupt_count=INT_COUNT;
729
        }
730
}
731
732 264 bneuman
ISR(TIMER1_OVF_vect)
733
{
734 355 bneuman
        wait(2); //wait a bit so we know the ouput gets set (which happens at timer = 0)
735 264 bneuman
736 355 bneuman
        TCNT1 = 0;//156; // start out at 156. Now OCR1B - 156 = duty cycle
737 264 bneuman
}
738
739 80 bneuman
ISR(PCINT_vect){;} //so the interrupt doesnt go to the reset vector