DIY Darkroom: paper preflasher and contact print light

Version beta. Prototype is still under improvement process!

Paper preflasher and contact print light source - based on power LED RGB.
  • Red - safe-light 
  • Green - low contrast for multigrade
  • Blue - high contrast for multigrade and non-mg papers




Preflash test failed - 1s green exposure produced 40-50x more light than needed to go below "0" exposure. Needed stronger filter on LED and support of 0.1s increments in software.

Red light safety test passed - no visible fog after 3min from 30cm (without tracing paper as diffuser).

Test contact print on Fomaspeed Variant
  1. low contrast
  2. mixed
  3. high contrast
Light was 1m from table with 3 layers of tracing paper on LED.


Parts list:
  • RGB power LED 1W
  • 3x ILR540 (or IRF540, or anything similar working for 5V gate high level)
  • Resistor 100Ohm
  • Buzzer 5V
  • Arduino Nano
  • LCD 16x2 with I2C interface
  • 4 buttons (NO)
  • 5V power supply (>1A)

Resistor limits LED current to lower level than nominal for this LED type, so even if it's not the best way to supply current for LED it works (no heat, so light output is stable enough). 
Wiring diagram:


Arduino code:

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

int16_t last, lastG, lastGx, lastB, lastBx;
int16_t pGtime, pBtime; //time*10
int16_t menu, in, mc, redon;
unsigned long keytime;
int8_t keylong, keyreleased;
int16_t vt_sec, vt_frac;

int key=-1;
int oldkey=-1;

const int redPin = 2;   //Arduino Pins D2-D9
const int greenPin = 3;
const int bluePin = 4;
const int beepPin = 5;
const int upPin = 6;
const int downPin = 7;
const int enterPin = 8;
const int escPin = 9;

const int kEsc = 1; //key codes
const int kUp = 2;
const int kDown = 3;
const int kEnter = 4;

LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

void beep() {
  digitalWrite(beepPin,LOW);
  delay(200);
  digitalWrite(beepPin,HIGH);
}

void setColourRgb(unsigned int red, unsigned int green, unsigned int blue) {
  //set pins for LED - HIGH = led on, LOW = led off - if transistor is used
  digitalWrite(redPin, red);
  digitalWrite(greenPin, green);
  digitalWrite(bluePin, blue);
 }

void LEDOff() {
  setColourRgb(LOW,LOW,LOW);
}

void LEDRed() {
  if (redon==1) setColourRgb(HIGH,LOW,LOW);
  else LEDOff();
}

void LEDBlue() {
 setColourRgb(LOW,LOW,HIGH);
}

void LEDGreen() {
  setColourRgb(LOW,HIGH,LOW);
}

int get_key() {
    int k,i;
    k=-1;
    //check if any key pressed - pin set to LOW
    if (digitalRead(upPin)==LOW) k=kUp;
    if (digitalRead(downPin)==LOW) k=kDown;
    if (digitalRead(enterPin)==LOW) k=kEnter;
    if (digitalRead(escPin)==LOW) k=kEsc;
    if (k>=0) {
          keyreleased=0;
          return k;
        }
    else {
          keyreleased=1; keylong=0;
          oldkey = k;
       }
    return k;
}

void drawMenu( unsigned int m) {
  lcd.clear();
  lcd.setCursor(0,0);
  if (m==1) lcd.print("[Preflash]");
  else
  if (m==2) lcd.print("[Contact print]");
  else
  if (m==3) lcd.print("[Red light]");
}

void drawPre( unsigned int pt , int prun) {
  int16_t vtl_sec, vtl_frac;
  vtl_sec=(int) pt/10;
  vtl_frac=pt-(vtl_sec*10);
  lcd.clear();
  lcd.setCursor(0,0);
  if (prun==0) lcd.print("Preflash time");
    else lcd.print("*Preflash*");
  lcd.setCursor(0,1);
  if (prun==0) { 
      lcd.print("<"); lcd.print(vtl_sec); 
      if (vtl_frac>0 || (vtl_sec<10 && vtl_sec>0) ) {lcd.print("."); lcd.print(vtl_frac);}
      lcd.print("s"); lcd.print(">"); 
      }
  else { 
      lcd.print(vtl_sec); 
      if (vtl_frac>0 || (vtl_sec<10 && vtl_sec>0) ) {lcd.print("."); lcd.print(vtl_frac);} 
      lcd.print("s"); 
      }
}

void drawCon( unsigned int pGt, unsigned int pBt, int prun, int pmc) {
  int16_t vtl_sec, vtl_frac;
  vtl_sec=(int) pGt/10;
  vtl_frac=pGt-(vtl_sec*10);
  lcd.clear();
  lcd.setCursor(0,0);
  if (prun==0) lcd.print("Contact print");
    else lcd.print("*Contact print*");
  lcd.setCursor(0,1);
  if (pmc==1) { 
      lcd.print("<"); lcd.print(vtl_sec);
      if (vtl_frac>0 || (vtl_sec<10 && vtl_sec>0) ) {lcd.print("."); lcd.print(vtl_frac);}
      lcd.print("s"); lcd.print(">"); 
      }
  else { 
      lcd.print(vtl_sec);
      if (vtl_frac>0 || (vtl_sec<10 && vtl_sec>0) ) {lcd.print("."); lcd.print(vtl_frac);}
      lcd.print("s"); 
    }
  vtl_sec=(int) pBt/10;
  vtl_frac=pBt-(vtl_sec*10);
  lcd.setCursor(7,1);
  if (pmc==2) { 
      lcd.print("<");  lcd.print(vtl_sec);
      if (vtl_frac>0 || (vtl_sec<10 && vtl_sec>0) ) {lcd.print("."); lcd.print(vtl_frac);}
      lcd.print("s"); lcd.print(">"); 
      }
  else { 
      lcd.print(vtl_sec);
      if (vtl_frac>0 || (vtl_sec<10 && vtl_sec>0) ) {lcd.print("."); lcd.print(vtl_frac);}
      lcd.print("s"); 
      }
}

void setup() {
  Serial.begin(9600); //debug
  //buzzer pin
  pinMode(beepPin,OUTPUT); digitalWrite(beepPin,HIGH);
  //led pins
  pinMode(redPin, OUTPUT); pinMode(greenPin, OUTPUT); pinMode(bluePin, OUTPUT);
  LEDOff();
  //key pins with internal pullup
  pinMode(upPin, INPUT_PULLUP); pinMode(downPin, INPUT_PULLUP);
  pinMode(enterPin, INPUT_PULLUP); pinMode(escPin, INPUT_PULLUP);
  //I2C for LCD
  Wire.begin();
  lcd.begin(16,2);
  last = -1; lastG = -1; lastB = -1;
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("DarkRoomFlasher");
  delay(1000);
  lcd.clear();
  menu=1;
  drawMenu(menu);
  pGtime=50; pBtime=50; //TODO EEPROM
  redon=1;
  LEDRed();
}

void rPreflash () {
  lastG=pGtime; lastGx=0;
  in=1; oldkey=-1;
  lcd.clear();
  while ( keyreleased==0 ) { key = get_key(); delay(50); } //wait for key release
  drawPre(pGtime,0);
  while (in) {
    if (pGtime != lastG) { //LCD update only if needed
      if (pGtime>1200) pGtime=1200; //max value 120s
      if (pGtime<1) pGtime=1; //min value 0.1s
      lastG=pGtime;
      drawPre(pGtime,0);      
    }
    key = get_key();  // convert into key press
    if ( keyreleased==1 ) { keytime=millis(); keylong=0; }
    else
      if ( (keytime+1500)<millis() && (oldkey == key) && (key==kUp || key==kDown) ) { keylong=1; }
    if ( (key != oldkey && key>=0 ) || keylong==1 ) {
      if ( keylong==0 ) {oldkey = key; keyreleased=0;}
      else delay(50);
      switch (key) {
        case kUp: if (pGtime<100) pGtime++; else pGtime=pGtime+10; break;
        case kDown: if (pGtime>=110) pGtime=pGtime-10; else pGtime--; break;
        case kEnter: 
          LEDOff();
          beep();
          //zGtime=pGtime;
          vt_sec=(int) pGtime/10;
          vt_frac=pGtime-(vt_sec*10);
          drawPre(pGtime,1);
          LEDGreen();
          while (vt_frac>0) { vt_frac--; delay(100); }
          while (vt_sec>0) {
            drawPre(vt_sec*10,1); vt_sec--;
            key = get_key(); if (key==kEsc) vt_sec=0;
            delay(950); //1s-time for LCD refresh code
          }
          LEDRed();
          while ( keyreleased==0 ) { key = get_key(); delay(50); } //wait for key release
          drawPre(pGtime,0);
          break;
        case kEsc:
          in=0;
          break;
      }
    }
    delay(100);
  }
  drawMenu(menu);
}

void rContact () {
  lastG=pGtime; lastGx=0;
  lastB=pBtime; lastBx=0;
  in=1; mc=1;
  lcd.clear();
  while ( keyreleased==0 ) { key = get_key(); delay(50); } //wait for key release
  drawCon(pGtime,pBtime,0,mc);
  while (in) {
    if (pGtime != lastG || pBtime != lastB) {
      if (pGtime>1200) pGtime=1200; //max 120s
      if (pGtime<0) pGtime=0;       //min 0
      if (pBtime>1200) pBtime=1200;
      if (pBtime<0) pBtime=0;
      lastG=pGtime; lastB=pBtime;
      drawCon(pGtime,pBtime,0,mc);
      }
    key = get_key();  // convert into key press
    if ( keyreleased==1 ) { keytime=millis(); keylong=0; }
    else
      if ( (keytime+1500)<millis() && (oldkey == key) && (key==kUp || key==kDown) ) { keylong=1; }
    if ( (key != oldkey && key>=0 ) || keylong==1 ) {
      if ( keylong==0 ) {oldkey = key; keyreleased=0;}
      else delay(50);
      switch (key) {
        case kUp: 
          if (mc==1) if (pGtime<100) pGtime++; else pGtime=pGtime+10;
          if (mc==2) if (pBtime<100) pBtime++; else pBtime=pBtime+10;
          break;
        case kDown: 
          if (mc==1) if (pGtime>=110) pGtime=pGtime-10; else pGtime--;
          if (mc==2) if (pBtime>=110) pBtime=pBtime-10; else pBtime--;
          break;
        case kEnter: 
          if (mc==2) {
            LEDOff();
            beep(); 
            if ( pGtime>0 )
            {
              vt_sec=(int) pGtime/10;
              vt_frac=pGtime-(vt_sec*10);
              drawCon(pGtime,pBtime,1,0);
              LEDGreen();
              while (vt_frac>0) { vt_frac--; delay(100); }
              while (vt_sec>0) {
                drawCon(vt_sec*10,pBtime,1,0);
                vt_sec--;
                key = get_key(); if (key==kEsc) { vt_sec=0; }
                delay(950);
              }
            }
            if ( (key!=kEsc) && (pBtime>0) )
            {
              vt_sec=(int) pBtime/10;
              vt_frac=pBtime-(vt_sec*10);
              drawCon(0,pBtime,1,0);
              LEDBlue();
              while (vt_frac>0) { vt_frac--; delay(100); }
              while (vt_sec>0) {
                drawCon(0,vt_sec*10,1,0);
                vt_sec--;
                key = get_key(); if (key==kEsc) vt_sec=0;
                delay(950);
              }
            }
            LEDRed();
            while ( keyreleased==0 ) { key = get_key(); delay(50); } //wait for key release
            mc=1;
            drawCon(pGtime,pBtime,0,mc);
          }
          else { mc=2; drawCon(pGtime,pBtime,0,mc); };
          break;
        case kEsc:
          if (mc==2) { mc=1; drawCon(pGtime,pBtime,0,mc); }
          else in=0;
          break;
      }
    }
    delay(100);
  }
  drawMenu(menu);
}

void loop() {
  if (menu != last) {
    //Serial.println("Draw menu");
    last=menu;
    drawMenu(menu);
  }
  key = get_key();  // convert into key press
  if (key != oldkey && key>0 ) {
    oldkey = key;
    switch (key) {
      case kUp: if (menu>1) menu--; break;
      case kDown: if (menu<3) menu++; break;
      case kEnter: 
        //Serial.println("Enter");
        if (menu==1) rPreflash();
        else
        if (menu==2) rContact();
        else
        if (menu==3) { redon=!redon; LEDRed(); }
        break;
    }
  }
  delay(100);
}

Comments

Popular Posts