That's a very useful reference for this. Thanks to that and your previous explanation, I think I'm going to get this. Chris, you've been a huge help.
I've now got the Tone code updated, and the first part of the project works. Because the speaker is loud and low-quality, I chose not to play a sound when an individual LED lights up to show the unlock sequence, marked in the code as
@TODO
in case I'd like to include it later. Pressing a button does make a sound in addition to lighting an LED.
If I understand correctly, I could also bring the volume down by adding a resistor (in series? 8 ohm to match the speaker? could I use 10 ohms, which I already have?). I see there's also this clever library option (3 links, same project, slightly different documentation)
https://create.arduino.cc/projecthub/connornishijima/tone-with-8-bit-volume-control-no-extra-components-370c66
https://github.com/connornishijima/arduino-volume1
https://hackaday.io/project/11957-10-bit-component-less-volume-control-for-arduino
but that's outside the scope of the project. I'll look into it for the next speaker project.
Now I'm going to add the Servo motion, using the original Servo library, inserting the instructions at the points marked with TODO (no '@').
Getting close! I'm excited.
const int OPEN_CNT = 4;
byte speakerPin = 8;
int notes[]= {262, 294, 330, 349, 523}; //4 notes of middle C, D, E, and F, then up an octave to C again. The values are in Hz.
//boolean button[] = {2, 3, 4, 5}; //The four button input pins
//boolean ledpin[] = {8, 9, 10, 11}; // LED pins
int button[] = {15, 16, 17, 18}; //The four button input pins
int ledpin[] = {2, 3, 4, 5}; // LED pins
int turn = 0; // turn counter
int buttonstate = 0; // button state checker
int randomArray[100]; //Intentionally long to store up to 100 inputs (doubtful anyone will get this far)
int inputArray[100];
bool wait4nextBtn = true;
// TODO import the Servo library
// TODO create an instance of the Servo library
// ===================================================
void setup()
{
Serial.begin(9600);
tone(8, notes[0]);
// TODO attach the servo to pin 9
// TODO move the servo to the locked position
// TODO print status to the Serial Monitor
for (int x = 0; x < 4; x++) // LED pins are outputs
{
pinMode(ledpin[x], OUTPUT);
pinMode(button[x], INPUT_PULLUP); // button pins are inputs
}
randomSeed(analogRead(0)); //Added to generate "more randomness" with the randomArray for the output function
for (int thisNote = 0; thisNote < 4; thisNote ++)
{
// play the next note:
tone(8, notes[thisNote], 100);
if (thisNote == 0) digitalWrite(ledpin[0], HIGH);
else if (thisNote == 1) digitalWrite(ledpin[1], HIGH);
else if (thisNote == 2) digitalWrite(ledpin[2], HIGH);
else if (thisNote == 3) digitalWrite(ledpin[3], HIGH);
delay(200);
allLEDs(LOW);
}
delay(100);
}
// ========================================================
void loop() // This 'loop' is automatically run repeatedly
{
for (int level = 0; level <= 99; level++)
{
allLEDs(LOW);
Serial.print("\n Turn: "); // Some serial output to follow along
Serial.print(turn);
if (turn==OPEN_CNT) {
// Code for victory sound and lights
for (int thisNote = 0; thisNote < 4; thisNote ++)
{
// play the next note:
tone(8, notes[thisNote], 100);
if (thisNote == 0) digitalWrite(ledpin[0], HIGH);
else if (thisNote == 1) digitalWrite(ledpin[1], HIGH);
else if (thisNote == 2) digitalWrite(ledpin[2], HIGH);
else if (thisNote == 3) digitalWrite(ledpin[3], HIGH);
delay(175);
allLEDs(LOW);
}
delay(100);
tone(8, notes[4], 500);
allLEDs(HIGH);
delay(300);
allLEDs(LOW);
delay(100);
// TODO CODE FOR SERVO OPEN, plus Serial.println("\n Simon Says Open the Lock ");
// TODO CODE FOR SERVO OPEN
// move the servo to the unlocked position
// TODO print out status Serial.println("The box is unlocked!");
delay(3000); // allow time for person to actually Open the door
// // TODO move the servo to the locked position
// TODO print out status Serial.println("The box is re-locked!");
wait4nextBtn = true;
}
if (wait4nextBtn) {
wait4nextBtn = false;
bool btnPushed = false;
while (! btnPushed) { // wait for a key-press before starting all over
for (int y = 0; y < 4; y++)
{ if (digitalRead(button[y]) == LOW) //Checking for button push
btnPushed = true;
}
}
turn = -1; //Reset turn value so the game starts over
exit;
}
// fill up the array to be matched by the player
randomArray[turn] = random(1, 5); //Assigning a random number (1-4) to the randomArray[turn count]
Serial.print(" Rand#: ");
Serial.println(randomArray[turn]);
for (int x = 0; x <= turn; x++)
{
Serial.print(randomArray[x]);
byte btn = randomArray[x]; // logical button/led # (1-4)
digitalWrite(ledpin[btn - 1], HIGH);
// @TODO play sound
delay(400);
digitalWrite(ledpin[btn - 1], LOW);
delay(100);
}
input();
}
}
// ===================================================
// local functions
void input() { //Function for allowing user input and checking input against the generated array
bool btnPushed;
for (int x = 0; x <= turn; x++)
{ // for each one in the current sequence wait for a button to be pushed
// if it is the correct one we keep looping through the sequence
btnPushed = false;
while (! btnPushed) {
for (int y = 0; y < 4; y++)
{
buttonstate = digitalRead(button[y]);
byte btn = y + 1; // logical button # (1-4)
if (buttonstate == LOW) //Checking for button push
{
btnPushed = true;
digitalWrite(ledpin[y], HIGH);
delay(100); // insures minimum LED illumination
inputArray[x] = btn;
// play sound
tone(8, notes[y], 150);
Serial.print(" btn pushed: ");
Serial.print(btn);
delay(100);
// was a poor way to allow for button release: delay(250);
wait_BtnRelease(); // much better this way
digitalWrite(ledpin[y], LOW);
if (inputArray[x] != randomArray[x]) { //Checks value input by user and checks it against
fail(); //the value in the same spot on the generated array
//The fail function is called if it does not match
exit;
}
}
}
} // end while
}
delay(500);
turn++; //Increments the turn count, also the last action before starting the output function over again
}
// ------------------------------------------------------
void fail() //Function used if the player fails to match the sequence
{
// Code for fail sound and lights
for (int y = 1; y <= 2; y++)
{
allLEDs(HIGH);
delay(100);
tone(8, notes[2-y], 150);
delay(300);
allLEDs(LOW);
delay(200);
// print out status
}
Serial.println("\n Oops!");
delay(500);
turn = -1; //Resets turn value so the game starts over without need for a reset button
}
// ------------------------------------------------------
void allLEDs(byte state) {
digitalWrite(ledpin[0], state);
digitalWrite(ledpin[1], state);
digitalWrite(ledpin[2], state);
digitalWrite(ledpin[3], state);
}
void wait_BtnRelease() {
bool btnStillDown;
int debounce=0; // need depends on button used. mine caused some double trips
while (debounce<2) {
delay(5);
btnStillDown = false;
for (int y = 0; y < 4; y++)
{
buttonstate = digitalRead(button[y]);
if (buttonstate == LOW) //Checking for button push
btnStillDown = true;
}
if (btnStillDown) debounce=0;
else debounce++;
}
}