Metronome project. Timing issue.

Hi everyone!

Hope all of you are ok =)

Soooo....dont know where to start. Well, i ve been trying to finish a metronome for about 3 days now, and have encountered with some issues with the timing tasks.

This metronome involves three buttons, a potenciometer, and obviously, a speaker.

1.- I want the buttons to acomplish the following:

a. Tap the tempo feature.
b. Number of notes for the time signature.
c. Dont know yet but maybe i´ll integrate a stop/start function.

I have no problems with b, the thing is, i´ve found me quite annoyed by the time setups and/or compatibility issues between delay() and millis() functions. Frankly, i feel so dumb hahaha.

I´ve manage to obtain the BPM, and thus, to start the endlesly beeping sound.
Everything ok to that point.

Now, with the tap feature...i have no idea how to do it. Can you guys help me? XP
I want to calculate the time, in miliseconds, from one push of a button to the second push. Like an "A to B" situation. Just wanna know that, and maybe from there, discover how to do it with three or four pushes.

Thats the general idea. Press the button once and start counting, press a second time (the same button) and stop the timer (or leave a mark). Calculate the difference in miliseconds, and give that number to the BPM factor.

I hope i´ve made myself clear enough so you guys can help me, my english is very rusty. Then again, if you guys can give me a clue at least of what i can do, it´ll be either way apreciated.

Thanks a lot Guys.
Have a nice day!

p.d : My code for now (pls, still a noob, be gentle hahah).

const int speaker = 8;
const int tapTempo = 7;           //Tap tempo function
int notespc = 6;       //Number of notes in a compass (2,3,4,5,6,7,8,9,10,11,12)
const int accent = 440;      //Frecuency of the accent note (first measure)
const int noAccent = 330;    //Notes after the accent
const int manualTempo = A0;  //Potenciometer to set tempo
int beat = 1;                //Beats starts at "1" Modified through time
int notes = 3; 





void setup() {
  
  Serial.begin(9600);
  pinMode(speaker, OUTPUT);
  pinMode(tapTempo, INPUT);
  pinMode(notes, INPUT);
   
}

void loop() {

  VariableTimedAction::updateActions();
  buttons();
  metronome(); 
  Serial.println(notes);
     

}
void metronome(){
  
  int potValue = map(analogRead(manualTempo), 0, 1023, 40, 300);
  Serial.println(potValue);
  int BPM = (60000/potValue);
  Serial.println(BPM);
    
   if(beat == 1){
   tone(speaker, accent, 50);
   }
   
  else {
    tone(speaker, noAccent, 50);
   }
      
  delay(BPM);
  noTone(speaker);
  if(beat > notes){
    beat = 1;        
  } 
  else {
     (beat++);
  }
}

void buttons(){

  int curNotes;
  curNotes = digitalRead(notespc);
  
  if(curNotes == HIGH){

    notes++;
  } else {

    notes = notes;
  }

  if(notes == 13){

    notes = 1;
    delay(10);
  }
}

There is a delay() call in your metronome() function. That's going to mess up the timing.

You'll also have to deal with button bounce.

Soooo...finally did it!

Hey wvmarle. I wanna thank you for your tips. I did not understand it at first but the keywords helped me.

Anyway, i managed to put together the manual tempo thingy and the tap tempo mode. Now, it is a working metronome with two features. You can select one of them and set the tempo easily.

If you guys want it i´ll put it right here.

The other thing is, the code looks kinda nasty. I think it would help to, maybe, rewrite part of it in some other simplest and concise way, you guys can give me any tips for that?

Thanks again for the help. Have a nice day everyone.

// Constants.
const byte speaker = 8;
const byte notespc = 7;
const byte modeSelector = 6;
const byte tap = 5;
long manualtempo = A0;

//Potentiometer Tempo Related Variables.
long pottempo = 60;
long potms = 250;

//Button Tap Related Variable.
byte count = 0;
unsigned long sTart, finished, elapsed;

//Number of notes (Time Signature) Related Variables.
byte notes = 4;
byte notesup = 0;

//Mode Selector Related Variables.
byte mode = 0;

//BPM and Pulse Related Variables.
unsigned long prevTime = 0;
long mssource = 500;
byte beat = 0;
int frec;


void setup() {
  Serial.begin(9600);
  pinMode(speaker, OUTPUT);
  pinMode(tap, INPUT);
  pinMode(notespc, INPUT);
  pinMode(manualtempo, INPUT);  
  pinMode(modeSelector, INPUT);

}

void loop() {

                                                   //MODE SELECTOR SETUP.

//Press button to swtich between Tap Mode (elapsed variable) and Manual Tempo Mode (potms variable) values. 
//If Tap mode its selected mssource will take th values given by "elapsed" variable in miliseconds. 
//Same with Manual Tempo Mode, thi will give mssource the same values that you get from "potms" variable.


//Toggle push button. Switch mode status and save it.  
if (digitalRead(modeSelector) == HIGH) {                          
mode = !mode;
} while(digitalRead(modeSelector) == HIGH);

// keeps a small delay 
delay(50);                                                   

//If mode == 0 , select Manual Tempo Mode. 
//If mode == 1, select Tap Mode.
if(mode == 0){               
  mssource = potms;
} else {
  mssource = elapsed;
}

  
//Start millis() Function to keep track of time.
 unsigned long curTime = millis();      



                                                       //MANUAL TEMPO AND POTENTIOMETER SETUP.

//Mapping of potentiometer to get estimate BPM values.
//Give a range of the bpm´s that you want. 
  pottempo = map(analogRead(manualtempo), 0, 660, 33, 220);  

//Calculate the miliseconds from the potentiometer values.
  potms = (60000/pottempo);

//This is to test the final values.   
//int Bpm = (60000/potms);


                                                        //TAP TEMPO SETUP.

//This is to test the bpm from tapping.
//int BPM = (60000/elapsed);

//I´ve made this like a one, two count system. 
//If you press the button start to count.
//If the count > 2, restart the count to one.
if (digitalRead(tap)== HIGH){
   count++;
if(count > 2){
   count = 1;
   }   
   
//Serial.println(count);    
delay(150);

//It takes the values of millis() when count == 1 (sTart = first mark).
if(count == 1){
   sTart = millis();
   Serial.println("Started...");
   }

//Then, if you press again with the desire tempo, it takes the values of millis() when count == 2. 
if(count == 2){
   finished = millis();

//Finally, it calculates the elapsed time in miliseconds between the two "marks".       
   elapsed=finished-sTart;
   Serial.print("Elapsed = ");
   Serial.println(elapsed);
   }
}

                                             //NUMBER OF NOTES PER COMPASS SETUP.

//Calling the button notesup.                                             
notesup = digitalRead(notespc);
                                             
//Notes up when button is pushed.   
if(notesup == HIGH){
   notes++; 
   delay(200);
} 


                                             //BEAT AND PULSE SETUP.

//If the difference between the current time versus the prevoius time
//is greater or equal to the miliseconds given by the source:
//Count up a beat and produce a tone with certain frecuency for 50 miliseconds.
//Repeat every time the comparison of the two variables is true.                                          
if((curTime - prevTime) >= mssource){
   prevTime = millis();
   beat++;  
   tone(speaker, frec, 50);

    
//If the count of beats is greater then the number of notes you set, then restart to 1. 
if(beat > notes){
   beat = 1;
}

//If the value of beat its not 1, the frecuency of the tone is 300Hz. 
if(beat != 1){
  frec = 300;
}

//If the value of beat its exactly one, then the frecuency of the tone is 400Hz.  
if(beat == 1){
  frec = 400;
}

//If the number of notes you´re setting its greater than 13, then restart the count to 2.  
if(notes >13){
   notes = 2;
}  
  //Serial.println(beat);
  //Serial.println(notes);
  //Serial.println(pottempo); 
  //Serial.println(Bpm);  
 }
}

One quick&easy major readability improvement would be an autoformat (ctrl-T in the IDE).

An analogRead returns a 10-bit number. No need to use a long, an int or unsigned int big enough.

Thanks again man.

Cheers.