This is my most complex use of arduino yet and I'd really appricate some pointers. I've hit a brick wall, although I have a feeling the answer is simple-ish! I'm reading a GP2Y0A2YK0F Sharp Distance Sensor, smoothing the results (using the Smoothing code by David A. Mellis) and then using this average to choose different resistance values for the digital pot (MCP4261 - Dual 10K pot). The eventual idea is to replace the LED that is on the pot for testing purposes, with an audio signal so that the closer you are to the sensor the louder the volume. The problem is that I cannot get the LED to light even if there is only one case that will do so (case:0). If I use the example code in the Digipot library (by Stephen Jones - TchnclFl) the LED fades in out and nicely.
I suspected that the pots resistance was changing too rapidly for me to see so I put a delay in but to no avail.
Kind regards,
#include <DigiPot.h>
const int numReadings = 200;
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; // the average
int inputPin = A0;
DigiPot mcp4261(1, 2, 3); //Start a new instance called "mcp4251"
//format: DigiPot <instance>(CS, SCK, SDI)
void setup()
{
// initialize serial communication with computer:
Serial.begin(9600);
// initialize all the readings to 0:
for (int thisReading = 0; thisReading < numReadings; thisReading++)
readings[thisReading] = 0;
//Set the Digital pot to 0 Ohms
mcp4261.clear(0); //clear both pots; they default to 127
mcp4261.clear(1); //format: <instance>.clear(pot)....pot is either 0 or 1
}
void loop() {
// subtract the last reading:
total= total - readings[index];
// read from the sensor:
readings[index] = analogRead(inputPin);
// add the reading to the total:
total= total + readings[index];
// advance to the next position in the array:
index = index + 1;
// if we're at the end of the array...
if (index >= numReadings)
// ...wrap around to the beginning:
index = 0;
// calculate the average:
average = total / numReadings;
// send it to the computer (as ASCII digits)
float distance = 12343.85 * pow(analogRead(average),-1.15);
int range = map(distance, 8, 70, 0, 10);
//Need to increase the amount of switches to be maped or use Else If statements
// do something different depending on the
// range value:
switch (range) {
case 0: // your hand is on the sensor
Serial.println("Full Volume");
mcp4261.write(0, 255);
delay(1000);
break;
case 1: // your hand is close to the sensor
Serial.println("Loud");
mcp4261.write(0, 0);
break;
case 2: // your hand is a few inches from the sensor
Serial.println("3/4 Volume");
mcp4261.write(0, 0);
break;
case 3: // your hand is nowhere near the sensor
Serial.println("Half Volume");
mcp4261.write(0, 0);
break;
case 4: // your hand is nowhere near the sensor
Serial.println("Half Volume");
mcp4261.write(0, 0);
break;
case 5: // your hand is nowhere near the sensor
Serial.println("Half Volume");
mcp4261.write(0, 0);
break;
case 6: // your hand is nowhere near the sensor
Serial.println("Quiet");
mcp4261.write(0, 0);
break;
case 7: // your hand is nowhere near the sensor
Serial.println("Silent");
mcp4261.write(0, 0);
break;
case 8: // your hand is nowhere near the sensor
Serial.println("Silent");
mcp4261.write(0, 0);
break;
case 9: // your hand is nowhere near the sensor
Serial.println("Silent");
mcp4261.write(0, 0);
break;
}
}
You have Serial.print() statements in your code already, so presumably you know how to use them.
What value are you getting from the analogRead(inputPin) call? Is it reasonable?
Does the average match the expected average from numReadings readings?
Is the distance value reasonable? When you put your hand in front of the sensor, does the value match the distance between hand and sensor, in a reasonable fashion?
Is that value actually in the range 7 to 80? What value do you get from the map function? -13 is probably not a reasonable value. Nor is 27. But, we have no idea what values you actually get.
You are only writing two values to the digital pot - full on and full off. Is that by design? If so, what is the role of the sensor?
At the moment I have purposely restricted the the scope of the pot just for testing. All the values are being mapped onto these 10 case(s) and the serial monitor is reporting the distance fine (i.e a few cms away and it's reporting "Full Volume", further away "3/4 Volume" etc etc). As it stands the sensor is doing it's job.
To answer your questions. I'm converting the voltage to centimetres using float distance = 12343.85 * pow(analogRead(average),-1.15); and then mapping this range from 0 to 10 (8 cm is the nearest distance before the data is gibberish and 80cm seemed a good far distance).
In the future I'd like to have 20 or more degrees of volume. Since the output of the sensor is always moving I thought I'd "bound" the data in ranges (although it might be the case that you cannot hear the minute volume fluctuations)
In the future I'd like to have 20 or more degrees of volume. Since the output of the sensor is always moving I thought I'd "bound" the data in ranges (although it might be the case that you cannot hear the minute volume fluctuations
If you mapped the sensor output to the range 0 to 255, you could use the value directly - no need to use a switch statement at all.
int inputPin = A0;
The A0 alias is the value of an analog pin being used as a digital pin. That is not what you are doing, so you shouldn't be using this alias. In my opinion, these aliases are poorly documented, and used inappropriately (i.e. wrong) in too many examples, and cause more grief than they alleviate.
DigiPot mcp4261(1, 2, 3); //Start a new instance called "mcp4251"
If you mapped the sensor output to the range 0 to 255, you could use the value directly - no need to use a switch statement at all.
I could and will do that if the constantly moving resistance is not audible.
I've changed int inputPin = A0; to 0 - Why do you say that it is being used as a digital pin?
Sorry this I should of explained:
DigiPot mcp4261(1, 2, 3); //Start a new instance called "mcp4251"
//format: DigiPot (CS, SCK, SDI).
Although as I'm using a library I not really sure how they function. All I've got to do is make sure that these line up correctly with the inputs on the digital pot. I've made sure the instance name is correct throughout.
Since you want to read from an analog pin, as evidenced by this statement,
readings[index] = analogRead(inputPin);
you do not want to reference pin 14. You want to reference pin 0.
//format: DigiPot (CS, SCK, SDI).
So, these refer to digital pins.
You are already using pins 0 and 1 for serial communication.
Serial.println("Full Volume");
So, you can't use pin 1 here, too.
DigiPot mcp4261(1, 2, 3); //Start a new instance called "mcp4251"
You need to follow Major Charles Emerson Winchester the Third's advice "I do one thing at a time, and I do that very well!" Trying to use pin 1 as part of the serial port and as a chip select pin will cause the chip to not work when you need it to, like now.
Of course! I had a feeling that I should shift over the pins used with communication! Works well, now to see if it will work as an audio fader (that may be a whole other topic regarding power supply de-coupling and like!)
Typically, volume controls do not use linear potentiometers, so you may have some work to do to make a linear potentiometer emulate an audio potentiometer. But, I'm sure you can get something reasonable for a finite number of steps.
You're right (volume i.e sound pressure level being a logarithmic scale) and the value of the digital pot is probably too small to completely silence the signal (which is the case as I've hooked up the audio now). For noise I could always use an opto-isolator controlled by the digital pot.