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:
Sun Apr 26 01:39:38 2015 +0000
Revision:
6:5eeb1acc1c50
Parent:
5:26cc18306d95
Child:
7:7abc04b4c474
Pulsator: named parameter idiom; various fixes

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 0:dda7f6f55dc1 19 #include <math.h>
huliyang 0:dda7f6f55dc1 20 #include <mbed.h>
huliyang 0:dda7f6f55dc1 21
huliyang 0:dda7f6f55dc1 22 #include <Pulsator.h>
huliyang 0:dda7f6f55dc1 23
huliyang 0:dda7f6f55dc1 24 #ifndef M_PI
huliyang 0:dda7f6f55dc1 25 # define M_PI 3.14159265358979323846
huliyang 0:dda7f6f55dc1 26 #endif
huliyang 0:dda7f6f55dc1 27
huliyang 0:dda7f6f55dc1 28 #ifndef M_PI_2
huliyang 0:dda7f6f55dc1 29 # define M_PI_2 1.57079632679489661923
huliyang 0:dda7f6f55dc1 30 #endif
huliyang 0:dda7f6f55dc1 31
huliyang 1:bcddb9898625 32 /*! \class Pulsator
huliyang 1:bcddb9898625 33 * \brief Pulsate an LED using hardware \a PwmOut and \a Ticker.
huliyang 1:bcddb9898625 34 * \code
huliyang 1:bcddb9898625 35 #include <mbed.h>
huliyang 1:bcddb9898625 36 #include <Pulsator.h>
huliyang 1:bcddb9898625 37
huliyang 6:5eeb1acc1c50 38 Pulsator led(LED1);
huliyang 1:bcddb9898625 39
huliyang 1:bcddb9898625 40 int main(void) {
huliyang 6:5eeb1acc1c50 41 led.period(2.0).gamma(1.8) = true;
huliyang 1:bcddb9898625 42 while(1) wait(1);
huliyang 1:bcddb9898625 43 }
huliyang 1:bcddb9898625 44 * \endcode
huliyang 1:bcddb9898625 45 * \see \a PwmOut, \a Ticker
huliyang 1:bcddb9898625 46 */
huliyang 1:bcddb9898625 47
huliyang 6:5eeb1acc1c50 48 void Pulsator::disable(void)
huliyang 0:dda7f6f55dc1 49 {
huliyang 6:5eeb1acc1c50 50 _enable = false;
huliyang 6:5eeb1acc1c50 51 detach();
huliyang 6:5eeb1acc1c50 52 out = _active_high ? 0.0 : 1.0;
huliyang 0:dda7f6f55dc1 53 }
huliyang 0:dda7f6f55dc1 54
huliyang 0:dda7f6f55dc1 55 void Pulsator::enable(void)
huliyang 0:dda7f6f55dc1 56 {
huliyang 0:dda7f6f55dc1 57 out.period(1.0 / 1024.0);
huliyang 0:dda7f6f55dc1 58 phase_2 = 0.0;
huliyang 0:dda7f6f55dc1 59 step();
huliyang 6:5eeb1acc1c50 60 _enable = true;
huliyang 6:5eeb1acc1c50 61 attach(this, &Pulsator::step, 0.5 * _period / (float)(_levels - 1));
huliyang 0:dda7f6f55dc1 62 }
huliyang 0:dda7f6f55dc1 63
huliyang 6:5eeb1acc1c50 64 //! Bit of a hack to update _delay without re-attaching the handler.
huliyang 6:5eeb1acc1c50 65 void Pulsator::reload(void)
huliyang 0:dda7f6f55dc1 66 {
huliyang 6:5eeb1acc1c50 67 _delay = 1000000.0 * 0.5 * _period / (float)(_levels - 1);
huliyang 0:dda7f6f55dc1 68 }
huliyang 0:dda7f6f55dc1 69
huliyang 6:5eeb1acc1c50 70 void Pulsator::step(void)
huliyang 0:dda7f6f55dc1 71 {
huliyang 6:5eeb1acc1c50 72 // sinf(phase_2)^2 == (1 - cosf(phase)) / 2
huliyang 6:5eeb1acc1c50 73 float s = sinf(phase_2);
huliyang 6:5eeb1acc1c50 74 float level = powf(s * s, _gamma);
huliyang 6:5eeb1acc1c50 75 out = _active_high ? level : 1.0 - level;
huliyang 6:5eeb1acc1c50 76 phase_2 += M_PI_2 / (float)(_levels - 1);
huliyang 6:5eeb1acc1c50 77 if(phase_2 >= M_PI)
huliyang 6:5eeb1acc1c50 78 phase_2 -= M_PI;
huliyang 0:dda7f6f55dc1 79 }
huliyang 0:dda7f6f55dc1 80
huliyang 6:5eeb1acc1c50 81 //! Create a \a Pulsator attached to the specified \a pin.
huliyang 6:5eeb1acc1c50 82 //! \param pin Pin to pulsate.
huliyang 6:5eeb1acc1c50 83 //! \note Some platforms can only drive certain pins with the hardware PWM.
huliyang 6:5eeb1acc1c50 84 Pulsator::Pulsator(PinName pin) : out(pin)
huliyang 6:5eeb1acc1c50 85 {
huliyang 6:5eeb1acc1c50 86 active_high(); disable(); gamma(); period(); levels();
huliyang 6:5eeb1acc1c50 87 }
huliyang 6:5eeb1acc1c50 88
huliyang 6:5eeb1acc1c50 89 //! Enable or disable the output.
huliyang 6:5eeb1acc1c50 90 /* \note Passing \a false deactivates the output completely, rather than
huliyang 6:5eeb1acc1c50 91 maintaining the LED brightness at the point when this is called.
huliyang 6:5eeb1acc1c50 92 Conversely, \a true starts pulsating from the inactive state.
huliyang 6:5eeb1acc1c50 93 Setting the curent state is a no-op. */
huliyang 0:dda7f6f55dc1 94 Pulsator& Pulsator::operator=(bool state)
huliyang 0:dda7f6f55dc1 95 {
huliyang 5:26cc18306d95 96 if(state != _enable)
huliyang 5:26cc18306d95 97 state ? enable() : disable();
huliyang 0:dda7f6f55dc1 98 return *this;
huliyang 0:dda7f6f55dc1 99 }
huliyang 5:26cc18306d95 100
huliyang 6:5eeb1acc1c50 101 //! Get the current state of the output.
huliyang 5:26cc18306d95 102 Pulsator::operator bool(void)
huliyang 5:26cc18306d95 103 {
huliyang 5:26cc18306d95 104 return _enable;
huliyang 5:26cc18306d95 105 }
huliyang 6:5eeb1acc1c50 106
huliyang 6:5eeb1acc1c50 107 //! Should the output pin be active high (\a true), or active low (\a false)?
huliyang 6:5eeb1acc1c50 108 Pulsator& Pulsator::active_high(bool high)
huliyang 6:5eeb1acc1c50 109 {
huliyang 6:5eeb1acc1c50 110 _active_high = high;
huliyang 6:5eeb1acc1c50 111 if(!_enable)
huliyang 6:5eeb1acc1c50 112 out = _active_high ? 0.0 : 1.0;
huliyang 6:5eeb1acc1c50 113 return *this;
huliyang 6:5eeb1acc1c50 114 }
huliyang 6:5eeb1acc1c50 115
huliyang 6:5eeb1acc1c50 116 //! Set the gamma correction for the output LED.
huliyang 6:5eeb1acc1c50 117 Pulsator& Pulsator::gamma(float power)
huliyang 6:5eeb1acc1c50 118 {
huliyang 6:5eeb1acc1c50 119 _gamma = power;
huliyang 6:5eeb1acc1c50 120 return *this;
huliyang 6:5eeb1acc1c50 121 }
huliyang 6:5eeb1acc1c50 122
huliyang 6:5eeb1acc1c50 123 //! Set the number (>= 2) of distinct brightness levels.
huliyang 6:5eeb1acc1c50 124 Pulsator& Pulsator::levels(int number)
huliyang 6:5eeb1acc1c50 125 {
huliyang 6:5eeb1acc1c50 126 _levels = number;
huliyang 6:5eeb1acc1c50 127 reload();
huliyang 6:5eeb1acc1c50 128 return *this;
huliyang 6:5eeb1acc1c50 129 }
huliyang 6:5eeb1acc1c50 130
huliyang 6:5eeb1acc1c50 131 //! Set the duration of each cycle, in seconds.
huliyang 6:5eeb1acc1c50 132 Pulsator& Pulsator::period(float seconds)
huliyang 6:5eeb1acc1c50 133 {
huliyang 6:5eeb1acc1c50 134 _period = seconds;
huliyang 6:5eeb1acc1c50 135 reload();
huliyang 6:5eeb1acc1c50 136 return *this;
huliyang 6:5eeb1acc1c50 137 }