Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (13.1 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 0
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 = 0x00;
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()
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
        i2c_init();
557
        i2c_putpacket(0x01,"I2C init'd on ARCHS\r\n", 21);
558
#endif
559
        
560
        
561
        /*GIMSK = (_BV(PCIE0)); //enable PCINT interrupts
562
        PCMSK1 = (_BV(PCINT10)); //enable pin change interrupt on ROBOT_RX
563
        MCUCR = (_BV(SE)|_BV(SM1));// (power-down mode)
564
        */
565
        
566
        OCR1B=0;
567
        
568
        sei();
569
  
570
  //test delay_ms
571
  PORTB|=_BV(LED2);
572
  PORTB|=_BV(LED1);
573
  delay_ms(1000);
574
  PORTB&=~_BV(LED2);
575
  PORTB&=~_BV(LED1);
576
        
577
        //*******************************
578
        while(1)
579
                trickle_charge();
580
        
581
        /*GIMSK = (_BV(PCIE0)); //enable PCINT interrupts
582
        sleep_cpu();*/
583
        
584
        PORTB=0;//clear outputs
585
        
586
        GIMSK = 0;
587
        
588
        error=0;
589
                
590
        i2c_init();
591
        int volt=0, last_volt=0, same_volt=0;
592
        int temp=0, dt;
593
        int curr=0;
594
        int meas_count;
595
        int mod=0;
596
        
597
        status=FAST_CHARGE;
598
        
599
        while(1)
600
        {
601
                mod=abs_time%4;
602
                while(abs_time%4==mod);
603
                
604
                /*if((abs_time>>3)%3==0)
605
                        OCR1B=21;
606
                else if((abs_time>>3)%3==1)
607
                        OCR1B=57;
608
                else
609
                        OCR1B=85;*/
610
                
611
                tempData[0] = 'C';
612
                tempData[1] = abs_time>>8;
613
                tempData[2] = abs_time&0xFF;
614
                i2c_putpacket(0x01, tempData, 3);
615
                
616
                mod=abs_time%4;
617
                while(abs_time%4==mod)
618
                {
619
      /* CONTACT */
620
                        if(supply_voltage())
621
                        {
622
                                //curr = regulate_current(500);
623
                                curr = get_avg_current();
624
                                
625
                                if(status==FAST_CHARGE)
626
                                        OCR1B=50;
627
                        }
628
      /* NO CONTACT */
629
                        else
630
                        {
631
                                curr = 0;
632
                                OCR1B = 0;
633
                        }
634
                }
635
                
636

    
637
                tempData[0] = 'P';
638
                tempData[1] = 0;
639
                tempData[2] = OCR1B;
640
                i2c_putpacket(0x01, tempData, 3);
641
                tempData[0] = 'I';
642
                tempData[1] = curr>>8;
643
                tempData[2] = curr&0xFF;
644
                i2c_putpacket(0x01, tempData, 3);
645
                curr=6666;
646
                
647
                mod=abs_time%4;
648
                while(abs_time%4==mod)
649
                {
650
                        volt = get_avg_voltage();
651
                }
652
                
653
    //Same volt - Last volt upkeep
654
                if(volt==last_volt && supply_voltage())
655
                                same_volt++;
656
    else
657
    {
658
      last_volt = volt;
659
      same_volt=0;
660
    }
661

    
662
                        
663
                tempData[0] = 'v';
664
                tempData[1] = same_volt>>8;
665
                tempData[2] = same_volt&0xFF;
666
                i2c_putpacket(0x01, tempData, 3);
667
                
668
    /* Voltage Dip Termination */
669
                if(volt<last_volt && same_volt>=VOLT_PLATEAU)
670
                {
671
                        OCR1B=0;
672
                        status=0;
673
                }
674

    
675
                tempData[0] = 'V';
676
                tempData[1] = volt>>8;
677
                tempData[2] = volt&0xFF;
678
                i2c_putpacket(0x01, tempData, 3);
679

    
680
                volt=6666;
681
                
682
    //Temp ring buffer upkeep
683
                mod=abs_time%4;
684
                while(abs_time%4==mod)
685
                {
686
                        temp = get_avg_temperature();                        
687
                }
688
                
689
                dt=ring_buffer_d10(temp);
690
                
691
                tempData[0] = 't';
692
                tempData[1] = dt>>8;
693
                tempData[2] = dt&0xFF;
694
                i2c_putpacket(0x01, tempData, 3);
695
                
696
    /* Temperature Rise Termination */
697
                if(dt < MAX_DT && temp < MAX_DT_ABS)
698
                {
699
                        status=0;
700
                        OCR1B=0;
701
                }
702
                
703
                tempData[0] = 'T';
704
                tempData[1] = temp>>8;
705
                tempData[2] = temp&0xFF;
706
                i2c_putpacket(0x01, tempData, 3);
707

    
708
                temp=6666;
709
        }
710

    
711
        
712
        return 1;
713
}
714

    
715
ISR(TIMER0_OVF_vect)
716
{
717
        if(error)
718
                PORTB ^= (_BV(LED1)|_BV(LED2));
719

    
720
        interrupt_count--;
721
        if(interrupt_count==0)
722
        {
723
                abs_time++;
724
                new_second=1;
725
                        
726
                interrupt_count=INT_COUNT;
727
        }
728
}
729

    
730
ISR(TIMER1_OVF_vect)
731
{
732
        wait(2); //wait a bit so we know the ouput gets set (which happens at timer = 0)
733
        
734
        TCNT1 = 0;//156; // start out at 156. Now OCR1B - 156 = duty cycle
735
}
736

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