Metronome - Beats Per Minute?

Hi
I am an absolute beginner and my first project is designing a metronome with the Arduino Uno. I am using two LEDs(green and red) until I get a speaker for my prototype. I have programmed the arduino with a 12 beat cycle on loop using a potentiometer to vary the speed. The range is 0 - 1023.
My question is this:
How do I program for beats per minute(or flashes per minute)... with a range of 30 to 250bbm?

with a range of 30 to 250bbm?

Assuming that was meant to be "bpm", then that is a range of 0.5Hz to 4.166Hz.
You need to map your reading to give milliseconds times in this range.
I'd probably adapt the "blink without delay" example.

I'd probably adapt the "blink without delay" example

Is it possible to vary the blink speed with a potentiometer when using the "blink without delay" program? I have tried to combine the AnalogRead example, but the potentiometer has no affect on the blink rate.

Is it possible to vary the blink speed with a potentiometer when using the "blink without delay" program?

Of course!

AWOL is being a bit coy here.

We are having some difficulty determining your exact intention here, and depending on how much time each person fancies dallying, most are reluctant to build your whole project (code) for you, preferring to direct you to study and learn from the many examples available.

For musical purposes, the Arduino (Uno) has a timebase which can readily be used to count the interval and there are ways of taking the reciprocal and calculating beats per minute.

The question is - do you wish a numerical display on an LCD or what? Do you wish to calibrate it in some other way, if so what?

If you observe the trend of digital devices, you will note that potentiometers are rarely used nowadays as they have a somewhat limited durability, being replaced by Up/ Down buttons or even rotary encoders. That one also has a "commit" pushbutton incorporated - you dial what you want and press. These are now the common method of data entry (well, were, prior to touchscreens) on medical monitors.


Some years ago, I dreamed up a metronome with one button and a digital (two numeral - or 2½) display. Using a MCU of course.

Press once, nothing happens, press twice or more in time with the music and it replicates the beat and displays the rate.

Press and hold, and it stops, but again, if you released it on one beat and pressed again on the next, it would synchronise to that. Some variation in this to produce emphasised beats.

AWOL is being a bit coy here.

Aren't they the big orange pond fish?

I was only being as coy as the OP when they wrote

I have tried to combine the AnalogRead example, but the potentiometer has no affect on the blink rate.

but omitted to post the code.

We are having some difficulty determining your exact intention here, and depending on how much time each person fancies dallying, most are reluctant to build your whole project (code) for you, preferring to direct you to study and learn from the many examples available.

I realize my question was somewhat unclear, as I said, I am a complete newbie to arduino or any electronics platform for that matter.

I basically want the LED to blink at variable tempo to represent Beats per Minute.
I have taken AWOL's suggestion to adapt the 'Blink with out delay' project' and have started to make some progress.

The question is - do you wish a numerical display on an LCD or what? Do you wish to calibrate it in some other way, if so what?

I might use an LCD display down the line, but for now I am gonna try and keep it simple. This project is just a 'getting started' project for me, to get my feet wet.

Thanks for your replies guys.

Here is the code I have used so far. I can now adjust the rate of blink with the potentiometer, but I can't get the Serial Monitor to reflect the Tempo change.... it just reads 120 whether it goes up; or down.

const int ledPin =  13;      // the number of the LED pin

int tempoPin = A0;
int ledState = LOW;           
long previousMillis = 0;        
int tempo = 120;

long interval = 1000;           // interval at which to blink (milliseconds)

void setup() {
 
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);      
}

void loop()
{

  int sensorValue = analogRead(A0);
  Serial.print("Sensor = ");
  Serial.print(sensorValue);
  Serial.print("\t Tempo = ");
  Serial.println(tempo);
  delay(2);
  float tempo = analogRead(tempoPin);
  tempo = map(tempo, 0, 1023, 60, 1000);
 
  //algorithm to convert tempo into BPM
  float interval = (1000/tempo)*60;
  
  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
  }
}

but I can't get the Serial Monitor to reflect the Tempo change.... it just reads 120 whether it goes up; or down.

I have resolved this issue - I had entered the mapping function incorrectly.

I have resolved this issue - I had entered the mapping function incorrectly.

int tempo = 120;

No, this variable was in scope when you printed your value.

Ok.... Got it now. Thanks.

AWOL:

AWOL is being a bit coy here.

Aren't they the big orange pond fish?

Koi

AWOL:
I was only being as coy as the OP when they wrote

I have tried to combine the AnalogRead example, but the potentiometer has no affect on the blink rate.

but omitted to post the code.

People are often reluctant to post their code - presumably suspect someone is going to take it and monetise it on eBay.

Paul__B:
People are often reluctant to post their code - presumably suspect someone is going to take it and monetise it on eBay.

Or perhaps they fear ridicule. It could be said that some of us do come across a little rough when we point out code mistakes...

tylernt:
Or perhaps ...

I do hope you realise I was being tongue-in-cheek.

So here is where I am at with my blinking LED metronome.

With a few small adjustments to the code in my earlier post, I can now use the potentiometer to increase or decrease tempo from 40 bpm to 210bpm. I did notice however, that when set to 60bpm, it is actually running a little fast at between 62 and 63 beats(flashes) per 60 seconds.

Can anyone tell me if it is possible to calibrate this exactly, and if so, push me in the right direction?

const int ledPin =  9;      // the number of the LED pin
const int analogInPin = A0; 

int ledState = LOW;           
long previousMillis = 0;        
long interval = 1000;           // interval at which to blink (milliseconds)
int tempo;
int sensorValue = 0;


void setup() {
 
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);      
}

void loop()
{
  sensorValue = analogRead(analogInPin);
  
  Serial.print("Sensor = ");
  Serial.print(sensorValue);
  Serial.print("\t Tempo = ");
  Serial.println(tempo);
  
  tempo = map(sensorValue, 0, 1023, 40, 210); //map in the range of 40 to 210 BPM
 
  
  float interval = (1000/tempo)*60/2; //algorithm to convert tempo into BPM
  
  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) {
     // save the last time you blinked the LED
    previousMillis = currentMillis;   
    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;
    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
  }
}
  float interval = (1000/tempo)*60/2; //algorithm to convert tempo into BPM

Integer arithmetic produces integer results. Storing an int in a float will not recover the truncated data. Roundoff errors abound, here.

Having a local variable, interval, with the same name as a global variable is hardly a good idea. A bit like Darryl's brother Darryl and his other brother Darryl, on the Bob Newhart show.

  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) {
     // save the last time you blinked the LED

Since time is in integer units, comparing the difference between two integer values to a float makes little sense.

Changing the interval on every pass through loop hardly seems like a good idea.

I would suggest only re-reading the sensor and recalculating the current interval at the end of each beat, to stop the thing from jittering. Depending on the characteristics of your potentiometer you might also want to include some smoothing so that it averages the period over a few beats rather than changing instantaneously.

The effects are only going to be small compared to the other issues, but if you want to maintain an accurate beat you should replace this:

previousMillis = currentMillis;

with

previousMillis += interval;

The distinction is subtle. The first version starts timing the next beat from when it noticed the previous beat ended. The second version starts timing the next beat from when the previous beat should have ended - even if the sketch didn't happen to be checking the time at the precise millisecond that the beat ended. I'd also suggest only performing serial printing once per beat because otherwise this will slow the loop down significantly, so your code won't detect the end of each beat promptly. Combined with the problem mentioned above, this could lead to a significant slip.

Thanks for your replies

For PaulS...

Integer arithmetic produces integer results. Storing an int in a float will not recover the truncated data. Roundoff errors abound, here.

Does amending the code to say 'int interval' instead of 'float interval' make more sense?

for PeterH..

I'd also suggest only performing serial printing once per beat because otherwise this will slow the loop down significantly, so your code won't detect the end of each beat promptly.

Does setting the delay following Serial.println to (1000) achieve this?

if(currentMillis - previousMillis >= interval) {

Makes more sense, surely?

Makes more sense, surely?

I changed the > to >= (which does make more sense) and set a print delay to (100) and that seems to have improved the timing a great deal. When set at 60 BPM it now flashes 60 times per minute. If it is out, it's gonna be a micro amount.

Does amending the code to say 'int interval' instead of 'float interval' make more sense?

Yes. Storing an integer in an int variable makes more sense than storing it in a float.