ATiny85 PWM LED Driver

/* 
rev.1 14 nov 2014 Elmars Ositis Power LED driver for Attiny85
rev.2 21 Dec 2014 revised for more stability. Added additional read cycles for setpoint measurements
  a) also added delays to give a bit of time before the next read
  b) finally added an overall delay to slow the loop
  c) these revisions enable stable light control at 2x LED max voltage. i.e. a 10v 1A LED can maintain stable light output at 20V 300mA current.
  d) may be necessary to fix Arduino ld bug for this to compile for ATtiny
requires the Arduino PID Library by Brett Beauregard

rev.3 27 Feb 2015 smoother start and faster pwm
  a) changed power sense logic to a running average, 3x the average of previous measurements plus new measurement, divide by 4.
  b) changed voltage sense division operations to use bitshift for speed. This has increased the pwm performance from 2KHz to 4KHz.
  c) The result of the two changes above have eliminated the startup flicker previously observed. Now startup is smooth and fast.
  d) Added a delay of 500 in the setup loop to allow voltages to stabilize before measuring the setpoint. Without this delay, light output after start is not consistent from start to start.
*/

#include <PID_v1.h>

//Use internal 1.1volt reference
//voltage across sense resistor should be less than 1 volt
//comparing against the internal 1.1 volt reference allows for greater dynamic range.
#define INTERNAL
#define INTERNAL1V1 INTERNAL

//define the variables
double Setpoint, Output, Volts;
int Input, Tot, Tot8;

const byte mask = B11111000; // mask bits that are not prescale values
int prescale = 2; //1 sets to 32kHz, 2 sets to 4kHz, 3 sets to 500 Hz
 //seems like 32kHz is a bit too much for the LM358

PID myPID(&Volts, &Output, &Setpoint, 0, 1, 0, DIRECT);
 //use the second field for a slow ramp. 1st and 3rd fields ramp too fast.
 
int SetCount=0;
int AvInput=0;
int SetRead=0;

void setup() {
 analogReference(INTERNAL1V1);
 TCCR0B = (TCCR0B & mask) | prescale; //set timer frequency
 pinMode(1,OUTPUT);
 delay(500);
 for (int x=0; x<8; x++) { // read 10 times and average
 Setpoint=Setpoint+map(analogRead(3), 0, 1024, 0, 255); //here is where you set the current.
 delay(1);
 }
 Setpoint=Setpoint/8;
 SetRead=Setpoint;
 Tot=0;
 myPID.SetMode(AUTOMATIC); //turn on the PID
}

void loop() {
 //since the ADC is a bit unstable and it is measuring PWM output, averaging 8 samples
 //to get a reasonably consistent value. Using 2nd order filter on the board.
 for (int x=0; x<8; x++){
 Input=map(analogRead(2), 0, 1024, 0, 255);
 Tot=Tot+Input;
 }
 Tot8=Tot >> 3; //Divide by 8 using bitshift for speed
 Volts=(Tot8+(AvInput * 3)) >> 2; // Divide by 4 using bitshift for speed
 myPID.Compute();
 analogWrite(1,Output); //and there is light!
 if ( SetCount>20 ){ //check the setpoint reference only once every 20 loops
 for (int x=0; x<8; x++) { // read 8 times and average
 Setpoint=Setpoint+map(analogRead(3), 0, 1024, 0, 255); //here is where you set the current.
 delay(1);
 }
 SetCount=0;
 Setpoint=Setpoint/8;
 }
 Tot=0;
 AvInput=Volts;
 SetCount=SetCount++;
 delay(100); // adding this delay eliminates light output oscillation
}
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s