Project showcase
ArduMeter - Arduino Incident Light Meter

ArduMeter - Arduino Incident Light Meter © CC BY-NC

Build a simple incident light meter for old meterless film cameras.

  • 2,392 views
  • 0 comments
  • 12 respects

Components and supplies

About this project

This is a practice project to make an Arduino-based incident light meter for old meterless mechanical film cameras, probably more useful for portrait photography. I don't have the means to test it yet; sometimes the measured values seems to be pretty accurate, sometimes they are quite different from reflective light meters readings on my digital or analog cameras.

(Usually I just use an app on my phone, which is reliable enough for my amatuer film photography. I only have two or three meterless cameras I would use occasionally, so why bother to buy a real light meter that cost more than any of these cameras?)

The device is powered by a small power bank, with results displayed on a 0.96" SSD1306 OLED each time you press the button. The input from the BH1750 light intensity sensor will be calculated into exposure values (EV). I set the incident-light meter calibration constant to 340 (reference). You can set aperture and ISO via two potentiometers. If you plug it on computers you can get more detailed data via serial port.

I used two mini breadboards glued back-to-back. But you can reproduce this on regular breadboards.

The library I used for the OLED display can be found here. The one for BH1750 is here.

Code

ArduMeterC/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");
  }
}

Schematics

ArduMeter circuit
Cleaner version by using a normal breadboard
Ardumeter ambhnsgrqd

Comments

Similar projects you might like

sC00p-4-b1l1tY Meter

Project showcase by sC00p-4-b1l1tY

  • 685 views
  • 2 comments
  • 1 respect

Stereo NeoPixel Ring VU Meter

Project showcase by ericBcreator

  • 29,175 views
  • 268 comments
  • 70 respects

Sigfox kWh Meter

Project tutorial by jassak

  • 6,113 views
  • 7 comments
  • 15 respects

Pick to Light Project 2 WiFi

Project tutorial by PAJ

  • 776 views
  • 14 comments
  • 4 respects

Pick to Light Project 1 Serial

Project tutorial by PAJ

  • 471 views
  • 0 comments
  • 4 respects

Match the Light

Project showcase by Team Valin

  • 1,895 views
  • 3 comments
  • 5 respects
Add projectSign up / Login