Shutter Speed


As analog cameras are getting older more and more, their mechanical shutters might loose some of their precisions.

It is quite easy to measure the exposure time if you manage to fix a light sensor in the area where the film used to be.

We used a pc board which fits where the cover of the camera used to be.

In the center of it we fixed a photo diode (BPX81, any other would do as well). The black and blue wires go to the Arduino.

To display the 4-digit measurements we used an HP QDSP-6064 bubble display.
Due to the 1/20 inch gap between d7 and d8 we had to use two separate strip boards to fix the display and the eight resistores. (As we ran out of port pins we had to use one of the analog pins as a digital one.)

The blue wire from the collector, the black one from the emitter of the BPX81.

To operate, remove the lens and hold a bright lamp against the front of the camera while pressing the release button.

The program alternatively will show the shutter time (given in seconds with 3 decimals) and the reciprocal which is printed on the wheel where you select the actual shutter speed. Leading zeroes will not be shown.

#define FILENAME "Shutter speed 4"

// don't use Pin-0 and Pin-1, used for Serial debug only
const byte sensorPin = 2; 
// INT-0 is used with Pin-2 on Arduino-UNO and Arduino-MEGA
// for Leonardo it is INT-1
const byte seg_a = 13;
const byte seg_b = 12;
const byte seg_c =  6;
const byte seg_d =  9;
const byte seg_e =  7;
const byte seg_f = 10;
const byte seg_g =  8;
const byte seg_dp = A0; // no more digital Pins available
const byte dig_1 =  5;
const byte dig_2 = 11;
const byte dig_3 =  4;
const byte dig_4 =  3;
const byte segs[]  = {seg_a, seg_b, seg_c, seg_d, seg_e, seg_f, seg_g};
const byte digit[] = {dig_1, dig_2, dig_3, dig_4};
//                          gfedcba
const byte segments[] = { B00111111, // 0
                          B00000110, // 1
                          B01011011, // 2
                          B01001111, // 3
                          B01100110, // 4
                          B01101101, // 5
                          B01111101, // 6
                          B00000111, // 7 
                          B01111111, // 8 
                          B01101111 }; // 9

void setup(){
  Serial.begin(9600);
  Serial.println(FILENAME);
  for (int i = 3; i <= A0; i++) pinMode(i,OUTPUT);
  attachInterrupt(0, shutter, CHANGE);
  digitalWrite(sensorPin,HIGH);
  TCCR2A = 0; // Timer clock = 16MHz/8 = 2Mhz or 0.5 micro-seconds
  TCCR2B = 3; // Timer2 Settings: Timer Prescaler /32, mode 0
  TIMSK2 = 1; // Timer2 Overflow Interrupt Enable
}

boolean flag = true;
long t1 = 1000; // faling edge
long t2 = 0; // rising edge
long dt; // time in micro-seconds
int time_ms = 0; // time [ms]
int reciprocal = 0; // fraction of a second

void loop(){
  if (flag) return;
  dt = t2 - t1;
  time_ms = dt / 1000;
  reciprocal = 1000000 / dt;
  Serial.print(dt);
  Serial.print(" micro-seconds = 1/");
  Serial.print(reciprocal);
  Serial.println(" s");
  flag = true;
}

void shutter() {
  boolean b = digitalRead(sensorPin);
  switch (b) {
    case false : t1 = micros(); break;
    case true  : t2 = micros(); flag = false; 
    // tell the loop that there is something to be done
  }
}

ISR(TIMER2_OVF_vect) { // Timer 2 interrupt service routine 
   const int max = 2000;
   static int cnt = max; 
   static boolean sr = false; // show reciprocal
   // what to display: sw: false -> time, true -> fraction
   static byte digNr = 0;
   digitalWrite(digit[digNr],HIGH); // off
   if (--cnt == 0) { sr = !sr; cnt = max; }
   if (++digNr > 3) digNr = 0;
   if (sr) {
     // suppress leading zeroes:
     if (digNr == 0 && reciprocal < 1000) return;
     if (digNr == 1 && reciprocal < 100) return;
     if (digNr == 2 && reciprocal < 10) return;
   }
   int w; // value to display
   if (sr) w = reciprocal; else w = time_ms;
   if (!sr && digNr == 0) digitalWrite(seg_dp,HIGH); else digitalWrite(seg_dp,LOW);
   int b = 0;
   switch (digNr) {
     case 0: b = w / 1000; break;
     case 1: b = w / 100; break;
     case 2: b = w / 10; break;
     case 3: b = w; break;
   }
   byte s = segments[b % 10];
   for (int i = 0; i <= 6; i++) digitalWrite(segs[i], s & 1 << i); 
   digitalWrite(digit[digNr],LOW); // on
   // the ISR just takes 0.5 ms, no need to optimize any more
}



contact: nji(at)gmx.de