pulseIn, map(), and tone() interfere?

I took the accelerometer out of a joystick I had, and I’m just playing around with it. However I ran into something rather strange.
Usually I’ve just missed something in my code but I’ve been staring at my screen for hours now.

When I use a sketch with nothing but a pulseIn() to read the accelerometer it gives about 300-600.
However in the sketch below it returns 25-35 ???

The idea is that tilting the arduino changes the pitch from a speaker.

int array[20];
int average = 0;
int freq = 0;
int pulse = 0;

void setup() {
  Serial.begin(9600);
  pinMode(8, OUTPUT);
  
}

void loop() {
  
  for (int x = 0; x < 19; x++) {  //Shift each number leaving [19] open
    array[x] = array[x+1];
  }
  
  
  pulse = pulseIn(2, HIGH);
  array[19] = pulse; //give [19] a new value

  Serial.print(array[19]);
  Serial.print("\t");
        
  for (int y = 0; y < 20; y++) {  // add the sum of the entire array to average
    average += array[y];
  }
  
  average = average/20;   //devide average to obtain the actual average
  
  Serial.print(average);
  Serial.print("\t");
   
  freq = map(average, 320, 520, 100, 1000);  //Remap to a range for the speaker
  
  average = 0;  //reset average
  
  Serial.println(freq);
  
  tone(8, freq);   //start tone or change pitch

}

As it is right now the serial reads average as ~30, and freq at about -600

Here are some things (that I know of so far) that when changed make the sketch perform as expected:

remove “tone(8, freq);”
add a duration < 15 to "tone(); ex. tone(8, freq, 10);
remove “freq = map(average, 320, 520, 100, 1000);”
change fromLow to anything < 100
remove “pulseIn(2, HIGH);”

I don’t understand how changing the map() would affect the pulseIn() reading.

  freq = map(average, 320, 520, 100, 1000);  //Remap to a range for the speaker

As it is right now the serial reads average as ~30, and freq at about -600

The map function generally is easier to understand when the value to be mapped is in the from range. 30 is not, so getting a value out that is in the to range is impossible.

Perhaps you could explain your choice of ranges.

Of course, calling the tone function with a negative value is not advised.

Perhaps you could explain your choice of ranges.

The map() is not behaving strangely, the pulseIn() is,

When I first measured the range of the accelerometer, I found it to be between 320 and 520. However when I added the map() into the sketch, the value read by pulseIn() jumped down to ~30. If I change the map()'s fromLow to 30, then the value I get from pulseIn() jumps back up to where it should be.

The map function generally is easier to understand when the value to be mapped is in the from range. 30 is not, so getting a value out that is in the to range is impossible.

check the constrain function x = constrain(x, lower, upper) - one of the underappreciated functions ;)

check the constrain function x = constrain(x, lower, upper) - one of the underappreciated functions

Wonderful! I added a constrain which seems to help.

average = average/20;
  
  average = constrain(average, 320, 600);
  
  Serial.print(average);
  Serial.print("\t");
  
  
  freq = map(average, 320, 500, 50, 2000);

If the lower constrain value is less than the map's fromLow it still goes berzerk. Something about that pulseIn... But whatever, I don't need it to go lower. Still weird though... Thanks for your help.

make that

#define LOWERIN 320
#define UPPERIN 600
#define LOWEROUT 50
#define UPPEROUT 2000

average = average/20;
  
average = constrain(average, LOWERIN , UPPERIN );
  
Serial.print(average);
Serial.print("\t");

freq = map(average, LOWERIN , UPPERIN , LOWEROUT , UPPEROUT );

you could write a wrapper function to do this automatically:

long constrainedMap(long x, long a, long b, long c, long d)
{
  return map(constrain(x,a,b),a,b,c,d);
}

I'd be hesitant to #define. I may want want the scale to change. For now that's certainly what I'll do. I like the idea of the function as well.

Thanks.

I'd be hesitant to #define. I may want want the scale to change

The advantage of #define is that you need to change the #define/constant only in one place, and it will be used all over your code (good names is half the work)

If you want to use a runtime definable range you need a variable. #defines are even more usefull then as defaults and for the reset() function. ;)

With #define you change al those magic numbers (scalar only) in your code to something that has a name (unit with semantic meaning)

The difference between if ( ti > 100)... versus if (ti > TIMETHRESHOLD) ...

So I should use something like this:

#define LOWERIN 320
#define UPPERIN 600
#define LOWEROUT 50
#define UPPEROUT 2000

#define OFFSET 200

average = map(average, LOWERIN-OFFSET, UPPERIN, LOWEROUT, UPPEROUT);

That just doesn't seem very practical. It's more dynamic without defining... Although I certainly see why one would define. I guess these are the types of things I'll learn over the years as I continue.

It's more dynamic without defining

What is more dynamic? The #define statements are removed by the precompiler after performing the specified character substitutions, so the compiler produces exactly the same output as if you had coded:

average = map(average, 320-200, 600, 50, 2000);

That just doesn't seem very practical.

Why not? It looks much more practical to me than the above code, especially if those constant values are used in multiple places.

What is more dynamic?

Quote That just doesn't seem very practical.

Why not?

A integer can be manipulated, added to, subtracted from. you can't say LOWERIN += ANOTHERNUMBER; Or can you?

But you could with int.

you can't say LOWERIN += ANOTHERNUMBER; Or can you?

No, because LOWERIN is (supposed to be) a constant. You could do:

int val = analogRead(pin) + ANOTHERNUMBER;