ATmega328 Camera Controller

 

The Arduino Sketch


Programming the ATmega328

Interim - 18 Jan 2013
Updated - 23 Jan 2013

This sketch was developed while the project was still on the breadboard. It's likely that it will be modified later in the light of experience as the controller is used "for real".

Download Arduino Sketch

/**********************************************************
 *   Camera  / Slave Flash Controller (c) vwlowen.co.uk   *
 **********************************************************/
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  * modified fonts in Adafruit_GFX library: glcdfont.c                              *
  * static unsigned char  font[] PROGMEM = {                                        *
  *     0x00, 0x00, 0x00, 0x00, 0x00,                                               *
  *	0x3C, 0x22, 0x2A, 0x22, 0x3C, 	 // Camera                                  *
  *	0x00, 0x0F, 0x78, 0x0E, 0x00, 	 // Spanner                                 *
  *	0xFC, 0x86, 0x86, 0xFC, 0x00,    // Battery                                 *
  *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

//https://github.com/adafruit/Adafruit-GFX-Library
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>

//http://www.rocketscream.com/blog/2011/07/04/lightweight-low-power-arduino-library/
#include "LowPower.h"

#include <EEPROM.h>

// Defines for setting and clearing register bits for analog pre-scaler
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

// Assign the Nokia 5110 BoB pins to the Arduino pins. ***Many different versions***

#define RST A3     // Most analog pins are used for OUTPUT
#define CE A2
#define DC A1
#define DIN A0

#define CLK  13
#define Vcc  12
#define LED  11

//Assign Arduino pins to the 7-function nav switch.

#define DOWN 7      // S2
#define UP 9        // S4
#define LEFT 10     // S5
#define RIGHT 8     // S3
#define OK 4        // S1

#define INT0 2      // A  interrupt from thumbwheel rotary encoder
#define INT1 3      // B  input from rotary encoder

#define FOCUS 5     // output to focus opto-isolator
#define SHUTTER 6   // output to shutter opto-isolator
#define FLASH A4    // output to flash opto-isolator

#define DIODE A5    // analog input from photodiode

int LEDON = 0;    // ON -  My display has an 'active low' backlight
int LEDOFF = 255; // OFF
int LEDHALF = 200;// HALF


// use Adafruit LCD controller and graphics libraries
Adafruit_PCD8544 lcd = Adafruit_PCD8544(CLK, DIN, DC, CE, RST);

// Arrays for menus and sub menus
char* camMainItemsNames[3] = {"Sensor", "Timer", "Bulb"};
int camTimerDelayValues[16] = {1,2,4,8,15,30,1,2,4,8,15,30,1,2,4,8};

char* flashMainItemsNames[3] = {"Slave", "Hi-Sp", "*"};
char* flashSlaveModes[6] = {"0", "1", "2", "3", "4", "Auto"};
char* flashHiSpeedUnits[2] = {"u", "m"};


char* setupMainItemsNames[3] = {"Cont", "BkLt", "BkTim"};
int setupBkLtOpt[4] = {48, 171, 49, 65};

char* exitStr ="(OK) to Exit";

//EEPROM locations for saving configuration

byte saved_camSelectedTimerRepeat = 0;
byte saved_camSelectedTimerDelay = 1;
byte saved_camShutterHold = 2;
byte saved_camSelectedBulbDelay = 3;
byte saved_flashSelectedSlaveMode = 4;
byte saved_flashHiSpeedDelay = 5;  // TWO bytes
byte saved_flashSelectedHiSpeedUnit = 7;
byte saved_setupContrast = 8;
byte saved_setupSelectedBkLt = 9;
byte saved_Delta =  10; // Two bytes
byte saved_BkTimer = 12;
byte saved_FlashFromCam = 13; 
byte saved_camFocusGap = 14; // two bytes
byte saved_activeMenu = 16;
byte saved_testMode = 17;

boolean eepromSaved1 = false;   // flags for each value to be saved to
boolean eepromSaved2 = false;   // avoid writing every item to EEPROM
boolean eepromSaved3 = false;   // every time. Only when a value is
boolean eepromSaved4 = false;   // changed will that value be written
boolean eepromSaved5 = false;   // to EEPROM
boolean eepromSaved6 = false;
boolean eepromSaved7 = false;
boolean eepromSaved8 = false;
boolean eepromSaved9 = false;
boolean eepromSaved10 = false;
boolean eepromSaved11 = false;
boolean eepromSaved12 = false;
boolean eepromSaved13 = false;
boolean eepromSaved14 = false;
boolean eepromSaved15 = false;

unsigned long eepromTimer = 0;   // only check for saving every 5 seconds.
                                 // This allows quick clicks of buttons without
                                 // writing to EEPROM for every click.

// end of EEPOM locations and saved flags.

// Camera Tab 'Values Column' values

int camSelectedMainItem = 0;
int camSelectedTimerDelay;
int camSelectedTimerRepeat;
char* camSelectedTimerUnit = "s";
int camFocusGap;
int camShutterHold;
int camActualShutterHold;


unsigned long camActualTimerDelay; 
unsigned long camActualBulbDelay; 
int camSelectedBulbDelay;
char* camSelectedBulbUnit = "s";


// Flash Tab 'Values Column' values

int flashSelectedMainItem = 0;
int flashSelectedSlaveMode;
int flashSelectedHiSpeedUnit;
unsigned long flashHiSpeedDelay;
unsigned long flashActualHiSpeedDelay;
int flashFromCam;

// Setup tab 'Values Column' values

int setupSelectedMainItem = 0;
int setupContrast;
int setupSelectedBkLtOpt;
int testMode = 0;
int setupTabLED = 0;                  // Backlight brightness. 0 = full on.
int BkTimer = 5;                      // backlight timer in seconds
unsigned long ledTimer;               // and in milliseconds

int activeMenu = 0;                   // 0 = cam, 1 = flash, 2 = setup
int activeColumn = 1;                 // 0 = tabs column, 1 = menu items column, 2 = values column

int delta  = 50;                      // Required difference between ambient and actual (photodiode etc)
int ambient;  

int buttonTim = 0;                    // Counters to time length of time buttons are held down.
int buttonTim1 = 0;                   // This allows 'value column' items with a large range of values
int buttonTim2 = 0;                   // to increase their increment/decrement rate as time increases.
int buttonTim3 = 0;
int buttonTim4 = 0;
int buttonTim5 = 0;

boolean adjustAllowed = true;         // prevent interrupt adjusting delta when delta isn't displayed
int count = 0;
unsigned long time, lasttime, firsttime;  // timers for Auto Slave flash
unsigned long flashWatchdog;
boolean oneFlashOnly = false;
boolean doSensorIsActive = false;
int watchdogTimeout = 1000;
int ledCounter = 0;                   // Timer & Bulb: Flash tell-tale led every 10 seconds if in Test Mode


void setup()   {
  // Read last values from EEPROM and check for sensible values rather than assuming EEPROM
  // is brand new and contains 255 in its unused EEPROM locations.

  activeMenu = EEPROM.read(saved_activeMenu);
  if ((activeMenu > 2) || (activeMenu < 0)) activeMenu = 0;

  camFocusGap = constrain(EEPROMReadInt(saved_camFocusGap), 0, 990);  
  camShutterHold = constrain(EEPROM.read(saved_camShutterHold), 0, 3);
  camSelectedTimerDelay = constrain(EEPROM.read(saved_camSelectedTimerDelay), 0, 15);
  camSelectedBulbDelay = constrain(EEPROM.read(saved_camSelectedBulbDelay), 0, 15);
  
  flashSelectedSlaveMode = constrain(EEPROM.read(saved_flashSelectedSlaveMode), 0, 5);
  flashHiSpeedDelay = constrain(EEPROMReadInt(saved_flashHiSpeedDelay), 0, 999);
  flashSelectedHiSpeedUnit = constrain(EEPROM.read(saved_flashSelectedHiSpeedUnit), 0, 1);
  flashFromCam = constrain(EEPROM.read(saved_FlashFromCam), 0, 4);
  
  setupContrast = constrain(EEPROM.read(saved_setupContrast), 20, 80);
  setupSelectedBkLtOpt = constrain(EEPROM.read(saved_setupSelectedBkLt), 0, 3);
  BkTimer = constrain(EEPROM.read(saved_BkTimer), 5, 20);
  testMode = constrain(EEPROM.read(saved_testMode), 0, 1);

  lcd.setContrast(setupContrast);
  switch (setupSelectedBkLtOpt) {
      case 0: setupTabLED = 255; break;
      case 1: setupTabLED = 200; break;
      case 2: setupTabLED = 0; break;
      case 3: setupTabLED = map(ambient, 0, 400, 100, 255); break;
      default: setupTabLED = 0;
  }
  analogWrite(LED, setupTabLED);  
 
  delta = EEPROMReadInt(saved_Delta);
 
  // Define pinModes and enable internal pullup resistors on INPUTS.
  
  pinMode(2, INPUT);
  pinMode(3, INPUT);
  pinMode(4, INPUT);
  pinMode(7, INPUT);
  pinMode(8, INPUT);
  pinMode(9, INPUT);
  pinMode(10, INPUT);        
    
  digitalWrite(2, HIGH);   // Enable internal pullups
  digitalWrite(3, HIGH);    
  digitalWrite(4, HIGH);
  digitalWrite(7, HIGH);
  digitalWrite(8, HIGH);
  digitalWrite(9, HIGH);
  digitalWrite(10, HIGH);
   
   
  for (int i = 11; i < 14; i++)  // define OUTPUTS 11 to 13
    pinMode(i, OUTPUT);
    
  pinMode(FOCUS, OUTPUT);        // OUTPUT 5 
  pinMode(SHUTTER, OUTPUT);      // OUTPUT 6
  
  digitalWrite(FOCUS, LOW);
  digitalWrite(SHUTTER, LOW);
    
  // Analog pins can be referenced as digital pins 14 to 19 but I've 
  // left them with their analog designations for clarity.  
  
  pinMode(DIN, OUTPUT);        // A0  |
  pinMode(DC, OUTPUT);         // A1  |
  pinMode(CE, OUTPUT);         // A2  |__outputs to Nokia LCD display
  pinMode(RST, OUTPUT);        // A3  |
  pinMode(FLASH, OUTPUT);      // A4 to opto isolator for flash
  pinMode(DIODE, INPUT);       // A5 input from photodiode
  
  digitalWrite(Vcc, HIGH);              // Vcc to LCD display . Power up display.
  
  
  analogReference(INTERNAL);   // set analog reference to 1.1v to increase sensitivity
  
  // Set analog prescale to 16 for much faster analog read.
  sbi(ADCSRA,ADPS2);
  cbi(ADCSRA,ADPS1);
  cbi(ADCSRA,ADPS0);  
  
  ambient = analogRead(DIODE);
  
  
  if (digitalRead(OK) == LOW) {        // OK button is held during startup - reset to defaults
    activeMenu = 2;                    // setup menu
    activeColumn = 2;                  // display will start up with Contrast Value highlighted
    camFocusGap = 100;                 // (100ms)
    camShutterHold = 1;
    camSelectedTimerDelay = 4;         // 15s
    camSelectedTimerRepeat = 0;        // (r)epeat
    camSelectedBulbDelay = 4;          // 15s
    
    flashSelectedSlaveMode = 5;        // Auto
    flashHiSpeedDelay = 100;           // 100
    flashSelectedHiSpeedUnit = 1;      // milliseconds
    flashFromCam = 0;                  // No linkage between Cam & Flash
    
    setupContrast = 55;                // LCD contrast 55
    setupSelectedBkLtOpt = 2;          // LED backlight 'Full'
    BkTimer = 10;                      // 10 s
    delta = 50;                        // delta 50
    testMode = 1;                      // enable tell-tale LED flashes on LCD
    
    saveEeprom();                      // save to EEPROM
  } 
 
  switch (setupSelectedBkLtOpt) {
    case 0: setupTabLED = 255; break;
    case 1: setupTabLED = 200; break;
    case 2: setupTabLED = 0; break;
    case 3: setupTabLED = map(ambient, 0, 400, 100, 255); break;
    default: setupTabLED = 0;
  } 

  lcd.begin(setupContrast);            // set LCD contrast
  lcd.clearDisplay();                
  lcd.display();  
  analogWrite(LED, setupTabLED);       // Set PWM value to LED backlight
  
  attachInterrupt(0, rotaryEncoder, FALLING);   // Attach thumbwheel rotary encoder interrupt
}

void saveEeprom() {
   if (!eepromSaved1) {EEPROM.write(saved_activeMenu, activeMenu); eepromSaved1 = true;}
   if (!eepromSaved2) {EEPROMWriteInt(saved_Delta, delta); eepromSaved2 == true;}  
   if (!eepromSaved3) {EEPROM.write(saved_camShutterHold, camShutterHold); eepromSaved3 == true;}
   if (!eepromSaved4) {EEPROMWriteInt(saved_camFocusGap, camFocusGap); eepromSaved4 = true;}
   if (!eepromSaved5) {EEPROM.write(saved_camSelectedTimerRepeat, camSelectedTimerRepeat); eepromSaved5 = true;}
   if (!eepromSaved6) {EEPROM.write(saved_camSelectedTimerDelay, camSelectedTimerDelay); eepromSaved6 = true;}  
   if (!eepromSaved7) {EEPROM.write(saved_camSelectedBulbDelay, camSelectedBulbDelay);  eepromSaved7 = true;}   
   if (!eepromSaved8) {EEPROM.write(saved_flashSelectedSlaveMode, flashSelectedSlaveMode); eepromSaved8 = true;}  
   if (!eepromSaved9) {EEPROMWriteInt(saved_flashHiSpeedDelay, flashHiSpeedDelay); eepromSaved9 = true;}
   if (!eepromSaved10) {EEPROM.write(saved_flashSelectedHiSpeedUnit, flashSelectedHiSpeedUnit); eepromSaved10 = true;}
   if (!eepromSaved11) {EEPROM.write(saved_FlashFromCam, flashFromCam); eepromSaved11 = true;}
   if (!eepromSaved12) {EEPROM.write(saved_setupContrast, setupContrast);  eepromSaved12 = true;}  
   if (!eepromSaved13) {EEPROM.write(saved_testMode, testMode); eepromSaved13 = true;}
   if (!eepromSaved14) {EEPROM.write(saved_setupSelectedBkLt, setupSelectedBkLtOpt); eepromSaved14 = true;}
   if (!eepromSaved15) {EEPROM.write(saved_BkTimer, BkTimer);  eepromSaved15 = true;}   
   
   eepromTimer = millis();   // start eeprom-saved timer so it won't save again for at least 5 seconds
}

void showHeader(char* name, int wait) {        // Opening screen for most options
  lcd.clearDisplay();                          // except Timer & Bulb.
  lcd.print(name);
  lcd.print("...");
  lcd.setCursor(2, 38);
  if (testMode == 1) lcd.write(2);
  lcd.setCursor(4, 24);
  lcd.print(exitStr);
  lcd.drawLine(0, 36, 84, 36, BLACK);
  lcd.setCursor(2, 38);
  if (testMode) lcd.write(2);  
  lcd.display();
  delay(wait);
}

void openMessage() {                           // Opening screen used by Timer & Bulb
  lcd.setCursor(4, 12);
  lcd.print("(OK) to Start");
  lcd.setCursor(12, 28);
  lcd.print("Hold (OK)");
  lcd.setCursor(15, 38);
  lcd.print("to Exit");
  lcd.display();
}

void restoreDisplay() {                        // Timer & Bulb shut down the display - this routine
  digitalWrite(Vcc, HIGH);                     // brings it back to life and sets up the backlight.
  lcd.begin(setupContrast);
  digitalWrite(LED, setupTabLED);
  ledTimer = millis();  
}

/********************************************************************************
 *         Main Menu Items - 'Action' routines                                  *
 ********************************************************************************/

/* Routine waits for rising or falling trigger and fires shutter. */

void doSensor() {
 doSensorIsActive = true;

 delay(40);
 while(digitalRead(OK) == LOW);
 adjustAllowed = false; 
 showHeader("Sensor", 2000);
 int ambient = analogRead(DIODE);
 int oldDelta = delta;
 unsigned long refresh = millis();
 
    if (delta > 0) {                                              // delta is positive - Rising edge
      while(1) {
         restart:
         refresh = millis(); 
         ambient = analogRead(DIODE);                             // Refresh ambient baseline
          while (analogRead(DIODE) < (ambient + abs(delta)))  {   // wait for rising edge
             if (millis() - ledTimer > (BkTimer * 1000)) digitalWrite(LED, LEDOFF);
             if (millis() - refresh > 2000) goto restart;         // refresh ambient baseline after 2s
             if (bitRead(PIND, 4) == 0) {                        // Allow escape - read OK button
               delay(40);
               ledTimer = millis();
               doSensorIsActive = false;
               adjustAllowed = true;  
               while (digitalRead(OK) == LOW);
               return;
             } 
          }
          fireShutter();
          while (analogRead(DIODE) > (ambient + abs(delta))){     // wait for possible long trigger to finish but
             if (millis() - refresh > 2000) break;                // wait 2s then quit waiting anyway
          }                                                       // and refresh ambient baseline
        }  
    } 
     
     if (delta < 0) {                                             // delta is negative - falling edge.
      while (1) {
         restart1:
         refresh = millis(); 
         ambient = analogRead(DIODE);
         while (analogRead(DIODE) > (ambient - abs(delta)))  {
             if (millis() - ledTimer > (BkTimer * 1000)) digitalWrite(LED, LEDOFF);
             if (millis() - refresh > 2000) goto restart1;        // refresh ambient baseline after 2s
             if (bitRead(PIND, 4) == 0) {                         // Allow escape - read OK button
               delay(40);     
               ledTimer = millis();
               doSensorIsActive = false;
               adjustAllowed = true;
               while (digitalRead(OK) == LOW);
               return;
             }
         } 
         fireShutter();
         while (analogRead(DIODE) <= (ambient - abs(delta))) {    // wait for possible long trigger to finish but
           if (millis() - refresh > 2000) break;                  // wait 2s then quit waiting anyway
         }                                                        // and refresh ambient baseline
       }
     }  
     adjustAllowed = true;   
     doSensorIsActive = false;
}

/* Timer routine fires shutter after pre-set delay - repeat indefinitely (if set to do so) */

void doTimer() {
  delay(70);
  adjustAllowed = false;
  ledTimer = millis();
  while(digitalRead(OK) == LOW);

  analogWrite(LED, setupTabLED);
  boolean repeat = true;
  
  lcd.clearDisplay();
  lcd.print("Timer ");
  
  lcd.print(camTimerDelayValues[camSelectedTimerDelay]);  
  lcd.print(camSelectedTimerUnit);
  if (camSelectedTimerRepeat == 0) lcd.print(" (r)");
  openMessage();
  
  while(digitalRead(OK) == HIGH) {
    if (millis() - ledTimer > (BkTimer * 1000)) digitalWrite(LED, LEDOFF);
  }
  digitalWrite(LED, LEDOFF);                                       // Turn off backlight
  unsigned long timerCount = 0;
  int loopCount = 0;
  delay(80);
  while(digitalRead(OK) == LOW);

  digitalWrite(Vcc, LOW);    // Shut down LCD display

  while(repeat) {                                               // repeat if set to do so
   ledCounter = 0;
   while(timerCount < camActualTimerDelay) { 
     if (bitRead(PIND, 4) == 0) {                               // provide escape route
       delay(20);
       restoreDisplay();
       adjustAllowed = true;
       while(digitalRead(OK) == LOW);
       return;
     }
     LowPower.powerDown(SLEEP_1S, ADC_OFF, BOD_OFF);           // put  ATmega328 to sleep. Wake at 
     timerCount++;                                             // 1s intervals to increment counter.
     if (testMode && (timerCount % 20 == 0)) timerCount++;     // every 20 sec  skip 1 sec to counteract
     if (testMode) ledCounter++;                               // telltale delay 
     if (ledCounter > 9) {                                     // every 10 seconds flash telltale
       ledCounter = 0;
       digitalWrite(Vcc, HIGH);
       digitalWrite(LED, LEDON);  
       delay(50);
       digitalWrite(Vcc, LOW);
       digitalWrite(LED, LEDOFF);
     }
   }
   fireShutter();
   timerCount = 0;
   loopCount++;
   (camSelectedTimerRepeat == 0 ? repeat = true : repeat = loopCount < camSelectedTimerRepeat);
  }
  restoreDisplay();                                            // bring LCD back to life.
  adjustAllowed = true;                                        // Allow delta to be adjusted
}

void doBulb() {
  adjustAllowed = false;
  delay(80);
  while(digitalRead(OK) == LOW);
  analogWrite(LED, setupTabLED);
  
  lcd.clearDisplay();
  lcd.print("Bulb... ");
  lcd.print(camTimerDelayValues[camSelectedBulbDelay]);  
  lcd.print(camSelectedBulbUnit);

  openMessage();
  ledTimer = millis();
  while(digitalRead(OK) == HIGH) {
    if (millis() - ledTimer > (BkTimer * 1000)) digitalWrite(LED, LEDOFF);
  }
  digitalWrite(LED, LEDOFF);  
  
  delay(80);
  while(digitalRead(OK) == LOW);
  digitalWrite(Vcc, LOW);  
  
  digitalWrite(FOCUS, HIGH);
  delay(camFocusGap);
  digitalWrite(SHUTTER, HIGH);
  unsigned long timerCount = 0;
  ledCounter = 0;
  while (timerCount  < camActualBulbDelay) {
     if (bitRead(PIND, 4) == 0) {
       digitalWrite(SHUTTER, LOW);
       delay(50);
       digitalWrite(FOCUS, LOW);
       restoreDisplay();
       adjustAllowed = true;
       while(digitalRead(OK) == LOW);
       return;
    }
     LowPower.powerDown(SLEEP_1S, ADC_OFF, BOD_OFF);           // ATmega328 to Power Down mode
     timerCount++;                                             // wake at 1s intervals until time is elapsed
     if (testMode && (timerCount % 20 == 0)) timerCount++;     // every 20s  skip 1s to counteract telltale delay  
     if (testMode) ledCounter++;
     if (ledCounter > 9) {
       ledCounter = 0;
       digitalWrite(Vcc, HIGH);
       digitalWrite(LED, LEDON);  
       delay(50);
       digitalWrite(Vcc, LOW);
       digitalWrite(LED, LEDOFF);
     }
  }
  digitalWrite(SHUTTER, LOW);
  delay(50);
  digitalWrite(FOCUS, LOW);
  restoreDisplay();
  adjustAllowed = true;
}

/* Slave flash routine. Always looks for rising edge(s) from pre-flash from camera. */

void doSlave() {
  doSensorIsActive = true;
  adjustAllowed = false;
  boolean repeat = true;
  unsigned long refresh;
  delay(400);
  while(digitalRead(OK) == LOW);

  showHeader("Slave",  2000);
  digitalWrite(LED, LEDOFF);
  ambient = analogRead(DIODE);
  count = 0;
  
  if (flashSelectedSlaveMode < 5) {               // Not Auto - 'manually' count the pre-flashes
    while (1) {
      ambient = analogRead(DIODE);
      while (analogRead(DIODE) - ambient < abs(delta)) {

        // Cam flash -to- slave flash with watchdog timer.
        if (oneFlashOnly && (millis() - flashWatchdog > watchdogTimeout)) {
         if (flashFromCam == 3) {
           delay(1000);
           lcd.setCursor(0, 15);
           lcd.print("ERROR (* w *)");
           lcd.display();
           digitalWrite(SHUTTER, LOW);
           delay(50);
           digitalWrite(FOCUS, LOW);            
           while(digitalRead(OK) == HIGH);
         }
          ledTimer = millis();
          doSensorIsActive = false;
          adjustAllowed = true;
          while (digitalRead(OK) == LOW);
          return;
        }                
        if (bitRead(PIND, 4) == 0) {           // Exit early with 'OK' button. Direct Port read 
          delay(40);                           // makes 'if' conditional check faster.
          ledTimer = millis();
          flashWatchdog = 0;
          doSensorIsActive = false;
          adjustAllowed = true;
          while(digitalRead(OK) == LOW);
          return;
        }  
      }      
      count++;
      
      if ((count == flashSelectedSlaveMode - 1) || (flashSelectedSlaveMode == 0)){
        fireFlash();
      } 
      while (analogRead(DIODE) - ambient >= abs(delta));        // make sure pulse has subsided before looping   
     }                                                          // or same pulse may be counted more than once.
   } else {               
  
  while(1) {                                                    // Auto - work out pre-flashes automatically.
     firsttime = 0;
     ambient = analogRead(DIODE);
     time = millis(); 
     while (analogRead(DIODE) - ambient < abs(delta)) {
       if (oneFlashOnly && (millis() - flashWatchdog > watchdogTimeout)) {
         if (flashFromCam == 3) {
           lcd.setCursor(0, 15);
           lcd.print("ERROR (");
           if (flashFromCam == 3) {lcd.print("* ");lcd.print("w"); lcd.print(" *");} 
           lcd.print(")");
           lcd.display();
           digitalWrite(SHUTTER, LOW);
           delay(50);
           digitalWrite(FOCUS, LOW);            
           while(digitalRead(OK) == HIGH);
         }
         ledTimer = millis();
         flashWatchdog = 0;
         adjustAllowed = true;
         doSensorIsActive = false;
         return;
      }              
        if (bitRead(PIND, 4) == 0) {       // Exit early with 'OK' button
         delay(40);
         ledTimer = millis();
         adjustAllowed = true;
         doSensorIsActive = false;
         while(digitalRead(OK) == LOW);
         return;
      }       
     }  
     count++;
     if (count == 2) firsttime = millis() - time;
  
       // If gap betwen 1st and 2nd pulse is > 250ms, assume 2nd pulse is main flash so Fire!
     if (firsttime > 250) {
         fireFlash();
         if (oneFlashOnly) {
           doSensorIsActive = false;
           return;
         }
     } else {
       if ((count > 1) && (millis() - time < 3 * firsttime))  lasttime = millis() - time;
    
      // If gap between previous pulse and current pulse is > (7 * previous gap) assume
      // current pulse is main flash and Fire!
       if (count > 1 && millis() - time > (lasttime * 7)) {
         fireFlash();
       
         if (oneFlashOnly) {
           doSensorIsActive = false;
           return;
         }
       }
     }
     while (analogRead(DIODE) - ambient >= abs(delta));  // make sure pulse has subsided before looping
    }                                                   // or same pulse may be counted more than once.
  }
  doSensorIsActive = false;
}

/* Hi-Speed routine opens shutter and waits for rising or falling trigger */

void doHiSpeed() {
  adjustAllowed = false;
  delay(40);
  while(digitalRead(OK) == LOW);
  unsigned long now; 
  switch (camShutterHold) {
    case 0: camActualShutterHold = 250; break;
    case 1: camActualShutterHold = 500; break;
    case 2: camActualShutterHold = 1000; break;
    case 3: camActualShutterHold = 2000; break;
    default: camActualShutterHold = 500;
  } 
  lcd.clearDisplay();
  lcd.print("Hi-Speed..");
  lcd.setCursor(0, 12);
  lcd.print(flashHiSpeedDelay);
  (flashSelectedHiSpeedUnit == 0 ? lcd.print(" usec") : lcd.print(" msec"));
  lcd.setCursor(9, 32);
  lcd.print(exitStr);
  lcd.display();
  digitalWrite(LED, LEDOFF);
  digitalWrite(FOCUS, HIGH);
  delay(camFocusGap);
  digitalWrite(SHUTTER, HIGH);
  int ambient = analogRead(DIODE);


  
  if (delta > 0) {                                            // wait forrising edge
      ambient = analogRead(DIODE);
      while (analogRead(DIODE) <= (ambient + abs(delta)))  {
        if (bitRead(PIND, 4) == 0) {
           digitalWrite(SHUTTER, LOW);  // Exit early. Don't leave shutter open
           delay(50);
           digitalWrite(FOCUS, LOW);
           adjustAllowed = true;
           ledTimer = millis();
           return;
        }
     } 
   } else {
     ambient = analogRead(DIODE);                             // wait for falling edge
     while (analogRead(DIODE) >= (ambient + abs(delta))) {
         if (bitRead(PIND, 4) == 0) { 
           digitalWrite(SHUTTER, LOW);  // Exit early. Don't leave shutter open
           delay(50);
           digitalWrite(FOCUS, LOW);
           adjustAllowed = true;
           ledTimer = millis();
           return;
        }
     } 
   }
   now = micros();
   while ((micros() - now)  < flashActualHiSpeedDelay);      // delay for set microseconds

   fireFlash();                                              // fire flash

   delay(camActualShutterHold);                               // wait for Shutter Hold time (just to make sure)
   digitalWrite(SHUTTER, LOW);                               // close shutter and release focus.
   delay(50);
   digitalWrite(FOCUS, LOW);
   ledTimer = millis();
   adjustAllowed = true;
}

/* fire flash - easy */

void fireFlash() {
  digitalWrite(FLASH, HIGH);
  delay(250);
  digitalWrite(FLASH, LOW);  
  count = 0;                                               // reset auto pre-flash counters and timers
  firsttime = 0;                                           
  lasttime = 0; 
   if ((testMode == 1)  && doSensorIsActive) {
     digitalWrite(LED, LEDON);
     delay(10);
     digitalWrite(LED, LEDOFF);
   }  
}

/* Fire shutter */

 
void fireShutter() {
   digitalWrite(FOCUS, HIGH);
   delay(camFocusGap);
   digitalWrite(SHUTTER, HIGH);
   

   if (flashFromCam == 1) {                            // flash to flash no watchdog
     flashWatchdog = millis();
     oneFlashOnly = true;
     doSlave();                                        // normal 'Slave' settings apply
     oneFlashOnly = false;
   }
   if (flashFromCam == 2) {                            // shutter to flash no watchdog
     unsigned long now;
     now = micros();
     while((micros() - now) < flashActualHiSpeedDelay);
     fireFlash();
   }
   
   if (flashFromCam == 3) {                            // flash to flash with watchdog
     oneFlashOnly = true;
     flashWatchdog = millis();
     doSlave(); 
     oneFlashOnly = false;
   }
   
   if (flashFromCam == 4) {  // shutter to flash with watchdog

     unsigned long now;
     now = micros();
     while((micros() - now) < flashActualHiSpeedDelay);
     while(analogRead(DIODE) - ambient > abs(delta)) ;
     fireFlash();
    
     flashWatchdog = millis();
     
     // wait for flash from slave 
     while (analogRead(DIODE) - ambient < abs(delta)) {
       if (millis() - ledTimer > (BkTimer * 1000)) analogWrite(LED, LEDOFF);
       if ((millis() - flashWatchdog > watchdogTimeout)) {
         digitalWrite(SHUTTER, LOW);
         delay(50);
         digitalWrite(FOCUS, LOW);             
         lcd.setCursor(0, 15);
         lcd.print("ERROR  (");
         lcd.write(175);
         lcd.print(" w *)");
         lcd.display();
         if (digitalRead(OK) == LOW) {
           ledTimer = millis();
           flashWatchdog = 0;
           adjustAllowed = true;
           return; 
          }            
       }
      }      // end of waiting for flash from slave
    }        // end shutter to flash with watchdog
    
    switch (camShutterHold) {
      case 0: camActualShutterHold = 250; break;
      case 1: camActualShutterHold = 500; break;
      case 2: camActualShutterHold = 1000; break;
      case 3: camActualShutterHold = 2000; break;
      default: camActualShutterHold = 500;
    }

   delay(camActualShutterHold);
   
   if (testMode  && doSensorIsActive) {
     digitalWrite(LED, LEDON);
     delay(20);
     digitalWrite(LED, LEDOFF);
      delay(50);
     digitalWrite(LED, LEDON);
     delay(20);
     digitalWrite(LED, LEDOFF);
   }     
   
   digitalWrite(SHUTTER, LOW);
   delay(50);
   digitalWrite(FOCUS, LOW); 
}  


/* main loop scans round buttons setting menus and values as requested */
   
void loop() {

  if (millis() - ledTimer > (BkTimer * 1000)) {
    analogWrite(LED, LEDOFF);
  } 
  else if (setupSelectedBkLtOpt == 3) {
      analogWrite(LED, map(analogRead(DIODE), 0, 400, 100, 255)); 
  } else analogWrite(LED, setupTabLED);
    
  // Set display column that cursor is active in
  
  if ((digitalRead(RIGHT) == LOW) ) {
    delay(40);
    if (activeColumn < 2) activeColumn++;
    while (digitalRead(RIGHT) == LOW);
    ledTimer = millis();
  }
  
  if ((digitalRead(LEFT) == LOW) ) {
    delay(40);
    if (activeColumn > 0) activeColumn--;
    while (digitalRead(LEFT) == LOW);
    ledTimer = millis();
  }
  
  // If cursor is in column 0 switch through Tabs (active menu)
  if (activeColumn == 0) {
    if (digitalRead(DOWN) == LOW) {
      delay(40);
      activeMenu++;
      if (activeMenu > 2) activeMenu = 2;
      while (digitalRead(DOWN) == LOW);
      eepromSaved1 = false;
      ledTimer = millis();
    }
  }
  if (activeColumn == 0) {
    if (digitalRead(UP) == LOW) {
      delay(40);
      activeMenu--;
      if (activeMenu < 0) activeMenu = 0;
      while (digitalRead(UP) == LOW);
      eepromSaved1 = false;
      ledTimer = millis();
    }
  }
  
  // Display appropriate Tab.  
  if (activeMenu == 0)  showTab1();  
  if (activeMenu == 1)  showTab2();
  if (activeMenu == 2)  showTab3();
  
  
  // If cursor is in middle column, scan UP/DOWN Tab1 items
  if ((activeMenu == 0) &&(activeColumn == 1)) {
    if (digitalRead(DOWN) == LOW) {
      delay(40);
      if (camSelectedMainItem < 2) camSelectedMainItem++;
      while(digitalRead(DOWN) == LOW);
      ledTimer = millis();
    }
    if (digitalRead(UP) == LOW) {
      delay(40);
      if (camSelectedMainItem > 0) camSelectedMainItem--;
      while(digitalRead(UP) == LOW);
      ledTimer = millis();
    }  
    
    // +++++++ Actions for Camera menu Items +++++++++++
    if (digitalRead(OK) == LOW) {
      delay(40);
      if (setupSelectedBkLtOpt == 3) {
         analogWrite(LED, map(analogRead(DIODE), 0, 400, 100, 255)); 
      } else analogWrite(LED, setupTabLED);  
      ledTimer = millis();
      if (camSelectedMainItem == 0) doSensor();
      if (camSelectedMainItem == 1) doTimer();
      if (camSelectedMainItem == 2) doBulb();
       while(digitalRead(OK) == LOW);
    } 
  }  
   
  
  // If cursor is in middle column, scan UP/DOWN Tab2 items
  if ((activeMenu == 1) &&(activeColumn == 1)) {
    if (digitalRead(DOWN) == LOW) {
      delay(40);
      if (flashSelectedMainItem < 2) flashSelectedMainItem++;
      while(digitalRead(DOWN) == LOW);
      ledTimer = millis();
    }
    if (digitalRead(UP) == LOW) {
      delay(40);
      if (flashSelectedMainItem > 0) flashSelectedMainItem--;
      while(digitalRead(UP) == LOW);
      ledTimer = millis();
    } 
    // +++++++ Actions for Flash menu Items +++++++++++
    if (digitalRead(OK) == LOW) {
      delay(40);
      if (flashSelectedMainItem == 0) doSlave();
      if (flashSelectedMainItem == 1) doHiSpeed();
      while(digitalRead(OK) == LOW);
    }    
  }
   
  // If cursor is in middlew column, scan UP/DOWN Tab3 items
  if ((activeMenu == 2) &&(activeColumn == 1)) {
    if (digitalRead(OK) == LOW) {
      ledTimer = millis();
    }      
    if (digitalRead(DOWN) == LOW) {
      delay(40);
      if (setupSelectedMainItem < 2) setupSelectedMainItem++;
      while(digitalRead(DOWN) == LOW);
      ledTimer = millis();
    }
    if (digitalRead(UP) == LOW) {
      delay(40);
      if (setupSelectedMainItem > 0) setupSelectedMainItem--;
      while(digitalRead(UP) == LOW);
      ledTimer = millis();
    }  
  }
  
/****************************************************************************
     Cursor in right-hand column - adjustments take place here.  
 ****************************************************************************/
  
// Camera Tab setting routines
// ===========================

// If cursor in right-most column, allow UP/DOWN to change focusing time and
// OK button to change Shutter Hold time.
  if ((activeMenu == 0) && (activeColumn == 2)&& (camSelectedMainItem == 0)) {
    if (digitalRead(OK) == LOW) {
      delay(30);
      camShutterHold++;
      if (camShutterHold > 3) camShutterHold = 0;
      eepromSaved3 = false;
      while(digitalRead(OK) == LOW);
      ledTimer = millis();
    }          
    if (digitalRead(UP) == LOW) {
       delay(50);
       camFocusGap += 10;
      if (camFocusGap > 990) camFocusGap = 0;
      showTab1();
      delay(160);
      eepromSaved4 = false;
      ledTimer = millis();
    } 
    if (digitalRead(DOWN) == LOW) {
       delay(50);
       camFocusGap -= 10;
       if (camFocusGap < 0) camFocusGap = 990;
       showTab1();
       delay(160);
       eepromSaved4 = false;
       ledTimer = millis();
    }    
  } 
  
  
  // If cursor is in right-most column  use UP/DOWN to set Timer delay 
  if ((activeMenu == 0) && (activeColumn == 2)&& (camSelectedMainItem == 1)) {
    if (digitalRead(OK) == LOW) {
      delay(40);
      camSelectedTimerRepeat++;
      if (camSelectedTimerRepeat > 5) camSelectedTimerRepeat = 0;
      while (digitalRead(OK) == LOW);
      eepromSaved5 = false;
      ledTimer = millis();
    }      
    if ((digitalRead(UP) == LOW)) {
       camSelectedTimerDelay++;
       if (camSelectedTimerDelay > 15) camSelectedTimerDelay = 0;
       showTab1();
       delay(350);
       eepromSaved6 = false;
       ledTimer = millis();
    }
    if ((digitalRead(DOWN) == LOW)) {
       camSelectedTimerDelay--;
       if (camSelectedTimerDelay < 0) camSelectedTimerDelay = 15;
       showTab1();
       delay(350);
       eepromSaved6 = false;
       ledTimer = millis();
    }    
  }  
  
  // If cursor is in right-most colum, use UP/DOWN to set Bulb delay
  if ((activeMenu == 0) && (activeColumn == 2)&& (camSelectedMainItem == 2)) {
    if (digitalRead(OK) == LOW) {
      ledTimer = millis();
    }  
    if ((digitalRead(UP) == LOW)) {
       camSelectedBulbDelay++;
       if (camSelectedBulbDelay > 15) camSelectedBulbDelay = 0;
       showTab1();
       delay(350);
       eepromSaved7 = false;
       ledTimer = millis();
    }
     if ((digitalRead(DOWN) == LOW)) {
       camSelectedBulbDelay--;
       if (camSelectedBulbDelay < 0) camSelectedBulbDelay = 15;
       showTab1();
       delay(350);
       eepromSaved7 = false;
       ledTimer = millis();
    }
  }
  
  // Flash Tab setting routines.
  //============================
  
  // Use UP/DOWN to set Slave pre-flash mode
  if ((activeMenu == 1) && (activeColumn == 2)&& (flashSelectedMainItem == 0)) {
    if (digitalRead(OK) == LOW) {
      flashSelectedSlaveMode = 5;
      ledTimer = millis();
    }              
    if ((digitalRead(UP) == LOW)) {
       delay(10);
       flashSelectedSlaveMode++;
       if (flashSelectedSlaveMode > 5) flashSelectedSlaveMode = 0;
       showTab2();
       delay(350);
       eepromSaved8 = false;
       ledTimer = millis();
    }
    if ((digitalRead(DOWN) == LOW)) {
       delay(10);
       flashSelectedSlaveMode--;
       if (flashSelectedSlaveMode < 0) flashSelectedSlaveMode = 5;
       showTab2();
       delay(350);
       eepromSaved8 = false;
       ledTimer = millis();
    }
  }  
  
  
  // Flash hi-speed - set delay
   if ((activeMenu == 1) && (activeColumn == 2)&& (flashSelectedMainItem == 1)) {
    if (digitalRead(OK) == LOW) {
      delay(40);
      (flashSelectedHiSpeedUnit == 0 ? flashSelectedHiSpeedUnit = 1 : flashSelectedHiSpeedUnit = 0);
      showTab2();
      while (digitalRead(OK) == LOW);
      eepromSaved10 = false;
      ledTimer = millis();
    }          
    if ((digitalRead(UP) == LOW)) {
       buttonTim++;
       int inc;
       delay(50);
       if (buttonTim < 10) inc = 1;
       if ((buttonTim > 10) && (buttonTim < 20)) inc = 5;
       if ((buttonTim > 20) && (buttonTim < 30)) inc = 10;
       if (buttonTim > 30) inc = 50;
       flashHiSpeedDelay += inc ;
       if (flashHiSpeedDelay > 999) flashHiSpeedDelay = 0;
       showTab2();
       delay(350);
       eepromSaved9 = false;
       ledTimer = millis();
    } else {
      buttonTim = 0;
    }
    if ((digitalRead(DOWN) == LOW)) {
       buttonTim1++;
       int inc;
       delay(50);
       if (buttonTim1 < 10) inc = 1;
       if ((buttonTim1 > 10) && (buttonTim1 < 20)) inc = 5;
       if ((buttonTim1 > 20) && (buttonTim1 < 30)) inc = 10;
       if  (buttonTim1 > 30)  inc = 50;
       flashHiSpeedDelay -= inc ;
       if ((flashHiSpeedDelay < 0) || (flashHiSpeedDelay > 999)) flashHiSpeedDelay = 999;
       showTab2();
       delay(350);
       eepromSaved9 = false;
       ledTimer = millis();
    }else {
      buttonTim1 = 0;
    }
  } 
  
 // select Flash From Cam timeout
  if ((activeMenu == 1) && (activeColumn == 2)&& (flashSelectedMainItem == 2)) {
    if ((digitalRead(OK) == LOW)) {
       flashFromCam = 0;
       eepromSaved11 = false;
       ledTimer = millis();
    }     
    if ((digitalRead(UP) == LOW)) {
       delay(10);
       flashFromCam++;
       if (flashFromCam > 4) flashFromCam = 0;
       showTab2();
       delay(350);
       eepromSaved11 = false;
       ledTimer = millis();
    } 
    if ((digitalRead(DOWN) == LOW)) {
       delay(10);
       flashFromCam--;
       if (flashFromCam < 0) flashFromCam = 4;

       showTab2();
       delay(350);
       eepromSaved11 = false;
       ledTimer = millis();
    }
  }  
  
  // SetupTab setting routines
  //==========================
  if ((activeMenu == 2) && (activeColumn == 2)&& (setupSelectedMainItem == 0)) {
    
    if ((digitalRead(UP) == LOW)) {
       delay(10);
       if (setupContrast < 100)  setupContrast++;
       lcd.setContrast(setupContrast);
       delay(150);
       eepromSaved12 = false;
       ledTimer = millis();
    }
    if ((digitalRead(DOWN) == LOW)) {
       delay(40);
       if (setupContrast > 10) setupContrast--;
       lcd.setContrast(setupContrast);
       delay(150);
       eepromSaved12 = false;
       ledTimer = millis();
    }
  }  
    
  if ((activeMenu == 2) && (activeColumn == 2)&& (setupSelectedMainItem == 1)) {
    if (digitalRead(OK) == LOW) {
      delay(40);
      (testMode == 0 ? testMode = 1 : testMode = 0);
      showTab3();
      while (digitalRead(OK) == LOW);
      eepromSaved13 = false;
      ledTimer = millis();
    }           
    
    
    if ((digitalRead(UP) == LOW)) {
       delay(10);
       setupSelectedBkLtOpt++;
       if (setupSelectedBkLtOpt > 3) setupSelectedBkLtOpt = 0;
       delay(350);
       eepromSaved14 = false;
       ledTimer = millis();
    }

    if ((digitalRead(DOWN) == LOW)) {
       delay(10);
       setupSelectedBkLtOpt--;
       if (setupSelectedBkLtOpt < 0) setupSelectedBkLtOpt = 3;
       delay(350);
       eepromSaved14 = false;
       ledTimer = millis();
    }
    switch (setupSelectedBkLtOpt) {
      case 0: setupTabLED = LEDOFF; break;
      case 1: setupTabLED = LEDHALF; break;
      case 2: setupTabLED = LEDON; break;
      case 3: setupTabLED = map(ambient, 0, 400, 100, 255); break;
      default: setupTabLED = 0;
    }
  } 
  
  if ((activeMenu == 2) && (activeColumn == 2)&& (setupSelectedMainItem == 2)) {
    if ((digitalRead(UP) == LOW)) {
       delay(10);
       if (BkTimer < 20)  BkTimer++;
       delay(150);
       eepromSaved15 = false;
       ledTimer = millis();
    }
    if ((digitalRead(DOWN) == LOW)) {
       delay(40);
       if (BkTimer > 5) BkTimer--;
       delay(150);
       eepromSaved15 = false;
       ledTimer = millis();
    }
  }    
   if (millis() - eepromTimer > 5000) saveEeprom();
}

/*****************************************************************************************
      Tab Drawing and updating routines
 ******************************************************************************************/
 
// Camera menu

void showTab1() {
  camSelectedTimerUnit = getUnits(camSelectedTimerDelay);
  camSelectedBulbUnit = getUnits(camSelectedBulbDelay);
       
  drawTabs();
  lcd.drawRect(0, 0, 10, 10, BLACK);  // Draw Tab.
  lcd.drawLine(9, 1, 9, 8, WHITE); // Remove rectangle edge for Tab to blend into Tab Page.
  
  // Print Menu Item Names - highlight if it is the selected item
  for (int i = 0; i < 3; i++) {
    lcd.setCursor(12, 10 * i +2);
    ((activeColumn == 1) && (camSelectedMainItem == i) ? lcd.setTextColor(WHITE, BLACK) : lcd.setTextColor(BLACK));
    lcd.print(camMainItemsNames[i]);
  }
  
  // If cursor is in 'Values' column , print values for 'Sensor' 
  lcd.setCursor(52, 2);
  ((activeColumn == 2) && (camSelectedMainItem == 0) ? lcd.setTextColor(WHITE, BLACK) : lcd.setTextColor(BLACK));
  if (camFocusGap < 10) lcd.print(" ");
  if (camFocusGap < 100) lcd.print(" ");
  lcd.print(camFocusGap);    
  lcd.print(":");
  if (camShutterHold == 0) lcd.write(172);
  if (camShutterHold == 1) lcd.write(171);
  if (camShutterHold == 2) lcd.print("1");
  if (camShutterHold == 3) lcd.print("2");
  
   // If cursor is in 'Values' column , print values for 'Timer'
  lcd.setCursor(52, 12);
  ((activeColumn == 2) && (camSelectedMainItem == 1) ? lcd.setTextColor(WHITE, BLACK) : lcd.setTextColor(BLACK));
  if (camTimerDelayValues[camSelectedTimerDelay] < 10) lcd.print(" ");
  lcd.print(camTimerDelayValues[camSelectedTimerDelay]);
  lcd.print(camSelectedTimerUnit);
  lcd.print(" ");
  (camSelectedTimerRepeat == 0 ? lcd.print("r") : lcd.print(camSelectedTimerRepeat));
  camActualTimerDelay = multiply(camSelectedTimerUnit, camSelectedTimerDelay);
  
  // If cursor is in 'Values' column , print values for 'Bulb'
  lcd.setCursor(52, 22);
  ((activeColumn == 2) && (camSelectedMainItem == 2) ? lcd.setTextColor(WHITE, BLACK) : lcd.setTextColor(BLACK));
  if (camTimerDelayValues[camSelectedBulbDelay] < 10) lcd.print(" ");
  lcd.print(camTimerDelayValues[camSelectedBulbDelay]);  
  lcd.print(camSelectedBulbUnit);
  camActualBulbDelay = multiply(camSelectedBulbUnit, camSelectedBulbDelay);
  
  lcd.display();    
} 

// Flash Menu

void showTab2() {
  drawTabs();
  lcd.drawRect(0, 11, 10, 10, BLACK);  // Draw Tab.
  lcd.drawLine(9, 12, 9, 19, WHITE); // Remove rectangle edge for Tab to blend into Tab Page.
  
  // Print Menu Item Names - highlight if it is the selected item
  for (int i = 0; i < 3; i++) {
    lcd.setCursor(12, 10 * i +2);
    ((activeColumn == 1) && (flashSelectedMainItem == i) ? lcd.setTextColor(WHITE, BLACK) : lcd.setTextColor(BLACK));
    if (i == 2) {
      lcd.write(1);lcd.print(" "); lcd.write(26);lcd.print(" *"); 
    } else {
      lcd.print(flashMainItemsNames[i]);
    }
  } 
  
    // If cursor is in 'Values' column , print values for 'Slave'
  lcd.setCursor(52, 2);
  ((activeColumn == 2) && (flashSelectedMainItem == 0) ? lcd.setTextColor(WHITE, BLACK) : lcd.setTextColor(BLACK));  
  lcd.print(flashSlaveModes[flashSelectedSlaveMode]);  // Auto, or 0, 1, 2, 3, 4  pre-flashes.
  
  // If cursor is in 'Values' column , print values for 'Hi-Speed'
  lcd.setCursor(52, 12);
  ((activeColumn == 2) && (flashSelectedMainItem == 1) ? lcd.setTextColor(WHITE, BLACK) : lcd.setTextColor(BLACK));  
  if (flashHiSpeedDelay < 10) lcd.print(" ");
  if (flashHiSpeedDelay < 100) lcd.print(" ");
  
  lcd.print(flashHiSpeedDelay); 
  lcd.print(" ");
  lcd.print(flashHiSpeedUnits[flashSelectedHiSpeedUnit]); 
  
  (flashSelectedHiSpeedUnit == 1 ? 
      flashActualHiSpeedDelay = flashHiSpeedDelay * 1000 : flashActualHiSpeedDelay = flashHiSpeedDelay);
      
    // If cursor is in 'Values' column , print values for 'Cam -to- Flash'
  lcd.setCursor(52, 22);
  ((activeColumn == 2) && (flashSelectedMainItem == 2) ? lcd.setTextColor(WHITE, BLACK) : lcd.setTextColor(BLACK)); 
  
  if (flashFromCam == 0) lcd.print("Off  ");
  if (flashFromCam == 1) {lcd.print("* "); lcd.write(26); lcd.print(" *");}
  if (flashFromCam == 2) {lcd.write(175); lcd.print(" ");lcd.write(26); lcd.print(" *");}   
  if (flashFromCam == 3) {lcd.print("* ");lcd.print("w"); lcd.print(" *");} 
  if (flashFromCam == 4) {lcd.write(175);lcd.print(" ");lcd.print("w"); lcd.print(" *");} 
  lcd.display();  
}

// Setup menu

void showTab3() {
  drawTabs();
  lcd.drawRect(0, 21, 10, 10, BLACK);  // Draw Tab.
  lcd.drawLine(9, 22, 9, 29, WHITE); // Remove rectangle edge for Tab to blend into Tab Page.
  
  // Print Menu Item Names - highlight if it is the selected item
  for (int i = 0; i < 3; i++) {
    lcd.setCursor(12, 10 * i +2);
    ((activeColumn == 1) && (setupSelectedMainItem == i) ? lcd.setTextColor(WHITE, BLACK) : lcd.setTextColor(BLACK));
    lcd.print(setupMainItemsNames[i]);
  } 
    // If cursor is in 'Values' column , print value for 'Contrast'
  lcd.setCursor(52, 2);
  ((activeColumn == 2) && (setupSelectedMainItem == 0) ? lcd.setTextColor(WHITE, BLACK) : lcd.setTextColor(BLACK));  
  lcd.print(setupContrast);  
  
    // If cursor is in 'Values' column , print values for 'Backlight Brightness and TestMode'
  lcd.setCursor(52, 12);
  ((activeColumn == 2) && (setupSelectedMainItem == 1) ? lcd.setTextColor(WHITE, BLACK) : lcd.setTextColor(BLACK)); 
  lcd.print(" "); lcd.write(setupBkLtOpt[setupSelectedBkLtOpt]); lcd.print(" ");
  
  (testMode == 0 ? lcd.print(" ") : lcd.write(2));
  
  lcd.setTextColor(BLACK);
    // If cursor is in 'Values' column , print values for 'Backlight timer'
  lcd.setCursor(52, 22);
  ((activeColumn == 2) && (setupSelectedMainItem == 2) ? lcd.setTextColor(WHITE, BLACK) : lcd.setTextColor(BLACK)); 
  lcd.print(BkTimer);
  lcd.print("s");
  lcd.display();
}  

// Draw common framework for Tab1, Tab2 and Tab3

void drawTabs() {
  lcd.clearDisplay();
  lcd.setTextColor(BLACK);  // May have been left WHITE 
  // Draw main Tab Page and Icons in left column.
  lcd.drawRect(9, 0, 75, 48, BLACK);  
  lcd.drawLine(9, 35, 82, 35, BLACK);
  lcd.drawLine(48, 0, 48, 48, BLACK);
  lcd.setCursor(2, 2);
  ((activeMenu == 0) && (activeColumn == 0) ? lcd.setTextColor(WHITE, BLACK) : lcd.setTextColor(BLACK));
  lcd.write(1);   // camera symbol
  lcd.setCursor(2, 12);
  ((activeMenu == 1) && (activeColumn == 0) ? lcd.setTextColor(WHITE, BLACK) : lcd.setTextColor(BLACK));
  lcd.print("*");
  lcd.setCursor(2, 22);
  ((activeMenu == 2) && (activeColumn == 0) ? lcd.setTextColor(WHITE, BLACK) : lcd.setTextColor(BLACK));  
  lcd.write(2);  // spanner symbol
  lcd.setTextColor(BLACK); 
  lcd.setCursor(3, 37);
  lcd.write(3);  // battery symbol
  lcd.setCursor(12, 38);
  float volts = readVcc();
  if ((volts < 3100) || (volts > 4300)) {
    digitalWrite(Vcc, LOW);
    LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
  }
  int v;
  if (volts >= 3600) {
    v = 40;
  } else if ((v < 3600) && (v >= 3200)) {
  } else v = 44;
  lcd.drawLine(4, v, 4, 44, BLACK);
  (volts < 3200 ? lcd.setTextColor(WHITE, BLACK) : lcd.setTextColor(BLACK)); 
  lcd.print(volts/1000);
  lcd.print("v");
  lcd.setCursor(54, 38);
  lcd.setTextColor(BLACK); 
  (delta >0 ? lcd.write(24) : lcd.write(25));
  lcd.print(abs(delta));
}


/*****************************************************************************************
       Utility routines
 *****************************************************************************************/
 
// Interrupt handler for rotary encoder
void rotaryEncoder() {
 if (!adjustAllowed) return;
 if ((activeMenu == 0) &&(camSelectedMainItem == 0) && (activeColumn == 2)) {
   if ((digitalRead(INT0) == digitalRead(INT1)) && (camFocusGap > 10)) camFocusGap-=10 ;
   if ((digitalRead(INT0) != digitalRead(INT1)) && (camFocusGap < 990)) camFocusGap+=10 ;
   eepromSaved4 = false;
   return;
 }
 if ((activeMenu == 1) && (flashSelectedMainItem == 1) && activeColumn == 2) {
   if ((digitalRead(INT0) == digitalRead(INT1)) && (flashHiSpeedDelay > 10)) flashHiSpeedDelay -= 10 ;
   if ((digitalRead(INT0) != digitalRead(INT1)) && (flashHiSpeedDelay < 990)) flashHiSpeedDelay += 10 ;
   eepromSaved9 = false;
   return;
 } 
 analogWrite(LED, setupTabLED);
 ledTimer = millis();
 (digitalRead(INT0) == digitalRead(INT1) ? delta-= 1 : delta+= 1); 
 delta = constrain(delta, -250, 250);
 eepromSaved2 = false;
} 

// Determine 'units' from value's position in Timer and Bulb arrays
char* getUnits(int value) {
  char* result = "s";
  if (value < 6) result = "s";
  if ((value > 5) && (value < 12)) result = "m";
  if (value > 11) result = "h";
  return result;
} 
 
// Calculate actual timer value from units 
unsigned long multiply(char* unit,  int value) {
  unsigned long result = 1000;
  if (unit == "s") result = camTimerDelayValues[value];
  if (unit == "m") result = camTimerDelayValues[value] * 60;
  if (unit == "h") result = camTimerDelayValues[value] * 3600;  
  return result;
} 
 
 
// Get Battery Voltage 

long readVcc() {
  long result;
  // Read 1.1V reference against AVcc
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  delay(2); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Convert
  while (bit_is_set(ADCSRA,ADSC));
  result = ADCL;
  result |= ADCH<<8;
  result = 1113000L / result; // Back-calculate AVcc in mV
  return result;
}


// Integer EEPROM routines (two bytes) Required for Hi-Sppeed Timer and delta

void EEPROMWriteInt(int p_address, int p_value) {
   byte lowByte = ((p_value >> 0) & 0xFF);
   byte highByte = ((p_value >> 8) & 0xFF);
   EEPROM.write(p_address, lowByte);
   EEPROM.write(p_address + 1, highByte);
}

unsigned int EEPROMReadInt(int p_address) {
    byte lowByte = EEPROM.read(p_address);
    byte highByte = EEPROM.read(p_address + 1);
    return ((lowByte << 0) & 0xFF) + ((highByte << 8) & 0xFF00);
}

    

 

Back to Index | Page 1 | Page 2 | Page 3 | Page 4 | Page 5 | Page 6 | Page 7

 


This site and its contents are © Copyright 2005 - All Rights Reserved.