User:Fako Berkers/simonsays

From XPUB & Lens-Based wiki

Simon Says on Arduino

Hardware

The hardware is very simple. Connect one end of the button to pin 8 and the other to pin 2. Set the speaker to pin 13 and ground.

Coding

#include <stdlib.h>

const int timelimit = 4000;
const int buttonlimit = 100;

const int pinIn = 2; 
const int pinOut = 8;
const int pinSpeaker = 13;

int butState = HIGH; // HIGH means not pressed

int marks[buttonlimit];
int imarks = 0;

unsigned long cmillis = 0;
unsigned long pmillis = 0;


void setup() {
  
  // Set the pins.
  pinMode(pinIn,INPUT);
  pinMode(pinOut, OUTPUT);
  digitalWrite(pinIn, HIGH);
  digitalWrite(pinOut, LOW); // Pin out is low and pinIn becomes low when button is pushed.
  
  // Set the Serial.
  Serial.begin(115200);
  Serial.println("START");
  
}

void loop() {

  // Read the input.
  int input_pin = digitalRead(pinIn);
  
  // If input changed, then work needs to be done!
  if (butState != input_pin) {

    butState = input_pin;
    
    // Get time values to work with.
    if(!pmillis) pmillis = millis(); // Only true the first push (makes first marker 0)
    cmillis = millis();
    
    // Save time difference between last button change and current time.
    marks[imarks] = cmillis - pmillis;
    imarks++;  
    
    // Save time value for next time.
    pmillis = cmillis; 
   
  }

  // Check if pattern should be played.
  if(millis() - pmillis > timelimit) play(); // No changes for a long time.
  if(imarks > buttonlimit) play(); // Button pressed too often.

}

void flushit() {

  memset(marks,0,buttonlimit); // Clears the array
  imarks = 0;
  cmillis = 0;
  pmillis = 0;

}

void play() {

  // Do not play anything if there's no input yet.
  if(!pmillis) return;
  
  // Visual output.
  for(int i=0; i<buttonlimit; i++) {
    Serial.print(marks[i]);
    Serial.print(" "); 
  }
  Serial.println("");
  
  // Play the pattern.
  int i = 1; // First element in array is always 0, so start at second
  while (marks[i]) { 
    if (i%2) tone(pinSpeaker,500,marks[i]); // Every odd index number is the length of a button push and sould create sound as long as that length.
    delay(marks[i]);
    i++;
  }
  
  // Flush the pattern after it is played.
  flushit();

}

Coding II

Michael had some idea's on how to code the above differently. Below is the result. I think this code is more readable and is easier to expand, this comes at the small cost of some repeated statements and the user screws up the code if he presses the button too long. So far from perfect, but interesting to build upon ...

#include <stdlib.h>

const int timelimit = 4000;
const int buttonlimit = 100;

const int pinIn = 2; 
const int pinOut = 8;
const int pinSpeaker = 13;

int marks[buttonlimit];
int imarks = 0;

unsigned long press_time = 0;
unsigned long release_time = 0;
int time_difference;

void setup() {
  
  // Set the pins.
  pinMode(pinIn,INPUT);
  pinMode(pinOut, OUTPUT);
  digitalWrite(pinIn, HIGH);
  digitalWrite(pinOut, LOW); // Pin out is low and pinIn becomes low when button is pushed.
  
  // Set the Serial.
  Serial.begin(115200);
  Serial.println("START");
  
}

void loop() {
  
  // START WAIT FOR PRESS
  Serial.println("START WAIT FOR PRESS");
  release_time = millis();
  while(digitalRead(pinIn)==HIGH) {
    // Check for timeout! 
    if(millis() - release_time > timelimit) {
      if(imarks>0) {
        play();
        flushit();
      }
      return;
    }
  }
  press_time = millis();
  time_difference = press_time - release_time;
  marks[imarks] = time_difference;
  imarks++;
  // END WAIT FOR PRESS
  
  // START WAIT FOR RELEASE
  Serial.println("START WAIT FOR RELEASE");
  while(digitalRead(pinIn)==LOW) {}
  release_time = millis();
  time_difference = release_time - press_time;
  marks[imarks] = time_difference;
  imarks++;
  // END WAIT FOR RELEASE
  
  // Check for buttonlimit!
  if(imarks > buttonlimit) {
    play();
    flushit();
  }

}

void flushit() {
  memset(marks,0,buttonlimit); // Clears the array
  imarks = 0;
}

void play() {
  
  // Do not play anything if there's no input yet.
  if(marks[0]==0) return;
  
  // Visual play.
  for(int i=1; i<imarks; i++) { // start at i==1 to skip first pauze
    Serial.print(marks[i]);
    Serial.print(" "); 
  }
  Serial.println("");
  
  // Sound play.
  for(int i=1; i<imarks; i++) { // start at i==1 to skip first pauze
    if (i%2) tone(pinSpeaker,500,marks[i]); // Every odd index number is the length of a button hold and sould create sound.
    delay(marks[i]);
  }
    
}