Event-Based Library for Arduino

After I worked in my first Arduino programs, maybe because I worked for a good time with languages like Java and C#, I have found that is a job a little outdated. Tasks like to handle push of buttons or turn a LED on smoothly through PWM, although of being easy to understand, require a reasonable volume of code to become consistent, especially when is necessary that various components work simultaneously.

Because I suffer with this problem that I decided to turn all my difficulties in Arduino programming in a collection of classes that assist the programmer. Currently this collection includes the following components:

AnalogEvent

Event handler for analog ports that can be used to read potentiometers or others sensors. Implements the event onChange.

In this example we configure the analog pin 1 to read values from a potentiometer with an hysteresis value of 3:

#include <AnalogEvent.h>

void setup() {
  AnalogEvent.addAnalogPort(1,        //potentiometer pin
                            onChange, //onChange event function
                            3);       //hysteresis
  
  Serial.begin(9600);
}

void loop() {
  AnalogEvent.loop();
}

void onChange(AnalogPortInformation* Sender) {
  Serial.print("Analog (pin:");
  Serial.print(Sender->pin);
  Serial.print(") changed to: ");
  Serial.print(Sender->value);
  Serial.println("!");
}

ButtonEvent

Event handler for buttons (tactile switches) on digital ports. Implements the events onUp, onDown, onHold and onDouble.

In this example we configure the pin 12 as a button with all events enabled:

#include <ButtonEvent.h>

void setup() {
  ButtonEvent.addButton(12,       //button pin
                        onDown,   //onDown event function
                        onUp,     //onUp event function
                        onHold,   //onHold event function
                        1000,     //hold time in milliseconds
                        onDouble, //double event function
                        200);     //double time interval

  Serial.begin(9600);
}

void loop() {
  ButtonEvent.loop();
}

void onDown(ButtonInformation* Sender) {
  Serial.print("Button (pin:");
  Serial.print(Sender->pin);
  Serial.println(") down!");
}

void onUp(ButtonInformation* Sender) {
  Serial.print("Button (pin:");
  Serial.print(Sender->pin);
  Serial.println(") up!");
}

void onHold(ButtonInformation* Sender) {
  Serial.print("Button (pin:");
  Serial.print(Sender->pin);
  Serial.print(") hold for ");
  Serial.print(Sender->holdMillis);
  Serial.println("ms!");
}

void onDouble(ButtonInformation* Sender) {
  Serial.print("Button (pin:");
  Serial.print(Sender->pin);
  Serial.print(") double click in ");
  Serial.print(Sender->doubleMillis);
  Serial.println("ms!");
}

LedControl

Simple LED functions with asynchronous capabilities. Permits turning on, off and dimmer.

In this example two LEDs blinking together in different manners. The LED in pin 9 is configured to 500ms of fade in/out with 1s of interval, and the LED at pin 8 is a simple blinker with 200ms of interval:

#include <LedControl.h>

void setup() {
  LedControl.startBlink(9,1000,500);
  LedControl.startBlink(8,200);
}

void loop() {
  LedControl.loop();
}

This project has their own repository with more information about the classes, usage instructions and download options. The project name is ebl-arduino, that means Event-Based Library for Arduino, and your page could be accessed through the URL GitHub - renatoferreirarenatoferreira/ebl-arduino: Automatically exported from code.google.com/p/ebl-arduino.

Source: Event-Based Library for Arduino

I think Pin Change Interrupts is more powerful way to implements Button Events. :slight_smile:

I understand, Vanyamba. But not all pins offers this feature, limiting the number of buttons that can be handled, and I'm not sure if timed events, like Hold or Double, would work properly due to some architecture's limitations during interrupts. Read this note from attachInterrupt() documentation that explain these limitations:

Inside the attached function, delay() won't work and the value returned by millis() will not increment. Serial data received while in the function may be lost. You should declare as volatile any variables that you modify within the attached function.

As you can see, use interrupts also limits what you could do when the event occurs. While the ButtonEvent class does not impose any limitation.

New classes were added to Event-Based Library for Arduino in your revision 45.

Two new components are now available in this revision:

Properties

Persistent variables handler. Can be used to save configuration data to Arduino EEPROM persistent memory area.

In this example two boot counter variables are saved in EEPROM, one in numeric type and another in string type:

#include <Properties.h>

#define PROPERTY_BOOTS 0
#define PROPERTY_TEXT 1

void setup() {
  Serial.begin(9600);
  
  if (Properties.load()) {
    if (Properties.getInt(PROPERTY_BOOTS)<=15) {
      //print data
      Serial.print("PROPERTY_BOOTS: ");
      Serial.println(Properties.getInt(PROPERTY_BOOTS));
      Serial.print("PROPERTY_TEXT (");
      Serial.print(Properties.get(PROPERTY_TEXT)->valueSize);
      Serial.print("): ");
      Serial.write((byte*)Properties.get(PROPERTY_TEXT)->value,Properties.get(PROPERTY_TEXT)->valueSize);
      Serial.println();
    
      //sum PROPERTY_BOOTS and update text
      Properties.set(PROPERTY_BOOTS,Properties.getInt(PROPERTY_BOOTS)+1);
      char* text = (char*)malloc(32);
      sprintf(text,"Boot times: %d...", Properties.getInt(PROPERTY_BOOTS));
      Properties.set(PROPERTY_TEXT,(void*)text,strlen(text));
      Properties.save();
    } else {
      Serial.println("Flushing!");
      
      //flush data
      Properties.flush();
      Properties.save();
    }
  } else {
    Serial.println("Starting!");
    
    //create data
    Properties.set(PROPERTY_BOOTS,1);
    char* text = (char*)malloc(32);
    sprintf(text,"Boot times: %d...", Properties.getInt(PROPERTY_BOOTS));
    Properties.set(PROPERTY_TEXT,(void*)text,strlen(text));
    Properties.save();
  }
}

void loop() {
  
}

TimedEvent

Simple task scheduler.

In this example one event (event1) is used to control when the another one (event2) is started and stopped at regular intervals while they send data through Serial Monitor:

#include <TimedEvent.h>

#define CONTROLLED_TIMER 1

bool flag = true;

void setup() {
  Serial.begin(9600);

  //event 1
  TimedEvent.addTimer(5000, event1);
  //event 2
  TimedEvent.addTimer(CONTROLLED_TIMER, 500, event2);
  TimedEvent.start(CONTROLLED_TIMER);
}

void loop() {
  TimedEvent.loop();
}

void event1(TimerInformation* Sender) {
  Serial.print("event1: ");
  if (flag=!flag) {
    TimedEvent.start(CONTROLLED_TIMER);
    Serial.println("START!");
  } else {
    TimedEvent.stop(CONTROLLED_TIMER);
    Serial.println("STOP!");
  }
}

void event2(TimerInformation* Sender) {
    Serial.println("event2!!");  
}

This project has their own repository with more information about the classes, usage instructions and download options. It could be accessed through the URL GitHub - renatoferreirarenatoferreira/ebl-arduino: Automatically exported from code.google.com/p/ebl-arduino.

Source: Event-Based Library for Arduino updated to R45!

This is a great idea.

I hope the main developers adopt these concepts and make it part of the core distribution.
Have you tried contacting them to inform them of this capability?

Thanks! I'm planning to write a few more classes and articles before doing it.

Looks cool! I downloaded the libraries, and will give them a try as soon as I get a chance.

theepdinker 8) Don't hesitate to post an issue if you have any problem....

Renato, this is very interesting and may be the thing that enables Arduino to go beyond "the Loop" for more complex tasks.

I'm an old EDX/EDL and other RTOS guy and I will be enjoying trying out your system...

Your idea of AnalogEvent in which the event is a known CHANGE in analog value is great! (I'm surprised I never thought of it! 8) ).

I have been working on Power Control for Arduino (http://arduino-info.wikispaces.com/ArduinoPower) and people want to be able to schedule actions while having flexibility to monitor sensors and conditions.

Can you give us a suggestion / example of scheduling an action some hours (days??) ahead?

I hope you will keep on developing this!!

First of all - thank you for this nice library. Everything works pretty well.
I have one question about ButtonEvent onHold().

The documentation says that the method is called only once. For my project I want to execute some code during the button was pressed.

The idea is to increment a variable by 1 during the button was pressed and to stop incrementing when the button is released.

Thank you in advance.

The idea is to increment a variable by 1 during the button was pressed and to stop incrementing when the button is released.

Then I would think you can start incrementing with onDown and stop with onUp.


Rob

Thanks for all who are enjoying this work! XD And sorry for this later reply. It will not happen anymore. :roll_eyes:

Terry King, are you trying to do a real-time based scheduler? It's a good idea. If you have a RTC circuit, it's possible to calculate the time left to reach a specific date/hour to use as event parameter. Or you could add an event for each second, for example, and then read RTC time to make the decision. Unfortunately I dont have a RTC circuit here to properly implemente this function. Remember that you can always change the interval directly through TimerInformation.intervalMillis (Sender->intervalMillis) variable when the event is raised.

Alexander Tzokev, are you trying to measure the button holding time? It can be read through ButtonInformation.holdMillis (Sender->holdMillis) on onUp event, and then you can transform it in your desirable scale.

More functionalities are comming soon. Any more ideas are welcome.

Thanks!!

Rferreira:
...
Terry King, are you trying to do a real-time based scheduler? It's a good idea. If you have a RTC circuit, it's possible to calculate the time left to reach a specific date/hour to use as event parameter. Or you could add an event for each second, for example, and then read RTC time to make the decision. Unfortunately I dont have a RTC circuit here to properly implemente this function.
...

Hi Renato, Sorry I was off on other things....

If you are interested in developing a way to integrate the RTC function,I'd be happy to send you one. Like this: http://arduino-direct.com/sunshop/index.php?l=product_detail&p=48 It will probably take a while through Infamous Brazil Shipping... Send me a shipping address to terry@yourduino.com

I think many people are looking for a straightforward way of scheduling events without writing it all in their own main loops. Ideally there would be a Processing/VB/Whatever program in an attachable computer that could update the schedule... Hmmmm.

The lastest ebl-arduino release (r52) brings to Arduino's users an easy way to exchange comands and data between PC and Arduino using .Net, being also easy to port to another languages and transports (TCP and so on).

AdvancedSerial

A new class that implements a serial protocol to make easier the communication between PC applications and Arduino sketches.

It is an example of sketch that receive commands from PC to control an LCD display:

#include <AdvancedSerial.h>
#include <LiquidCrystal.h>

#define BACKLIGHT_ON_MESSAGE 0
#define BACKLIGHT_OFF_MESSAGE 1
#define TEXT_MESSAGE 2

//pins
#define PIN_BACKLIGHT 7

//configure lcd
LiquidCrystal lcd(13, 12, 11, 10, 9, 8);

void setup() {
  //configure backlight pin
  pinMode(PIN_BACKLIGHT, OUTPUT);
  //configure LCD
  lcd.begin(16, 2);
  //begin serial port with a desirable speed
  Serial.begin(115200);
  //configure receiver callback
  AdvancedSerial.setReceiver(onMessage);
}

void loop() {
  //AdvancedSerial job
  AdvancedSerial.loop();
}

void onMessage(AdvancedSerialMessage* message) {
  switch (message->id) {
    case BACKLIGHT_ON_MESSAGE:
      digitalWrite(PIN_BACKLIGHT, HIGH);
      break;
      
    case BACKLIGHT_OFF_MESSAGE:
      digitalWrite(PIN_BACKLIGHT, LOW);
      break;
      
    case TEXT_MESSAGE:
      lcd.clear();
      for (int i=0; i<message->size; i++) {
        if (i==16) lcd.setCursor(0, 1);
        lcd.write((char)message->payload[i]);
      }
      break;
  }
}

Client API - AdvancedSerialClient

AdvancedSerialClient is the communication entry-point for AdvancedSerial based sketches. It permits to ensure that the device is connect, send messages to it and receive asynchronous events.

This part of a C# code is responsible to send control messages to LCDWriter sketch from last example:

try
{
    //create object
    AdvancedSerialClient ArduinoClient = new AdvancedSerialClient();
    //connect to device
    ArduinoClient.Open(Arguments[PARAMETER_PORT].ToString(), 115200);

    //command for LED
    if (Arguments.ContainsKey(PARAMETER_BACKLIGHT))
    {
        SerialProtocol.AdvancedSerialMessage BacklightMessage = new SerialProtocol.AdvancedSerialMessage();

        if ((bool)Arguments[PARAMETER_BACKLIGHT])
            BacklightMessage.ID = BACKLIGHT_ON_MESSAGE;
        else
            BacklightMessage.ID = BACKLIGHT_OFF_MESSAGE;

        ArduinoClient.Send(BacklightMessage);
    }

    //command for text
    if (Arguments.ContainsKey(PARAMETER_TEXT))
    {
        SerialProtocol.AdvancedSerialMessage TextMessage = new SerialProtocol.AdvancedSerialMessage();
        TextMessage.ID = TEXT_MESSAGE;
        TextMessage.Payload = new System.Text.ASCIIEncoding().GetBytes(Arguments[PARAMETER_TEXT].ToString());
        TextMessage.Size = (byte)TextMessage.Payload.Length;
        ArduinoClient.Send(TextMessage);
    }
}
catch (Exception ex)
{
    Console.Write("Error: " + ex.Message);
}

The complete, and ready to use, source for this example is available in library source tree.

Running the example

It's needed to properly run this example:

  • 1 Arduino;
  • 1 Breadboard (don't forget the jumper wires);
  • 1 Display 1602A (16x2 with backlight);
  • 1 10k potentiometer.

The components must be assembled in breadboard as following:

Click here to download the Fritzing source file for this project.

Once you've uploaded the LCDWriter sketch from AdvancedSerial examples (IDE menu: File/Examples/AdvancedSerial/LCDWriter) to your Arduino board the LCDWrite.exe client API example (IDE directory: libraries\AdvancedSerial\clientapi\dotnet\Release) will be able to control the backlight and text shown in LCD display.

In closing, a short demonstration of this example running:

This project has their own repository with more information about the classes, usage instructions and download options. It could be accessed through the URL GitHub - renatoferreirarenatoferreira/ebl-arduino: Automatically exported from code.google.com/p/ebl-arduino.

Source: Controlling Arduino with .Net

Hello Renato,

Wow, you have been busy with this..

I am convinced this will be the way to go for sophisticated Arduino applications such as 24-7 Automation for Home, and other controls such as Garden/Hydroponic systems etc, etc.

I will write up my notes on a scheduling concept later today and maybe we can discuss that further.

I am in the throes of packing my Lab and other belongings that will be shipped to Italy for next year, and the Arduino stuff I will bring back to the US for the Summer. In a couple days that will settle down and I will be writing more...

The combination of non-blocking functions in your RTOS and efficient and easy to set up scheduling (A scheduled Time is just an Event, right?) will make many cool applications possible.

Hello, Terry... It's a bit boring to debug an serial application when the only interface to it is the same serial port. The IDE's Serial Monitor holds an exclusive access to serial port and does not permit things to work toguether. :smiley:

Send me an email when you feel ready to get back our discussion. OK? :wink:

Hi Renato,

Today all my stuff going to Italy for next year from here (Saudi Arabia) is going on the truck.

Couple more days and I can Think. (As we used to say in IBM ...)

From Saudi Arabia to Italy by truck?! :astonished:

Hi,

I have just been looking over your event lib. Very nice piece of work, well done. I also programme in .NET SF/CF/MF.

I was wondering if you might like to consider extending the properties lib to use an SD card to overcome the R/W cycle limitations.

I would also be very interested in an event driven ethernet lib and I2C for RFID etc. I am happy to collaborate on these if you fancy taking them on.

Cheers Pete.

Bainesbunch, I'm also interested to add more capabilities to the library. My main problem is that I don't have abundant access to electronics components. But feel free to colaborate. New members are realy needed for this project.