millis with floats?

Hello. I had this code

// tempo = bpm / 24

if(millis() - lastTime >= tempo) {
      
lastTime += tempo;


    play();
   
  }

lastTime is an unsigned long. I declared it like that because i read it should be a long, because of the rollover or something... but I have a problem. tempo has float values. I'm using it as a MIDI clock generator. And if the BPM is 120 the 1/4 note will be 500ms, and that divided by 24, is 20.833ms. In that example, i need that play(); ejecutes every 20.833ms. But long variables can't hold floats... so it's not accurate and the slave reads 125bpm instead of 120bpm. So i changed it to:

if(micros() - lastTime >= tempo) {
    
lastTime += tempo;

  play()
  }

so instead of 20.833ms, tempo is 20833uS (in this example). It works. But I feel like it's overkill to use micros() for such a big number. Should i leave it like that? I also read that by the way I'm calculating the time, I won't have a rollover problem so i could use float instead of long for the millis part? thanks

Using micros() is fine as far as I am concerned. Floats are not a good idea here.

But I feel like it's overkill to use micros() for such a big number. Should i leave it like that?

you know, even micros() is not exact probably ==> 28333.333333333....

floats have 6-7 digits while an unsigned long has 9-10 so in terms of precision using UL is the best you can get.

You need to understand that millis() uses a timer interrupt and returns a value which is an unsigned long. Using the result in an equation with a float won't work.

capicoso: so instead of 20.833ms, tempo is 20833uS (in this example). It works. But I feel like it's overkill to use micros() for such a big number. Should i leave it like that?

In what way is is overkill? You're not using any more resources and you have code that does what you need...

Using floats on the otherhand would be overkill, there is no floating point hardware so floating point operations are an order of magnitude slower than longs, and the code to do float ops uses up valuable program space.

robtillaart:

But I feel like it's overkill to use micros() for such a big number. Should i leave it like that?

you know, even micros() is not exact probably ==> 28333.333333333....

floats have 6-7 digits while an unsigned long has 9-10 so in terms of precision using UL is the best you can get.

I think he's just trying to play music. The difference between 28333 microseconds and 28333.3333..... microseconds is almost certainly beneath his concern.

capicoso: so instead of 20.833ms, tempo is 20833uS (in this example). It works. But I feel like it's overkill to use micros() for such a big number. Should i leave it like that?

Big numbers are not a problem for the Arduino, especially if you're just adding and subtracting them. A long can hold numbers up to about 2147 million. An unsigned long can hold numbers up to about 4294 million. Unless you deal with bigger numbers than that, you won't have a problem.

And I strongly recommend using an integer for tempo. Keep in mind that one minute is 60 million microseconds.

Thanks guys.. I'll leave it with micros() then! I don't need a super accuracy, but the long with millis instead of 20.833ms every clock it was 20ms, so, multiplied by 24(24ppqn for midi clock) gave me a total of 480ms when it should be 500ms. So 125bpm instead of 120bpm. Now it's accurate anyways, the slave always see the correct bpm without errors thanks