Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (13.6 KB)

1 80 bneuman
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <avr/sleep.h>
4 355 bneuman
#include "ring_buffer.h"
5 80 bneuman
#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 547 bneuman
#define DEBUG 1 //enable I2C outputs of form time, OCR, current, voltage, temp
26 955 nhergert
#define USE_I2C 1
27 80 bneuman
28 355 bneuman
29 80 bneuman
#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 355 bneuman
250 403 bneuman
#if USE_I2C
251 80 bneuman
        char tempData;
252
        //Finished, leave
253
        tempData = 'F';
254
        i2c_putpacket(0x01, &tempData, 1);
255 355 bneuman
#endif
256 80 bneuman
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 355 bneuman
#if DEBUG
265 80 bneuman
        //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 403 bneuman
        PORTB &= ~(_BV(LED1) | _BV(LED2)); //clear LEDs without messing everything else up!
270 80 bneuman
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 266 bneuman
        TCCR1B |= _BV(CS10); //leave timer on and set compare to 0 to make output off
279 264 bneuman
280
        //hack stuff so it will run in continuous mode
281 610 bneuman
        //TIMSK |= _BV(TOIE1); //enable overflow interrupt for timer 1
282 264 bneuman
283 80 bneuman
        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 403 bneuman
uint8_t read_homing(void)
349 80 bneuman
{
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 266 bneuman
        PORTB &= ~(_BV(LED1)|_BV(LED2));
406
407
408 80 bneuman
        while(status!=2)
409
        {
410
                mod=abs_time%4;
411
412 266 bneuman
                PORTB ^= _BV(LED2);
413
414 80 bneuman
                if(supply_voltage())
415
                  while(abs_time%4==mod);
416
417
    /* TIME TERMINATION */
418 266 bneuman
                if(abs_time>12000) //12000=25 minutes
419 80 bneuman
                {
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 410 bneuman
        delay_ms(50);
430 80 bneuman
                i2c_putpacket(0x01, tempData, 3);
431 410 bneuman
        delay_ms(50);
432 80 bneuman
#endif
433
434
                mod=abs_time%4;
435
                while(abs_time%4==mod)
436
                {
437
      /* CONTACT */
438
                        if(supply_voltage())
439
                        {
440 266 bneuman
                                PORTB |= _BV(LED1);
441 80 bneuman
                                //curr = regulate_current(500);
442 355 bneuman
                                curr = get_avg_current();
443 80 bneuman
444
                                if(status==0)
445
                                {
446
                                        status=1;
447 403 bneuman
#if USE_I2C
448 80 bneuman
                                        data[1]='a';
449
                                        i2c_putpacket(0x01, data, 2);
450
                                        data[1]=I2C_MSG_BATTERY_CHARGING;
451
                                        i2c_putpacket(0x01, data, 2);
452 355 bneuman
#endif
453 80 bneuman
                                }
454
455
        /* Trickle Charge */
456
                                if(status==1)
457 610 bneuman
                                        OCR1B = 100;
458 80 bneuman
                        }
459
      /* NO CONTACT */
460
                        else
461
                        {
462 266 bneuman
                                PORTB &= ~_BV(LED1);
463 80 bneuman
                                if(status==1)
464
                                {
465
                                        status=0;
466 403 bneuman
#if USE_I2C
467 80 bneuman
                                        data[1]=I2C_MSG_CONTACT_ERROR;
468
                                        i2c_putpacket(0x01, data, 2);
469 355 bneuman
#endif
470 80 bneuman
                                }
471
                                else
472
                                {
473 266 bneuman
          /*get_delay(); //reject the first reading //homing import stuff, uncomment this!!!!!!
474 80 bneuman
                                        data[0]=I2C_MSG_HOMING;
475
                                        data[1]=get_delay();
476 266 bneuman
          i2c_putpacket(0x01, data, 2);*/
477 80 bneuman
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 410 bneuman
        delay_ms(50);
490 80 bneuman
                i2c_putpacket(0x01, tempData, 3);
491 410 bneuman
        delay_ms(50);
492 80 bneuman
                tempData[0] = 'I';
493
                tempData[1] = curr>>8;
494
                tempData[2] = curr&0xFF;
495 410 bneuman
        delay_ms(50);
496 80 bneuman
                i2c_putpacket(0x01, tempData, 3);
497 410 bneuman
        delay_ms(50);
498 80 bneuman
#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 410 bneuman
        delay_ms(50);
519 80 bneuman
                i2c_putpacket(0x01, tempData, 3);
520 410 bneuman
        delay_ms(50);
521 80 bneuman
#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 410 bneuman
        delay_ms(50);
542 80 bneuman
                i2c_putpacket(0x01, tempData, 3);
543 410 bneuman
        delay_ms(50);
544 80 bneuman
#endif
545
546
                temp=6666;
547
        }
548 403 bneuman
#if USE_I2C
549 80 bneuman
        data[1]=I2C_MSG_BATTERY_FULL;
550
        i2c_putpacket(0x01, data, 2);
551 355 bneuman
#endif
552 80 bneuman
}
553
554
int main(void)
555
{
556
        new_second=0;
557
        char tempData[5];        //For i2c communication
558
559
        setup();
560 355 bneuman
561 955 nhergert
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 403 bneuman
#if USE_I2C
574
        delay_ms(500);
575 80 bneuman
        i2c_init();
576 355 bneuman
        i2c_putpacket(0x01,"I2C init'd on ARCHS\r\n", 21);
577 403 bneuman
        delay_ms(500);
578 547 bneuman
#else
579
    #if DEBUG
580
        i2c_init();
581
    #endif
582 355 bneuman
#endif
583 80 bneuman
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 264 bneuman
ISR(TIMER1_OVF_vect)
755
{
756 355 bneuman
        wait(2); //wait a bit so we know the ouput gets set (which happens at timer = 0)
757 264 bneuman
758 592 bneuman
        TCNT1 = 0;//156; // start out at 156. Now OCR1B - 156 = duty cycle
759 264 bneuman
}
760
761 80 bneuman
ISR(PCINT_vect){;} //so the interrupt doesnt go to the reset vector