delayMicroseconds() not as expected

I expected the following 2 code snippets to have similar behaviour.
I want to use the 2nd snippet so that I can have greater control over the timing resolution.

The loops are writing to an I2C IO Expander. I want to be able to turn one pin on for 8.xx ms and another for 9.xx ms. Currently I can only getting timing resolutions of 1ms (1000 microseconds) for an unknown reason.

//With delayMicroseconds(1000):
//Note: Only have timing resolution of 1ms. This works.

void loop()
{
int offTime = 350;
float maxOnTime = 35;
int toWrite = 0;
float currentTime = 0;
while(currentTime < maxOnTime)
{
toWrite = 0xff;
if (currentTime > 8)
{
toWrite -= LLED;
}

if (currentTime > 9)
{
toWrite -= RLED;
}

writeI2C(I2C_ADDRESS, toWrite);
delayMicroseconds(1000);
currentTime += 1;
}
writeI2C(I2C_ADDRESS, 0x00);
delay(offTime);
}

//With delayMicroseconds(10):
//Note: Should have timing resolution of 0.01ms. This doesn’t work. The timing is very off for some reason. Is there some problem with currentTime += 0.01?

void loop()
{
int offTime = 350;
float maxOnTime = 35;
int toWrite = 0;
float currentTime = 0;
while(currentTime < maxOnTime)
{
toWrite = 0xff;
if (currentTime > 8.15)
{
toWrite -= LLED;
}

if (currentTime > 9.25)
{
toWrite -= RLED;
}

writeI2C(I2C_ADDRESS, toWrite);
delayMicroseconds(10);
currentTime += 0.01;
}
writeI2C(I2C_ADDRESS, 0x00);
delay(offTime);
}

Any suggestions?

Floating-point operations are rather expensive on the Arduino processors. It is entirely possible that there isn’t enough horsepower to do what you’re trying to do.

It doesn’t look like your code needs floating-point datatypes. I suggest something like this (untested)…

void loop()
{
 int offTime = 350;
 long maxOnTime = 3500;
 int toWrite = 0;
 long currentTime = 0;
 while(currentTime < maxOnTime)
 {
   toWrite = 0xff;
   if (currentTime > 815)
   {
     toWrite -= LLED; 
   }

   if (currentTime > 925)
   {
     toWrite -= RLED; 
   }   

   writeI2C(I2C_ADDRESS, toWrite); 
   delayMicroseconds(10);
   ++currentTime;
 }
 writeI2C(I2C_ADDRESS, 0x00);
 delay(offTime);
}
  • Brian

Thanks for the suggestion.

I tried the code, but ran in to the same issue.

It turns out that I was assuming writeI2C(I2C_ADDRESS, toWrite); would take 0 time to complete. This of course isn't true, so as my delay got smaller and writeI2C(I2C_ADDRESS, toWrite); was run more often, it became a significant timing issue.

I added a check. If the toWrite value hadn't changed since the last loop, then don't run writeI2C(I2C_ADDRESS, toWrite);

Your suggestion got me thinking along the right track of limitted resources. I've also switched my variable types to longs as you suggested so that they also don't become an issue with the timing.