Pages: [1]   Go Down
Author Topic: Other ways to Blink !  (Read 3257 times)
0 Members and 1 Guest are viewing this topic.
SF Bay Area (USA)
Offline Offline
Tesla Member
***
Karma: 135
Posts: 6788
Strongly opinionated, but not official!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

There are relatively common questions along the lines of "what if I don't want to use the Arduno library functions, so that my code looks more like the code used with WINAVR or AVRStudio or AVR gcc, or whatever?"

Here are several examples of Arduino sketches that implement "Blink" (blink the pin 13 LED in a one second on, one second off pattern) in ways that do NOT use the Arduino functions.  However, they ARE all arduino "sketches", and compile and run from within the arduino environment on regular arduino hardware.

Enjoy!
Logged

SF Bay Area (USA)
Offline Offline
Tesla Member
***
Karma: 135
Posts: 6788
Strongly opinionated, but not official!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Here is blink implemented in assembler (inline assembler within the C compiler, withing C++, within Arduino.
There are two copies here; one pretty-printed, and one that should be easily cut&pasteable.
Quote
/* blick-asm.pde
 *
 * Blink using inline assembler, from Arduino IDE.
 *
 * Turns on an LED on for one second, then off for one second, repeatedly.
 *
 * One of a series of "Blink" examples using various techniques.
 *   This praticular example uses inline assembler, and ignores the
 *   arduino functions and "background" tasks.
 *
 * The circuit:
 *     LED connected from digital pin 13 to ground, with suitable resistor.
 *
 *     Note: On most Arduino boards, there is already an LED on the board
 *     connected to pin 13, so you don't need any extra components for this example.
 *
 * Created Nov 2009, by Bill Westfield.
 *   Based on the blink.pde example distributer with the Arduino IDE,
 *      Created 1 June 2005 By David Cuartielles
 *        based on an orginal by H. Barragan for the Wiring i/o board
 */

#define LEDPORT PORTB    // Arduino pin 13 is bit 5 of port B
#define LEDPORT_DIR DDRB
#define LEDBIT 5

// The setup() method runs once, when the sketch starts
// For this example, we're going to put ALL of our code in setup, and
// never actually return...

void setup()   {

  asm volatile ("  sbi %[portdir], %[lbit]  \n"    // Set bit direction
      "3: "                                        // main loop label
      "   sbi %[port], %[lbit] \n"                 //  Turn on.
          /*
           * About the delay loop:
           *   The inner loop (dec, brne) is 3 cycles.
           *   For one second, we want 16million cycles, or 16000000/(3*256*256) loops.
           *   This is "about" 81.
           */
      "    clr r16  \n"
      "    clr r17  \n"
      "    ldi r18, 81  \n"   // 100 * 256
      "1:"  // 1st delay loop label
      "        dec r16  \n"
      "        brne 1b  \n"
      "      dec r17    \n"
      "      brne 1b    \n"
      "    dec r18      \n"
      "    brne 1b      \n"
      
      "    cbi   %[port], %[lbit] \n"             // Turn off.
      
      "    clr r16  \n"
      "    clr r17  \n"
      "    ldi r18, 81  \n"
      "2:"  // 2nd delay loop label
      "        dec r16  \n"
      "        brne 2b  \n"
      "      dec r17    \n"
      "      brne 2b    \n"
      "    dec r18      \n"
      "    brne 2b      \n"
      
      "    rjmp 3b  \n"
      :
      :"I" (_SFR_IO_ADDR(LEDPORT_DIR)),
       "I" (_SFR_IO_ADDR(LEDPORT)),
      [lbit] "I" (LEDBIT)
      );
}

// Note that we never get to loop, since setup above loops forever.
void loop()                    
{
}
Code:
/* blick-asm.pde
 *
 * Blink using inline assembler, from Arduino IDE.
 *
 * Turns on an LED on for one second, then off for one second, repeatedly.
 *
 * One of a series of "Blink" examples using various techniques.
 *   This praticular example uses inline assembler, and ignores the
 *   arduino functions and "background" tasks.
 *
 * The circuit:
 *     LED connected from digital pin 13 to ground, with suitable resistor.
 *
 *     Note: On most Arduino boards, there is already an LED on the board
 *     connected to pin 13, so you don't need any extra components for this example.
 *
 * Created Nov 2009, by Bill Westfield.
 *   Based on the blink.pde example distributer with the Arduino IDE,
 *      Created 1 June 2005 By David Cuartielles
 *        based on an orginal by H. Barragan for the Wiring i/o board
 */

#define LEDPORT PORTB    // Arduino pin 13 is bit 5 of port B
#define LEDPORT_DIR DDRB
#define LEDBIT 5

// The setup() method runs once, when the sketch starts
// For this example, we're going to put ALL of our code in setup, and
// never actually return...

void setup()   {

  asm volatile ("  sbi %[portdir], %[lbit]  \n"    // Set bit direction
      "3: "                                        // main loop label
      "   sbi %[port], %[lbit] \n"                 //  Turn on.
          /*
           * About the delay loop:
           *   The inner loop (dec, brne) is 3 cycles.
           *   For one second, we want 16million cycles, or 16000000/(3*256*256) loops.
           *   This is "about" 81.
           */
      "    clr r16  \n"
      "    clr r17  \n"
      "    ldi r18, 81  \n"   // 100 * 256
      "1:"  // 1st delay loop label
      "        dec r16  \n"
      "        brne 1b  \n"
      "      dec r17    \n"
      "      brne 1b    \n"
      "    dec r18      \n"
      "    brne 1b      \n"
      
      "    cbi   %[port], %[lbit] \n"             // Turn off.
      
      "    clr r16  \n"
      "    clr r17  \n"
      "    ldi r18, 81  \n"
      "2:"  // 2nd delay loop label
      "        dec r16  \n"
      "        brne 2b  \n"
      "      dec r17    \n"
      "      brne 2b    \n"
      "    dec r18      \n"
      "    brne 2b      \n"
      
      "    rjmp 3b  \n"
      :
      : [portdir] "I" (_SFR_IO_ADDR(LEDPORT_DIR)),
        [port] "I" (_SFR_IO_ADDR(LEDPORT)),
      [lbit] "I" (LEDBIT)
      );
}

// Note that we never get to loop, since setup above loops forever.
void loop()                    
{
}
Logged

SF Bay Area (USA)
Offline Offline
Tesla Member
***
Karma: 135
Posts: 6788
Strongly opinionated, but not official!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

This one uses pure C code to manipulate the LED IO, but uses the timer maintained by the arduino runtime to time the delay loop.  Again, two copies...

Quote
/* blick-c.pde
 *
 * Blink in "pure" C, within the Arduino environment.
 *
 * Turns on an LED on for one second, then off for one second, repeatedly.
 *
 * One of a series of "Blink" examples using various techniques.
 *   This praticular example uses pure C code writing directly to the AVR PORTS,
 *   and none of the actual Arduino library functions, but it uses the millisecond
 *   timer maintained by the arduino runtime environment for the delay loop.
 *
 * The circuit:
 *     LED connected from digital pin 13 to ground, with suitable resistor.
 *
 *     Note: On most Arduino boards, there is already an LED on the board
 *     connected to pin 13, so you don't need any extra components for this example.
 *
 * Created Nov 2009, by Bill Westfield.
 *   Based on the blink.pde example distributer with the Arduino IDE,
 *      Created 1 June 2005 By David Cuartielles
 *        based on an orginal by H. Barragan for the Wiring i/o board
 */

#define LEDPORT PORTB    // Arduino pin 13 is bit 5 of port B
#define LEDPORT_DIR DDRB
#define LEDBIT 5

/*
 * timer0_millis is a variable maintained by the arduino environment.
 * it is incremented as appropriate inside a timer0 interrupt routine,
 * and must be declared "volatile" so that the compiler knows its value
 * can change even though we don't change it.
 */
extern volatile unsigned long timer0_millis;  // maintained by arduino environment

// The setup() method runs once, when the sketch starts

void setup()   {                
  // initialize the digital pin as an output:
  LEDPORT_DIR = _BV(LEDBIT);
}

// the loop() method runs over and over again,
// as long as the Arduino has power

void loop()                    
{
  unsigned long timeout;
  
  LEDPORT |= _BV(LEDBIT);         // on
  timeout = timer0_millis;        // "now"
  while (timer0_millis - timeout < 1000)  // wait till "now" is 1000 ms later.
    ; // spin for one second
    
  LEDPORT &= ~_BV(LEDBIT);       // off
  timeout = timer0_millis;
  while (timer0_millis - timeout < 1000)
    ; // spin for one second
}
Code:
/* blick-c.pde
 *
 * Blink in "pure" C, within the Arduino environment.
 *
 * Turns on an LED on for one second, then off for one second, repeatedly.
 *
 * One of a series of "Blink" examples using various techniques.
 *   This praticular example uses pure C code writing directly to the AVR PORTS,
 *   and none of the actual Arduino library functions, but it uses the millisecond
 *   timer maintained by the arduino runtime environment for the delay loop.
 *
 * The circuit:
 *     LED connected from digital pin 13 to ground, with suitable resistor.
 *
 *     Note: On most Arduino boards, there is already an LED on the board
 *     connected to pin 13, so you don't need any extra components for this example.
 *
 * Created Nov 2009, by Bill Westfield.
 *   Based on the blink.pde example distributer with the Arduino IDE,
 *      Created 1 June 2005 By David Cuartielles
 *        based on an orginal by H. Barragan for the Wiring i/o board
 */

#define LEDPORT PORTB    // Arduino pin 13 is bit 5 of port B
#define LEDPORT_DIR DDRB
#define LEDBIT 5

/*
 * timer0_millis is a variable maintained by the arduino environment.
 * it is incremented as appropriate inside a timer0 interrupt routine,
 * and must be declared "volatile" so that the compiler knows its value
 * can change even though we don't change it.
 */
extern volatile unsigned long timer0_millis;  // maintained by arduino environment

// The setup() method runs once, when the sketch starts

void setup()   {                
  // initialize the digital pin as an output:
  LEDPORT_DIR = _BV(LEDBIT);
}

// the loop() method runs over and over again,
// as long as the Arduino has power

void loop()                    
{
  unsigned long timeout;
  
  LEDPORT |= _BV(LEDBIT);         // on
  timeout = timer0_millis;        // "now"
  while (timer0_millis - timeout < 1000)  // wait till "now" is 1000 ms later.
    ; // spin for one second
    
  LEDPORT &= ~_BV(LEDBIT);       // off
  timeout = timer0_millis;
  while (timer0_millis - timeout < 1000)
    ; // spin for one second
}
Logged

SF Bay Area (USA)
Offline Offline
Tesla Member
***
Karma: 135
Posts: 6788
Strongly opinionated, but not official!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

This version is pure C and ignores the arduino runtime environment as well as the arduino functions.
It uses the delay.h timing loops that come with the avr gcc environment.  (If you copy this outside the arduino environment, be sure to compile with optimization turned on.  Otherwise the floating point macros won't optimize away to integer loops, and won't be accurate either...
Quote
/* blick-utildelay.pde
 *
 * Blink in "pure" C, from the Arduino IDE.
 *
 * Turns on an LED on for one second, then off for one second, repeatedly.
 *
 * One of a series of "Blink" examples using various techniques.
 *   This praticular example uses pure C code writing directly to the AVR PORTS,
 *   and none of the actual Arduino library functions, nor the runtime arduino
 *   functions (timer.)  It uses the busy-loop delay functions provided with gcc.
 *
 * The circuit:
 *     LED connected from digital pin 13 to ground, with suitable resistor.
 *
 *     Note: On most Arduino boards, there is already an LED on the board
 *     connected to pin 13, so you don't need any extra components for this example.
 *
 * Created Nov 2009, by Bill Westfield.
 *   Based on the blink.pde example distributer with the Arduino IDE,
 *      Created 1 June 2005 By David Cuartielles
 *        based on an orginal by H. Barragan for the Wiring i/o board
 */
 
 #include <util/delay.h>

#define LEDPORT PORTB    // Arduino pin 13 is bit 5 of port B
#define LEDPORT_DIR DDRB
#define LEDBIT 5

// The setup() method runs once, when the sketch starts

void setup()   {                
  // initialize the digital pin as an output:
  LEDPORT_DIR = _BV(LEDBIT);
}

// the loop() method runs over and over again,
// as long as the Arduino has power

void loop()                    
{
  unsigned long timeout;
  
  LEDPORT |= _BV(LEDBIT);         // on
  _delay_ms(1000.0);   // magic delay loop
    
  LEDPORT &= ~_BV(LEDBIT);       // off
  _delay_ms(1000.0);   // magic delay loop
}

Code:
/* blick-utildelay.pde
 *
 * Blink in "pure" C, from the Arduino IDE.
 *
 * Turns on an LED on for one second, then off for one second, repeatedly.
 *
 * One of a series of "Blink" examples using various techniques.
 *   This praticular example uses pure C code writing directly to the AVR PORTS,
 *   and none of the actual Arduino library functions, nor the runtime arduino
 *   functions (timer.)  It uses the busy-loop delay functions provided with gcc.
 *
 * The circuit:
 *     LED connected from digital pin 13 to ground, with suitable resistor.
 *
 *     Note: On most Arduino boards, there is already an LED on the board
 *     connected to pin 13, so you don't need any extra components for this example.
 *
 * Created Nov 2009, by Bill Westfield.
 *   Based on the blink.pde example distributer with the Arduino IDE,
 *      Created 1 June 2005 By David Cuartielles
 *        based on an orginal by H. Barragan for the Wiring i/o board
 */
 
 #include <util/delay.h>

#define LEDPORT PORTB    // Arduino pin 13 is bit 5 of port B
#define LEDPORT_DIR DDRB
#define LEDBIT 5

// The setup() method runs once, when the sketch starts

void setup()   {                
  // initialize the digital pin as an output:
  LEDPORT_DIR = _BV(LEDBIT);
}

// the loop() method runs over and over again,
// as long as the Arduino has power

void loop()                    
{
  unsigned long timeout;
  
  LEDPORT |= _BV(LEDBIT);         // on
  _delay_ms(1000.0);   // magic delay loop
    
  LEDPORT &= ~_BV(LEDBIT);       // off
  _delay_ms(1000.0);   // magic delay loop
}
Logged

SF Bay Area (USA)
Offline Offline
Tesla Member
***
Karma: 135
Posts: 6788
Strongly opinionated, but not official!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Feel free to post other interesting methods, preferably in the same general format as the Blink.pde example...
Logged

Norway@Oslo
Offline Offline
Edison Member
*
Karma: 13
Posts: 2033
loveArduino(true);
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Cool idea westfw!

I think all examples will boil down to a) waiting, b) polling or c) interrupts

Here are the procedures I could think of now [those of the ideas that were sane]: (sorry for not implementing/displaying code)

Waiting:
  • Light the LED. Do some action that takes 1 second. Shut off the LED. (repeat)
Polling:
  • Use a library like TimedAction, EventFuse, Scheduler or simply 'Blink without delay'
Interrupt:
  • Use a timer to blink the LED
  • Use an external interrupt wired to an external source that toggles a logic state each second. (Any clock should be a good source.)

My head started spinning.
Maybe we should have a 'most complex blink' competition? Hhehe.
[Hey, have I read about that somwhere?]
« Last Edit: November 08, 2009, 08:42:14 pm by AlphaBeta » Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 18
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

In the assembler example, was there a reason for placing the infinite loop in setup(), or was the decision arbitrary?  This is getting off topic now, but what happens between the call to setup() and the first call to loop(), anything important?
Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 309
Posts: 26495
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
but what happens between the call to setup() and the first call to loop(),
Nothing.
Code:
int main(void)
{
    init();

    setup();
    
    for (;;)
        loop();

    return 0;
}
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Boston, MA
Offline Offline
Edison Member
*
Karma: 0
Posts: 1024
wiblocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I started a C++ debug LED class called LED_debug. Currently the only
parameter for the constructor uses is the pin number. I was thinking of adding an on delay and off delay to the constructor so that the duty cycle defaults could be modified. The code is at http://tinyurl.com/y86gwyk

Here is a usage example ---

Code:
#include <debug_LED.h>
LED_debug led(7); // LED connected to pin 7

void loop() {
   led.blink(3); // blink three times
   led.blink(0); // blink forever
}

(* jcl *)

------------------------------------
www: http://www.wiblocks.com
twitter: http://twitter.com/wiblocks
blog: http://luciani.org
Logged


SF Bay Area (USA)
Offline Offline
Tesla Member
***
Karma: 135
Posts: 6788
Strongly opinionated, but not official!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
was there a reason for placing the infinite loop in setup(), or was the decision arbitrary?
Arbitrary.  Or perhaps "style"; I wanted the assembler to be all in one spot, rather than having a single instruction in setup() to do the equiv of "pinMode", with the rest of the code in loop().
Logged

Pages: [1]   Go Up
Jump to: