Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (13.4 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
        delay_ms(50);
431
                i2c_putpacket(0x01, tempData, 3);
432
        delay_ms(50);
433
#endif
434
                
435
                mod=abs_time%4;
436
                while(abs_time%4==mod)
437
                {
438
      /* CONTACT */
439
                        if(supply_voltage())
440
                        {
441
                                PORTB |= _BV(LED1);
442
                                //curr = regulate_current(500);
443
                                curr = get_avg_current();
444
                                
445
                                if(status==0)
446
                                {
447
                                        status=1;
448
#if USE_I2C
449
                                        data[1]='a';
450
                                        i2c_putpacket(0x01, data, 2);
451
                                        data[1]=I2C_MSG_BATTERY_CHARGING;
452
                                        i2c_putpacket(0x01, data, 2);
453
#endif
454
                                }
455
                                
456
        /* Trickle Charge */
457
                                if(status==1)
458
                                        OCR1B = 128;
459
                        }
460
      /* NO CONTACT */
461
                        else
462
                        {
463
                                PORTB &= ~_BV(LED1);
464
                                if(status==1)
465
                                {
466
                                        status=0;
467
#if USE_I2C
468
                                        data[1]=I2C_MSG_CONTACT_ERROR;
469
                                        i2c_putpacket(0x01, data, 2);
470
#endif
471
                                }
472
                                else
473
                                {
474
          /*get_delay(); //reject the first reading //homing import stuff, uncomment this!!!!!!
475
                                        data[0]=I2C_MSG_HOMING;
476
                                        data[1]=get_delay();
477
          i2c_putpacket(0x01, data, 2);*/
478
          
479
          data[0]='D';
480
                                }
481
                                curr = 0;
482
                                OCR1B = 0;
483
                        }
484
                }
485
                
486
#if DEBUG
487
                tempData[0] = 'P';
488
                tempData[1] = 0;
489
                tempData[2] = OCR1B;
490
        delay_ms(50);
491
                i2c_putpacket(0x01, tempData, 3);
492
        delay_ms(50);
493
                tempData[0] = 'I';
494
                tempData[1] = curr>>8;
495
                tempData[2] = curr&0xFF;
496
        delay_ms(50);
497
                i2c_putpacket(0x01, tempData, 3);
498
        delay_ms(50);
499
#endif
500
                curr=6666;
501
                
502
    /* Absolute Voltage Termination */
503
                mod=abs_time%4;
504
                while(abs_time%4==mod)
505
                {
506
                        volt = get_avg_voltage();
507
                }
508
                
509
                if(volt>1010)
510
                {
511
                        //SEND ERROR
512
                        status=0;
513
                }
514
    
515
#if DEBUG
516
                tempData[0] = 'V';
517
                tempData[1] = volt>>8;
518
                tempData[2] = volt&0xFF;
519
        delay_ms(50);
520
                i2c_putpacket(0x01, tempData, 3);
521
        delay_ms(50);
522
#endif
523
                volt=6666;
524
                
525
    /* Absolute Temperature Termination */
526
                mod=abs_time%4;
527
                while(abs_time%4==mod)
528
                {
529
                        temp = get_avg_temperature();
530
                }
531
                
532
                if(temp<250)
533
                {
534
                        //SEND ERROR
535
                        status=0;
536
                }
537

    
538
#if DEBUG
539
                tempData[0] = 'T';
540
                tempData[1] = temp>>8;
541
                tempData[2] = temp&0xFF;
542
        delay_ms(50);
543
                i2c_putpacket(0x01, tempData, 3);
544
        delay_ms(50);
545
#endif
546

    
547
                temp=6666;
548
        }
549
#if USE_I2C
550
        data[1]=I2C_MSG_BATTERY_FULL;
551
        i2c_putpacket(0x01, data, 2);
552
#endif
553
}
554

    
555
int main(void)
556
{
557
        new_second=0;
558
        char tempData[5];        //For i2c communication
559
  
560
        setup();
561

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

    
646
                tempData[0] = 'P';
647
                tempData[1] = 0;
648
                tempData[2] = OCR1B;
649
                i2c_putpacket(0x01, tempData, 3);
650
                tempData[0] = 'I';
651
                tempData[1] = curr>>8;
652
                tempData[2] = curr&0xFF;
653
                i2c_putpacket(0x01, tempData, 3);
654
                curr=6666;
655
                
656
                mod=abs_time%4;
657
                while(abs_time%4==mod)
658
                {
659
                        volt = get_avg_voltage();
660
                }
661
                
662
    //Same volt - Last volt upkeep
663
                if(volt==last_volt && supply_voltage())
664
                                same_volt++;
665
    else
666
    {
667
      last_volt = volt;
668
      same_volt=0;
669
    }
670

    
671
                        
672
                tempData[0] = 'v';
673
                tempData[1] = same_volt>>8;
674
                tempData[2] = same_volt&0xFF;
675
                i2c_putpacket(0x01, tempData, 3);
676
                
677
    /* Voltage Dip Termination */
678
                if(volt<last_volt && same_volt>=VOLT_PLATEAU)
679
                {
680
                        OCR1B=0;
681
                        status=0;
682
                }
683

    
684
                tempData[0] = 'V';
685
                tempData[1] = volt>>8;
686
                tempData[2] = volt&0xFF;
687
                i2c_putpacket(0x01, tempData, 3);
688

    
689
                volt=6666;
690
                
691
    //Temp ring buffer upkeep
692
                mod=abs_time%4;
693
                while(abs_time%4==mod)
694
                {
695
                        temp = get_avg_temperature();                        
696
                }
697
                
698
                dt=ring_buffer_d10(temp);
699
                
700
                tempData[0] = 't';
701
                tempData[1] = dt>>8;
702
                tempData[2] = dt&0xFF;
703
                i2c_putpacket(0x01, tempData, 3);
704
                
705
    /* Temperature Rise Termination */
706
                if(dt < MAX_DT && temp < MAX_DT_ABS)
707
                {
708
                        status=0;
709
                        OCR1B=0;
710
                }
711
                
712
                tempData[0] = 'T';
713
                tempData[1] = temp>>8;
714
                tempData[2] = temp&0xFF;
715
                i2c_putpacket(0x01, tempData, 3);
716

    
717
                temp=6666;
718
        }
719

    
720
        
721
        return 1;
722
}
723

    
724
ISR(TIMER0_OVF_vect)
725
{
726
        if(error)
727
                PORTB ^= (_BV(LED1)|_BV(LED2));
728

    
729
        interrupt_count--;
730
        if(interrupt_count==0)
731
        {
732
                abs_time++;
733
                new_second=1;
734
                        
735
                interrupt_count=INT_COUNT;
736
        }
737
}
738

    
739
ISR(TIMER1_OVF_vect)
740
{
741
        wait(2); //wait a bit so we know the ouput gets set (which happens at timer = 0)
742
        
743
        TCNT1 = 0;//156; // start out at 156. Now OCR1B - 156 = duty cycle
744
}
745

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