An embedded C++ library to control LEDs. It uses a non-blocking approach and cancontrol LEDs in simple (on/off) and complex (blinking,breathing and more) ways in a time-driven manner.
JLed got some coverage on Hackadayand someone did a video tutorial for JLed - Thanks!
JLed in action | Interactive JLed playground |
---|---|
// breathe LED (on gpio 9) 6 times for 1500ms, waiting for 500ms after each run
#include <jled.h>
auto led_breathe = JLed(9).Breathe(1500).Repeat(6).DelayAfter(500);
void setup() { }
void loop() {
led_breathe.Update();
}
In the main menu of the Arduino IDE, select Sketch
> Include Library
>Manage Libraries...
and search for jled
, then press install
.
Add jled
to your library dependencies in your platformio.ini
project file,e.g.
...
[env:nanoatmega328]
platform = atmelavr
board = nanoatmega328
framework = arduino
lib_deps=jled
...
First, the LED object is constructed and configured, then the state is updatedwith subsequent calls to the Update()
method, typically from the loop()
function. While the effect is active, Update
returns true
, otherwisefalse
.
The constructor takes the pin, to which the LED is connected to asthe only argument. Further configuration of the LED object is done using a fluentinterface, e.g. JLed led = JLed(13).Breathe(2000).DelayAfter(1000).Repeat(5)
.See the examples section below for further details.
Calling On()
turns the LED on. To immediately turn a LED on, make a calllike JLed(LED_BUILTIN).On().Update()
.
Off()
works like On()
, except that it turns the LED off, i.e. it sets thebrightness to 0.
Use the Set(uint8_t brightness)
method to set the brightness to the givenvalue, i.e. Set(255)
is equivalent to calling On()
and Set(0)
isequivalent to calling Off()
.
Technically Set
, On
and Off
are effects with a period of 1ms thatset the brightness to a constant value.
#include <jled.h>
// turn builtin LED on after 1 second.
auto led = JLed(LED_BUILTIN).On().DelayBefore(1000);
void setup() { }
void loop() {
led.Update();
}
In blinking mode, the LED cycles through a given number of on-off cycles, on-and off-cycle durations are specified independently. The Blink()
method takesthe duration for the on- and off cycle as arguments.
#include <jled.h>
// blink internal LED every second; 1 second on, 0.5 second off.
auto led = JLed(LED_BUILTIN).Blink(1000, 500).Forever();
void setup() { }
void loop() {
led.Update();
}
In breathing mode, the LED smoothly changes the brightness using PWM. TheBreathe()
method takes the period of the effect as an argument.
#include <jled.h>
// connect LED to pin 13 (PWM capable). LED will breathe with period of
// 2000ms and a delay of 1000ms after each period.
auto led = JLed(13).Breathe(2000).DelayAfter(1000).Forever();
void setup() { }
void loop() {
led.Update();
}
In candle mode, the random flickering of a candle or fire is simulated.The builder method has the following signature:Candle(uint8_t speed, uint8_t jitter, uin16_t period)
speed
- controls the speed of the effect. 0 for fastest, increasing speeddivides into halve per increment. The default value is 7.jitter
- the amount of jittering. 0 none (constant on), 255 maximum. Defaultvalue is 15.period
- Period of effect in ms. The default value is 65535 ms.The default settings simulate a candle. For a fire effect for example usecall the method with Candle(5 /*speed*/, 100 /* jitter*/)
.
#include <jled.h>
// Candle on LED pin 13 (PWM capable).
auto led = JLed(13).Candle();
void setup() { }
void loop() {
led.Update();
}
In FadeOn mode, the LED is smoothly faded on to 100% brightness using PWM. TheFadeOn()
method takes the period of the effect as an argument.
The brightness function uses an approximation of this function (example withperiod 1000):
#include <jled.h>
// LED is connected to pin 9 (PWM capable) gpio
auto led = JLed(9).FadeOn(1000).DelayBefore(2000);
void setup() { }
void loop() {
led.Update();
}
In FadeOff mode, the LED is smoothly faded off using PWM. The fade starts at100% brightness. Internally it is implemented as a mirrored version of theFadeOn function, i.e. FadeOn(t) = FadeOff(period-t). The FadeOff()
methodtakes the period of the effect as argument.
It is also possible to provide a user defined brightness evaluator. The classmust be derived from the jled::BrightnessEvaluator
class and implementtwo methods:
uint8_t Eval(uint32_t t) const
- the brightness evaluation function thatcalculates a brightness for the given time t
. The brightness must be returnedas an unsigned byte, where 0 means LED off and 255 means full brightness.uint16_t Period() const
- period of the effect.All time values are specified in milliseconds.
The user_func example demonstrates a simple user providedbrightness function, while the morse example shows how a morecomplex application, allowing you to send morse codes (not necessarily with anLED), can be realized.
The example uses a user provided function to calculate the brightness.
class UserEffect : public jled::BrightnessEvaluator {
public:
uint8_t Eval(uint32_t t) const override {
// this function changes between 0 and 255 and
// vice versa every 250 ms.
return 255*((t/250)%2);
}
// duration of effect: 5 seconds.
uint16_t Period() const override { return 5000; }
};
Use the DelayBefore()
method to specify a delay before the first effect starts.The default value is 0 ms.
Use the DelayAfter()
method to specify a delay after each repetition ofan effect. The default value is 0 ms.
Use the Repeat()
method to specify the number of repetitions. The defaultvalue is 1 repetition. The Forever()
methods sets to repeat the effectforever. Each repetition includes a full period of the effect and the timespecified by DelayAfter()
method.
Call Update()
periodically to update the state of the LED. Update
returnstrue
if the effect is active, and false
when it finished.
IsRunning()
returns true
if the current effect is running, else false
.
A call to Reset()
brings the JLed object to its initial state. Use it whenyou want to start-over an effect.
Call Stop()
to immediately turn the LED off and stop any running effects.Further calls to Update()
will have no effect unless the Led is reset (usingReset()
) or a new effect activated.
Use the LowActive()
method when the connected LED is low active. All outputwill be inverted by JLed (i.e. instead of x, the value of 255-x will be set).
The MaxBrightness(uint8_t level)
method is used to set the maximum brightnesslevel of the LED. A level of 255 (the default) is full brightness, while 0effectively turns the LED off.
The uint_8 MaxBrightness() const
method returns the current maximumbrightness level. Since currently only the upper 5 bits of the providedbrighness value are used, the lower 3 bits returned are always 0.
If you want to programmatically increment or decrement the maximum brightnesslevel, use the JLed::kBrightnessStep
constant (which is defined as 1 << (8-JLed::kBitsBrightness)
as the increment (instead of the hard wired value8
) to be independent of the current JLed implementation using 5 bits.
The JLedSequence
class allows controlling a group of JLed
objectssimultaneously, either in parallel or sequentially, starting the next JLed
effect when the previous finished. The constructor takes the mode (PARALLEL
,SEQUENCE
), an array of JLed
objects and the size of the array, e.g.
JLed leds[] = {
JLed(4).Blink(750, 250).Repeat(10),
JLed(3).Breathe(2000).Repeat(5);
};
auto sequence = JLedSequence(JLedSequence::eMode::PARALLEL, leds).Repeat(2);
void setup() {
}
void loop() {
sequence.Update();
}
Because the size of the array is known at compile time in this example, it isnot necessary to pass the array size to the constructor. A second constructoris available in case the JLed
array is created dynamically at runtime:JLed(eMode mode, JLed* leds, size_t n)
.
The JLedSequence
provides the following methods:
Update()
- updates the active JLed
objects controlled by the sequence.Like the JLed::Update()
method, it returns true
if an effect is running,else false
.Repeat(n)
method to specify the number of repetitions. The defaultvalue is 1 repetition. The Forever()
methods sets to repeat the sequenceforever.Stop()
- turns off all JLed
objects controlled by the sequence andstops the sequence. Further calls to Update()
will have no effect.Reset()
- Resets all JLed
objects controlled by the sequence andthe sequence, resulting in a start-over.JLed supports the Arduino and mbed frameworks. Whenusing platformio, the framework to be used is configured in the platform.ini
file, as shown in the following example, which for example selects the mbed
framework:
[env:nucleo_f401re_mbed]
platform=ststm32
board = nucleo_f401re
framework = mbed
build_flags = -Isrc
src_filter = +<../../src/> +<./>
upload_protocol=stlink
An mbed example is provided here.To compile it for the F401RE, make your plaform.ini look like:
...
[platformio]
default_envs = nucleo_f401re_mbed
src_dir = examples/multiled_mbed
...
The DAC of the ESP8266 operates with 10 bits, every value JLed writes out getsautomatically scaled to 10 bits, since JLed internally only uses 8 bits. Thescaling methods make sure that min/max relationships are preserved, i.e. 0 ismapped to 0 and 255 is mapped to 1023. When using a user-defined brightnessfunction on the ESP8266, 8-bit values must be returned, all scaling is done byJLed transparently for the application, yielding platform-independent code.
The ESP32 Arduino SDK does not provide an analogWrite()
function. Tobe able to use PWM, we use the ledc
functions of the ESP32 SDK.(See esspressif documentation for details).
The ledc
API connects so-called channels to GPIO pins, enabling them to usePWM. There are 16 channels available. Unless otherwise specified, JLedautomatically picks the next free channel, starting with channel 0 and wrappingover after channel 15. To manually specify a channel, the JLed object must beconstructed this way:
auto esp32Led = JLed(jled::Esp32Hal(2, 7)).Blink(1000, 1000).Forever();
The jled::Esp32Hal(pin, chan)
constructor takes the pin number as the firstargument and the ESP32 ledc channel number on the second position. Note thatusing the above-mentioned constructor yields non-platform independent code, soit should be avoided and is normally not necessary.
I had success running JLed on a STM32 Nucleo64 F401REboard using thisSTM32 Arduinocoreand compiling examples from the Arduino IDE. Note that the stlink
isnecessary to upload sketches to the microcontroller.
When using JLed on a Raspberry Pi Pico, the Pico-SDK and tools must beinstalled. The Pico supports up to 16 PWM channels in parallel. Seethe pico-demo for an example and build instructions.
Example sketches are provided in the examples directory.
To build an example using the PlatformIO ide,uncomment the example to be built in the platformio.iniproject file, e.g.:
[platformio]
; uncomment example to build
src_dir = examples/hello
;src_dir = examples/breathe
To build an example sketch in the Arduino IDE, select an example fromthe File
> Examples
> JLed
menu.
JLed uses a very thin hardware abstraction layer (hal) to abstract access tothe actual MCU/framework used (e.g. ESP32, ESP8266). The hal object encapsulateaccess to the GPIO and time functionality of the MCU under the framework beingused. During the unit test, mocked hal instances are used, enabling tests tocheck the generated output. The Custom HAL projectprovides an example for a user define HAL.
JLed comes with an exhaustive host-based unit test suite. Info on how to runthe host-based provided unit tests is provided here.
make lint
). Hint: use clang-format
with theprovided settingsJLed::Update
method: the method returns true
ifthe effect is still running, otherwise false
.JLed::IsRunning
method returns true
if an effect is running, else false
.Call Reset()
on a JLed
object to start over.
Just 'reconfigure' the JLed
with any of the effect methods (e.g. FadeOn
,Breathe
, Blink
etc). Time-wise, the effect will start over.
Copyright 2017, 2018 by Jan Delgado, jdelgado[at]gmx.net.