root / toolbox / current.c @ e8960789
History  View  Annotate  Download (1.85 KB)
1 
#include "current.h" 

2 
#include <avr/io.h> 
3 
#include <avr/interrupt.h> 
4 
#include <math.h> 
5  
6 
#define CYCLES_PER_SECOND 60 // wall power 
7 
#define SAMPLES_PER_CYCLE 16 
8 
#define N_SAMPLES 48 
9  
10 
unsigned int samples[N_SAMPLES]; 
11 
int sample_idx;

12  
13 
unsigned int sum; 
14 
unsigned long sum_sq; 
15  
16 
void current_init() {

17  
18 
/* TODO reduce power consumption with DIDR* */

19  
20 
/*

21 
* COM1A = COM1B = 0, disconnect pins

22 
* WGM1 = 4, clear timer on compare A

23 
* CS1 = 1, no prescaler

24 
*/

25 
TCCR1B = _BV(WGM12)  _BV(CS10); 
26  
27 
/* Timer is cleared on A, ADC is triggered on B */

28 
OCR1A = F_CPU / SAMPLES_PER_CYCLE / CYCLES_PER_SECOND; 
29 
OCR1B = OCR1A; 
30  
31 
/*

32 
* REFS = 0, Vcc reference (set to 2 for internal 1.1V reference)

33 
* MUX = 8, PB3(ADC8)

34 
*/

35 
ADMUX = _BV(MUX3); 
36  
37 
/*

38 
* ADLAR = 0, right adjust result

39 
* ADTS = 5, start on timer 1 compare match B

40 
*/

41 
ADCSRB = _BV(ADTS2)  _BV(ADTS0); 
42  
43 
/*

44 
* ADEN = 1, enable

45 
* ADSC = 0, don't start yet

46 
* ADATE = 1, auto trigger

47 
* ADIE = 1, enable interrupt

48 
* ADPS = 6, prescale clock by 64

49 
*/

50 
ADCSRA = _BV(ADEN)  _BV(ADATE)  _BV(ADIE)  _BV(ADPS2)  _BV(ADPS1); 
51 
} 
52  
53 
ISR(ADC_vect) { 
54 
unsigned int old, new; 
55  
56 
/* clear the timer interrupt flag so that the ADC will be triggered again

57 
* next time the timer resets */

58 
TIFR = _BV(OCF1B); 
59  
60 
new = ADC; 
61  
62 
/* put sample into ring buffer */

63 
old = samples[sample_idx]; 
64 
samples[sample_idx++] = new; 
65 
if (sample_idx == N_SAMPLES)

66 
sample_idx = 0;

67  
68 
/* keep a running total of samples and samples squared */

69 
sum += new; 
70 
sum = old; 
71 
sum_sq += (unsigned long)new*new; 
72 
sum_sq = (unsigned long)old*old; 
73 
} 
74  
75 
unsigned int current_read() { 
76 
unsigned int _sum; 
77 
unsigned long _sum_sq; 
78  
79 
cli(); 
80 
_sum = sum; 
81 
_sum_sq = sum_sq; 
82 
sei(); 
83  
84 
/* calculate the variance using sum and sum_sq */

85 
return (N_SAMPLES*_sum_sq  (unsigned long)_sum*_sum) / 
86 
(N_SAMPLES*(N_SAMPLES1));

87 
} 