Project

General

Profile

Statistics
| Revision:

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

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

    
516
#if DEBUG
517
                tempData[0] = 'T';
518
                tempData[1] = temp>>8;
519
                tempData[2] = temp&0xFF;
520
                i2c_putpacket(0x01, tempData, 3);
521
#endif
522
                  }
523

    
524
                temp=6666;
525
        }
526
        
527
        data[1]=I2C_MSG_BATTERY_FULL;
528
        i2c_putpacket(0x01, data, 2);
529

    
530
}
531

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

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

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

    
656
                tempData[0] = 'V';
657
                tempData[1] = volt>>8;
658
                tempData[2] = volt&0xFF;
659
                i2c_putpacket(0x01, tempData, 3);
660

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

    
689
                temp=6666;
690
        }
691

    
692
        
693
        return 1;
694
}
695

    
696
ISR(TIMER0_OVF_vect)
697
{
698
        if(error)
699
                PORTB ^= (_BV(LED1)|_BV(LED2));
700

    
701
        interrupt_count--;
702
        if(interrupt_count==0)
703
        {
704
                abs_time++;
705
                new_second=1;
706
                        
707
                interrupt_count=INT_COUNT;
708
        }
709
}
710

    
711
ISR(TIMER1_OVF_vect)
712
{
713
        delay_ms(1); //wait a clock cycle so we know the ouput gets set (which happens at timer = 0)
714
        
715
        TCNT1 = 156; // start out at 156. Now OCR1B - 156 = duty cycle
716
}
717

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