DIY Arduino 入射式测光表

A Lightmeter/Flashmeter for photographers, based on Arduino. Components: 1. Arduino NANO v.3 2. BH1750 light sensor 3. SSD1306 128*96 OLED SPI Display 4. Buttons Thanks @morozgrafix https://github.com/morozgrafix for creating schematic diagram for this device. The lightmeter based on Arduino as a main controller and BH1750 as a metering cell. Information is displayed on SSD1306 OLED display. The device is powered by 2 AAA batteries. Functions list:

  • Ambient light metering
  • Flash light metering
  • ND filter correction
  • Aperture priority
  • Shutter speed priority
  • ISO range 8 - 4 000 000
  • Aperture range 1.0 - 3251
  • Shutter speed range 1/10000 - 133 sec
  • ND Filter range ND2 - ND8192
  • Displaying amount of light in Lux.
  • Displaying exposure value, EV
  • Recalculating exposure pair while one of the parameter changing
  • Battery information
  • Power 2xAAA LR03 batteries

Detailed information on my site: https://www.pominchuk.com/lightmeter/

!!!此简易测光表对付负片足以!!!

!!!如果用于正片或是需要精确曝光的环境请使用商业测光表!!!

 


所需元件

  • 主机
    1. Arduino nano
    2. BH1750光强度模块
    3. 0.96寸 7针SPI接口oled屏幕(SSD1306)
    4. 微动开关
  • 供电
    1. 3v升压5v模块
      • 如果用锂电池供电的话记得换成充电宝升压模块
    2. 电池
      • 可以用两节AAA电池
      • 或者使用CR123等一次性锂电池
      • 或者用锂电池
    3. 拨动开关

设计PCB

  • ☑ 尺寸5*5
  • ☑ 独立供电模块
  • ☑ 独立开关
  • ❎ CR2032供电
    • 供电不足
      • 改用CR123A供电
  • 🔄 设计底板

源码&&焊接

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <BH1750.h>
#include <EEPROM.h>
#include <avr/sleep.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for SSD1306 display connected using software SPI (default case):
#define OLED_DC 11
#define OLED_CS 12
#define OLED_CLK 8 //10
#define OLED_MOSI 9 //9
#define OLED_RESET 10 //13
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT,
OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);

BH1750 lightMeter;

#define DomeMultiplier 2.17 // Multiplier when using a white translucid Dome covering the lightmeter
#define MeteringButtonPin 2 // Metering button pin
#define PlusButtonPin 3 // Plus button pin
#define MinusButtonPin 4 // Minus button pin
#define ModeButtonPin 5 // Mode button pin
#define MenuButtonPin 6 // ISO button pin
#define MeteringModeButtonPin 7 // Metering Mode (Ambient / Flash)
//#define PowerButtonPin 2

#define MaxISOIndex 57
#define MaxApertureIndex 70
#define MaxTimeIndex 80
#define MaxNDIndex 13
#define MaxFlashMeteringTime 5000 // ms

float lux;
boolean Overflow = 0; // Sensor got Saturated and Display “Overflow”
float ISOND;
boolean ISOmode = 0;
boolean NDmode = 0;

boolean PlusButtonState; // “+” button state
boolean MinusButtonState; // “-“ button state
boolean MeteringButtonState; // Metering button state
boolean ModeButtonState; // Mode button state
boolean MenuButtonState; // ISO button state
boolean MeteringModeButtonState; // Metering mode button state (Ambient / Flash)

boolean ISOMenu = false;
boolean NDMenu = false;
boolean mainScreen = false;

// EEPROM for memory recording
#define ISOIndexAddr 1
#define apertureIndexAddr 2
#define modeIndexAddr 3
#define T_expIndexAddr 4
#define meteringModeAddr 5
#define ndIndexAddr 6

#define defaultApertureIndex 12
#define defaultISOIndex 11
#define defaultModeIndex 0
#define defaultT_expIndex 19

uint8_t ISOIndex = EEPROM.read(ISOIndexAddr);
uint8_t apertureIndex = EEPROM.read(apertureIndexAddr);
uint8_t T_expIndex = EEPROM.read(T_expIndexAddr);
uint8_t modeIndex = EEPROM.read(modeIndexAddr);
uint8_t meteringMode = EEPROM.read(meteringModeAddr);
uint8_t ndIndex = EEPROM.read(ndIndexAddr);

int battVolts;
#define batteryInterval 10000
double lastBatteryTime = 0;

#include “lightmeter.h”

void setup() {
pinMode(PlusButtonPin, INPUT_PULLUP);
pinMode(MinusButtonPin, INPUT_PULLUP);
pinMode(MeteringButtonPin, INPUT_PULLUP);
pinMode(ModeButtonPin, INPUT_PULLUP);
pinMode(MenuButtonPin, INPUT_PULLUP);
pinMode(MeteringModeButtonPin, INPUT_PULLUP);

//Serial.begin(115200);

battVolts = getBandgap(); //Determins what actual Vcc is, (X 100), based on known bandgap voltage

Wire.begin();
lightMeter.begin(BH1750::ONE_TIME_HIGH_RES_MODE_2);
//lightMeter.begin(BH1750::ONE_TIME_LOW_RES_MODE); // for low resolution but 16ms light measurement time.

display.begin(SSD1306_SWITCHCAPVCC, 0x3D);
display.setTextColor(WHITE);
display.clearDisplay();

// IF NO MEMORY WAS RECORDED BEFORE, START WITH THIS VALUES otherwise it will read “255”
if (apertureIndex > MaxApertureIndex) {
apertureIndex = defaultApertureIndex;
}

if (ISOIndex > MaxISOIndex) {
ISOIndex = defaultISOIndex;
}

if (T_expIndex > MaxTimeIndex) {
T_expIndex = defaultT_expIndex;
}

if (modeIndex < 0 modeIndex > 1) {
// Aperture priority. Calculating shutter speed.
modeIndex = 0;
}

if (meteringMode > 1) {
meteringMode = 0;
}

if (ndIndex > MaxNDIndex) {
ndIndex = 0;
}

lux = getLux();
refresh();
}

void loop() {
if (millis() >= lastBatteryTime + batteryInterval) {
lastBatteryTime = millis();
battVolts = getBandgap();
}

readButtons();

menu();

if (MeteringButtonState == 0) {
// Save setting if Metering button pressed.
SaveSettings();

lux = 0;
refresh();

if (meteringMode == 0) {
  // Ambient light meter mode.
  lightMeter.configure(BH1750::ONE\_TIME\_HIGH\_RES\_MODE\_2);

  lux = getLux();

  if (Overflow == 1) {
    delay(10);
    getLux();
  }

  refresh();
  delay(200);
} else if (meteringMode == 1) {
  // Flash light metering
  lightMeter.configure(BH1750::CONTINUOUS\_LOW\_RES\_MODE);

  unsigned long startTime = millis();
  uint16\_t currentLux = 0;
  lux = 0;

  while (true) {
    // check max flash metering time
    if (startTime + MaxFlashMeteringTime < millis()) { break; } currentLux = getLux(); delay(16); if (currentLux > lux) {
      lux = currentLux;
    }
  }

  refresh();
}

}
}

 


DIY测光表测光模式相当于相机内中央平均测光。在大多数拍摄情况下中央平均测光是一种非常实用的测光模式,在拍摄人像旅游照等对于中央亮度起到决定性作用的拍摄场景时,应用广泛。


Bugs

❌ 大E了

  1. ❌板子上画的是CR2032的电池尺寸,装起来发现带不动测光表
  2. ❌ 供电模块画反了

样片

咕咕咕

 

2020.11.23