arduino‎ > ‎

yet another blink example

Arduino - Blink tutorial examples with a few programming tips.


A bad example


#define LED_PIN 13
#define LED_ON  HIGH
#define LED_OFF LOW
#define LED_DELAY_MSEC 1000

void setup() {
  /* initialize LED_PIN for output */
  pinMode(LED_PIN, OUTPUT);
}

void loop() {
  int ledstat = LED_OFF;

  ledstat = (ledstat == LED_ON) ? LED_OFF : LED_ON;
  digitalWrite(LED_PIN, ledstat);
  delay(LED_DELAY_MSEC);
}

LED_PIN, LED_ON, LED_OFF, LED_DELAY_MSEC macros definitions(line 1-4) are good for represent what we want to do.And it's easy to change If we want to change LED layout or blink interval.

Operator A ? B : C (of programing language C) stands for if A { B } else { C }. We can rewrite with if-else statement. Strictly speaking, those are not same.

What is wrong with the above example?

Function loop() is called every time by function main(). In function loop(), storage class of the variable ledstat is auto. Every time loop() is called make:

ledstat is initialized to LED_OFF.
int ledstat = LED_OFF;
ledstat is set to LED_ON after all.
ledstat = (ledstat == LED_ON) ? LED_OFF : LED_ON;

Our LED is always ON, this is why the above is a bad example.

LED status with a global variable


#define LED_PIN 13
#define LED_ON  HIGH
#define LED_OFF LOW
#define LED_DELAY_MSEC 1000
int ledstat;

void setup() {
  /* initialize LED_PIN for output */
  pinMode(LED_PIN, OUTPUT);
  ledstat = LED_OFF;
}

void loop() {
  ledstat = (ledstat == LED_ON) ? LED_OFF : LED_ON;
  digitalWrite(LED_PIN, ledstat);
  delay(LED_DELAY_MSEC);
}

Define ledstat as a global variable. A global variable can be seen and modifed in the whole sketch. In the example, declare the global variable ledstat almost top of the sketch, initialize the variable in the function setup(), flip the value in the function loop().

We had better remember that many programmers say that a few global variables are useful, but many global variables are confusing.

LED status with a local variable


#define LED_PIN 13
#define LED_ON  HIGH
#define LED_OFF LOW
#define LED_DELAY_MSEC 1000

void setup() {
  /* initialize LED_PIN for output */
  pinMode(LED_PIN, OUTPUT);
}

void loop() {
  static int ledstat;
  
  ledstat = (ledstat == LED_ON) ? LED_OFF : LED_ON;
  digitalWrite(LED_PIN, ledstat);
  delay(LED_DELAY_MSEC);
}


What is the difference from the bad example?

Look at the example carefully, the variable ledstat is defined as 'static' storage class. A static storage class variable keep the value when function has finished unlike auto storage class variable. And a local static variable can be seen and modified only in the scope(i.e. in the function loop()).

By the way, what is the value of ledstat at first? The answer is I don't know and care. Anyway, the statement
ledstat = (ledstat == LED_ON) ? LED_OFF : LED_ON;
will determine the value LED_ON or LED_OFF (and flip the value).

LED status with a general purpose register of AVR


#define LED_PIN 13
#define LED_ON  HIGH
#define LED_OFF LOW
#define LED_DELAY_MSEC 1000
register unsigned char ledstat asm("r2");

void setup() {
  /* initialize LED_PIN for output */
  pinMode(LED_PIN, OUTPUT);
  asm volatile("clr r2");
}

void loop() {
  ledstat = (ledstat == LED_ON) ? LED_OFF : LED_ON;
  digitalWrite(LED_PIN, ledstat);
  delay(LED_DELAY_MSEC);
}


It looks like the example with a global variable, but the definition of ledstat and the initialization in setup() function is different.

A register is a tiny(8 bit, declared as unsigned char) area inside of CPU with the name of register:

register unsigned char ledstat asm("r2");

We need a special instruction for clear register in setup() function:

asm volatile("clr r2");

For more information, visit avr-libc: Frequently Asked Questions and avr-libc: Inline Assembler Cookbook . Further reading(or if you were a professional), we can get detailed information from Atmel Products Datasheets web site.

Play the above sketches

Ok, we can get those.