ArduMeter - Arduino Incident Light Meter
Build a simple incident light meter for old meterless film cameras
Components and supplies
1
Pushbutton switch 12mm
1
Resistor 10k ohm
1
Arduino Nano R3
1
BH1750FVI Digital Light Intensity Sensor Module
1
Breadboard (generic)
2
Rotary potentiometer (generic)
1
0.96" 128x64 OLED I2C Display
Apps and platforms
1
Arduino IDE
Project description
Code
ArduMeter
c_cpp
Code for ArduMeter (v2)
1/* 2 ArduMeter (Arduino incident light meter) version 2 3 by Alan Wang 4 5 BH1750/BH1750FVI digital light intensity sensor: 6 Library: https://github.com/claws/BH1750 7 VCC -> 3.3V 8 GND -> GND 9 SDA -> pin A4 10 SCL -> pin A5 11 ADD -> (none) 12 13 0.96" SSD1306 OLED 128x64 display: 14 Library: https://github.com/greiman/SSD1306Ascii 15 VCC -> 3.3V 16 GND -> GND 17 SDA -> pin A4 18 SCL -> pin A5 19 20 1x push button 21 leg 1 -> pin D2 22 leg 2 -> GND 23 24 2x 10 kOhms potentiometer (knob) 25 leg 1 -> 3.3V 26 leg 2 (middle) -> pin A0/A1 (max analog signal about 730-740) 27 leg 3 -> GND 28 29 ------------------------------ */ 30 31// Set this to true if you wish to get "standard" shutter settings 32#define STANRARD_SHUTTER_SPEED false 33 34// Calibration constant (C) for incident light meters. 35// see https://en.wikipedia.org/wiki/Light_meter#Calibration_constants 36#define INCIDENT_CALIBRATION 330 37 38// Max analog readings from potentiometers. Change it only if you are 39// using different input voltage or potentiometers that are not 10K. 40#define KNOB_MAX_ANALOG_READING 740 41 42// Define pins 43#define BUTTON_PIN 2 // D2 44#define KNOB_APERTURE_PIN 0 // A0 45#define KNOB_ISO_PIN 1 // A1 46 47// Pre-defined aperture and ISO settings. Modify them for your own preference. 48// Elements in the array have to be sorted from min to max. 49const double APERATURE_TABLE[] = {1.0, 1.4, 1.8, 2.0, 2.8, 3.5, 4.0, 4.5, 5.6, 6.3, 8.0, 11.0, 12.7, 16.0, 22.0, 32.0}; 50const int ISO_TABLE[] = {6, 12, 25, 50, 100, 160, 200, 400, 800, 1600, 3200}; 51 52// The "shutterspeed table" array is used when STANRARD_SHUTTER_SPEED is set to true. 53// 1/2 (0.5) seconds is expressed as 2, and 2 seconds is expressed as -2. 54double SHUTTERSPEED_TABLE[] = {-60, -30, -15, -8, -4, -2, -1, 2, 4, 8, 15, 30, 60, 125, 250, 500, 1000, 2000, 4000}; 55 56// If you are using older cameras which have different shutter speed settings, 57// you can switch to the folloing array: 58// double SHUTTERSPEED_TABLE[] = {-1, 2, 5, 10, 25, 50, 100, 250, 500, 1000}; 59 60/* ------------------------------ */ 61 62#include <math.h> 63#include <Wire.h> 64#include <BH1750.h> 65#include "SSD1306Ascii.h" 66#include "SSD1306AsciiAvrI2c.h" 67 68BH1750 bh1750; 69SSD1306AsciiAvrI2c oled; 70 71bool started = false; 72int EV, apertureIndex, apertureIndexOld, isoIndex, isoIndexOld; 73long lux; 74 75void setup() { 76 77 // initialize serial port 78 Serial.begin(9600); 79 Wire.begin(); 80 81 // prepare the shutterspeed table array if needed 82 if (STANRARD_SHUTTER_SPEED) { 83 for (int i = 0; i < (sizeof(SHUTTERSPEED_TABLE) / sizeof(double)); i++) { 84 if (SHUTTERSPEED_TABLE[i] < 0) { 85 SHUTTERSPEED_TABLE[i] = 1 / abs(SHUTTERSPEED_TABLE[i]); 86 } 87 } 88 } 89 90 // setup button 91 pinMode(BUTTON_PIN, INPUT_PULLUP); 92 93 // set the BH1750 in BH1750_ONE_TIME_HIGH_RES_MODE_2 94 bh1750.begin(0x21); 95 96 // "initialize" BH1750 by using it once 97 bh1750.readLightLevel(); 98 99 // initialize OLED 100 oled.begin(&Adafruit128x64, 0x3c); 101 oled.setFont(System5x7); 102 oled.set2X(); 103 104 Serial.println("ArduMeter (Arduino incident light meter for camera) READY:"); 105 Serial.println("- Press button to measure light."); 106 Serial.println("- Turn knobs to change aperature/ISO."); 107 108 oled.clear(); 109 oled.println("ArduMeter"); 110 oled.println("READY"); 111 oled.println("press"); 112 oled.println("button"); 113} 114 115void loop() { 116 117 //read status from button and potentiometers 118 getKnobIndex(); 119 120 if (buttonPressed()) { //measure light 121 if (!started) started = true; 122 displayExposureSetting(true); 123 delay(150); 124 125 } else { //change aperture/ISO settings 126 if ((apertureIndex != apertureIndexOld || isoIndex != isoIndexOld) && started) { 127 displayExposureSetting(false); 128 delay(150); 129 } 130 } 131 132 //record potentiometer previous status 133 apertureIndexOld = apertureIndex; 134 isoIndexOld = isoIndex; 135 136 delay(50); 137} 138 139// read if the button is pressed (pulled low) 140bool buttonPressed() { 141 return !digitalRead(BUTTON_PIN); 142} 143 144// map knob analog readings to array indexes 145void getKnobIndex() { 146 apertureIndex = round(map(analogRead(KNOB_APERTURE_PIN), 0, KNOB_MAX_ANALOG_READING, 0, sizeof(APERATURE_TABLE) / sizeof(float))); 147 isoIndex = round(map(analogRead(KNOB_ISO_PIN), 0, KNOB_MAX_ANALOG_READING, 0, sizeof(ISO_TABLE) / sizeof(int))); 148} 149 150// measure/calculate and display exposure settings 151void displayExposureSetting(bool measureNewEV) { 152 153 double aperature = APERATURE_TABLE[apertureIndex]; 154 int iso = ISO_TABLE[isoIndex]; 155 156 // measure light level (illuminance) and get a new lux value 157 if (measureNewEV) { 158 lux = bh1750.readLightLevel(); 159 Serial.print("Measured illuminance = "); 160 Serial.print(lux); 161 Serial.println(" lux"); 162 } 163 164 //calculate EV 165 EV = log10(lux * iso / INCIDENT_CALIBRATION) / log10(2); 166 167 if (isfinite(EV)) { //calculate shutter speed if EV is neither NaN nor infinity 168 169 // calculate shutter speed 170 double shutterspeed = (pow(2, EV) / pow(aperature, 2)); 171 172 // choose standard shutter speed if needed 173 if (STANRARD_SHUTTER_SPEED) { 174 for (int i = 0; i < (sizeof(SHUTTERSPEED_TABLE) / sizeof(double)) - 1; i++) { 175 if (shutterspeed >= SHUTTERSPEED_TABLE[i] && shutterspeed <= SHUTTERSPEED_TABLE[i + 1]) { 176 if (abs(shutterspeed - SHUTTERSPEED_TABLE[i]) <= abs(shutterspeed) - SHUTTERSPEED_TABLE[i + 1]) { 177 shutterspeed = SHUTTERSPEED_TABLE[i]; 178 } else { 179 shutterspeed = SHUTTERSPEED_TABLE[i + 1]; 180 } 181 break; 182 } 183 } 184 } 185 186 // output result to serial port 187 Serial.print("Exposure settings: EV = "); 188 Serial.print(EV); 189 Serial.print(", ISO = "); 190 Serial.print(iso); 191 Serial.print(", aperture = f/"); 192 Serial.print(aperature, 1); 193 Serial.print(", "); 194 Serial.print("shutter speed = "); 195 if (shutterspeed > 1) { 196 Serial.print("1/"); 197 Serial.print(shutterspeed); 198 } else { 199 Serial.print((1 / shutterspeed)); 200 } 201 Serial.println("s"); 202 203 // output result to OLED 204 oled.clear(); 205 oled.print("EV: "); 206 oled.println(EV, 1); 207 oled.print("ISO "); 208 oled.println(iso); 209 oled.print("-- f/"); 210 oled.println(aperature, 1); 211 oled.print("-- "); 212 if (shutterspeed > 1) { 213 oled.print("1/"); 214 oled.print(shutterspeed, 0); 215 } else { 216 oled.print((1 / shutterspeed), 0); 217 } 218 oled.println("s"); 219 220 } else { 221 Serial.println("Exposure out of bounds"); 222 oled.clear(); 223 oled.println("Exposure"); 224 oled.println("value"); 225 oled.println("out of"); 226 oled.println("bounds"); 227 } 228}
Downloadable files
ArduMeter circuit
Cleaner version by using a normal breadboard
ArduMeter circuit

ArduMeter circuit
Cleaner version by using a normal breadboard
ArduMeter circuit

Comments
Only logged in users can leave comments