Andrea Faustinelli / espresso-for-geeks-master
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers phasecontrol.cpp Source File

phasecontrol.cpp

00001 /* Copyright (c) 2017 Philippe Kalaf, MIT License
00002  *
00003  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
00004  * and associated documentation files (the "Software"), to deal in the Software without restriction, 
00005  * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
00006  * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
00007  * furnished to do so, subject to the following conditions:
00008  *
00009  * The above copyright notice and this permission notice shall be included in all copies or 
00010  * substantial portions of the Software.
00011  *
00012  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
00013  * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
00014  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
00015  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
00016  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00017  */
00018 
00019 // Phase control class (used for pump)
00020 #include "phasecontrol.h"
00021 
00022 // estimate of lag caused by ZCD circuit in usec
00023 // measured as per http://espresso-for-geeks.kalaf.net/mod-list/#hw-zero-cross
00024 #define ZCD_DELAY 36
00025 
00026 // power frequency half-period in usec
00027 // set to 8333 for 60Hz
00028 // set to 10000 for 50Hz
00029 #define HALF_PERIOD_USEC 8333
00030 
00031 // the time in usec to wait after zero-cross before switching off
00032 // this eliminates the back-EMF by waiting for current to drop before switching off
00033 #define DELAY_AFTER_STOP (HALF_PERIOD_USEC / 2)
00034 
00035 // TODO PRECACULATE 50Hz numbers
00036 // These are precalculated values (usec) of the required phase delays for 0 to 100% power.
00037 // Equation used is: 1000000 usec / 120 * (acos(2*x/100 - 1) / pi)
00038 const uint16_t PhaseControl::_timeouts_usec[101] =
00039     {0, 531, 753, 924, 1068, 1196, 1313, 1421, 1521, 1616, 
00040     1707, 1793, 1877, 1957, 2035, 2110, 2183, 2255, 2324,
00041     2393, 2460, 2525, 2590, 2654, 2716, 2778, 2839, 2899,
00042     2958, 3017, 3075, 3133, 3190, 3246, 3303, 3358, 3414,
00043     3469, 3524, 3578, 3633, 3687, 3740, 3794, 3848, 3901,
00044     3954, 4007, 4061, 4114, 4167, 4220, 4273, 4326, 4379, 
00045     4432, 4486, 4539, 4593, 4647, 4701, 4755, 4810, 4864,
00046     4919, 4975, 5031, 5087, 5144, 5201, 5258, 5316, 5375,
00047     5435, 5495, 5556, 5617, 5680, 5743, 5808, 5874, 5941,
00048     6009, 6079, 6150, 6223, 6299, 6376, 6457, 6540, 6626,
00049     6717, 6812, 6913, 7020, 7137, 7265, 7410, 7581, 7802,
00050     8333};
00051     
00052 PhaseControl::PhaseControl(PinName pin, PinName pin2) : _zcd(pin), _control_signal(pin2) {
00053     // if your zcd circuit has it's own pullup, set to None
00054         _zcd.mode(PullUp);
00055         _zcd.fall(callback(this, &PhaseControl::delayed_start));
00056         _zcd.rise(callback(this, &PhaseControl::delayed_stop));
00057         _level = 75;
00058         _control_signal = 0;
00059 
00060     // This is a workaround until timeouts for 50Hz are calculated
00061     if (HALF_PERIOD_USEC == 8333)
00062         _timeout_usec = HALF_PERIOD_USEC - _timeouts_usec[_level] - ZCD_DELAY; 
00063     else
00064         _timeout_usec = HALF_PERIOD_USEC - (_timeouts_usec[_level]*10000/8333) - ZCD_DELAY; 
00065         
00066         /* debug info
00067          _t.start();
00068         counter = 0;
00069         */
00070 }
00071 
00072 PhaseControl::~PhaseControl()
00073 {
00074 }
00075 
00076 void PhaseControl::stop()
00077 {
00078     /* debug info
00079     if (counter < 2000)
00080     {
00081         times[counter][0] = _t.read_us();
00082         times[counter][1] = 0;
00083         //times[counter][2] = _level; 
00084         counter++;
00085     }
00086     */
00087 
00088     _control_signal = 0;
00089     _control_timeout.detach();
00090 }
00091 
00092 void PhaseControl::start()
00093 {
00094     /* debug info
00095     if (counter < 2000)
00096     {
00097         times[counter][0] = _t.read_us();
00098         times[counter][1] = 1;
00099         //times[counter][2] = _level;
00100         counter++;
00101     }
00102     */
00103 
00104     _control_signal = 1;
00105 }
00106 
00107 void PhaseControl::delayed_start()
00108 {
00109     // Level 100 is full power (minus zcd lag)
00110     if (_level == 100)
00111         start();
00112     // Level 0 just stop
00113     else if (_level == 0)
00114         stop();
00115     // otherwise do a delayed start (start after timeout_usec elapses)
00116     else
00117         _control_timeout.attach_us(callback(this, &PhaseControl::start), _timeout_usec);
00118 }
00119 
00120 // We wait DELAY_AFTER_STOP before stopping to avoid back-EMF
00121 void PhaseControl::delayed_stop()
00122 {
00123     _test_timeout.attach_us(callback(this, &PhaseControl::stop), DELAY_AFTER_STOP);
00124 }
00125 
00126 uint8_t PhaseControl::get_level()
00127 {
00128     return _level;
00129 }
00130 
00131 void PhaseControl::set_level(uint8_t level)
00132 {
00133     if (level > 100)
00134         _level = 100;
00135     else
00136         _level = level;
00137     
00138     // This is a workaround until timeouts for 50Hz are calculated
00139     if (HALF_PERIOD_USEC == 8333)
00140         _timeout_usec = HALF_PERIOD_USEC - _timeouts_usec[_level] - ZCD_DELAY;
00141     else
00142         _timeout_usec = HALF_PERIOD_USEC - (_timeouts_usec[_level]*10000/8333) - ZCD_DELAY;
00143 }
00144 
00145 void PhaseControl::level_up(uint8_t value)
00146 {
00147     if (_level < 100)
00148          set_level(_level + value);
00149 }
00150 
00151 void PhaseControl::level_down(uint8_t value)
00152 {
00153     if (_level > 0)
00154         set_level(_level - value);
00155 }