Skip to content

Instantly share code, notes, and snippets.

Created February 9, 2017 20:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/c47f3ab42c39678716136837f08872ae to your computer and use it in GitHub Desktop.
Save anonymous/c47f3ab42c39678716136837f08872ae to your computer and use it in GitHub Desktop.
//#include <wiring_private.h>
// included for access to cbi(), sbi() macros, and TCCR1B register definitions
// Nov, 2011 - commented out wiring_private.h and copied the macros here
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
#include <avr\wdt.h>
// access to watchdog timer macros
unsigned int power_level = 0;
// The target regulated voltage, default power level 0V (output will be input voltage +/-1V)
// Do not change this definition (change the SetVoltage(v) assignment in setup, below)
unsigned int SetVoltage(double voltage);
// Calculate the desired analog input reading, for a given voltage
signed int duty = 0; // used in the main program loop
// it's assigned to the analog output, to control the output voltage.
// the relationship between duty cycle and voltage depends on output load and input voltage.
// since neither the load or input are assumed, the program estimates/seeks
// the correct duty cycle by sensing the output voltage and making small adjustments.
// A greater duty cycle makes a greater voltage.
void setup() {
// I use pin 13 to indicate power, with an LED. (like the older revisions had built-in)
// For my rev.c arduino, I put an LED between pin 13 and GND (outputs only source 20mA).
pinMode(13,OUTPUT);
digitalWrite(13,HIGH);
// The following code increases the PWM frequency
// This might have an effect on delay(n) and millis() functions.
// The ideal frequency depends on the inductor, but it'll only be important if you need alot more power.
// My earlier tests indicated 20-300KHz are usable (depending on the inductor).
// (If 1KHz is used, the inductor will make a buzzing sound.)
#if defined(__AVR_ATmega168__)
// 62.5KHz PWM for the ATMega168 -> only on Arduino pins 9 and 10
// set prescaler to 1
// (sbi means "set bit register", cbi means "clear bit register")
cbi(TCCR1B, CS12);
cbi(TCCR1B, CS11);
sbi(TCCR1B, CS10);
// set fast PWM
cbi(TCCR1B, WGM13);
sbi(TCCR1B, WGM12);
// with fast PWM, the frequency is (CLK/256*prescaler) = 16MHz/256 = 62.5KHz
// with slow PWM, it is half that speed (31KHz)
#else
// 22KHz for the ATMega8 (this is a low frequency, so fewer inductors might work with it)
TCCR2 = ((TCCR2 & ~0x07) | 0x01);
TCCR1B = ((TCCR1B & ~0x07) | 0x01);
#endif
// enable the watchdog timer (a failsafe reset: if the program freezes, the voltage booster will shut off)
// the Arduino will reset if this timer isn't cleared in less than 400ms.
wdt_enable(400);
// set the voltage you want the program to maintain (any decimal value greater than your input voltage)
power_level = SetVoltage(9);
// Do not exceed 24V without taking special precautions.
// Do not exceed 60V with the circuit/schematic provided with this software. (75V or more will damage the arduino)
// Do not exceed 250mW (aka 1/4W, aka quarter watt) of power. (MAX: 5V 50mA, 9V 28mA, 12V 21mA, 24V 10mA, 48V 5mA)
}
void loop() {
unsigned int measure = analogRead(0);
wdt_reset(); // watchdog timer reset (see above)
if (measure>power_level+18) {
// "panic" if the measured voltage is more than 1V above where it should be,
// cut power by 50% to respond quickly.
duty=duty/2;
} else if (measure>power_level) {
// decrease duty cycle to compensate for smaller load
duty=max(0,duty-1);
} else if (measure<power_level) {
// increase duty cycle to compensate for larger load
duty=min(191,duty+1);
// Without the 191 limit, it can cause regulation to fail at high loads or high voltages.
// Only modify this limit if you're using an improved version of the schematic I've given.
} else {
return;
}
analogWrite(10,duty);
// If you have HF noise problems, you might want to add a small microseconds delay here to see if it helps.
// Delays can make voltage regulation worse, by reacting slower to changes in the output load.
// If you have regulation problems, make sure your output filter capacitor is at least 0.1uF.
// As your circuit's load changes, the capacitor will slow down output fluctuations.
}
// Calculate the desired analog input reading, for a given voltage
unsigned int SetVoltage(double voltage) {
if (voltage>60) {
return 0; // do not exceed 60V
}
// This function converts the voltage value (0 to 5V reading; 0 to 60V actual), into a value for an analog input (from 0 to 1024)
// If your resistor voltage divider is not perfectly 15:1 you'll need to change the formula below
// with ideal resistors and a perfect 5V Analog Reference voltage (AREF), an analog input value of 13.65 would be 1V
return (voltage*12.8);
// ideal ADC value, per volt = voltage*(1024/5)/(15/1) = 13.65
// the real value for my circuit = voltage*(204.8)/(16.5) = 12.41
// 16.5 was my measured resistor voltage divier ratio.
// I increased my calculated 12.41 constant to 12.8, by trial and error, in order to get closer to the target voltage
// My results were +/-0.2V, at a 0.1mA (100Kohm) load when powered by the Arduino.
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment