0

I have a simple sketch here that should just blink a led once a second or so (approximately):

boolean onOff=true;
int count=0;

void setup() {
  pinMode(13, OUTPUT);
 }

void loop() {
    count++;
    delay(1);

    if (count == 316) { 
    onOff=!onOff;
    digitalWrite(13, onOff);
    count=0;
    }
}

So, if count is 316 it changes the state of led. It works right now, but it does not without delay() function or some other complex ones like digitalWrite() being in the loop() too. If i am deleting delay(), than led is just always on. I can feel it is smth about interrupts, but i am not sure.


What am i trying to do here is to make an alternative to delay() and millis() for my other project. One of the most needed thing for me is to make ASAP (as soon as possible) "timer", so that some code could run every 2(3-4...) iterations of loop(). delay() is bad always, and millis() uses long variable (which is bad for cpu time and ram), and while having problems with ram and cpu time in my project, i want smth lighter for ASAP and other not very precise timing. So, the questions are:

  1. Why does my sketch works only with delay(), but does not work without it?
  2. Why does blinking sketches work with millis(), while they do not use any delay() just like my sketch.
  3. Am i a bad person for trying to make smth like an ASAP timer?:) Is saved ram and cpu time worth of it? Any other possible problems?
  4. Can this sketch be workable without delay() or other complex or ram and cpu costly functions?

Thank you.

So, the sketch up there works indeed, but here is the version that you can can observe with your eyes:

boolean onOff=1;
unsigned int counter=0;
unsigned long time=0;

void setup() {
  pinMode(13, OUTPUT);
  Serial.begin(57600);
}

void loop() {
   if (counter==0)  time=micros();
    counter++;
    if (counter == 0) {
        onOff= !onOff;
    digitalWrite(13, onOff);
    Serial.println(micros()-time);
    }
}

With Serial i was checking delay between blinks, and it is 140164 mcs = 140 ms = 0.14s. But to be honest it feels slower, so please correct me if i can benchmark it in a better way.

7
  • 1
    Without delay() it is doing exactly what you tell it. It is blinking the LED - just far too fast for you to see. Try using values in the hundreds of millions instead of just a few hundred for your counter.
    – Majenko
    Commented Aug 20, 2016 at 11:58
  • 1
    The typical design pattern used to perform a delay without delay() is described here: arduino.cc/en/Tutorial/BlinkWithoutDelay Commented Aug 20, 2016 at 12:02
  • millis() uses long variable (which is bad for cpu time and ram)” If you never need to compare timestamps more than 65 seconds apart, then you can do the timekeeping with 16-bit unsigned integers. Commented Aug 20, 2016 at 13:16
  • @Edgar Bonet , i was thinking about it, but what happens, when previous millis() value is 60000, and than it overflowed and current millis() is 3000? 3000-60000=-57000, and who knows what will arduino do next... Or did i miss smth? Tell me please if so, that would a nice solution. Commented Aug 20, 2016 at 20:41
  • @ Dirk Grappendorf , thank you for that, but it also uses millis(), and it is too costly in my current project. Commented Aug 20, 2016 at 20:45

2 Answers 2

1

As majenko answered in the comments, the blinking rate will be so fast you can not see it.
Also it is possible that without the delay the optimizer removes the whole counting. So increasing the number as proposed by majenko may not even work due to compiler optimisations.
Using a method based on counters is a very unreliable way to use timings.

Look at the blinkwithout delay example as proposed by Dirk.
It boils down to using millis() for timing. millis tells you how many millis the arduino is running.

void loop() {
  // here is where you'd put code that needs to be running all the time.

  // check to see if it's time to blink the LED; that is, if the
  // difference between the current time and last time you blinked
  // the LED is bigger than the interval at which you want to
  // blink the LED.
  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);
  }
}
7
  • There is absolutely no reason for the optimizer to remove the counting. If it did that sort of thing then nothing would ever work. The compiler has no clue what delay() does.
    – Majenko
    Commented Aug 20, 2016 at 12:56
  • You are right when delay is there. I mean when delay is gone.
    – jantje
    Commented Aug 20, 2016 at 13:38
  • Why do you think that removing a function that has no relationship at all with the counting would affect how the compiler optimizes the counting?
    – Majenko
    Commented Aug 20, 2016 at 13:39
  • because loop() is actually in a while(true) loop. So without the delay you get while(true){count++;if(count==316){[something]}}. Which can get optimized to while(true){[something]}. I have had that happen to me.
    – jantje
    Commented Aug 20, 2016 at 13:44
  • What makes you think the optimizer would ever do something as idiotic as that? (By the way: try it for your self. Compile the code without delay() and look at the assembly output. You'll see the count never gets optimized out). The only time the optimizer would remove the counting is if the result of the counting does nothing (i.e., if the if is empty).
    – Majenko
    Commented Aug 20, 2016 at 13:50
0

This sketch blinks an LED on D10 (on a Uno) at one second intervals. It does not use delay, micros, millis or any unsigned long variables (apart from a constant).

const int STROBE_FREQ = 1000;     // sets the period in milliseconds 
const unsigned long countTo = ((float) F_CPU / 1024.0) / (1000.0 / STROBE_FREQ); 

void setup ()
  {
  // D10 to output
  bitSet (DDRB, 2);

  // Fast PWM top at OCR1A
  TCCR1A = bit (WGM10) | bit (WGM11); // fast PWM
  TCCR1B = bit (WGM12) | bit (WGM13) | bit (CS12) | bit (CS10);   // fast PWM, prescaler of 1024
  OCR1A = countTo - 1;                 // zero relative 
  OCR1B = (countTo / 2) - 1;           // 50% duty cycle
  bitSet (TCCR1A, COM1B1);   // clear OC1B on compare
  }  // end of setup

 void loop ()
   {
    // do something useful
   }

It frees up the main loop to do something useful without worrying about time taken to do the blinking.

For more details see my page about timers.

2
  • Wow, thank you for that! But that is so much more than i know for know, i do not really understand that sketch. Can you please provide some more info or some links, so that i could learn what is going on there? Do i understand correctly that some hardware timer is used here? Also i have no clue how to make a second timer for another pin in that sketch, would love extended example. Thank you again! Commented Aug 21, 2016 at 0:38
  • See amended reply. Yes, it uses a hardware timer.
    – Nick Gammon
    Commented Aug 21, 2016 at 1:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.