"blink without delay" for a function

OK, so I'm trying to play the GMT pips with my Arduino. It works great. Because I'm still waiting for my ethernet shield, I have no way of setting my RTC accurately (the compile delay means it's 15 seconds slow). If there's a way to say RTC.adjust(DateTime(__DATE__, __TIME__+15s)); it's news to me :wink:

At the moment I compensate for it in my code. This is OK as an interim solution.

So here's my question:-

    if (now.second() == 39 && now.minute() == 59)
    {
     digitalWrite(ledPin2, HIGH);
      playTone(100, 2000);
      delay(900);
      playTone(100, 2000);
      delay(900);
      playTone(100, 2000);
      delay(900);
      playTone(100, 2000);
      delay(900);
      playTone(100, 2000);
      delay(900);
      playTone(500, 2000);}
      else

I want to avoid the use of delay, because it means no other LEDs can be lit, no other if statements dealt with, right?

But if I say playTone (900, 0), I just get a very low rumble from my piezo buzzer which brings the loop to a complete halt.

Any tips?

THANKS

I want to avoid the use of delay, because it means no other LEDs can be lit, no other if statements dealt with, right?

Right.

But if I say playTone (900, 0), I just get a very low rumble from my piezo buzzer which brings the loop to a complete halt.

What does this function do? It is not included in the snippet you posted.

      delay(900);
      delay(900);
      delay(900);
      delay(900);
      delay(900);

These are the delay()s you need to eliminate.

Any tips?

Look at the blink with delay example.

PaulS:

But if I say playTone (900, 0), I just get a very low rumble from my piezo buzzer which brings the loop to a complete halt.

What does this function do? It is not included in the snippet you posted.

It's my attempt at playing a tone of nothing instead of using delay...

I'll have another look at blink without delay.

Do you see what I was trying to do, though?

Do you see what I was trying to do, though?

Not without knowing what playTone() is doing.

To save further confusion, I think this is the playTone() function referred to, from the OP's previous thread Greenwich mean time pips - #4 by Dan_ce - Programming Questions - Arduino Forum

// duration in mSecs, frequency in hertz
void playTone(long duration, int freq) {
    duration *= 1000;
    int period = (1.0 / freq) * 1000000;
    long elapsed_time = 0;
    while (elapsed_time < duration) {
        digitalWrite(pinSpeaker,HIGH);
        delayMicroseconds(period / 2);
        digitalWrite(pinSpeaker, LOW);
        delayMicroseconds(period / 2);
        elapsed_time += (period);
    }
}

dxw00d:
To save further confusion, I think this is the playTone() function referred to, from the OP's previous thread

aha. Thanks!

Does that clear things up, Paul? :slight_smile:

If you are calling playTone(900,0), then you have a 'divide by zero' condition. I'm not sure what the Atmega does under those circumstances, but it might well explain your symptoms.

dxw00d:
If you are calling playTone(900,0), then you have a 'divide by zero' condition. I'm not sure what the Atmega does under those circumstances, but it might well explain your symptoms.

hmm.. thanks. I've tried the following:

First I tried to eliminate the need for "delay" by calling if statements to play the pip for each second, but of course the pips all merged into one because I wasn't able to call per ms.

Then I tried writing code using the blink without delay example. But I found that the blink without delay example sets a pin to HIGH, whereas I need to tell a function to go to work.

    DateTime now = RTC.now();
    if (now.second() == 54 && now.minute() == 59)
    {
        unsigned long currentMillis = millis();
      if(currentMillis - previousMillis > interval) {
    // save the last time you sounded the buzzer 
    previousMillis = currentMillis;   

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

    // set the buzzer with the buzzerState of the variable:
     playTone(100, 2000);
      }
     }

doesn't work

To do that you would use the technique demonstrated in 'blink without delay' to detect when it was time to start and end each note, and define a function (for example 'outputTone()') to poll the clock and see whether it was time to change the output. Your existing function 'playTone()' would configure the variable used by outputTone() to tell it what tone and duration it was supposed to be playing.
Your loop() function would call outputTone() and then go on to do whatever else you wanted to happen at the same time as playing the tones.

I don't have a buzzer, so I tried the on-board LED as a "speaker" and adapted the cooperative multi-tasking code I referred you to elsethread to keep time in usec instead of msec. Providing my own tone generation code to produce the GTS "pips" looks like:

// 1 kHz tone has cycle every 1 msec or 1000 usec (500 usec up, 500 usec down)
// 1/10 sec = 100 msec = 100,000 usec = 100 cycles short pip
// 1/2 sec = 500 msec = 500,000 usec = 500 cycles long pip

// typedef unsigned long long time_t   /* Define the time_t data type         */
#define time_t unsigned long long      /* Arduino 1.0 can't handle typedef    */
// typedef void (*fptr_t)();           /* Define the fptr_t data type         */
#define fptr_t(x) void(*x)()           /* Arduino 1.0 can't handle typedef    */

int aftr(time_t dlay,fptr_t(what));

unsigned long_pip;
unsigned short_pip;
unsigned cycles;
unsigned busy;

void cycle_down(void)
{  digitalWrite(13,LOW);
   if (--cycles) aftr(500,cycle_up);
   else
   {  if (short_pip > 1) 
      {  --short_pip;
         cycles = 100;
         aftr(900000,cycle_up);
      }
      else 
      {  if (long_pip)
         {  long_pip = 0;
            cycles = 500;
            aftr(900000,cycle_up);
         }
         else aftr(2000000,unbusy);
      }
   }
}

void unbusy(void)
{  busy = 0;
}

void cycle_up(void)
{  if (busy)
   {  digitalWrite(13,HIGH);
      aftr(500,cycle_down);
   }
}

void gts(void)
{  while (busy) idle();
   busy = 1;
   long_pip = 1;
   short_pip = 5;
   cycles = 100;
   cycle_up();
}

void setup(void)
{  pinMode(13,OUTPUT);
   busy = 0;
   delay(1000);
}

void loop(void)
{  gts();

   while (busy) idle();
}

In place of audio tones, my on-board LED does the tones with half-bright (because of the duty cycle) pips - and it's running as I type. :slight_smile:

Thanks, Morris! I'll check this out when I get home... much appreciated.

Hi, in an effort to do some coding myself, I wrote the following:-

Do you think it'll work? I'm at work so can't test. But I will when I get home...

unsigned int pip1 = 0;
unsigned int pip2 = 0;
unsigned int pip3 = 0;
unsigned int pip4 = 0;
unsigned int pip5 = 0;
unsigned int pip6 = 0;
    if (now.minute() == 59 && now.second() == 55)  {
    if (pip1 < 1)  {
    pip1 = 1;
    playTone(100, 2000);
  }
}
  if (now.minute() == 59 && now.second() == 56)  {
    if (pip2 < 1)  {
    pip2 = 1;
    playTone(100, 2000);
  }
}
  if (now.minute() == 59 && now.second() == 57)  {
    if (pip3 < 1)  {
    pip3 = 1;
    playTone(100, 2000);
  }
}
  if (now.minute() == 59 && now.second() == 58)  {
    if (pip4 < 1)  {
    pip4 = 1;
    playTone(100, 2000);
  }
}
  if (now.minute() == 59 && now.second() == 59)  {
    if (pip5 < 1)  {
    pip5 = 1;
    playTone(100, 2000);
  }
}
  if (now.minute() == 00 && now.second() == 0)  {
    if (pip6 < 1)  {
    pip6 = 1;
    playTone(500, 2000);
  }
}
  if (now.minute() == 00 && now.second() == 1)  {
   pip1 = 0;
   pip2 = 0;
   pip3 = 0;
   pip4 = 0;
   pip5 = 0;
   pip6 = 0;
  }
}

The function is:--

// duration in mSecs, frequency in hertz 
void playTone(long duration, int freq) {
  duration *= 1000;
  int period = (1.0 / freq) * 1000000;
  long elapsed_time = 0;
  while (elapsed_time < duration) {
    digitalWrite(pinSpeaker,HIGH);
    delayMicroseconds(period / 2);
    digitalWrite(pinSpeaker, LOW);
    delayMicroseconds(period / 2);
    elapsed_time += (period);
  }

}

DANE:
Hi, in an effort to do some coding myself, I wrote the following:-
Do you think it'll work? I'm at work so can't test. But I will when I get home...

If you can write it at work then you can test it at work. :slight_smile:

runaway_pancake:
If you can write it at work then you can test it at work. :slight_smile:

Can I? :P. Well, that's good news. Just let me tell IT that.

It only chuffin' works!

The first bit of code I've come up with and authored solo that actually worked first time...

Thanks all