Back to Parent

/*  
Author: Alex Alspach
Date: 09/18/15
Title: earduino_making_things_interactive_2015.ino
Description: Microphone sampling and LED PWM output for 
  earduino: a pocket-sized hearing loss prevention device, 
  Making Things Interactive, CMU, Fall 2015    
*/


const boolean DEBUG = false; // If true, the mic value can be input by Serial comm. Mic value not used.
const boolean BUZZERS = true; // if false, buzzers will not vibrate
const boolean SHOW = false; // if true, the mic value will run from 0-1023 over the course of about a minute. Mic value not used.

const boolean PRINT_LEDS = false; // If true, LED PWM values will print to serial

float seconds = 0.0; // time counted in seconds from the beginning of the program

// For controlling device over serial.
float controlValue = 0.0; // Takes place of the mic raw data when debugging

// Pin numbers
int led1 = 3;
int led2 = 4;
int led3 = 5;
int micPin = 7;
int vibePinOne = 23;
int vibePinTwo = 22;

// Buzzer Parameters
float vibeMin = 50.0; // Lowest PWM value that I can feel
float vibeMax = 255.0; // Max vibration PWM value
float vibeAmp = (vibeMax - vibeMin) / 2.0; // Sine wave amplitube
float vibeCenter = vibeMin + vibeAmp; // Sine wave center

// MIC Parameters
float micMin = 0.0;
float micMax = 1023.0; //1023 actual max (Lower number maxes max volume lower

// LED Parameters
float ledMin = 0.0;
float ledMax = 255.0;


// PWM values for buzzers
float vibeCommandOne = 0.0;
float vibeCommandTwo = 0.0;

// PWM values for LEDs
float tempVal = 0.0;
float led1Val = 0.0;
float led2Val = 0.0;
float led3Val = 0.0;

// Mic value thresholds that determine which mode we are in: Safe, Warning, Danger
float threshOne = 340.0;
float threshTwo = 680.0;
// Overlap between modes. Not used
float overlap = 0.0; 
// Mic value from ADC
float micRaw = 0.0;
// Which mode, 1 (safe), 2 (warning), 3 (Dangerous)
int mode = 0;

// Filtering
// How many samples are taken into the average
const unsigned long windowSize = 4000;
// Data stored here for averaging
float data[windowSize];
// Used for moving average
float total = 0.0;
float average = 0.0;
int dataIndex = 0;


void setup() {

  //setTime(0);

  // Microphone analog input
  pinMode( micPin, INPUT );

  // LED PWM output
  pinMode( led1, OUTPUT );
  pinMode( led2, OUTPUT );
  pinMode( led3, OUTPUT );

  // Buzzer PWM output
  pinMode( vibePinOne, OUTPUT );
  pinMode( vibePinTwo, OUTPUT );

  Serial.begin(9600);

  // Fill up the data array with zeros before we start gathering data
  for (int thisReading = 0; thisReading < windowSize; thisReading++)
    data[thisReading] = 0;
}

void loop() {


  // keep time in seconds
  seconds = millis() * 0.001;

  // If in debugging mode, the value obtained via serial is used as the microphone signal
  // The average is also updated immediately to produce an immediate state change in the device
  if ( DEBUG == true ) {
    if (Serial.available() > 0) {
      // read the incoming integer
      controlValue = Serial.parseInt();
      // say what you got:
      Serial.println(controlValue);
      micRaw = controlValue;
      average = controlValue;
    }
  }

  // If in show mode, the full microphone signal range is linearly traversed,
  // producing the full range of device output states
  if (SHOW == true) {
    if ((millis() % 50) == 0 ) micRaw += 1.0; //50
    if ( micRaw > micMax ) {
      micRaw = 0.0;
      average = 0.0;
    }
  }

  // Read the mic via the ADC when not in debugging or show mode
  if ( DEBUG == false && SHOW == false) {
    micRaw = analogRead(micPin);
  }

  // See movingAverage function at bottom of code
  average = movingAverage();
  delay(1);



  // Which Mode are we in (1-3: Safe, Warning, Danger)
  mode = 0;

  // Reset LED PWM values to Zero
  led1Val = 0.0;
  led2Val = 0.0;
  led3Val = 0.0;


  // First Range, Safe Range, Mode1
  if ( (average >= micMin) && (average < threshOne) )
  {
    tempVal = mapfloat(average, micMin, threshOne, ledMin, ledMax);
    if (tempVal < ledMin) tempVal = ledMin;
    if (tempVal > ledMax) tempVal = ledMax;
    led1Val = tempVal;
    mode = 1;
  }

  // Second Range, Warning Range, Mode2
  if ( (average >= (threshOne - overlap) ) && (average < threshTwo) )
  {
    tempVal = mapfloat(average, (threshOne - overlap), threshTwo, ledMin, ledMax);
    if (tempVal < ledMin) tempVal = ledMin;
    if (tempVal > ledMax) tempVal = ledMax;
    led2Val = tempVal;

    if (average >= threshOne) mode = 2;
  }

  // Third Range, Danger Range, Mode3
  if ( (average >= (threshTwo - overlap) ) && (average <= micMax ) )
  {
    tempVal = mapfloat(average, (threshTwo - overlap), micMax, ledMin, ledMax);
    if (tempVal < ledMin) tempVal = ledMin;
    if (tempVal > ledMax) tempVal = ledMax;
    led3Val = tempVal;

    if (average >= threshTwo) mode = 3;
  }


  // First Range, Safe Range, Mode1
  if (mode == 1) {

    vibeCommandOne = 0;
    vibeCommandTwo = 0;
  }

  // Second Range, Warning Range, Mode2
  if (mode == 2) {

    float wavePeriod = mapfloat(led2Val, 0.0, 255.0, 3.0, 1.0);

    led1Val = sinWave(wavePeriod, PI, led2Val / 2, led2Val / 2);
    led2Val = sinWave(wavePeriod, 0.0, led2Val / 2, led2Val / 2);

    vibeCommandOne = 0.0;
    vibeCommandTwo = 0.0;

    //Serial.println(wavePeriod);

  }

  // Third Range, Danger Range, Mode3
  if (mode == 3) {

    float wavePeriod = mapfloat(led3Val, 0.0, 255.0, 2.0, 1.0);

    led1Val = squareWave(wavePeriod / 1.0, PI, led3Val);
    led2Val = squareWave(wavePeriod / 1.0, PI / 2.0, led3Val);
    led3Val = squareWave(wavePeriod / 1.0, 0.0, led3Val);

    vibeCommandOne = sinWave(wavePeriod / 2.0, 0.0, vibeCenter, vibeAmp);
    vibeCommandTwo = sinWave(wavePeriod / 2.0, PI, vibeCenter, vibeAmp);

    //Serial.println(wavePeriod);
  }



  // LED PWM Control! // ~~~~~~~~
  analogWrite( led1, led1Val );
  analogWrite( led2, led2Val );
  analogWrite( led3, led3Val );

  // Buzzers! // ~~~~~~~~

  // For debugging you can turn the buzzers off for sanity
  if (BUZZERS == false) {
    vibeCommandOne = 0;
    vibeCommandTwo = 0;
  }

  // Thresholding the PWM input values
  if (vibeCommandOne < 0) vibeCommandOne = 0;
  if (vibeCommandOne > vibeMax) vibeCommandOne = vibeMax;

  // Buzzer PWM Control
  analogWrite(vibePinOne, vibeCommandOne);
  analogWrite(vibePinTwo, vibeCommandTwo);



  Serial.println(average);

  if (PRINT_LEDS == true ) {
    Serial.print(average);
    Serial.print("\t");
    Serial.print(led1Val);
    Serial.print("\t");
    Serial.print(led2Val);
    Serial.print("\t");
    Serial.print(led3Val);
    Serial.print("\n");
  }

}


float sinWave(float period, float phase, float center, float amplitude) {

  //float period = 1.0;
  float frequency = 1 / period;
  //float phase = 0;
  float wave = 0.0;
  //Serial.println(seconds);
  return wave =   (sin(seconds * frequency * 1.0 + phase ) * (amplitude) + center); //magic 6.12

}


float squareWave(float period, float phase, float amplitude) {

  if ( period <= 0.001 ) return 0.0;

  int wave = 0;
  int periodMs = period * 1000; //convert to milliseconds
  int phaseMillis = (phase / (2.0 * PI)) * (periodMs);
  int ms = millis() + phaseMillis;

  if ( (ms % periodMs) >= (periodMs / 2) ) wave = amplitude;
  else wave = 0;

  return wave;

}

float movingAverage() {

  total = total - data[dataIndex];
  data[dataIndex] = micRaw;
  total = total + data[dataIndex];
  dataIndex = dataIndex + 1;

  if (dataIndex >= windowSize)
    dataIndex = 0;

  return ( total / windowSize );

}

float mapfloat(float x, float in_min, float in_max, float out_min, float out_max)
{
  // Modified version of skumlerud's function from
  // http://forum.arduino.cc/index.php?topic=3922.0
  return (float)(x - in_min) * (out_max - out_min) / (float)(in_max - in_min) + out_min;
}
Alex Alspach (2015) Click to Expand

Content Rating

Is this a good/useful/informative piece of content to include in the project? Have your say!

1