Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (12.9 KB)

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

    
27
#define MAX_T 300
28
#define MIN_T 730
29
//range is 0 to 45 C
30
//cal tests:
31
//room temp - 25
32
//value ~500, varies from battery to battery, but is consistent on one battery
33
//freezer 737
34
//heat gun at a distance 461
35

    
36
#define MAX_DT -4 //this is the LOWEST ACCEPTABLE ADC value
37
#define MAX_DT_ABS 400
38
#define VOLT_PLATEAU 50
39

    
40

    
41
//The following times are in seconds
42
#define MAX_FAST_TIME 5400
43
#define MAX_TRICKLE_TIME 600
44

    
45
//debug pins
46
#define debug_time PA3
47
#define debug_curr PA4
48
#define debug_volt PA5
49
#define debug_temp PA6
50
#define debug_12in PA7
51

    
52
//be sure admux also sets the MUX5 bit which is in ADCSRB
53
#define ADMUX_I
54
#define ADMUX_V
55
#define ADMUX_T
56

    
57
#define ROBOT_TX PB1
58
#define ROBOT_RX PB2
59
#define PWM PB3
60
#define DETECT_12V PB6
61

    
62
#define LED1 PB4 //Green
63
#define LED2 PB5 //Red
64

    
65

    
66
//LED States:
67
//Red - Fast Charging
68
//Green - Trickle Charging
69
//Both steady - done charging
70
//Both Blinking - Error
71

    
72
#define INT_COUNT 2 //interrupts per second
73
#define AVG_COUNT 64 //number of times to count current
74

    
75
//To enable the PWM write :         TCCR1B = (_Bv(CS10));//enable PWM
76

    
77
uint8_t interrupt_count = INT_COUNT;
78

    
79
volatile uint32_t abs_time=1; // start at one second so it doesnt do the minute checks right away
80
volatile uint8_t new_second=0; //only used as a boolean
81

    
82
volatile uint8_t error=0;
83
volatile uint8_t status;
84

    
85
volatile uint8_t steady_current = 0;
86

    
87
//DT must be triggered twice in a row
88
volatile uint8_t last_DT = 0;
89
//same for DV
90
volatile uint8_t last_DV = 0;
91

    
92
#define FAST_CHARGE 1
93
#define TRICKLE_CHARGE 2
94

    
95
RING_BUFFER_NEW(ring_buffer, 12, int, buffer);
96

    
97
void wait(int ops)
98
{
99
        int i = 0;
100
        while(i<ops)
101
                i++;
102
}
103

    
104

    
105

    
106
int avg_ADC(void)
107
{
108
        int av;
109
        char i;
110

    
111
        //Calculate a average out of the next 8 A/D conversions
112
    for(av=0,i=8;i;--i)
113
    {
114
        ADCSRA |= _BV(ADSC);                      // start new A/D conversion
115
        while (!(ADCSRA & (_BV(ADIF))))        // wait until ADC is ready
116
            ;      
117
        av = av+ADC;
118
    }
119
    av = av/8;
120
        
121
        //ADCSRA &= ~_BV(ADEN);
122

    
123
        return av;
124
        
125
}
126

    
127
int get_voltage(void)
128
{
129
        ADMUX = _BV(MUX0);
130
        
131
        ADCSRB &= ~_BV(MUX5);
132
        
133
        return avg_ADC();
134
}
135

    
136
int get_current(void)
137
{
138
        ADMUX = _BV(MUX1);
139
        
140
        ADCSRB |= _BV(MUX5);
141
        
142
        return avg_ADC();
143
}
144

    
145
int get_temperature(void)
146
{
147
        ADMUX = _BV(MUX1);
148
        
149
        ADCSRB &= ~_BV(MUX5);
150
        
151
        return avg_ADC();
152
}
153

    
154
int get_avg_voltage(void)
155
{
156
        int count=0;
157
        uint32_t sum=0;
158
                
159
                //OCR1B =120;
160
        while(count < AVG_COUNT)
161
        {
162
                sum += get_voltage();
163
                count++;
164
        }
165

    
166
        return sum/AVG_COUNT;
167
}
168

    
169
int get_avg_current(void)
170
{
171
        int count=0;
172
        uint32_t sum=0;
173
                
174
                //OCR1B =120;
175
        while(count < AVG_COUNT)
176
        {
177
                sum += get_current();
178
                count++;
179
        }
180

    
181
        return sum/AVG_COUNT;
182
}
183

    
184
int get_avg_temperature(void)
185
{
186
        int count=0;
187
        uint32_t sum=0;
188
                
189
                //OCR1B =120;
190
        while(count < AVG_COUNT)
191
        {
192
                sum += get_temperature();
193
                count++;
194
        }
195

    
196
        return sum/AVG_COUNT;
197
}
198

    
199

    
200
uint8_t supply_voltage(void)
201
{
202
        return PINB & _BV(DETECT_12V);
203
}
204

    
205
void clear_err(void)
206
{
207
        error=0;
208
        PORTB &= ~(_BV(LED1)|_BV(LED2));
209
        
210
        if(status==FAST_CHARGE)
211
                PORTB |= _BV(LED2);
212
                
213
        if(status==TRICKLE_CHARGE)
214
                PORTB |= _BV(LED1);
215
}
216
        
217
void wait_8th(void)
218
{
219
        uint8_t start = abs_time % 8;
220
        
221
        while(abs_time % 8 == start)
222
        {
223
                /*if(supply_voltage())
224
                        PORTB |= _BV(LED1);
225
                else
226
                        PORTB &= ~_BV(LED1);
227
                if(get_voltage()>100)
228
                        PORTB |= _BV(LED2);
229
                else
230
                        PORTB &= ~_BV(LED2);*/
231
        }
232
}
233

    
234
void send_err(void)
235
{
236
        OCR1B=0;//turn off the PWM to be safe
237

    
238
        PORTB &= ~(_BV(LED1)|_BV(LED2));
239
        if(status!=0)//leave last error if there was one
240
                PORTA &= ~(_BV(debug_time)|_BV(debug_curr)|_BV(debug_volt)|_BV(debug_temp)|_BV(debug_12in)); 
241
        error=1;
242
        status=0;
243
}
244

    
245
void send_done(void)
246
{
247
        char tempData;
248
        //Finished, leave
249
        tempData = 'F';
250
        i2c_putpacket(0x01, &tempData, 1);
251
        
252
        PORTA &= ~(_BV(debug_time)|_BV(debug_curr)|_BV(debug_volt)|_BV(debug_temp)|_BV(debug_12in)); 
253
        
254
}
255

    
256
void setup(void)
257
{
258
      DDRA = _BV(PA3);
259
#ifdef debug
260
        //DDRA = (_BV(debug_time)|_BV(debug_curr)|_BV(debug_volt)|_BV(debug_temp)|_BV(debug_12in));
261
#endif
262
        PORTA = 0x00;
263
        DDRB = (_BV(ROBOT_TX)|_BV(PWM)|_BV(LED1)|_BV(LED2)); //confiure output pins
264
        PORTB = 0x00;
265
        
266
        ADCSRA = (_BV(ADEN)|_BV(ADPS2)|_BV(ADPS1)); //start ADC with a division factor of 64
267
        
268
        TCCR0B = (_BV(CS01)); //set timer 0 for realtime mode
269
        TCCR0A = (_BV(TCW0));
270
        TIMSK = (_BV(TOIE0)); //enable overflow interrupts
271
        
272
        TCCR1A = (_BV(COM1B1)|_BV(PWM1B)|_BV(COM1A1)|_BV(PWM1A)); //clear timer 1 on compare, set at 0x00. Fast PWM mode
273
        TCCR1B |= _BV(CS10); //leave timer on and set compare to 0 to make output off        
274
        
275
        //hack stuff so it will run in continuous mode
276
        TIMSK |= _BV(TOIE1); //enable overflow interrupt for timer 1
277
        
278
        OCR1B = 0;
279
        OCR1A = 0;
280
        
281
        
282
        RING_BUFFER_CLEAR(buffer);
283
        RING_BUFFER_INIT(buffer, 12);
284
        for(int i=0;i<10;i++)
285
                RING_BUFFER_ADD(buffer, 0);
286
        
287
        sei();
288
}
289

    
290

    
291

    
292

    
293
//takes a 7-bit ionteger and displays it on the 7 LEDs with the Green being the MSB
294
void LED_out(int i)
295
{
296
        if(i & 64)
297
                PORTB |= _BV(LED1);
298
        else
299
                PORTB &= ~_BV(LED1);
300
                
301
        if(i & 32)
302
                PORTB |= _BV(LED2);
303
        else
304
                PORTB &= ~_BV(LED2);
305
                
306
        if(i & 16)
307
                PORTA |= _BV(PA3);
308
        else
309
                PORTA &= ~_BV(PA3);
310
        
311
        if(i & 8)
312
                PORTA |= _BV(PA4);
313
        else
314
                PORTA &= ~_BV(PA4);
315
                
316
        if(i & 4)
317
                PORTA |= _BV(PA5);
318
        else
319
                PORTA &= ~_BV(PA5);
320
        
321
        if(i & 2)
322
                PORTA |= _BV(PA6);
323
        else
324
                PORTA &= ~_BV(PA6);
325
                
326
        if(i & 1)
327
                PORTA |= _BV(PA7);
328
        else
329
                PORTA &= ~_BV(debug_12in);
330
}
331

    
332
//get the difference of the current value minues the value 10 entires ago
333
int ring_buffer_d10(int y)
334
{        
335
        int x;
336
        RING_BUFFER_REMOVE(buffer, x);
337
                
338
        RING_BUFFER_ADD(buffer, y);
339
        return y-x;
340
}
341

    
342

    
343
uint8_t read_homing()
344
{
345
    uint8_t ret = PINA & _BV(HOMING_PIN);
346
    if(ret)
347
        PORTA |= _BV(PA3);
348
    else
349
        PORTA &= ~_BV(PA3);
350
    return ret;
351
}
352

    
353
//copied from scheduler/seeking.c
354
uint8_t get_delay(void)
355
{
356
    uint8_t count = 0;
357
    
358
        PORTB|=_BV(LED2);
359
    while(read_homing())
360
    {
361
        delay_ms(1);
362
        count++;
363
        if (count >= 100)
364
            return 1;
365
    } //wait a beacon cycle to make sure we aren't starting the count in the middle of one
366
        PORTB&=~_BV(LED2);
367
    count = 0;
368
    PORTB|=_BV(LED1);
369
    while(!read_homing())
370
    {
371
        delay_ms(1);
372
        count++;
373
        if(count==255)
374
          return 2;
375
    }
376
    PORTB&=~_BV(LED1);
377
        
378
  /*RECH_PUTS("\n\rCount: ");
379
        RECH_PUTI(count);
380
        RECH_PUTC('.');*/
381
        
382
    return count;
383
}
384

    
385
void trickle_charge(void)
386
{
387

    
388
        abs_time = 0;
389
        status = 0;
390
        char tempData[5];
391
        char data[2];
392
        data[0]='D';
393
        int volt = 0;
394
        int temp = 0;
395
        int curr = 0;
396
        int meas_count = 0;
397
        int mod=0;
398
        OCR1B = 0;
399
        
400
        PORTB &= ~(_BV(LED1)|_BV(LED2));
401

    
402
        
403
        while(status!=2)
404
        {
405
                mod=abs_time%4;
406
                
407
                PORTB ^= _BV(LED2);
408
                
409
                if(supply_voltage())
410
                  while(abs_time%4==mod);
411
                
412
    /* TIME TERMINATION */
413
                if(abs_time>12000) //12000=25 minutes
414
                {
415
                        //SEND_DONE
416
                        OCR1B=0;
417
                        break;
418
                }
419
                
420
#if DEBUG                
421
                tempData[0] = 'C';
422
                tempData[1] = abs_time>>8;
423
                tempData[2] = abs_time&0xFF;
424
                i2c_putpacket(0x01, tempData, 3);
425
#endif
426
                
427
                mod=abs_time%4;
428
                while(abs_time%4==mod)
429
                {
430
      /* CONTACT */
431
                        if(supply_voltage())
432
                        {
433
                                PORTB |= _BV(LED1);
434
                                //curr = regulate_current(500);
435
                                //+++curr = get_avg_current();
436
                                
437
                                if(status==0)
438
                                {
439
                                        status=1;
440
                                        data[1]='a';
441
                                        i2c_putpacket(0x01, data, 2);
442
                                        data[1]=I2C_MSG_BATTERY_CHARGING;
443
                                        i2c_putpacket(0x01, data, 2);
444
                                }
445
                                
446
        /* Trickle Charge */
447
                                if(status==1)
448
                                        OCR1B = 200;
449
                        }
450
      /* NO CONTACT */
451
                        else
452
                        {
453
                                PORTB &= ~_BV(LED1);
454
                                if(status==1)
455
                                {
456
                                        status=0;
457
                                        data[1]=I2C_MSG_CONTACT_ERROR;
458
                                        i2c_putpacket(0x01, data, 2);
459
                                }
460
                                else
461
                                {
462
          /*get_delay(); //reject the first reading //homing import stuff, uncomment this!!!!!!
463
                                        data[0]=I2C_MSG_HOMING;
464
                                        data[1]=get_delay();
465
          i2c_putpacket(0x01, data, 2);*/
466
          
467
          data[0]='D';
468
                                }
469
                                curr = 0;
470
                                OCR1B = 0;
471
                        }
472
                }
473
                
474
#if DEBUG
475
                tempData[0] = 'P';
476
                tempData[1] = 0;
477
                tempData[2] = OCR1B;
478
                i2c_putpacket(0x01, tempData, 3);
479
                tempData[0] = 'I';
480
                tempData[1] = curr>>8;
481
                tempData[2] = curr&0xFF;
482
                i2c_putpacket(0x01, tempData, 3);
483
#endif
484
                curr=6666;
485
                
486
    /* Absolute Voltage Termination */
487
                if(supply_voltage())
488
                  {
489
                mod=abs_time%4;
490
                while(abs_time%4==mod)
491
                {
492
                        volt = get_avg_voltage();
493
                }
494
                
495
                if(volt>1010)
496
                {
497
                        //SEND ERROR
498
                        status=0;
499
                }
500
    
501
#if DEBUG
502
                tempData[0] = 'V';
503
                tempData[1] = volt>>8;
504
                tempData[2] = volt&0xFF;
505
                i2c_putpacket(0x01, tempData, 3);
506
#endif
507
                volt=6666;
508
                
509
    /* Absolute Temperature Termination */
510
                mod=abs_time%4;
511
                while(abs_time%4==mod)
512
                {
513
                        temp = get_avg_temperature();
514
                }
515
                
516
                if(temp<250)
517
                {
518
                        //SEND ERROR
519
                        status=0;
520
                }
521

    
522
#if DEBUG
523
                tempData[0] = 'T';
524
                tempData[1] = temp>>8;
525
                tempData[2] = temp&0xFF;
526
                i2c_putpacket(0x01, tempData, 3);
527
#endif
528
                  }
529

    
530
                temp=6666;
531
        }
532
        
533
        data[1]=I2C_MSG_BATTERY_FULL;
534
        i2c_putpacket(0x01, data, 2);
535

    
536
}
537

    
538
int main(void)
539
{
540
        new_second=0;
541
        char tempData[5];        //For i2c communication
542
  
543
        setup();
544
        i2c_init();
545
        
546
        
547
        /*GIMSK = (_BV(PCIE0)); //enable PCINT interrupts
548
        PCMSK1 = (_BV(PCINT10)); //enable pin change interrupt on ROBOT_RX
549
        MCUCR = (_BV(SE)|_BV(SM1));// (power-down mode)
550
        */
551
        
552
        OCR1B=0;
553
        
554
        sei();
555
  
556
  //test delay_ms
557
  PORTB|=_BV(LED2);
558
  PORTB|=_BV(LED1);
559
  delay_ms(1000);
560
  PORTB&=~_BV(LED2);
561
  PORTB&=~_BV(LED1);
562
        
563
        //*******************************
564
        while(1)
565
                trickle_charge();
566
        
567
        /*GIMSK = (_BV(PCIE0)); //enable PCINT interrupts
568
        sleep_cpu();*/
569
        
570
        PORTB=0;//clear outputs
571
        
572
        GIMSK = 0;
573
        
574
        error=0;
575
                
576
        i2c_init();
577
        int volt=0, last_volt=0, same_volt=0;
578
        int temp=0, dt;
579
        int curr=0;
580
        int meas_count;
581
        int mod=0;
582
        
583
        status=FAST_CHARGE;
584
        
585
        while(1)
586
        {
587
                mod=abs_time%4;
588
                while(abs_time%4==mod);
589
                
590
                /*if((abs_time>>3)%3==0)
591
                        OCR1B=21;
592
                else if((abs_time>>3)%3==1)
593
                        OCR1B=57;
594
                else
595
                        OCR1B=85;*/
596
                
597
                tempData[0] = 'C';
598
                tempData[1] = abs_time>>8;
599
                tempData[2] = abs_time&0xFF;
600
                i2c_putpacket(0x01, tempData, 3);
601
                
602
                mod=abs_time%4;
603
                while(abs_time%4==mod)
604
                {
605
      /* CONTACT */
606
                        if(supply_voltage())
607
                        {
608
                                //curr = regulate_current(500);
609
                                curr = get_avg_current();
610
                                
611
                                if(status==FAST_CHARGE)
612
                                        OCR1B=50;
613
                        }
614
      /* NO CONTACT */
615
                        else
616
                        {
617
                                curr = 0;
618
                                OCR1B = 0;
619
                        }
620
                }
621
                
622

    
623
                tempData[0] = 'P';
624
                tempData[1] = 0;
625
                tempData[2] = OCR1B;
626
                i2c_putpacket(0x01, tempData, 3);
627
                tempData[0] = 'I';
628
                tempData[1] = curr>>8;
629
                tempData[2] = curr&0xFF;
630
                i2c_putpacket(0x01, tempData, 3);
631
                curr=6666;
632
                
633
                mod=abs_time%4;
634
                while(abs_time%4==mod)
635
                {
636
                        volt = get_avg_voltage();
637
                }
638
                
639
    //Same volt - Last volt upkeep
640
                if(volt==last_volt && supply_voltage())
641
                                same_volt++;
642
    else
643
    {
644
      last_volt = volt;
645
      same_volt=0;
646
    }
647

    
648
                        
649
                tempData[0] = 'v';
650
                tempData[1] = same_volt>>8;
651
                tempData[2] = same_volt&0xFF;
652
                i2c_putpacket(0x01, tempData, 3);
653
                
654
    /* Voltage Dip Termination */
655
                if(volt<last_volt && same_volt>=VOLT_PLATEAU)
656
                {
657
                        OCR1B=0;
658
                        status=0;
659
                }
660

    
661
                tempData[0] = 'V';
662
                tempData[1] = volt>>8;
663
                tempData[2] = volt&0xFF;
664
                i2c_putpacket(0x01, tempData, 3);
665

    
666
                volt=6666;
667
                
668
    //Temp ring buffer upkeep
669
                mod=abs_time%4;
670
                while(abs_time%4==mod)
671
                {
672
                        temp = get_avg_temperature();                        
673
                }
674
                
675
                dt=ring_buffer_d10(temp);
676
                
677
                tempData[0] = 't';
678
                tempData[1] = dt>>8;
679
                tempData[2] = dt&0xFF;
680
                i2c_putpacket(0x01, tempData, 3);
681
                
682
    /* Temperature Rise Termination */
683
                if(dt < MAX_DT && temp < MAX_DT_ABS)
684
                {
685
                        status=0;
686
                        OCR1B=0;
687
                }
688
                
689
                tempData[0] = 'T';
690
                tempData[1] = temp>>8;
691
                tempData[2] = temp&0xFF;
692
                i2c_putpacket(0x01, tempData, 3);
693

    
694
                temp=6666;
695
        }
696

    
697
        
698
        return 1;
699
}
700

    
701
ISR(TIMER0_OVF_vect)
702
{
703
        if(error)
704
                PORTB ^= (_BV(LED1)|_BV(LED2));
705

    
706
        interrupt_count--;
707
        if(interrupt_count==0)
708
        {
709
                abs_time++;
710
                new_second=1;
711
                        
712
                interrupt_count=INT_COUNT;
713
        }
714
}
715

    
716
ISR(TIMER1_OVF_vect)
717
{
718
        wait(5); //wait a bit so we know the ouput gets set (which happens at timer = 0)
719
        
720
        TCNT1 = 156; // start out at 156. Now OCR1B - 156 = duty cycle
721
}
722

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