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 May 18 13:28:03 2015 +0000
Revision:
10:1ade8e824939
Parent:
9:b40252f5fee7
Debouncer: uint16_t _levels is enough for anyone; private Ticker.

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