Revision cbda92cc
Untested current RMS calculation
It's not actually RMS, it's variance. Same general idea.
toolbox/current.c  

1  1 
#include "current.h" 
2  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 10 

8 
#define N_SAMPLES 20 

9  
10 
unsigned int samples[N_SAMPLES]; 

11 
int sample_idx; 

12  
13 
unsigned int sum; 

14 
unsigned long sum_sq; 

3  15  
4  16 
void current_init() { 
17  
18 
/* 

19 
* COM0A = 0, disconnect pin 

20 
* WGM0 = 2, clear timer on compare 

21 
*/ 

22 
TCCR0A = _BV(WGM01); 

23  
24 
/* 

25 
* CS0 = 5, 1024 prescaler 

26 
*/ 

27 
TCCR0B = _BV(CS02)  _BV(CS00); 

28  
29 
OCR0A = F_CPU / 1024 / SAMPLES_PER_CYCLE / CYCLES_PER_SECOND; 

30  
5  31 
/* 
6  32 
* REFS = 0, Vcc reference (set to 2 for internal 1.1V reference) 
7  33 
* MUX = 8, PB3(ADC8) 
8  34 
*/ 
9  35 
ADMUX = _BV(MUX3); 
36  
10  37 
/* TODO reduce power consumption with DIDR* */ 
38  
11  39 
/* 
12  40 
* ADLAR = 0, right adjust result 
13 
* ADTS = 0, free running mode


41 
* ADTS = 3, start on timer 0 compare match A


14  42 
*/ 
15 
ADCSRB = 0; 

43 
ADCSRB = _BV(ADTS1)  _BV(ADTS0); 

44  
16  45 
/* 
17  46 
* ADEN = 1, enable 
18 
* ADSC = 1, start now


47 
* ADSC = 0, don't start yet


19  48 
* ADATE = 1, auto trigger 
20 
* ADIE = 0, disable interrupt


21 
* ADPS = 3, prescale clock by 8


49 
* ADIE = 1, enable interrupt


50 
* ADPS = 4, prescale clock by 16


22  51 
*/ 
23 
ADCSRA = _BV(ADEN)  _BV(ADSC)  _BV(ADATE)  _BV(ADPS1)  _BV(ADPS0);


52 
ADCSRA = _BV(ADEN)  _BV(ADATE)  _BV(ADIE)  _BV(ADPS2);


24  53 
} 
25  54  
26 
int current_read() { 

27 
return ADC; 

55 
ISR(ADC_vect) { 

56 
unsigned int old, new; 

57  
58 
new = ADC; 

59  
60 
/* put sample into ring buffer */ 

61 
old = samples[sample_idx]; 

62 
samples[sample_idx++] = new; 

63 
if (sample_idx == N_SAMPLES) 

64 
sample_idx = 0; 

65  
66 
/* keep a running total of samples and samples squared */ 

67 
sum += new; 

68 
sum = old; 

69 
sum_sq += new*new; 

70 
sum_sq = old*old; 

71 
} 

72  
73 
/*unsigned char isqrt(unsigned int x) { 

74 
unsigned int sqrt, mulmask; 

75 
sqrt = 0; 

76 
mulmask = 0x80; 

77 
if (x > 0) { 

78 
while (mulmask) { 

79 
sqrt = mulmask; 

80 
if (sqrt * sqrt > x) 

81 
sqrt &= ~mulmask; 

82 
mulmask >>= 1; 

83 
} 

84 
} 

85 
return sqrt; 

86 
}*/ 

87  
88 
unsigned int current_read() { 

89 
unsigned int _sum; 

90 
unsigned long _sum_sq; 

91  
92 
cli(); 

93 
_sum = sum; 

94 
_sum_sq = sum_sq; 

95 
sei(); 

96  
97 
/* calculate the variance using sum and sum_sq */ 

98 
return (N_SAMPLES*_sum_sq  _sum*_sum) / (N_SAMPLES*(N_SAMPLES1)); 

28  99 
} 
Also available in: Unified diff