Speedometer for an old movie projector


Most of those old machines have a knob to control the speed of the film. In some cases they provide a stroboscope wheel which allows you to adjust the exact speed for the film, mostly 16, 18, 24, or 25 frames per second.

If you want to check the speed as accurate as possible you have to trigger on either edge of the brightness of the light sent out to the screen.

In this case, we used a cheap photo transistor SP201 (any other one certainly would do as well) and a four digit LED display CL6542BH.

Connections:
Segments Arduino Pin
a 4
b 5
c 6
d 7
e 8
f 9
g 10
colon 11
anodes Arduino Pin
digit 1 A1
digit 2 A2
digit 3 A3
digit 4 A4
photo transistor Arduino Pin
anode 2 (interrupt)
cathode GND

Usually, you have to add resistors for each segment, but up to now it work fine without any.

And this ist the code.
Only a minimum of the character set for the 7-segment LED display was coded.

The sketch uses two interrupt service routines:


The program was written for projectors that have three wings on their axis. If your machine has only two or even one wing you have to modify the wing constant accordingy.

/*
 * Counting the frame rate.
 * Attention: when exposing to artificial light 
 * the value 50 / wings = 16 fps will be shown.
 */

const byte sensorPin = 2; // PORT D
const byte mask = B00000100;
const byte wings = 3;
const byte N = 100;
char VRAM[] = " FPS ";
// used in event ISR:
volatile boolean ready = false;
volatile byte count = 0;
volatile long startTime;
volatile long stopTime;

void setup() {
  Serial.begin(9600);
  Serial.println(F(__FILE__));  
  DDRB = B10001111; // pins 8 - 13
  DDRD = B11110000; // pins 0 - 7
  DDRC = B10011110; // pins A0 - A5
  PORTD = mask;
  setupTimer();
  delay(1000);
  attachInterrupt(0, newPic, RISING);
}

void loop() {
  if (!ready) return;
  // here ready = true
  long dt = stopTime - startTime;
  long fps = 100000L * N / dt / wings; 
  itoa(10000 + fps, VRAM, 10);
  Serial.println(fps * 0.01);
  count = 255; // the following interrupt advances to zero
  ready = false; // by now the ISR can work
}

void newPic() {
  if (ready) return;
  // here ready = false
  count++;
  switch (count) {
    case 0: startTime = millis(); break;
    case N: stopTime = millis(); ready = true; 
  }
}

void setupTimer() {
  cli();
  TCCR2A = 0; // Timer clock = 16MHz/8 = 2Mhz or 0.5 Ás
  TCCR2B = 6; // Timer2 Settings: Timer Prescaler
  TIMSK2 = 1; // Timer2 Overflow Interrupt Enable
  sei();
}

const byte digits[] = {
  // seg a = Arduino pin4  PORT D, bit 4
  // seg b = Arduino pin5  PORT D, bit 5
  // seg c = Arduino pin6  PORT D, bit 6
  // seg d = Arduino pin7  PORT D, bit 7
  // seg e = Arduino pin8  PORT B, bit 0
  // seg f = Arduino pin9  PORT B, bit 1
  // seg g = Arduino pin10 PORT B, bit 2
  // seg : = Arduino pin11 PORT B, bit 3
  // all bits inverted
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 0 - 15
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 16 - 31
  255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 32 - 47
// dcba:gfe
// DDDDBBBB
// 00001100 pin (10er)
// 76541098 pin (1er)
  B00000100, // 0
  B10010111, // 1
  B01000010, // 2
  B00000011, // 3
  B10010001, // 4
  B00100001, // 5
  B00100000, // 6
  B10000111, // 7
  B00000000, // 8
  B00000001, // 9
  0, 0, 0, 0, 0, 0, 0,  // 58 - 64
  0,  // A
  0,  // B
  0,  // C
  0,  // D
  0,  // E
  B11101000,  // F
  0,  // G
  0,  // H
  0,  // I
  0,  // J
  0,  // K
  0,  // L
  0,  // M
  0,  // N
  0,  // O
  B11001000,  // P
  0,  // Q
  0,  // R
  B00101001,  // S
  0,  // T
  0,  // U
  0,  // V
  0,  // W
  0,  // X
  0,  // Y
  0   // Z
};

ISR(TIMER2_OVF_vect) {
  static byte pos = 1;
  PORTC = 1 << pos; // anodes pos = 1..4
  char num = VRAM[pos];
  byte a = digits[num];
  PORTB = a;
  PORTD = a | mask;
  if (pos++ > 4) pos = 1;
}



contact: nji(at)gmx.de