Ticker

Table of Contents

  1. Hello World!
  2. API
  3. Examples

The Ticker interface is used to setup a recurring interrupt to repeatedly call a function at a specified rate.

Any number of Ticker objects can be created, allowing multiple outstanding interrupts at the same time. The function can be a static function, or a member function of a particular object.

Hello World!

A simple program to setup a Ticker to invert an LED repeatedly...

» Import this program

#include "mbed.h"
 
Ticker flipper;
DigitalOut led1(LED1);
DigitalOut led2(LED2);
 
void flip() {
    led2 = !led2;
}
 
int main() {
    led2 = 1;
    flipper.attach(&flip, 2.0); // the address of the function to be attached (flip) and the interval (2 seconds)
 
    // spin in a main loop. flipper will interrupt it to call flip
    while(1) {
        led1 = !led1;
        wait(0.2);
    }
}

API

API summary

» Import latest build into a program

Public Member Functions

void  attach (void(*fptr)(void), float t)
  Attach a function to be called by the Ticker , specifiying the interval in seconds.
template<typename T >
void  attach (T *tptr, void(T::*mptr)(void), float t)
  Attach a member function to be called by the Ticker , specifiying the interval in seconds.
void  attach_us (void(*fptr)(void), unsigned int t)
  Attach a function to be called by the Ticker , specifiying the interval in micro-seconds.
template<typename T >
void  attach_us (T *tptr, void(T::*mptr)(void), unsigned int t)
  Attach a member function to be called by the Ticker , specifiying the interval in micro-seconds.
void  detach ()
  Detach the function.

Static Public Member Functions

static void  irq (uint32_t id)
  The handler registered with the underlying timer interrupt.

Warning

Note that timers are based on 32-bit int microsecond counters, so can only time up to a maximum of 2^31-1 microseconds i.e. 30 minutes. They are designed for times between microseconds and seconds. For longer times, you should consider the time()/Real time clock.

No blocking code in ISR

In ISR you should avoid any call to wait, infinitive while loop, or blocking calls in general.

No printf, malloc, or new in ISR

In ISR you should avoid any call to bulky library functions. In particular, certain library functions (like printf, malloc and new) are non re-entrant and their behaviour could be corrupted when called from an ISR.

RTOS Timer

Consider using the mbed RTOS Timer instead of a Ticker. In this way your periodic function will not be executed in a ISR, giving you more freedom and safety in your code.

Examples

Example attaching a member function to a ticker:

» Import this program

#include "mbed.h"
 
// A class for flip()-ing a DigitalOut 
class Flipper {
public:
    Flipper(PinName pin) : _pin(pin) {
        _pin = 0;
    }
    void flip() {
        _pin = !_pin;
    }
private:
    DigitalOut _pin;
};
 
DigitalOut led1(LED1);
Flipper f(LED2);
Ticker t;
 
int main() {
    t.attach(&f, &Flipper::flip, 2.0); // the address of the object, member function, and interval
 
    // spin in a main loop. flipper will interrupt it to call flip
    while(1) {
        led1 = !led1;
        wait(0.2);
    }
}




33 comments:

06 Dec 2010

Has anyone used Ticker() to develop a thread scheduler or some other type of preemptive multiprocessor OS?

» Show archived comment by satorud
07 Dec 2010

the function says attach_us where the description says micro-seconds

» Show archived comment by simon
07 Dec 2010

Hi Stephan,

Yes, that is correct. In general:

  • milli-seconds is shortened to ms
  • micro-seconds is shortened to us

Simon

19 Dec 2010

When I create multiple Ticker objects, are the attached functions executed in parallel? E.g. When I have one ticker updating the first line of a LCD every second, and other ticker updating the second line of the same LCD every 5 second, do I need some form of synchronization (a semaphore) or are these calls executed after each other?

28 Dec 2010

Just a suggestion...

The example code for Ticker in the "mbed" library browser declares the ticker object using the identifier "timer". Would "ticker" be a more appropriate identifier? There's nothing wrong with the code, but this caused me a little confusion between the Timer and Ticker classes for about half an hour. All sorted now :) (P.S. mbed is a superb product)

28 Dec 2010

Hendrick; they don't execute in parallel, as one will get there first and they both have the same priority. So you should be fine

John; thanks for the pointer. I'll note that to be updated at the next natural point.

Simon

11 Jan 2011

how small can I make the wait time?

11 Jan 2011

user shang wang wrote:

how small can I make the wait time?

AFAIK one microsecond (when you use the attach_us methods). But then your callbacks would need to be really fast...

29 Jan 2011

My question is the opposite...how LONG can I make the wait time?

I have two tickers set up, one that goes off every 0.25 seconds, and another that goes off...well, if I set it to every minute, they both work, if I set it to every hour (60.0*60.0) then the shorter one never goes off. And I haven't waited around long enough to see if the longer one does ;)

20 Mar 2011

How do I pass arguments to a function that is to be attached using the Ticker function.

for e.g using the above example if the function flip was something like

void flip (int x) { x= x+1; }

How do I attacn this function with Ticker???

09 Apr 2011

I have the same question as Kunai.

I have the function: void ledpwmonoff(int lednr) {

And the ticker attach attempt: ticker.attach(&ledpwmonoff(1),24.0);

Which gives the error: expression must be an lvalue or a function designator (E158)

tried some (()()())))()()'s around ledpwnonoff in the attach, but didn't work.

09 Apr 2011

Make a small wrapper and attach that.

void ledon()
{
  ledpwmonoff(1);
}
[...]
ticker.attach(ledon, 24.0);
15 Apr 2011

What I mean to accomplish is something like

void ledpwmonoff(int lednr) {
    switch(lednr) {
        case 1: led1=!led1;
        case 2: led2=!led2;
        case 3: led3=!led3;
        case 4: led4=!led4;
    }
}

int main() {
    ticker.attach(&ledpwmonoff(int variable),2.0); //variable = the lednr; 1,2,3 or 4
    wait(0.5);
    ticker.attach(&ledpwmonoff(int variable),2.0); //variable = the lednr; 1,2,3 or 4
    wait(0.5);
    ticker.attach(&ledpwmonoff(int variable),2.0); //variable = the lednr; 1,2,3 or 4
    wait(0.5);
    ticker.attach(&ledpwmonoff(int variable),2.0); //variable = the lednr; 1,2,3 or 4
}

which should create a very simple lightshow ;) The wrapper does solve the error, but not the problem I was having ;)

Regards,

Melchior

15 Apr 2011

Simple solution is probably to make 4 seperate functions :)

15 Apr 2011

You could always use templates to do the work for you if you did want to go down this closure-style route:

#include "mbed.h"

DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);

void ledpwmonoff(int lednr) {
    switch(lednr) {
        case 1: led1=!led1;
        case 2: led2=!led2;
        case 3: led3=!led3;
        case 4: led4=!led4;
    }
}

template<void (*fptr)(int), int value>
void caller() { 
    fptr(value);
}

Ticker ticker;

int main() {
    ticker.attach(caller<&ledpwmonoff,1>, 2.0);
    wait(0.5);
    ticker.attach(caller<&ledpwmonoff,2>, 2.0);
    wait(0.5);
    ticker.attach(caller<&ledpwmonoff,3>, 2.0);
    wait(0.5);
    ticker.attach(caller<&ledpwmonoff,4>, 2.0);
    wait(0.5);
}

Simon

20 Apr 2011

I'm a novice C++ programmer and I've been playing with the examples above, even though I don't fully understand what I'm doing! That said, it looks like the above example should be using 4 different tickers rather than just 1. When I tried it, only LED4 does anything. I modded the code:

Ticker ticker1;
Ticker ticker2;
Ticker ticker3;
Ticker ticker4;
int main() {
    ticker1.attach(caller<&ledpwmonoff,1>, 2.0);
    wait(0.5);
    ticker2.attach(caller<&ledpwmonoff,2>, 2.0);
    wait(0.5);
    ticker3.attach(caller<&ledpwmonoff,3>, 2.0);
    wait(0.5);
    ticker4.attach(caller<&ledpwmonoff,4>, 2.0);
//  wait(0.5);
}

now all 4 LEDs dance!

Graeme

21 Apr 2011

Ah right, that makes sense Graeme : )

I wrote the example just to explain what I wanted to achieve but I see that it would just overwrite the ticker 4 times, leaving only the last one with LED4. Your solution solves that!

And cheers Simon, I will have a go with the template when I'm at home. Graeme's response is cause for optimism ^^

Thanks,

Melchior

17 Nov 2011

From the http://mbed.org/forum/mbed/topic/1189/?page=1#comment-14619 post:

Quote:

All mbed tickers use the TIMER3 object, so you can create a critical section in your main code to access a buffer being written to by a Ticker handler:

NVIC_DisableIRQ(TIMER3_IRQn);

// critical section
 
NVIC_EnableIRQ(TIMER3_IRQn);

21 Nov 2011

Hello guys, i am new to programming and try to set up a ticker. my code looks like this:

class1.h
#include "mbed.h"

class class1 {
  private:
    Ticker ticker;
  public
    class1();
    void func();
};

class1.cpp
#include "class1.h"

class1::class1() {
  ticker.attach(&class1::func, 2.0);
}

class1::func() {
  //Do something
}

i always get the error: "no instance of overloaded function "mbed::Serial::attach" matches the argument list"

if i put the function func() in a separate .h-file not as a memberfunction and then call:

  ticker.attach(func,2.0);

everything works fine. Can someone help me with the correct syntax?? Thank You.

21 Nov 2011

The member-function version of attach() also needs an instance pointer. Try:

class1::class1() {
  ticker.attach(this, &class1::func, 2.0);
}

Posting new comments for this page has been disabled