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
#include <avr/io.h>
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
#include <avr/sleep.h>
5
#include "ring_buffer.h"
6
#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
#define DEBUG 1
27
#define USE_I2C 1
28

    
29

    
30
#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

    
251
#if USE_I2C
252
        char tempData;
253
        //Finished, leave
254
        tempData = 'F';
255
        i2c_putpacket(0x01, &tempData, 1);
256
#endif
257
        
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
#if DEBUG
266
        //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
        PORTB &= ~(_BV(LED1) | _BV(LED2)); //clear LEDs without messing everything else up!
271
        
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
        TCCR1B |= _BV(CS10); //leave timer on and set compare to 0 to make output off        
280
        
281
        //hack stuff so it will run in continuous mode
282
        TIMSK |= _BV(TOIE1); //enable overflow interrupt for timer 1
283
        
284
        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
uint8_t read_homing(void)
350
{
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
        PORTB &= ~(_BV(LED1)|_BV(LED2));
407

    
408
        
409
        while(status!=2)
410
        {
411
                mod=abs_time%4;
412
                
413
                PORTB ^= _BV(LED2);
414
                
415
                if(supply_voltage())
416
                  while(abs_time%4==mod);
417
                
418
    /* TIME TERMINATION */
419
                if(abs_time>12000) //12000=25 minutes
420
                {
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
                                PORTB |= _BV(LED1);
440
                                //curr = regulate_current(500);
441
                                curr = get_avg_current();
442
                                
443
                                if(status==0)
444
                                {
445
                                        status=1;
446
#if USE_I2C
447
                                        data[1]='a';
448
                                        i2c_putpacket(0x01, data, 2);
449
                                        data[1]=I2C_MSG_BATTERY_CHARGING;
450
                                        i2c_putpacket(0x01, data, 2);
451
#endif
452
                                }
453
                                
454
        /* Trickle Charge */
455
                                if(status==1)
456
                                        OCR1B = 128;
457
                        }
458
      /* NO CONTACT */
459
                        else
460
                        {
461
                                PORTB &= ~_BV(LED1);
462
                                if(status==1)
463
                                {
464
                                        status=0;
465
#if USE_I2C
466
                                        data[1]=I2C_MSG_CONTACT_ERROR;
467
                                        i2c_putpacket(0x01, data, 2);
468
#endif
469
                                }
470
                                else
471
                                {
472
          /*get_delay(); //reject the first reading //homing import stuff, uncomment this!!!!!!
473
                                        data[0]=I2C_MSG_HOMING;
474
                                        data[1]=get_delay();
475
          i2c_putpacket(0x01, data, 2);*/
476
          
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
#if USE_I2C
543
        data[1]=I2C_MSG_BATTERY_FULL;
544
        i2c_putpacket(0x01, data, 2);
545
#endif
546
}
547

    
548
int main(void)
549
{
550
        new_second=0;
551
        char tempData[5];        //For i2c communication
552
  
553
        setup();
554

    
555
#if USE_I2C
556
        delay_ms(500);
557
        i2c_init();
558
        i2c_putpacket(0x01,"I2C init'd on ARCHS\r\n", 21);
559
        delay_ms(500);
560
#endif
561
        
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
ISR(TIMER1_OVF_vect)
733
{
734
        wait(2); //wait a bit so we know the ouput gets set (which happens at timer = 0)
735
        
736
        TCNT1 = 0;//156; // start out at 156. Now OCR1B - 156 = duty cycle
737
}
738

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