Christmas gift code problem

Hi,

I am a noob who is trying hard to learn. I am attempting to make a Christmas gift for my daughter. She is a huge fan of the TV show Supernatural. I am trying to make a simple toy version of their EMF detector so she can go around the house hunting "demons". If you have seen the show you will know what I mean.

I have put together something using a couple of tutorials (here is one http://blog.makezine.com/2009/05/15/making-the-arduino-emf-detector/). I know it's not a real EMF detector, it's the lights and sound that is important here :wink:

I have the LEDs lighting up properly, but I have tried to add sound based on a code for a Pitch Follower and I am not getting any sound from my speaker. I checked to make sure the speaker is working. Could someone check out my code and see whether there is anything obvious wrong?

Any help would be greatly appreciated. :blush:

//Pitch follower and sequential LED lighter

//Plays a pitch and lights LEDs based on a changing analog input

//8-ohm speaker on digital pin 8

//"antenna in analog pin 5



//====constants=====//

const int NUM_READINGS=15;//raise this number to increase data smoothing for LEDs

const int SENSE_LIMIT=15;//raise this number to decrease LED sensitivity (up to 1023 max)



const int LEDS=5;

const int LED_PINS[LEDS]={2, 3, 4, 5, 6};

const int LED_THRESHOLDS[LEDS]={50, 150, 250, 350, 450};//what value the reading should be for LED i to light



const int PROBE_PIN=5;//analog input for both LEDs and pitch following



//=====global variables=====//

//variables for smoothing

int gReadings[NUM_READINGS];//the readings from the analog input

int gIndex=0;//the index of the current reading

int gTotal=0;//the running total



//=====main=====//

void setup(){

	Serial.begin(9600);

	for(int i=0; i<LEDS; ++i) pinMode(LED_PINS[i], OUTPUT);

	for(int i=0; i<NUM_READINGS; ++i) gReadings[i]=0;

}



void loop(){

	int sensorReading=analogRead(PROBE_PIN);

	

	//-----pitch following-----//

	//print the sensor reading so you know its range

	Serial.println(sensorReading);

	//map the analog input range (in this case, 400 - 1000 from the photoresistor)

	//to the output pitch range (120 - 1500Hz)

	//change the minimum and maximum input numbers below

	//depending on the range your sensor's giving:

	int thisPitch=map(sensorReading, 400, 1000, 120, 1500);

	//play the pitch:

	tone(9, thisPitch, 10);

	

	//-----LEDs-----//

	int val=constrain(sensorReading, 1, SENSE_LIMIT);//constrain between 1 and SENSE_LIMIT

	val=map(val, 1, SENSE_LIMIT, 1, 1023);//remap the constrained value to a 1 to 1023 range

	gTotal-=gReadings[gIndex];//subtract the oldest reading

	gReadings[gIndex]=val;

	gTotal+=gReadings[gIndex];//add the new reading to the total

	++gIndex;

	gIndex%=NUM_READINGS;

	int average=gTotal/NUM_READINGS;

	for(int i=0; i<LEDS; ++i) digitalWrite(LED_PINS[i], (average>LED_THRESHOLDS[i])?HIGH:LOW);

	

	delay(1);//delay in between reads for stability

}

Speaker at pin 8, tone at pin 9 ?

You are using analog readings of 0 to 15 to light the LEDs but you appear to be using readings og 400 to 1000 for your pitch. You may not be getting value near that range.

Since the LEDs are working you should try using that value for the pitch. Instead of:

	int thisPitch=map(sensorReading, 400, 1000, 120, 1500);

	//play the pitch:
	tone(9, thisPitch, 10);

Try something like:

	int average=gTotal/NUM_READINGS;

	for(int i=0; i<LEDS; ++i) 
            digitalWrite(LED_PINS[i], (average>LED_THRESHOLDS[i])?HIGH:LOW);

        tone(9, map(average, 0,450,120,1500), 10);  // Play tone

arduinokov:

	int thisPitch=map(sensorReading, 400, 1000, 120, 1500);
tone(9, thisPitch, 10);

That would seem to define a frequency in the range 120Hz - 1500Hz and play it for 10 milliseconds. Those frequencies seem a little on the low side and you might want to compare them with the range supported by your speaker (small speakers don't usually support low frequencies). The duration of 10ms is obviously far too short to be heard. Perhaps you intended 10000ms (ten seconds)?

Thanks for all the answers. I think I left out an important fact. I was able to use the following code on a breadboard with my current speaker and it worked perfectly. It was when Itried to combine it into my LED code that I ran into the problem of no sound.

// Pitch follower
 
//Plays a pitch that changes based on a changing analog input
 
//circuit:
//* 8-ohm speaker on digital pin 8
// * photoresistor on analog 0 to 5V
// * 4.7K resistor on analog 0 to ground
 
//This example code is in the public domain.
//http://arduino.cc/en/Tutorial/Tone2
 



void setup() {
  // initialize serial communications (for debugging only):
  Serial.begin(9600);
}

void loop() {
  // read the sensor:
  int sensorReading = analogRead(A0);
  // print the sensor reading so you know its range
  Serial.println(sensorReading);
  // map the analog input range (in this case, 400 - 1000 from the photoresistor)
  // to the output pitch range (120 - 1500Hz)
  // change the minimum and maximum input numbers below
  // depending on the range your sensor's giving:
  int thisPitch = map(sensorReading, 400, 1000, 120, 1500);

  // play the pitch:
  tone(9, thisPitch, 10);
  delay(1);        // delay in between reads for stability
}

I suggest you remove the third parameter from the call to tone(), so that the output continues until loop() runs again and redefines the output frequency.

I don't know whether it's safe to call tone() very frequently - it seems to me that this could easily cause the output timing code to reset, preventing it from actually producing a changing output. It might be safer to slow down the loop() so that it runs e.g. once every 100ms so that you definitely have time to produce some complete output waves before the next sample.

What actual frequencies were you passing to tone() in the original, working sketch and how frequently were you calling tone()? Same question for the new, non-working sketch.

Is the hardware setup identical in both cases?

I have two breadboard projects set up. Separately, they work perfectly. It's just combining them to work with just the one analog input from pin 5 that is causing the problem.

First code:

// EMF Detector with LEDs


#define NUMREADINGS 15 // raise this number to increase data smoothing

int senseLimit = 15; // raise this number to decrease sensitivity (up to 1023 max)
int probePin = 5; // analog 5
int val = 0; // reading from probePin

// connections to LEDs with resistors in series

int LED6 = 6;
int LED5 = 5;
int LED4 = 4;
int LED3 = 3;
int LED2 = 2;

// variables for smoothing

int readings[NUMREADINGS];                // the readings from the analog input
int index = 0;                            // the index of the current reading
int total = 0;                            // the running total
int average = 0;                          // final average of the probe reading


void setup() {

  pinMode(2, OUTPUT);  // specify LED outputs
  pinMode(3, OUTPUT); 
  pinMode(4, OUTPUT); 
  pinMode(5, OUTPUT); 
  pinMode(6, OUTPUT); 

  Serial.begin(9600);  // initiate serial connection for debugging/etc

  for (int i = 0; i < NUMREADINGS; i++)
    readings[i] = 0;                      // initialize all the readings to 0
}

void loop() {

  val = analogRead(probePin);  // take a reading from the probe

  if(val >= 1){                // if the reading isn't zero, proceed

    val = constrain(val, 1, senseLimit);  // turn any reading higher than the senseLimit value into the senseLimit value
    val = map(val, 1, senseLimit, 1, 1023);  // remap the constrained value within a 1 to 1023 range

    total -= readings[index];               // subtract the last reading
    readings[index] = val; // read from the sensor
    total += readings[index];               // add the reading to the total
    index = (index + 1);                    // advance to the next index

    if (index >= NUMREADINGS)               // if we're at the end of the array...
      index = 0;                            // ...wrap around to the beginning

    average = total / NUMREADINGS;          // calculate the average


    if (average > 50){                // if the average is over 50 ...
      digitalWrite(LED2, HIGH);   // light the first LED
    }
    else{                         // and if it's not ...
      digitalWrite(LED2, LOW);    // turn that LED off
    }


    if (average > 150){               // and so on ...
      digitalWrite(LED3, HIGH);
    }
    else{
      digitalWrite(LED3, LOW);
    }

    if (average > 250){
      digitalWrite(LED4, HIGH);
    }
    else{
      digitalWrite(LED4, LOW);
    }

    if (average > 350){
      digitalWrite(LED5, HIGH);
    }
    else{
      digitalWrite(LED5, LOW);
    }

    if (average > 450){
      digitalWrite(LED6, HIGH);
    }
    else{
      digitalWrite(LED6, LOW);
    }


    Serial.println(val); // use output to aid in calibrating
  }
}

Second code (the sound from the speaker works just fine here):

// Pitch follower
 
//Plays a pitch that changes based on a changing analog input
 
//circuit:
//* 8-ohm speaker on digital pin 8
// * photoresistor on analog 0 to 5V
// * 4.7K resistor on analog 0 to ground
 
//This example code is in the public domain.
//http://arduino.cc/en/Tutorial/Tone2
 



void setup() {
  // initialize serial communications (for debugging only):
  Serial.begin(9600);
}

void loop() {
  // read the sensor:
  int sensorReading = analogRead(A0);
  // print the sensor reading so you know its range
  Serial.println(sensorReading);
  // map the analog input range (in this case, 400 - 1000 from the photoresistor)
  // to the output pitch range (120 - 1500Hz)
  // change the minimum and maximum input numbers below
  // depending on the range your sensor's giving:
  int thisPitch = map(sensorReading, 400, 1000, 120, 1500);

  // play the pitch:
  tone(9, thisPitch, 10);
  delay(1);        // delay in between reads for stability
}