Last active
February 29, 2016 02:10
-
-
Save brian-lc/1eb9867eb261f669ca25 to your computer and use it in GitHub Desktop.
Prototype code for EMF sensing to tone based alert on Particle Photon
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "SparkIntervalTimer/SparkIntervalTimer.h" | |
#include "Adafruit_TPA2016.h" | |
#include "wave_data.h" | |
#include "math.h" | |
#define ADC_BITS 12 // 12-bit ADC resolution for Particle Photon | |
#define SAMP_FEQ 260 // ~3.84kHz - 64 samples per 60hz cycle | |
#define ADC_SAMPLES 256 // 4 full cycles captured (256 makes sample division a bit shift operation) | |
#define ON_THRESHOLD 1.0 // Device is on when current goes over 1 amp | |
IntervalTimer sample_clock; | |
IntervalTimer audio_clock; | |
volatile int sample_ix = 0; | |
volatile int wave_ix = 0; | |
int sample_data[ADC_SAMPLES]; | |
Adafruit_TPA2016 audioamp = Adafruit_TPA2016(); | |
const int audioL = DAC1; | |
const int audioR = DAC2; | |
const int amp_active = D5; | |
const int led = D7; | |
const int iPin = A0; | |
double irms = 0.0; | |
double prevIrms = 0.0; | |
bool active_on = false; | |
String status = ""; | |
void setup() { | |
// initialize the data array | |
for (int i=0; i < ADC_SAMPLES; i++){ | |
sample_data[i] = 2048; | |
} | |
sample_clock.begin(grab_sample, SAMP_FEQ, uSec); | |
pinMode(led, OUTPUT); | |
pinMode(amp_active, OUTPUT); | |
digitalWrite(amp_active, LOW); | |
audioamp.begin(); | |
pinMode(audioL, OUTPUT); | |
pinMode(audioR, OUTPUT); | |
} | |
void grab_sample(void) { | |
sample_data[sample_ix] = analogRead(iPin); | |
// reset the sample location if = to the sample count | |
if (sample_ix < ADC_SAMPLES){ | |
sample_ix ++; | |
} | |
else{ | |
sample_ix = 0; | |
} | |
} | |
void stop_sample(void){ | |
sample_clock.end(); | |
sample_ix = 0; | |
} | |
void loop() { | |
irms = calcIrms(); | |
// if it was off and is now on | |
if ((prevIrms < ON_THRESHOLD) && (irms > ON_THRESHOLD)){ | |
active_on = true; | |
} else { | |
// it was on and is still on, or off and is stil off | |
// or check if it was on and is now off | |
if ((irms < ON_THRESHOLD) && active_on){ | |
active_on = false; | |
digitalWrite(amp_active, HIGH); | |
start_play(); | |
Particle.publish("kettle_status", "alert"); | |
} | |
} | |
if (active_on){ | |
status = "kettle_on"; | |
} else { | |
status = "kettle_off"; | |
} | |
reportUsage(status, irms); | |
prevIrms = irms; | |
delay(1000); | |
} | |
void reportUsage(String eventName, double irms){ | |
String msg = String::format("%.3f Amps", irms); | |
Particle.publish(eventName, msg); | |
} | |
// Will calculate the RMS with whatever | |
// values are in the data sample buffer | |
double calcIrms() | |
{ | |
double Irms; | |
double Vrms; | |
uint32_t vSum = 0; | |
uint32_t vAvg = 0; | |
double vVal = 0; | |
int vAdj = 0; | |
for (int n = 0; n < ADC_SAMPLES; n++){ | |
vAvg += sample_data[n]; | |
} | |
// vAvg is the mid-point of the voltage over the samples | |
// subtracting the midpoint from the measured voltages | |
// gives us the +/- voltages to use for the Vrms | |
vAvg = vAvg >> 8; // int val offset. Divide by number of samples (256) | |
for (int n = 0; n < ADC_SAMPLES; n++) | |
{ | |
vAdj = sample_data[n] - vAvg; // int val adjusted measurment | |
vSum += (vAdj * vAdj); // Squaring the value, adding it to the accumulator | |
} | |
vVal = vSum >> 8; // divide by number of samples (256); | |
Vrms = sqrt(vVal) * 0.0008; // 12-bit ADC w/ 3.3 maxV gives 3.3V/4096 units | |
Irms = Vrms * 20.15; | |
return Irms; // Iprimary = Isecondary * CT ratio | |
} | |
void play_wave(void) { | |
if (wave_ix < frame_count) { | |
int v = wave_data[wave_ix]; | |
analogWrite(audioL, v); | |
analogWrite(audioR, v); | |
wave_ix++; | |
} | |
else { | |
stop_play(); | |
} | |
} | |
void start_play(void) { | |
audioamp.enableChannel(true, true); | |
wave_ix = 0; | |
digitalWrite(led, HIGH); | |
audio_clock.begin(play_wave, 44, uSec); //44usec ~22,050hz | |
} | |
void stop_play(void) { | |
analogWrite(audioL, 0); | |
analogWrite(audioR, 0); | |
audioamp.enableChannel(false, false); | |
audio_clock.end(); | |
digitalWrite(led, LOW); | |
wave_ix = 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment