MHVLib
20111011
An efficiency oriented runtime library for AVR microcontrollers
|
00001 /* 00002 * Copyright (c) 2011, Make, Hack, Void Inc 00003 * All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions are met: 00007 * * Redistributions of source code must retain the above copyright 00008 * notice, this list of conditions and the following disclaimer. 00009 * * Redistributions in binary form must reproduce the above copyright 00010 * notice, this list of conditions and the following disclaimer in the 00011 * documentation and/or other materials provided with the distribution. 00012 * * Neither the name of the Make, Hack, Void nor the 00013 * names of its contributors may be used to endorse or promote products 00014 * derived from this software without specific prior written permission. 00015 * 00016 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 00017 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00018 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00019 * DISCLAIMED. IN NO EVENT SHALL MAKE, HACK, VOID BE LIABLE FOR ANY 00020 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 00021 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00022 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 00023 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00024 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00025 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00026 */ 00027 00028 /* 00029 * Allows the AVR to act as a voltage regulator 00030 * Inspired by: http://spritesmods.com/?art=ucboost 00031 * 00032 * Boost Mode: 00033 * Refer to http://www.ladyada.net/library/diyboostcalc.html for the schematic & calculator 00034 * 00035 * Buck mode: 00036 * Refer to http://www.daycounter.com/Calculators/Switching-Converter-Calculator.phtml for the schematic & calculator 00037 * 00038 * The ADC input is capped at 1.1V or 2.56V - you must use a resistor divider (total impedance should be <10kOhm) 00039 * to bring the feedback voltage down into this range. Use the divider parameter to tell the library the value 00040 * of this divider network 00041 */ 00042 00043 #include <MHV_io.h> 00044 #include <MHV_VoltageRegulator.h> 00045 #include <MHV_AD.h> 00046 00047 #ifdef MHV_AD_RESOLUTION 00048 #ifdef MHV_TIMER16_1 00049 00061 MHV_VoltageRegulator::MHV_VoltageRegulator(MHV_VREG_MODES mode, float voltage, float vrefVoltage, uint8_t vref, 00062 float divider, MHV_Timer16 *timer, uint8_t channel) { 00063 _targetADC = (uint16_t)(voltage * divider * MHV_AD_RESOLUTION / vrefVoltage); 00064 _vref = vref; 00065 _vrefVoltage = vrefVoltage; 00066 _timer = timer; 00067 _adcChannel = channel; 00068 _mode = mode; 00069 _pwm = 1; 00070 _lastADC = 0; 00071 _lastMoveUp = true; 00072 _invert = false; 00073 _divider = divider; 00074 } 00075 00076 /* Regulate as a boosting regulator 00077 */ 00078 inline void MHV_VoltageRegulator::regulateBoost() { 00079 uint16_t adc = mhv_ad_busyRead(_adcChannel, _vref); 00080 uint16_t newPWM = (uint16_t)(_pwm * (float)_targetADC / (float)adc); 00081 00082 if (newPWM == _pwm) { 00083 if (_targetADC < adc) { 00084 newPWM = _pwm - 1; 00085 } else if (_targetADC > adc) { 00086 newPWM = _pwm + 1; 00087 } 00088 } 00089 00090 // set a minimum on and off time - boost regulators are useless if the transistor is always on or off 00091 if (newPWM < 1) { 00092 newPWM = 1; 00093 } else if (newPWM + 1 > _timer->getTop()) { 00094 newPWM = _timer->getTop() - 1; 00095 } 00096 00097 _pwm = newPWM; 00098 _timer->setOutput2(_pwm); 00099 00100 _lastADC = adc; 00101 } 00102 00106 inline void MHV_VoltageRegulator::regulateBuck() { 00107 uint16_t adc = mhv_ad_busyRead(_adcChannel, _vref); 00108 00109 if (adc < _targetADC) { 00110 _lastMoveUp = true; 00111 } else { 00112 _lastMoveUp = false; 00113 } 00114 00115 // _lastMoveUp now contains the move we want to make 00116 uint16_t newPWM; 00117 if (adc != _targetADC) { 00118 if ((!_invert && !_lastMoveUp) || (_invert && _lastMoveUp)) { 00119 newPWM = _pwm - 1; 00120 } else { 00121 newPWM = _pwm + 1; 00122 } 00123 00124 // set a minimum on and off time 00125 if (newPWM < 1) { 00126 newPWM = 1; 00127 } else if (newPWM > uint16_t(_timer->getTop() - 1)) { 00128 newPWM = _timer->getTop() - 1; 00129 } 00130 00131 _pwm = newPWM; 00132 _timer->setOutput2(_pwm); 00133 } 00134 00135 _lastADC = adc; 00136 } 00137 00142 void MHV_VoltageRegulator::regulate() { 00143 switch (_mode) { 00144 case MHV_VREG_MODE_BOOST: 00145 regulateBoost(); 00146 break; 00147 case MHV_VREG_MODE_BUCK: 00148 regulateBuck(); 00149 break; 00150 } 00151 } 00152 00156 void MHV_VoltageRegulator::enable() { 00157 _timer->enable(); 00158 _timer->setOutput2(1); 00159 00160 MHV_AD_ENABLE; 00161 } 00162 00166 void MHV_VoltageRegulator::disable() { 00167 _timer->setOutput2(0); 00168 _timer->disable(); 00169 } 00170 00174 float MHV_VoltageRegulator::getVoltage() { 00175 return (float)(_lastADC * _vrefVoltage) / (_divider * MHV_AD_RESOLUTION); 00176 } 00177 00178 #endif // MHV_TIMER16_1 00179 #endif // MHV_AD_RESOLUTION 00180