Projet 07 - Can't play keys simultaneously

Hello,

I've recently acquired a starter kit, and am currently working on Project 07 - Keyboard Instrument. I can play notes individually and it works fine, but when I press two buttons simultaneously, analogRead returns the value associated with only one of them (the one whose associated "if" statement appears first in my code). I don't know exactly what values I should get, but the Projects Book does state that I should get a unique value, different from the ones I get when I press only one button at a time.

It would be no use to post a schematic diagram for my system, since I believe (perhaps wrongly) that I've built my circuit exactly how the book told me to. So here's a photo from the book:

And just for comparison, here's the book's illustration:

And a photo of my circuit:

My code:

int notes[6] = {262, 294, 330, 349};

void setup() {
  Serial.begin(9600);
}

void loop() {
  int keyVal = analogRead(A0);
  Serial.println(keyVal);
  if(keyVal >= 1015){
    tone(8, notes[0]);
  }
  else if(keyVal >= 990 && keyVal <= 1010){
    tone(8, notes[1]);
  }
  else if(keyVal >= 490 && keyVal <= 510){
    tone(8, notes[2]);
  }
  else if(keyVal >= 15 && keyVal <= 25){
    tone(8, notes[3]);
  }
  else{
    noTone(8);
  }
}

It differs from the code in the book only slightly; I had to adjust the values in the "if" statements just a little. But like I said, the keyboard works just fine when I press only one button at a time, so if there's a problem I don't think it comes from the code.

I know I shouldn't expect to hear a new note when I press two buttons at once, since my code only takes into consideration the analog values for individual buttons; like I said above, what concerns me is what I see in the serial monitor. I only ever see 5 values: around 1023 when I press the first button, around 1000 for the second button, around 500 for the third, around 20 for the fourth, and around 10 when I press no button (which I think indicates my circuit is noisy?).

Any help appreciated.

Your code is ONLY looking for very specific ranges of values, so there should be NO expectation of anything different. If you want differences, then you have to code for them.

is no "problem". Only one if-condition can be true at a time and tone() can only make one note at a time.

You have a voltage divider which determines the voltage (and ADC reading) depending on which button(s) are pressed.

When more than button is pushed the "top" resistance in the voltage divider is the result of two (or more) resistors in parallel. (parallel resistors)

In parallel, there are two (or more) paths for current so there is less resistance to current flow. With two equal resistor values, the resistance is cut in half.

In this case where one resistor has much lower resistance than the other, the lower resistance will "dominate".

...Personally, I kind-of HATE to see analog used in cases like this where we really want digital. :face_with_tongue: But it's OK as a learning exercise or if you don't have enough digital inputs, etc.

Thank you for your answers.

Like I said, I know I shouldn't expect to hear a new note, but I should see something different in the serial monitor, according to the book. It prints the ADC readings regardless of whether they're taken care of by my code.

This doesn't seem to be consistent with what the book says, namely:

"You'll connect up a number of switches that are connected in parallel to Analog In 0. (...) If you press two buttons simultaneously, you'll get a unique input based on the relationship between the two resistors in parallel."

And on another page:

"Press multiple buttons simultaneously and see what values you get in the serial monitor. Use the new values to play even more sounds."

Am I missing something?

You write different code and wire a different configuration and expect it to work exactly as the instructions describe?

The only things I've changed in the code are the ranges in the if-statements. Like the book says, you have to account for resistor tolerances, which is what I did based on my ADC readings, but I didn't change the values by much.

As for the wiring, perhaps you misunderstood what I said: to the best of my knowledge, I've replicated the wiring presented in the book. If I had to draw a schematic, it would be the exact same. Emphasis on "to the best of my knowledge"; there's a possibility I messed up somewhere since I'm new to this.

Problem is that the values of the resistors, 220, 10K, and 1M, are so far apart that two of them in parallel does not make enough difference in a 10-bit ADC. As an example, 220 in parallel with 10K is about 215, 10K in parallel with 1M is about 9900. 10K should give an input value of 512, 9900 would be about 509, not enough to differentiate from noise.

One of the characteristics of this technique for putting multiple switches onto a single analog input is that only one switch is intended to be closed at a time.

Oh, I think I get it now. That's unfortunate. I could try to narrow the ranges, but I think my circuit's too noisy for that. I'll see what I can do with the other resistors in the kit.

Thank you!

Nonsense. There is no noise source in your project. Use you DVM, digital volt meter to measure the voltage when you press two buttons and convert that to what your A/D returns as a value.

What I meant is that there's a lot of fluctuation in my readings. For instance, in the light theremin project, the note it played when I did nothing and stayed away from the photo-transistor should have been steady, but it wasn't. The pitch was all over the place, and changing very rapidly, in line with the readings I saw in the serial monitor.

In this project, even with a pull-down resistor, analogRead() returns values between 5 and 15 when I don't press any button, when in the book, those values are encompassed in the if-condition of the last button, i.e. instead of else if(keyVal >= 15 && keyVal <= 25) as in my code, the book has else if(keyVal >= 5 && keyVal <= 10). So I interpreted it as my circuit being noisy, but perhaps I was wrong.

I'm not sure what you mean by that. When you say "DVM", you mean I can use one of my analog inputs as one, or do you mean something else? If the former, I've already done it, but like I said I don't get anything different when I press two buttons at once. Well, actually, I've rewired the circuit, and while this is still true for most combinations, one of them gives me something slightly different. Namely, Button #3, associated with a 10k resistor, gives me something around 500 when pressed alone; Button #4 (1M resistor) is around 20; when I press them simultaneously, I get something around 503. But those are averages and they're way too close, so when I implement the adequate changes in my code and associate a fifth tone with this combination, the results are inconsistent.

What I mean is for you to use a different, accurate, device to actually measure the voltages that your Arduino program is attempting to measure. In addition, actually measure the voltage that is being used as a comparison base for the A/D part of your Arduino. How much does the Arduino power vary while you are pressing the buttons?

You could use the reading of A0, and "note" (heh) the values on all button combinations.

void setup() {
  Serial.begin(115200);
}

void loop() {
  Serial.println( analogRead(A0));
  delay(500);
}

A grid...

NONE pressed = 
ALL pressed  =
    |  B0   |  B1  |  B2  |  B3  |B0+B1 |B0+B2 |B0+B3 |B1+B2 |B1+B3 |B2+B3 |
----+-------+------+------+------+------+------+------+------+------+------+
B0  |  x    |      |      |      |  x   |  x   |  x   |      |      |      |
----+-------+------+------+------+------+------+------+------+------+------+
B1  |  x    |  x   |      |      |  x   |      |      |  x   |  x   |      |
----+-------+------+------+------+------+------+------+------+------+------+
B2  |  x    |  x   |  x   |      |      |  x   |      |  x   |      |  x   |
----+-------+------+------+------+------+------+------+------+------+------+
B3  |  x    |  x   |  x   |  x   |      |      |  x   |      |  x   |  x   |
----+-------+------+------+------+------+------+------+------+------+------+

I've just tried it with my multimeter; like with analogRead(), pressing multiple buttons always returns the same value as when I press the one associated with the lower resistance individually, except the combination of buttons #3 and #4. But like in the analogRead() version of the experiment, the difference between the two is negligible (#3 alone: 2.37V; #3+#4: 2.38V).

My DMM only shows three digits, and I've gotten it very recently for 18 euros on Amazon; I don't know how accurate it is.

I had already done it!

I've also tried something based on david_2018's reply: using resistors that weren't as far apart as the ones the book told me to. Namely, 100, 220 and 330 ohms, but I've kept the 10k resistor to ground like in the book (maybe I shouldn't? I'm not entirely sure what its purpose is). In addition, I've switched to 12-bit resolution. This time it was much better, and I was able to get two more tones/combinations relatively consistently, but still not very cleanly.

What are the values and the buttons used?

I've done it with two resistor configurations; the numbers in parenthesis are the values of the resistors, starting with Button 2 (Button 1 has no resistor attached to it; see diagram in my first post).

I've made a calibration test of sorts. The values were recorded (and the mean calculated) each for 15 seconds.

Configuration 1 (220, 10k, 1M):

B1:    min=1007, max=1023, mean=1022
B2:    min=997,  max=1005, mean=1001
B3:    min=495,  max=504,  mean=499
B4:    min=15,   max=25,   mean=19

B1+B2: min=1008, max=1023, mean=1022
B1+B3: min=1010, max=1023, mean=1022
B1+B4: min=1006, max=1023, mean=1022
B2+B3: min=994,  max=1009, mean=1002
B2+B4: min=999,  max=1006, mean=1001
B3+B4: min=499,  max=504,  mean=502

Configuration 2 (100, 220, 330):

B1:    min=1012, max=1023, mean=1022
B2:    min=1009, max=1019, mean=1013
B3:    min=995,  max=1010, mean=1001
B4:    min=989,  max=994,  mean=991

B1+B2: min=1019, max=1023, mean=1022
B1+B3: min=1008, max=1023, mean=1022
B1+B4: min=1010, max=1023, mean=1022
B2+B3: min=1012, max=1023, mean=1017
B2+B4: min=1013, max=1023, mean=1016
B3+B4: min=1003, max=1012, mean=1010

You are using the Arduino power for the A/D measurement standard and it is NOT a steady voltage. Change your program to use an internal voltage standard.

I've tried with a 9V battery, but it's not optimal because the connection between the ends of the battery snap and the Arduino pins isn't very good and it keeps disconnecting and reconnecting; I suppose I could make the connection better by stripping a little more of the wires, but I don't have a stripper handy right now. I'll definitely try that when I can.

But I was able to almost solve the biggest problem with this project: the resistor values just aren't right for this, like david_2018 said. So I've made some changes to my configuration: first, I connected the first button to a resistor (the project as presented in the book had it connected to power directly, which made it unusable in combination with other buttons); then I changed the analog read resolution to 12 bits; lastly, I made a program that finds the best configuration of four resistors from a list of all the resistor values you have at your disposal. Basically it performs a circuit analysis of all the possible combinations, and returns the one whose button presses (of one or more buttons simultaneously) are the most distinguishable.

Out of my 10, 100, 220, 330, 560, 1k, 2k, 4.7k, 5.1k, 10k, 100k, 1M, 10M resistors, it picked 1k, 2k, 4.7k and 10k, and I'm now able to get 9 tones from my four buttons! I've stuck with 2-button simultaneous presses; I suppose I could have tested for the four 3-button presses and the 4-button one, but I didn't.

There is actually a tenth tone I should be able to get with one of the 2-button presses, but for some reason it doesn't work... And two other ones sound a little strange. I'll try to find out more tomorrow, but for now I'll call it a day.

I've coded the program in Python, but if anyone's interested I can share. Note that the criterion I've chosen to determine the best configuration could probably be improved: the program looks for the config with the largest difference between its two closest voltages. The downside to that is that it could in theory pick a config whose voltages are all very close together, and discard another where all the voltages except one pair of them are far apart, for instance; one could argue the latter would be preferable.

Here's my table of values for this config, by the way:

Configuration 3 (1k, 2k, 4.7k, 10k)


B1:    min=3713, max=3741, mean:3723
B2:    min=3376, max=3421, mean:3400
B3:    min=2721, max=2751, mean=2743
B4:    min=1997, max=2028, mean=2003

B1+B2: min=3811, max=3870, mean=3840
B1+B3: min=3778, max=3821, mean=3784
B1+B4: min=3749, max=3776, mean=3755
B2+B3: min=3576, max=3591, mean=3586
B2+B4: min=3460, max=3521, mean=3503
B3+B4: min=3052, max=3104, mean=3075

Update: I've stripped the battery snap's wires, which made the connection a little better. The results I get using the battery instead of USB power are noticeably more consistent indeed; thanks for the suggestion!

I've also found the problem with the button combination that didn't work. It was the dumbest of problems; at one point I had deleted one of the frequencies/notes from my array, so there was no tenth note to play haha.

For the two tones that sounded strange, things are a little more complicated. Ultimately it's because the voltages associated with them are a little too close together, but I noticed that the values I got were pretty different depending on whether I was using Serial.print() during the measurements or not.

Anyway, I did what needed to be done, and now I got my ten tones to sound like they should.

Thanks to all of you for your help.