My first arduino thing... tones with counter and a reset mechanism

OK, this probably wont WOW any of you but it sure makes me happy.... Im an Arduino newbie so I just wanted to tell someone!!!

There's nothing new here, I just combined a few tutorials into one ... This will play a different tone with each button press up to 5 presses. Then nothing. However, if you press and hold the button after you've reached the limit for 2 seconds it restarts the program.

This is a step on some sort of code cracker puzzle thing that I want to build.

*** Anyone want to speak to why I had to add a tiny delay in the loop so I didnt get doubled up button presses... is my button wonky or is this just something that happens? I'm not electrical by nature but it seems odd to me that the flow would turn off and then back on again on the way up ...? ***

Here is the sketch:

#include "pitches.h"
const int buttonPin = 2; // the number of the pushbutton pin
int note1 = NOTE_C4; // define note sound
int buttonCount = 0; 
int lineOut = 8;  // speaker line out
int buttonState;  // button is high or low
unsigned long start_hold; // hold timer
int lastButtonState = LOW; // Need to know this for comparisons
int HOLD_DELAY = 2000;  //  How long before we reset
//extra button push variable (buttonPushed) is kept for when the button count 
//is beyond 6 and we want to start initial timer
boolean buttonPushed = false; 

void setup() {
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);
  Serial.begin(9600);           // set up Serial library at 9600 bps
}

void loop(){
  buttonState = digitalRead(buttonPin);

  //Is this a new push or a new release?  
  if (buttonState != lastButtonState) {
    if (buttonState == HIGH) {
      Serial.println("on");
      Serial.print("number of button pushes:  ");
      Serial.println(buttonCount);
      Serial.print("delay is:  ");
      Serial.println(start_hold);
      Serial.print("---------------------");

      if (buttonCount < 6)
      {
        tone(lineOut, note1);
      }
      else
      {
        start_hold = millis();   // mark the time
        buttonPushed = true;
      }
      buttonCount++;

      switch (buttonCount) {
      case 1:
        note1 = NOTE_A4;
        break;
      case 2:
        note1 = NOTE_D4;
        break;
      case 3:
        note1 = NOTE_E4;
        break;
      case 4:
        note1 = NOTE_F4;
        break;
      case 5:
        note1 = NOTE_G4;
        break;
      default:
        buttonCount = 6;
        break;
      }
    }
    else {
      Serial.println("off");
      start_hold = 0;
      noTone(lineOut);
    }
    // save the current state as the last state,
    lastButtonState = buttonState;
    delay(100);  // this tiny delay stops bad button pushes I was getting on release
  }
  //current and last state are the same, are all the variables right to start timing for a reset?
  else if ( buttonPushed == true && buttonState == HIGH && lastButtonState == HIGH && buttonCount == 6 ){
     if ((millis() - start_hold) >= HOLD_DELAY){  
      //Sweet!  RESET!!!
      buttonPushed = false;
      buttonCount = 0;
      tone(lineOut, NOTE_B4);
    }
  }
}

Welcome to the forum. Glad to see someone with a successful project! (vs inability to get the IDE running or downloading or something as a first post).

Thanks CrossRoads!

I did have my share of issues in the beginning (with Windows 8, Uno, USB port) but I eventually found the answers...they're all out there somewhere. :slight_smile:

Anyone want to speak to why I had to add a tiny delay in the loop so I didnt get doubled up button presses

There's nothing wrong with your buttons - look up debouncing. Using a small delay as you did is a common solution.

wildbill:
There's nothing wrong with your buttons - look up debouncing. Using a small delay as you did is a common solution.

Not so much nothing wrong with the button, as nothing unusual. Switch contacts in general do bounce for a number of milliseconds, and digital devices are so fast that they tend to see every part of this bounce as a separate event.

You may be interested in my code framework for performing differently timed events in concert and robustly debouncing switch inputs. Detection of a prolonged press can easily be integrated by using your time comparison (for HOLD_DELAY) against the single button state flag that I provide.

// Blink without "delay()" - multi!

const int led1Pin =  13;    // LED pin number
const int led2Pin =  10;
const int led3Pin =  11;
const int button1 =  4;
int led1State = LOW;        // initialise the LED
int led2State = LOW;
int led3State = LOW;
char bstate1 = 0;
unsigned long count1 = 0;   // will store last time LED was updated
unsigned long count2 = 0;
unsigned long count3 = 0;
unsigned long bcount1 = 0;

// Have we completed the specified interval since last confirmed event?
// "marker" chooses which counter to check 
boolean timeout(unsigned long *marker, unsigned long interval) {
  if (millis() - *marker >= interval) { 
    *marker += interval;    // move on ready for next interval
    return true;       
  } 
  else return false;
}

// Deal with a button read; true if button pressed and debounced is a new event
// Uses reading of button input, debounce store, state store and debounce interval.
boolean butndown(char button, unsigned long *marker, char *butnstate, unsigned long interval) {
  switch (*butnstate) {               // Odd states if was pressed, >= 2 if debounce in progress
  case 0: // Button up so far, 
    if (button == HIGH) return false; // Nothing happening!
    else { 
      *butnstate = 2;                 // record that is now pressed
      *marker = millis();             // note when was pressed
      return false;                   // and move on
    }

  case 1: // Button down so far, 
    if (button == LOW) return false; // Nothing happening!
    else { 
      *butnstate = 3;                 // record that is now released
      *marker = millis();             // note when was released
      return false;                   // and move on
    }

  case 2: // Button was up, now down.
    if (button == HIGH) {
      *butnstate = 0;                 // no, not debounced; revert the state
      return false;                   // False alarm!
    }
    else { 
      if (millis() - *marker >= interval) {
        *butnstate = 1;               // jackpot!  update the state
        return true;                  // because we have the desired event!
      }
      else 
        return false;                 // not done yet; just move on
    }

  case 3: // Button was down, now up.
    if (button == LOW) {
      *butnstate = 1;                 // no, not debounced; revert the state
      return false;                   // False alarm!
    }
    else { 
      if (millis() - *marker >= interval) {
        *butnstate = 0;               // Debounced; update the state
        return false;                 // but it is not the event we want
      }
      else 
        return false;                 // not done yet; just move on
    }
  default:                            // Error; recover anyway
    {  
      *butnstate = 0;
      return false;                   // Definitely false!
    }
  }
}

void setup() {
  pinMode(led1Pin, OUTPUT);      
  pinMode(led2Pin, OUTPUT);      
  pinMode(led3Pin, OUTPUT);      
  pinMode(button1, INPUT);      
  digitalWrite(button1,HIGH);        // internal pullup all versions
}

void loop() {
  // Toggle LED if button debounced
  if (butndown(digitalRead(button1), &bcount1, &bstate1, 10UL )) {
    if (led1State == LOW) {
      led1State = HIGH;
    }
    else {
      led1State = LOW; 
    } 
    digitalWrite(led1Pin, led1State);
  } 

  // Act if the latter time (ms) has now passed on this particular counter,
  if (timeout(&count2, 300UL )) {
    if (led2State == LOW) {
      led2State = HIGH;
    }
    else {
      led2State = LOW; 
    } 
    digitalWrite(led2Pin, led2State);
  } 

  if (timeout(&count3, 77UL )) {
    if (led3State == LOW) {
      led3State = HIGH;
    }
    else {
      led3State = LOW; 
    } 
    digitalWrite(led3Pin, led3State);
  } 
}