1

I'm trying to replicate a short music clip with two piezos, and I want them to play at the same time. While the right piezo is playing, I want the left one to still be looping. The problem is, I'm not sure how.

enter image description here

//Left hand
const int leftPin = 10; /Left pin
const int leftTones[] = {123.4, 103.83, 138.59, 92.50}; //The looping left tones
const int leftDelays[] = {700, 1300, 900, 900}; //How long those tones last
const int leftNotes = 4; //How many left notes there are

//Right hand const int rightPin = 2; //Right pin const int rightTones[] = {739.99, 587.33, 587.33, 659.25, 698.46, //The looping right tones 659.25, 587.33, 554.37, 587.33, 659.25, 739.99, 987.77, 493.88, 554.37, 587.33, 659.25, 587.33, 554.37, 880.00, 783.99, 739.99, 587.33, 587.33, 659.25, 698.46, 659.25, 587.33, 554.37, 587.33, 659.25, 739.99, 987.77, 987.77, 1108.73, 1174.66, 783.99, 739.99, 698.46, 1174.66, 1318.51}; const int rightDelays[] = {700, 1000, 100, 100, 300, 300, 200, //How long those tones last 300, 300, 200, 700, 700, 250, 150, 200, 400, 300, 300, 400, 200, 700, 1000, 100, 100, 300, 300, 200, 400, 300, 200, 700, 700, 300, 200, 400, 300, 200, 400, 300, 200}; const int rightNotes = 40; //How many right notes there are

void setup(){ pinMode(leftPin, OUTPUT); pinMode(rightPin, OUTPUT); delay(1000); }

void loop(){ for (int i = 0; i < leftNotes; i++){ tone(leftPin, leftTones[i]); delay(leftDelays[i]); noTone(leftPin); } for (int i = 0; i < rightNotes; i++){ tone(rightPin, rightTones[i]); delay(rightDelays[i]); noTone(rightPin); } }

With this code, the left piezo plays first, and then the right piezo plays. It should be at the same time.

Edited Code:

long currentMillis = 0;
long leftPreviousMillis = 0; // previous time for left hand
long rightPreviousMillis = 0; // previous time for right hand

const int leftNotes = 4; // The amount of left notes const int rightNotes = 40; // The amount of right notes int leftIndex = 0; // The specific index for the left piezo int rightIndex = 0; // The specific index for the right piezo const int leftPin = 10; // The left piezo const int rightPin = 2; // The right piezo

// The specific left pitches (as float) const float leftTones[] = {123.4, 103.83, 138.59, 92.50}; // How long the left pitches last for const long leftDelays[] = {700, 1300, 900, 900};

// The specific right pitches (as float) const float rightTones[] = {739.99, 587.33, 587.33, 659.25, 698.46, 659.25, 587.33, 554.37, 587.33, 659.25, 739.99, 987.77, 493.88, 554.37, 587.33, 659.25, 587.33, 554.37, 880.00, 783.99, 739.99, 587.33, 587.33, 659.25, 698.46, 659.25, 587.33, 554.37, 587.33, 659.25, 739.99, 987.77, 987.77, 1108.73, 1174.66, 783.99, 739.99, 698.46, 1174.66, 1318.51}; // How long the right pitches last for const long rightDelays[] = {700, 1000, 100, 100, 300, 300, 200, 300, 300, 200, 700, 700, 250, 150, 200, 400, 300, 300, 400, 200, 700, 1000, 100, 100, 300, 300, 200, 400, 300, 200, 700, 700, 300, 200, 400, 300, 200, 400, 300, 200};

void setup() { pinMode(leftPin, OUTPUT); pinMode(rightPin, OUTPUT); Serial.begin(9600); delay(1000); tone(rightPin, rightTones[rightIndex]); tone(leftPin, leftTones[leftIndex]); }

void loop() { currentMillis = millis(); // Left hand notes if (currentMillis - leftPreviousMillis >= leftDelays[leftIndex]) { noTone(leftPin); // Turn off the left note leftPreviousMillis = currentMillis; leftIndex++; if (leftIndex == leftNotes) // Reset left hand index leftIndex = 0; tone(leftPin, leftTones[leftIndex]); // Turn on the new left note }

// Right hand notes if (currentMillis - rightPreviousMillis >= rightDelays[rightIndex]) { noTone(rightPin); // Turn off the right note rightPreviousMillis = currentMillis; rightIndex++; if (rightIndex == rightNotes) // Reset right hand index rightIndex = 0; tone(rightPin, rightTones[rightIndex]); // Turn on the new right note } }

I've done some testing, and I think it's a problem with the tones function. Right now, this code only plays the right hand notes. The problem is this part:

tone(rightPin, rightTones[rightIndex]);
tone(leftPin, leftTones[leftIndex]);

When I do this:

tone(leftPin, leftTones[leftIndex]);
tone(rightPin, rightTones[rightIndex]);

Only the left hand notes are heard. But, it's not perfect. There's little beeps and buzzes every now and then. This leaves me with the conclusion that if there are two tones at the same time, it only plays the one it reads first. I've tested it with simpler code, and it stands true.

So that begs the question, is it even possible to use two piezos at the same time with one Arduino? I'm testing it with the Arduino simulator tinkercad, so maybe that's the problem? My code works for the left piezo, and the right piezo. But when you put them together, everything messes up.

Harrisino
  • 13
  • 3

2 Answers2

0

How do you use two piezos at the same time?

Consider using a finite state machine type of programming method.

As has been discovered, using calls to the delay() function (where the processor does nothing) blocks any other feature of the sketch (user's program). In a finite state machine programming pattern, there are no calls to the delay() function. Instead the sketch's loop() function is allowed to execute as fast as possible. The trick is to control what code is executed in the loop() function based on a state machine. And, in this case, use time to change between different states.

In an Arduino platform (the hardware and software you never or seldom see that makes up an Arduino) a counter is always tracking elapsed time. Use the millis() function to retrieve the current value in milliseconds (1000 milliseconds = 1 second) each time through the loop() function. Consider using a 2 state state machine. In the 1st state get the current counter value, add to it the delay in milliseconds of the next note, start the note playing and finally change the variable tracking states to the 2nd state. The next time through the loop() function, while in the 2nd state, check if the response from calling millis() again is larger then the value saved while in the 1st state. If it is, stop playing the note and change the variable tracking states to the 1st state.

Once working, create a second similar state machine to play the counter melody.

However, as delta-g has pointed out, the library picked out by the O.P. apparently can not play more than one note at a time. But,ve7jro has pointed out that this Arduino tunes library may be able to satisfy the requirement of playing 2 notes at the same time as stated in the O.P.'s question.

Creating a state machine in a invaluable programming lesson. However, this Arduino state machine library is available should the programmer wish to take advantage of it.

st2000
  • 7,513
  • 2
  • 13
  • 19
0

It's always good to look at the documentation when you have a question about how a piece of code works. In this case I looked at the page for the tone function which can be found here. https://www.arduino.cc/reference/en/language/functions/advanced-io/tone/

And the second sentence on that page says it all:

Only one tone can be generated at a time. If a tone is already playing on a different pin, the call to tone() will have no effect. If the tone is playing on the same pin, the call will set its frequency.

Delta_G
  • 3,391
  • 2
  • 13
  • 24