Monday, August 5, 2013

Arduino Tutorial - Quick and Dirty Blink Without Delay

I was writing a sketch for a project I am working on and I needed to add a blinking cursor on a character. My first thought was on how many new variables would need to be added to keep track of state and time between states and the time since the last change. It's not a big deal but it seems like a lot just for a little bit of the on off on off. I had just been working with bitRead() on a different problem and the light blub flicked on that I could use that to watch a bit of millis() and use the toggling of the bit as my on/off switch.

The easiest way to demonstrate this is with the Blink sketch.

const int led = 13;  

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

void loop() {
  digitalWrite(led, HIGH);   
  delay(1000);               
  digitalWrite(led, LOW);   
  delay(1000);               
}

This is what you get from the Arduino IDE built-in Blink sketch. The issue with this that makes it almost useless code, other than for learning, is that nothing can happen during those delays. Each delay is 1 second your project will be doing nothing.

So then you've got the BlinkWithDelay Sketch:

const int ledPin =  13;     
int ledState = LOW;             
long previousMillis = 0;      
long interval = 1000;           

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

void loop()
{
  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) 
  {
    previousMillis = currentMillis;   
    
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;

    digitalWrite(ledPin, ledState);
  }
}

Now that ends up with 3 variables and some logic for tracking. Again, not a big deal and pretty easy to follow what's going on. But if you just need repetitive high low action then here is what you can do to get it quick and easy:

const int led = 13;  

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

void loop() {
  if(bitRead(millis(),10) == 0)
  {
    digitalWrite(led, HIGH); 
  )
  else
  {
    digitalWrite(led, LOW);  
  }          
}

That's it, just replace the delays with an if/else statement checking the 10th bit of the unsigned long returned from millis() and you will get about a 1 second delay. It's ease starts to degrade when you need more control over the blinking interval but if you want an even tempo flash then this will get the job done.

Now if you care for a bit of explaining you can read on.

bitRead(data, n) will take the data and put out the n-th bit from it. So bitRead(B00001000, 3) would return 0 and bitRead(B00001000, 4) would return 1.

millis() gives the number of milliseconds since the sketch started. After 3 seconds of running millis() would return 3000. So every 1ms the first (from the right) bit of millis() would flip. After every 2ms the second bit would flip, 4ms the third, 8ms the forth and so on. This lets you get an equal beat without a lot of code.

As a bit of a bonus (pun intended) if you check the 9th bit and the 8th bit in the if statement you will get a longer on then off period. I was able to get a uniquely blinking cursor by checking the 9th bit and the 7th bit. There is a brief on period and then a Double Flash.
   
     unsigned long time = millis();
     if(bitRead(time,9) == 0 && bitRead(time,7) == 0)
  

No comments:

Post a Comment