Being named Beethoven, I had to live up to my name somehow, so I decided to create a (very) mini piano.
What I had in mind was a button that acts as a switch, a potentiometer that affects the frequency of the notes, and seven buttons to be clicked as the basic fundamental notes (C4, D4, E4, F4, G4, A4, B4). So this is how I imagined my circuit to look like and it actually ended up being the same exact thing.
Interestingly, for this assignment, I faced challenges only in code and not in wiring at all. So I just kept changing my strategy of coding in order to suit what I was building.
So in my first trial, I used if conditions to play the notes according to the corresponding button. I made the potentiometer be like some kind of volume changer. When I tested the potentiometer only, it changed the volume from 0 to 255 perfectly and worked well using analogWrite().
I would write analogWrite(piezo, pwm) , where pwm is the mapped value of knobValue from 0 to 125.
When I used the buttons only and the function tone(), they worked perfectly fine and the switch worked too.
I would write tone(piezo, notes[i], 100).
But when I merged the two in code, it was weird. The switch button almost did not work, the buttons wouldn’t work if the switch was off, but the buzzer still produced some background noise all the time. In addition, the potentiometer would only turn on the keys after a certain point, and turn them before that, there was no spectrum but rather as if it was a switch. The circuit would only be silenced if the potentiometer was at 0 and while one of the keys was held.
In my second attempt, I tried to separate analogWrite() and tone() because I realized the two cannot work simultaneously on the same output device. So instead of changing volume I changed the frequency by keeping the range 0 to 1023 mapped into 0 to 100 and multiplying some of the keys by the mapped value (specifically the last button) and adding the value to the rest as you change the potentiometer.
But then I just felt like multiplying the frequencies by any number just produces an 8-bit very annoying sound, and adding the same number to them makes it actually hard to differentiate between them because they are all already not equal and have increasing values which differ by around 32 Hz. So I decided to dismiss the idea of changing the volume using the potentiometer like in trial 1 and stick to changing frequency like trial 2. I decided to make the mapping in range 0 to 32 (unlike trial 2) because that’s the average difference between them, and then I would add pwm to the first, 2*pwm to the second, 3*pwm to the third, … and so on, to keep the difference between them constant. I also chose a relatively low number so the tones could still be identifiable and fit in an instrument that can be bearable. I have to point out that the piezo that I have produces low quality sounds in any case so the videos might be a bit noisy.
The piano turned out to be not very enjoyable to be honest, but with more trials and better equipment, it could be improved and shaped into a more realistic one.
The code I used for this assignment:
#include "pitches.h" int button = 2; //button pin int key1 = 5; int key2 = 6; int key3 = 7; int key4 = 8; int key5 = 9; int key6 = 10; int key7 = 11; int notes[7] = {NOTE_C4, NOTE_D4, NOTE_E4, NOTE_F4, NOTE_G4, NOTE_A4, NOTE_B4}; //standard notes int piezo = 3; bool prevButtonState = LOW; //initializing button to be unpressed bool gameOn = false; int knob = A0; //pin of potentiometer void setup() { pinMode(button, INPUT); //button initialized as input pinMode(key1, INPUT); //button initialized as input pinMode(key2, INPUT); //button initialized as input pinMode(key3, INPUT); //button initialized as input pinMode(key4, INPUT); //button initialized as input pinMode(key5, INPUT); //button initialized as input pinMode(key6, INPUT); //button initialized as input pinMode(key7, INPUT); //button initialized as input, these are the piano keys pinMode(piezo, OUTPUT); //buzzer is output Serial.begin(9600); } void loop() { int buttonState = digitalRead(button); //storing reading from button Serial.println(buttonState); if (buttonState == HIGH && prevButtonState == LOW) { //if button is clicked change the piano states to their opposites gameOn = !gameOn; } if (gameOn == true) { //if the piano were previously off then were turned on by button int knobValue = analogRead(knob); //store reading from photocell int button1 = digitalRead(key1); int button2 = digitalRead(key2); int button3 = digitalRead(key3); int button4 = digitalRead(key4); int button5 = digitalRead(key5); int button6 = digitalRead(key6); int button7 = digitalRead(key7); //read current values from buttons/keys byte pwm = map(knobValue, 0, 1023, 0, 32); //mapping analog values into range of average difference between the standard notes Serial.println(knobValue); if (button1 == HIGH) { //if button is pressed tone(piezo, notes[0] + pwm, 100); //add to the standard frequency the corresponding value from potentiometer } if (button2 == HIGH) { tone(piezo, notes[1] + 2*pwm, 100); //add twice the value from potentiometer to frequency } if (button3 == HIGH) { tone(piezo, notes[2] + 3*pwm, 100); //add 3 times the values from potentiometer to frequency } if (button4 == HIGH) { tone(piezo, notes[3] + 4*pwm, 100); //add 4 times the values from potentiometer to frequency } if (button5 == HIGH) { tone(piezo, notes[4] + 5*pwm, 100); // add 5 times the values from potentiometer to frequency } if (button6 == HIGH) { tone(piezo, notes[5] + 6*pwm, 100); //add 6 times the values from potentiometer to frequency } if (button7 == HIGH) { tone(piezo, notes[6] + 7*pwm, 100); //add 7 times the values from potentiometer to frequency } if (button1 == LOW && button2 == LOW && button3 == LOW && button4 == LOW && button5 == LOW && button6 == LOW && button7 == LOW){ analogWrite(piezo, 255); //if none of the buttons is pressed then make buzzer make no noise } delay(10); } else { analogWrite(piezo, 255); //if the switch is off turn buzzer off } prevButtonState = buttonState; //update prevButtonState in each loop }