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

Committer:
huliyang
Date:
Mon Apr 27 11:15:08 2015 +0000
Revision:
8:ddedf56b2eb0
Parent:
7:7abc04b4c474
Child:
9:b40252f5fee7
Pulsator::fun(): parametrise over intensity function.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
huliyang 1:bcddb9898625 1 /* Copyright (c) 2015 Liyang HU, MIT License
huliyang 1:bcddb9898625 2 *
huliyang 1:bcddb9898625 3 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
huliyang 1:bcddb9898625 4 * and associated documentation files (the "Software"), to deal in the Software without restriction,
huliyang 1:bcddb9898625 5 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
huliyang 1:bcddb9898625 6 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
huliyang 1:bcddb9898625 7 * furnished to do so, subject to the following conditions:
huliyang 1:bcddb9898625 8 *
huliyang 1:bcddb9898625 9 * The above copyright notice and this permission notice shall be included in all copies or
huliyang 1:bcddb9898625 10 * substantial portions of the Software.
huliyang 1:bcddb9898625 11 *
huliyang 1:bcddb9898625 12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
huliyang 1:bcddb9898625 13 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
huliyang 1:bcddb9898625 14 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
huliyang 1:bcddb9898625 15 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
huliyang 1:bcddb9898625 16 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
huliyang 1:bcddb9898625 17 */
huliyang 1:bcddb9898625 18
huliyang 8:ddedf56b2eb0 19 #include <algorithm>
huliyang 0:dda7f6f55dc1 20 #include <math.h>
huliyang 0:dda7f6f55dc1 21 #include <mbed.h>
huliyang 0:dda7f6f55dc1 22 #include <Pulsator.h>
huliyang 0:dda7f6f55dc1 23
huliyang 1:bcddb9898625 24 /*! \class Pulsator
huliyang 1:bcddb9898625 25 * \brief Pulsate an LED using hardware \a PwmOut and \a Ticker.
huliyang 1:bcddb9898625 26 * \code
huliyang 1:bcddb9898625 27 #include <mbed.h>
huliyang 1:bcddb9898625 28 #include <Pulsator.h>
huliyang 1:bcddb9898625 29
huliyang 6:5eeb1acc1c50 30 Pulsator led(LED1);
huliyang 1:bcddb9898625 31
huliyang 1:bcddb9898625 32 int main(void) {
huliyang 6:5eeb1acc1c50 33 led.period(2.0).gamma(1.8) = true;
huliyang 1:bcddb9898625 34 while(1) wait(1);
huliyang 1:bcddb9898625 35 }
huliyang 1:bcddb9898625 36 * \endcode
huliyang 1:bcddb9898625 37 * \see \a PwmOut, \a Ticker
huliyang 1:bcddb9898625 38 */
huliyang 1:bcddb9898625 39
huliyang 6:5eeb1acc1c50 40 void Pulsator::disable(void)
huliyang 0:dda7f6f55dc1 41 {
huliyang 6:5eeb1acc1c50 42 _enable = false;
huliyang 6:5eeb1acc1c50 43 detach();
huliyang 7:7abc04b4c474 44 out = _active_high ? 0.0f : 1.0f;
huliyang 0:dda7f6f55dc1 45 }
huliyang 0:dda7f6f55dc1 46
huliyang 0:dda7f6f55dc1 47 void Pulsator::enable(void)
huliyang 0:dda7f6f55dc1 48 {
huliyang 7:7abc04b4c474 49 out.period(1.0f / 1024.0f);
huliyang 8:ddedf56b2eb0 50 phase = 0.0f;
huliyang 8:ddedf56b2eb0 51 _enable = true;
huliyang 0:dda7f6f55dc1 52 step();
huliyang 7:7abc04b4c474 53 attach(this, &Pulsator::step, 0.5f * _period / (float)(_levels - 1));
huliyang 0:dda7f6f55dc1 54 }
huliyang 0:dda7f6f55dc1 55
huliyang 6:5eeb1acc1c50 56 //! Bit of a hack to update _delay without re-attaching the handler.
huliyang 6:5eeb1acc1c50 57 void Pulsator::reload(void)
huliyang 0:dda7f6f55dc1 58 {
huliyang 7:7abc04b4c474 59 _delay = 1000000.0f * 0.5f * _period / (float)(_levels - 1);
huliyang 0:dda7f6f55dc1 60 }
huliyang 0:dda7f6f55dc1 61
huliyang 6:5eeb1acc1c50 62 void Pulsator::step(void)
huliyang 0:dda7f6f55dc1 63 {
huliyang 8:ddedf56b2eb0 64 float x = _fun(phase);
huliyang 8:ddedf56b2eb0 65 if(x < 0.0f) x = 0.0f;
huliyang 8:ddedf56b2eb0 66 if(x > 1.0f) x = 1.0f;
huliyang 8:ddedf56b2eb0 67 float level = powf(x, _gamma);
huliyang 7:7abc04b4c474 68 out = _active_high ? level : 1.0f - level;
huliyang 8:ddedf56b2eb0 69 phase += 0.5f / (float)(_levels - 1);
huliyang 8:ddedf56b2eb0 70 if(phase >= 1.0f)
huliyang 8:ddedf56b2eb0 71 phase -= 1.0f;
huliyang 0:dda7f6f55dc1 72 }
huliyang 0:dda7f6f55dc1 73
huliyang 6:5eeb1acc1c50 74 //! Create a \a Pulsator attached to the specified \a pin.
huliyang 6:5eeb1acc1c50 75 //! \param pin Pin to pulsate.
huliyang 6:5eeb1acc1c50 76 //! \note Some platforms can only drive certain pins with the hardware PWM.
huliyang 6:5eeb1acc1c50 77 Pulsator::Pulsator(PinName pin) : out(pin)
huliyang 6:5eeb1acc1c50 78 {
huliyang 8:ddedf56b2eb0 79 active_high(); disable(); fun(); gamma(); period(); levels();
huliyang 6:5eeb1acc1c50 80 }
huliyang 6:5eeb1acc1c50 81
huliyang 6:5eeb1acc1c50 82 //! Enable or disable the output.
huliyang 6:5eeb1acc1c50 83 /* \note Passing \a false deactivates the output completely, rather than
huliyang 6:5eeb1acc1c50 84 maintaining the LED brightness at the point when this is called.
huliyang 6:5eeb1acc1c50 85 Conversely, \a true starts pulsating from the inactive state.
huliyang 6:5eeb1acc1c50 86 Setting the curent state is a no-op. */
huliyang 0:dda7f6f55dc1 87 Pulsator& Pulsator::operator=(bool state)
huliyang 0:dda7f6f55dc1 88 {
huliyang 5:26cc18306d95 89 if(state != _enable)
huliyang 5:26cc18306d95 90 state ? enable() : disable();
huliyang 0:dda7f6f55dc1 91 return *this;
huliyang 0:dda7f6f55dc1 92 }
huliyang 5:26cc18306d95 93
huliyang 6:5eeb1acc1c50 94 //! Get the current state of the output.
huliyang 5:26cc18306d95 95 Pulsator::operator bool(void)
huliyang 5:26cc18306d95 96 {
huliyang 5:26cc18306d95 97 return _enable;
huliyang 5:26cc18306d95 98 }
huliyang 6:5eeb1acc1c50 99
huliyang 6:5eeb1acc1c50 100 //! Should the output pin be active high (\a true), or active low (\a false)?
huliyang 6:5eeb1acc1c50 101 Pulsator& Pulsator::active_high(bool high)
huliyang 6:5eeb1acc1c50 102 {
huliyang 6:5eeb1acc1c50 103 _active_high = high;
huliyang 6:5eeb1acc1c50 104 if(!_enable)
huliyang 7:7abc04b4c474 105 out = _active_high ? 0.0f : 1.0f;
huliyang 6:5eeb1acc1c50 106 return *this;
huliyang 6:5eeb1acc1c50 107 }
huliyang 6:5eeb1acc1c50 108
huliyang 8:ddedf56b2eb0 109 #define TAU 6.2831853f
huliyang 8:ddedf56b2eb0 110 static float sinusoidal(float phase) { return 0.5f - 0.5f * cosf(TAU * phase); }
huliyang 8:ddedf56b2eb0 111
huliyang 8:ddedf56b2eb0 112 //! Set the intensity function.
huliyang 8:ddedf56b2eb0 113 /* \param fp Pointer to a function returning an intensity
huliyang 8:ddedf56b2eb0 114 in the range [0,1]. Values outside will be clamped. */
huliyang 8:ddedf56b2eb0 115 //! \param phase Input to \a fp, in the range [0, 1).
huliyang 8:ddedf56b2eb0 116 //! \note Pass \a NULL for the default sinusoidal function.
huliyang 8:ddedf56b2eb0 117 Pulsator& Pulsator::fun(float (*fp)(float phase))
huliyang 8:ddedf56b2eb0 118 {
huliyang 8:ddedf56b2eb0 119 _fun = fp ? fp : &sinusoidal;
huliyang 8:ddedf56b2eb0 120 return *this;
huliyang 8:ddedf56b2eb0 121 }
huliyang 8:ddedf56b2eb0 122
huliyang 6:5eeb1acc1c50 123 //! Set the gamma correction for the output LED.
huliyang 6:5eeb1acc1c50 124 Pulsator& Pulsator::gamma(float power)
huliyang 6:5eeb1acc1c50 125 {
huliyang 6:5eeb1acc1c50 126 _gamma = power;
huliyang 6:5eeb1acc1c50 127 return *this;
huliyang 6:5eeb1acc1c50 128 }
huliyang 6:5eeb1acc1c50 129
huliyang 6:5eeb1acc1c50 130 //! Set the number (>= 2) of distinct brightness levels.
huliyang 6:5eeb1acc1c50 131 Pulsator& Pulsator::levels(int number)
huliyang 6:5eeb1acc1c50 132 {
huliyang 6:5eeb1acc1c50 133 _levels = number;
huliyang 6:5eeb1acc1c50 134 reload();
huliyang 6:5eeb1acc1c50 135 return *this;
huliyang 6:5eeb1acc1c50 136 }
huliyang 6:5eeb1acc1c50 137
huliyang 6:5eeb1acc1c50 138 //! Set the duration of each cycle, in seconds.
huliyang 6:5eeb1acc1c50 139 Pulsator& Pulsator::period(float seconds)
huliyang 6:5eeb1acc1c50 140 {
huliyang 6:5eeb1acc1c50 141 _period = seconds;
huliyang 6:5eeb1acc1c50 142 reload();
huliyang 6:5eeb1acc1c50 143 return *this;
huliyang 6:5eeb1acc1c50 144 }