0
/**************************************/
const int lowestPin = 1;//the lowest one attach to
const int speaker = 13;
int ts = 4;//how many beats you want
int count = 1;
const int keyPin = 12;
int buttonState = 0;
int bpm = 120;
/**************************************/
void setup()
{
  for (int thisPin = 1; thisPin <= ts; thisPin++)
  {
    pinMode(thisPin, OUTPUT); //initialize thisPin as an output
    pinMode(6, INPUT);


  }
  pinMode(keyPin, INPUT);
}

/****************************************/
void loop()
{

  //iterate over the pins
  //turn the led on from lowest to the highest



  if (digitalRead(keyPin) == HIGH && ts == 2) {
    ts = 3;
    delay(2000);
  }

  else if (digitalRead(keyPin) == HIGH && ts == 3) {
    ts = 4;
    delay(2000);
  }

  else if (digitalRead(keyPin) == HIGH && ts == 4)
  {
    ts = 2;
    delay(2000);
  }

  for (int thisPin = 1; thisPin <= ts; thisPin++)
  {

    bpm = pulseIn(6, HIGH);

    pinMode(13, OUTPUT);
    if (ts > 4)
    {
      if (count > 3)
        for (int a = 4; a <= ts; a++) {
          digitalWrite(a - 3, HIGH);
        }

    }
    else
      digitalWrite(thisPin, HIGH);

    if (count == 1)
      tone(13, 1500, 100);
    else
      tone(13, 1000, 100);

    delay(bpm - 52);
    pinMode(13, INPUT);
    digitalWrite(thisPin, LOW);


    count++;
    if (count > ts)
      count = 1;


  }

}

I am trying to make a metronome using Arduino Uno, with 4 LEDs, each LED is a beat. I want to change the time signature every time I press the pushbutton, so that there are different number of beats per measure, but when I do press the button, it runs the code for 2 and 3 beats per measure once, and then goes back to its default, 4 beats per measure.

Sometimes, it even changes without pressing the button, randomly. I am using a 220 ohm resister instead of 10, as 10 starts much more randomly than the 220.

Metronome project picture

  • Do you have resistors in series with those LEDs? – Nick Gammon Mar 13 '16 at 0:30
  • No resistors are with those LEDs – Mike Zhou Mar 13 '16 at 2:47
1

You must have resistors in series with the LEDs. See The care and feeding of LEDs. 330 ohms in series with each LED would be about right in your situation.

With no resistors you are drawing far too much current from the output pins. That would drop the voltage and the processor would reset. Thus it goes back to the default of 4 beats per measure.

It also damages both the processor and the LEDs.

You can tell if the processor resets by putting extra code into setup. For example, after setting the pins to outputs:

 for (int i = 0; i < 10; i++)
    {
    digitalWrite (3, HIGH);
    delay (200);
    digitalWrite (3, LOW);
    delay (200);
    }

If you see pin 3 flashing 10 times, you know the processor has reset.


I think your problem now is that you have a floating input for the switch. When I tried your sketch, with a couple of modifications, it worked fine.

My code:

/**************************************/
const int lowestPin = 1;//the lowest one attach to
const int speaker = 13;
int ts = 4;//how many beats you want
int count = 1;
const int keyPin = 12;
int buttonState = 0;
int bpm = 120;
/**************************************/
void setup()
{
  for (int thisPin = 1; thisPin <= ts; thisPin++)
  {
    pinMode(thisPin, OUTPUT); //initialize thisPin as an output
    pinMode(6, INPUT);
  }
  pinMode(keyPin, INPUT_PULLUP);
}

/****************************************/
void loop()
{

  //iterate over the pins
  //turn the led on from lowest to the highest

  if (digitalRead(keyPin) == LOW && ts == 2) {
    ts = 3;
    delay(2000);
  }

  else if (digitalRead(keyPin) == LOW && ts == 3) {
    ts = 4;
    delay(2000);
  }

  else if (digitalRead(keyPin) == LOW && ts == 4)
  {
    ts = 2;
    delay(2000);
  }

  for (int thisPin = 1; thisPin <= ts; thisPin++)
  {

    bpm = pulseIn(6, HIGH);
    //bpm = 1000;

    pinMode(speaker, OUTPUT);
    if (ts > 4)
    {
      if (count > 3)
        for (int a = 4; a <= ts; a++) {
          digitalWrite(a - 3, HIGH);
        }
    }
    else
      digitalWrite(thisPin, HIGH);

    if (count == 1)
      tone(speaker, 1500, 100);
    else
      tone(speaker, 1000, 100);

    unsigned long now = millis ();
    while (millis () - now < (bpm - 52))
      {
      // quit delay if switch pressed
      if (digitalRead(keyPin) == LOW)
        break;
      }

    pinMode(speaker, INPUT);
    digitalWrite(thisPin, LOW);

    count++;
    if (count > ts)
      count = 1;

  } // end of for each pin

} // end of loop

Note that the input from the switch is now INPUT_PULLUP which means it is pulled HIGH by an internal resistor. Thus, the tests are now for == LOW rather than == HIGH.

Also, instead of a delay for the timing of the metronome, I changed it to testing millis() and seeing if time is up. Otherwise you have to hold the switch down for the entire time that a cycle repeats.

  • Now that I have resistors, the button still does not change the time signature (ts). How can I wire this differently or change the code? – Mike Zhou Mar 14 '16 at 0:58
  • See amended reply. – Nick Gammon Mar 14 '16 at 1:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.