Use the hardware PwmOut to pulsate an LED (or something else), with selectable active high/low, customisable intensity function, gamma correction, and number of brightness levels.

Dependents:   RedButton

Pulsator.cpp

Committer:
huliyang
Date:
2015-04-24
Revision:
3:a789d816b3a2
Parent:
2:e351afc2a3a8
Child:
4:55b287904199

File content as of revision 3:a789d816b3a2:

/* Copyright (c) 2015 Liyang HU, MIT License
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
 * and associated documentation files (the "Software"), to deal in the Software without restriction, 
 * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or 
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <math.h>
#include <mbed.h>

#include <Pulsator.h>

#ifndef M_PI
# define M_PI    3.14159265358979323846
#endif

#ifndef M_PI_2
# define M_PI_2  1.57079632679489661923
#endif

/*! \class Pulsator
 * \brief Pulsate an LED using hardware \a PwmOut and \a Ticker.
 * \code
#include <mbed.h>
#include <Pulsator.h>

Pulsator led(LED1, 2.0, false);

int main(void) {
    led = true;
    while(1) wait(1);
}
 * \endcode
 * \see \a PwmOut, \a Ticker
 */

void Pulsator::step(void)
{
    // sinf(phase_2)^2 == (1 - cosf(phase)) / 2
    float s = sinf(phase_2);
    float level = powf(s * s, gamma);
    out = active_high ? level : 1.0 - level;
    phase_2 += M_PI_2 / (float)(levels - 1);
    if(phase_2 >= M_PI)
        phase_2 = 0.0;
}

void Pulsator::enable(void)
{
    out.period(1.0 / 1024.0);
    phase_2 = 0.0;
    step();
    ticker.attach(this, &Pulsator::step, 0.5 * period / (float)(levels - 1));
}

void Pulsator::disable(void)
{
    ticker.detach();
    out = active_high ? 0.0 : 1.0;
}

/*! Create a \a Pulsator object.
 * \param pin Pin to pulsate. Note that some platforms can only
 *      drive certain pins with the hardware PWM.
 * \param period Duration of each cycle, in seconds.
 * \param active_high Should the output pin be active high (\a true),
 *      or active low (\a false)?
 * \param gamma Gamma correction for the output LED.
 * \param levels Number of distinct brightness levels: a minimum of 2.
 */
Pulsator::Pulsator(PinName pin, float period, bool active_high, float gamma, int levels)
    : out(pin), period(period), active_high(active_high), gamma(gamma), levels(levels)
{
    disable();
}

/*! Enable or disable the output.
 * \param state Pulsate the output?
 * \note Passing \a false deactivates the output completely, rather than
 *      keeping the LED brightness at the point where this is called.
 *      Conversely, \a true starts pulsating from the inactive state.
 */
Pulsator& Pulsator::operator=(bool state)
{
    state ? enable() : disable();
    return *this;
}