alankrantas
Published © CC BY-NC

ArduMeter - Arduino Incident Light Meter

Build a simple incident light meter for old meterless film cameras

EasyShowcase (no instructions)3,734
ArduMeter - Arduino Incident Light Meter

Things used in this project

Hardware components

Arduino Nano R3
Arduino Nano R3
×1
BH1750FVI Digital Light Intensity Sensor Module
×1
0.96" 128x64 OLED I2C Display
×1
Rotary potentiometer (generic)
Rotary potentiometer (generic)
×2
Pushbutton switch 12mm
SparkFun Pushbutton switch 12mm
×1
Breadboard (generic)
Breadboard (generic)
×1
Resistor 10k ohm
Resistor 10k ohm
×1

Story

Read more

Schematics

ArduMeter circuit

Cleaner version by using a normal breadboard
Ardumeter ambhnsgrqd

Code

ArduMeter

C/C++
Code for ArduMeter
/*
  ArduMeter (Arduino incident light meter for cameras)
  by Alan Wang

  BH1750/BH1750FVI digital light intensity sensor:
  VCC -> 3.3V
  GND -> GND
  SDA -> pin A4
  SCL -> pin A5
  ADD -> (none)

  0.96" SSD1306 OLED 128x64 display:
  VCC -> 3.3V
  GND -> GND
  SDA -> pin A4
  SCL -> pin A5

  1x push button
  leg 1 -> 3.3V
  leg 2 -> pin D5 with 10 kOhms pull-down resistor connect to GND

  2x 10 kOhms potentiometer (knob)
  leg 1 -> 3.3V
  leg 2 (middle) -> pin A2/A3 (max analog signal about 730-740)
  leg 3 -> GND

  The Arduino Nano is powered by a USB powerbank via USB cable.

*/

#include <math.h>
#include <Wire.h>
#include <BH1750.h> //for BH1750, https://github.com/claws/BH1750
#include "SSD1306Ascii.h" //for OLED, https://github.com/greiman/SSD1306Ascii
#include "SSD1306AsciiAvrI2c.h" //same as above

BH1750 bh1750LightMeter;
SSD1306AsciiAvrI2c oled1306;
bool started = false; //if user started to use light meter (pressed button)
bool buttonMeasurePressed; //status of measure light button
int knobApertureStatus; //status of aperture select knob
int prevKnobApertureStatus; //previous status of aperture select knob
int knobISOstatus; //status of ISO select knob
int prevKnobISOstatus; //previous status of ISO select knob
long lux; //illuminance
float EV; //exposure value
int ISO; //film or digital sensor sensitivity
const int incidentCalibration = 340; //incident light calibration const, see https://en.wikipedia.org/wiki/Light_meter#Calibration_constants

void setup() {
  //initialize
  pinMode(5, INPUT);
  Serial.begin(9600);
  Wire.begin();
  bh1750LightMeter.begin(0x21); //BH1750_ONE_TIME_HIGH_RES_MODE_2
  //"initialize" BH1750 by using it, or it will return NaN at the first time
  lux = bh1750LightMeter.readLightLevel();
  //initialize OLED
  oled1306.begin(&Adafruit128x64, 0x3C);
  oled1306.setFont(System5x7);
  oled1306.set2X();
  Serial.println("ArduMeter (Arduino incident light meter for camera) READY:");
  Serial.println("button -> measure light");
  Serial.println("knobs -> change aperature/ISO");
  oled1306.clear();
  oled1306.println("ArduMeter");
  oled1306.println("READY");
  oled1306.println("press");
  oled1306.println("button");
}

void loop() {
  //read status from button and potentiometers
  buttonMeasurePressed = digitalRead(5);
  knobApertureStatus = map(analogRead(2), 0, 730, 1, 16);
  knobISOstatus = map(analogRead(3), 0, 730, 1, 10);
  if (buttonMeasurePressed) {
    //measure light
    if (!started) started = true;
    displayExposureSetting(true);
  } else {
    //change aperture/ISO settings
    if ((knobApertureStatus != prevKnobApertureStatus || knobISOstatus != prevKnobISOstatus) && started) {
      displayExposureSetting(false);
    }
  }
  //record potentiometer previous status
  prevKnobApertureStatus = knobApertureStatus;
  prevKnobISOstatus = knobISOstatus;
  delay(250);
}

void displayExposureSetting(bool measureNewExposure) {
  float aperature;
  float shutterSpeed;
  //select aperature via potentiometer 1; the values are based on most common aperatures you'll find on digital and analog cameras
  switch (knobApertureStatus) {
    case 1: aperature = 1.4; break;
    case 2: aperature = 1.7; break;
    case 3: aperature = 2; break;
    case 4: aperature = 2.8; break;
    case 5: aperature = 3.5; break;
    case 6: aperature = 4; break;
    case 7: aperature = 4.5; break;
    case 8: aperature = 5.6; break;
    case 9: aperature = 6.3; break;
    case 10: aperature = 8; break;
    case 11: aperature = 10; break;
    case 12: aperature = 11; break;
    case 13: aperature = 12.7; break;
    case 14: aperature = 16; break;
    case 15: aperature = 22; break;
    case 16: aperature = 32;
  }
  //select ISO via potentiometer 2; the values are based on common film speeds
  switch (knobISOstatus) {
    case 1: ISO = 12; break;
    case 2: ISO = 25; break;
    case 3: ISO = 50; break;
    case 4: ISO = 100; break;
    case 5: ISO = 160; break;
    case 6: ISO = 200; break;
    case 7: ISO = 400; break;
    case 8: ISO = 800; break;
    case 9: ISO = 1600; break;
    case 10: ISO = 3200;
  }
  if (measureNewExposure) {
    //measure light level (illuminance) and get a new lux value
    lux = bh1750LightMeter.readLightLevel();
    Serial.print("Measured illuminance = ");
    Serial.print(lux);
    Serial.println(" lux");
  }
  //calculate EV
  EV = (log10(lux * ISO / incidentCalibration) / log10(2));
  if (isfinite(EV)) {
    //calculate shutter speed if EV is not NaN or infinity
    shutterSpeed = pow(2, EV) / pow(aperature, 2);
    //output results to serial port and OLED
    Serial.print("Exposure settings: ISO = ");
    Serial.print(ISO);
    Serial.print(", EV = ");
    Serial.print(EV);
    Serial.print(", aperture = f/");
    Serial.print(aperature, 1);
    Serial.print(", ");
    Serial.print("shutter speed = ");
    if (shutterSpeed >= 1) {
      Serial.print("1/");
      Serial.print(shutterSpeed);
    } else {
      Serial.print((1 / shutterSpeed));
    }
    Serial.println("s");
    oled1306.clear();
    oled1306.print("ISO ");
    oled1306.println(ISO);
    oled1306.print("EV: ");
    oled1306.println(EV, 1);
    oled1306.print("-- f/");
    oled1306.println(aperature, 1);
    oled1306.print("-- ");
    if (shutterSpeed >= 1) {
      oled1306.print("1/");
      oled1306.print(shutterSpeed, 0);
    } else {
      oled1306.print((1 / shutterSpeed), 0);
    }
    oled1306.println("s");
  } else {
    Serial.println("Error: exposure out of bounds");
    oled1306.clear();
    oled1306.println("Exposure");
    oled1306.println("value");
    oled1306.println("out of");
    oled1306.println("bounds");
  }
}

Credits

alankrantas

alankrantas

0 projects • 3 followers

Comments