Hackster is hosting Hackster Holidays, Finale: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Tuesday!Stream Hackster Holidays, Finale on Tuesday!
Mirko Pavleski
Published © GPL3+

How to make Arduino LED Tester + Resistor Calculator

Useful tool for testing, and determining characteristics of LEDs, as well as a calculator for calculating the series resistor.

BeginnerFull instructions provided3 hours1,981
How to make Arduino LED Tester + Resistor Calculator

Things used in this project

Hardware components

Arduino Nano R3
Arduino Nano R3
×1
I2C 16x2 Arduino LCD Display Module
DFRobot I2C 16x2 Arduino LCD Display Module
×1
PTS 645 Series Switch
C&K Switches PTS 645 Series Switch
×4
resistors
×6
Capacitor 470 µF
Capacitor 470 µF
×1

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)
Solder Wire, Lead Free
Solder Wire, Lead Free

Story

Read more

Schematics

Schematic

...

Code

Arduino code

C/C++
...
/*
Arduino LED Tester
DPIN--39R--+--10R---TESTLED---GND
           |      |         |
          470u    ATOP     ABOT
           |
          GND

 Measures LED characteristics by charging up the cap to deliver target current and find forward voltage
 From target current, we can calculate R to be used with a design supply voltage and a matching part number.
  */
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
//lcd update interval
#define LCDINT 500
//key check interval
#define KEYINT 200
//pin for buttons
#define KEYPIN A0
//button constants
#define btnRIGHT  6
#define btnUP     5
#define btnDOWN   4
#define btnLEFT   3
#define btnSELECT 2
#define btnNONE   (-1)
LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD adress
//Globals for display
long itest=10;    //test current, in mA
long vset =14000;  //display voltage in mV
long vled,vrr,irr,pset;  //LED voltage, Resistor voltage, resistor current, display power
//resistors in Jaycar 1/2 W range, part nos start at RR0524 for 10R
#define RCOUNT 121
long rvals[]={10,11,12,13,15,16,18,20,22,24,27,30,33,36,39,43,47,51,56,62,68,75,82,91,100,110,120,130,150,160,180,200,220,240,270,300,330,360,390,430,470,510,560,620,680,750,820,910,1000,1100,1200,1300,1500,1600,1800,2000,2200,2400,2700,3000,3300,3600,3900,4300,4700,5100,5600,6200,6800,7500,8200,9100,10000,11000,12000,13000,15000,16000,18000,20000,22000,24000,27000,30000,33000,36000,39000,43000,47000,51000,56000,62000,68000,75000,82000,91000,100000,110000,120000,130000,150000,160000,180000,200000,220000,240000,270000,300000,330000,360000,390000,430000,470000,510000,560000,620000,680000,750000,820000,910000,1000000};
long lastlcd=0;  //time of last lcd update
long lastkey=0;  //time of last key check
int lcdflash=0;  //lcd flashing phase variable
long pdes;
long rval;      //calculated resistor value for display
long rindex;    //index of selected resistor in rvals[]
int pwmout=0;    //pwm output of current driver
int rvalid=0;    //flag if resistor value is valid 
//pins for test interface
#define ATOP A2
#define ABOT A3
#define DPIN 3
#define OSAMP 16

void setup() {
  Serial.begin(9600);
// lcd.begin(16, 2);        //lcd 
  lcd.begin();
  lcd.clear();         
  lcd.backlight(); 
  pinMode(DPIN,OUTPUT);    //pwm pin
}

void loop() {
  long atop,abot,arr;      //analog sample values
  rvalid=0;                //set flag to not valid
  atop=analogoversample(ATOP,OSAMP)/OSAMP;
  abot=analogoversample(ABOT,OSAMP)/OSAMP;  
  arr=atop-abot;      //this is the analog value across the 10R sense resistor
  if(arr<0){arr=0;}    //sanity check
  vled=abot*5000/1023;  //5000mV=1023 => voltage across LED
  vrr=arr*5000/1023;    //voltage across sense resistor
  irr=vrr/10;     //led and resistor current in mA (cos it's a 10R resistor)
    
  if(irr<itest){pwmout++;if(pwmout>255){pwmout=255;}}    //ramp up current if too low
  if(irr>itest){pwmout--;if(pwmout<0){pwmout=0;}}        //ramp down if too high
  if(irr>24){pwmout=pwmout-5;if(pwmout<0){pwmout=0;}}    //ramp down quick if too too high
  if(irr>itest*3){pwmout=pwmout-5;if(pwmout<0){pwmout=0;}}    //ramp down quick if too too high
  analogWrite(DPIN,pwmout);                              //output new PWM
  rval=(vset-vled)/itest;                                //mV/mV => ohms resistance of display resistor
  for(int i=0;i<RCOUNT;i++){                             //find next highest E24 value
    if(rvals[i]>=rval){rindex=i;rval=rvals[rindex];i=RCOUNT+1;rvalid=1;}
  }
  if(abs(irr-itest)>(itest/5)+1){rvalid=0;}              //has current settled within 20%?
  if(vled>vset){rvalid=0;}                               //if vled>vset, no valid resistor exists
  pset=0;        //work out dissipation in ballast resistor if valid)
  if(rvalid){pset=itest*itest*rval;}      //this will be in microwatts (milliamps squared)
  
  if(millis()-lastlcd>LCDINT){      //check if display due to be updated
    lastlcd=millis();
    dolcd();        //update display
    lcdflash=1-lcdflash;  //toggle flash variable
    }
  if(millis()-lastkey>KEYINT){    //check if keys due to be checked
    lastkey=millis();
    dobuttons();
    }
    delay(1);
}        //end of loop

void dolcd(){
  lcd.setCursor(0,0);    //first line
  //milliamps
  if(lcdflash||rvalid){        //show if correct if on flashing phase
    if(itest>9){lcd.write(((itest/10)%10)+'0');}else{lcd.write(' ');}    //blank tens if zero
    lcd.write((itest%10)+'0');
  }
  else{      //blank if not
    lcd.write(' ');lcd.write(' ');
  }
    lcd.write('m');lcd.write('A');lcd.write(' ');
  //VLED
  lcd.write(((vled/1000)%10)+'0');
  lcd.write('.');
  lcd.write(((vled/100)%10)+'0');
  lcd.write('V');lcd.write(' ');

  //actual LED current
  if(irr>9){lcd.write(((irr/10)%10)+'0');}else{lcd.write(' ');}    //blank tens if zero
  lcd.write((irr%10)+'0');
  lcd.write('m');lcd.write('A');lcd.write(' ');
  if((pset>499999)&&(lcdflash)){lcd.write('P');}else{lcd.write(' ');} //flash P if power above 1/2 watt
  
  lcd.setCursor(0,1);   //second line
  //
  if(vset>9999){lcd.write(((vset/10000)%10)+'0');}else{lcd.write(' ');}    //tens of vset, blank if zero
  lcd.write(((vset/1000)%10)+'0');      //units of vset
  lcd.write('V');lcd.write(' ');
  
  if(rvalid){
    lcdprintrval(rval);  //resistor value (4 characters)
    lcd.write(' ');
    lcdprintpartno(rindex);    //resistor part no (6 characters)
    if(pset>499999){lcd.write('!');}else{lcd.write(' ');} //show ! if power above 1/2 watt
  }else{
    lcd.write(' ');
    lcd.write('-');
    lcd.write('-');
    lcd.write('-');
    lcd.write(' ');
    lcd.write('-');
    lcd.write('-');
    lcd.write('-');
    lcd.write('-');
    lcd.write('-');
    lcd.write('-');
    lcd.write(' ');
  }    
}

void lcdprintpartno(int index){
  //part number
  lcd.write('R');
  lcd.write('R');
  lcd.write('0');
  lcd.write((((index+524)/100)%10)+'0');      //part no's start at RR0524 for 10R
  lcd.write((((index+524)/10)%10)+'0');
  lcd.write((((index+524))%10)+'0');
}

void lcdprintrval(long rval){        //print a value in 10k0 format, always outputs 4 characters
  	long mult=1;
	long modval;
	if(rval>999){mult=1000;}
	if(rval>999999){mult=1000000;}
	modval=(10*rval)/mult;		//convert to final format, save a decimal place
	if(modval>999){		//nnnM
		lcd.write(((modval/1000)%10)+'0');
		lcd.write(((modval/100)%10)+'0');
		lcd.write(((modval/10)%10)+'0');
		lcdprintmult(mult);
			}else{
	if(modval>99){		//nnMn
		lcd.write(((modval/100)%10)+'0');
		lcd.write(((modval/10)%10)+'0');
		lcdprintmult(mult);
		lcd.write(((modval)%10)+'0');
			}else{	//_nMn
		lcd.write(' ');
		lcd.write(((modval/10)%10)+'0');
		lcdprintmult(mult);
		lcd.write(((modval)%10)+'0');
    }
  }
}
void lcdprintmult(long mult){      //helper function to print multiplier
	switch (mult){
	case 1:	lcd.print('R');break;
	case 1000:	lcd.print('k');break;
	case 1000000:	lcd.print('M');break;
	default:	lcd.print('?');break;
  }
}
int read_LCD_buttons(){
  int adc_key_in    = 0;
  adc_key_in = analogRead(KEYPIN);      // read the value from the sensor 
  delay(5); //switch debounce delay. Increase this delay if incorrect switch selections are returned.
  int k = (analogRead(KEYPIN) - adc_key_in); //gives the button a slight range to allow for a little contact resistance noise
  if (5 < abs(k)) return btnNONE;  // double checks the keypress. If the two readings are not equal +/-k value after debounce delay, it tries again.
  // my buttons when read are centered at these valies: 0, 144, 329, 504, 741
  // we add approx 50 to those values and check to see if we are close
  if (adc_key_in > 1000) return btnNONE; // We make this the 1st option for speed reasons since it will be the most likely result
  if (adc_key_in < 50)   return btnRIGHT;  
  if (adc_key_in < 195)  return btnUP; 
  if (adc_key_in < 380)  return btnDOWN; 
  if (adc_key_in < 555)  return btnLEFT; 
  if (adc_key_in < 790)  return btnSELECT;   
  return btnNONE;  // when all others fail, return this...
 
}
void dobuttons(){      //updates variables. debounces by only sampling at intervals
    int key;
    key = read_LCD_buttons();
    if(key==btnLEFT){itest=itest-1;if(itest<1){itest=1;}}
    if(key==btnRIGHT){itest=itest+1;if(itest>20){itest=20;}}
    if(key==btnUP){vset=vset+1000;if(vset>99000){vset=99000;}}
    if(key==btnDOWN){vset=vset-1000;if(vset<0){vset=0;}}   
}
long analogoversample(int pin,int samples){      //read pin samples times and return sum
  long n=0;
  for(int i=0;i<samples;i++){
    n=n+analogRead(pin);
  }
  return n;
}

Credits

Mirko Pavleski
155 projects • 1305 followers

Comments