HALO-Photographs | 'The remote shutter release timer for NIKON D300 project' | Project Index Page |
This code has been tested on a FREEDUINO and a ATMEGA168 Board (both 100% ARDUINO compatible)
You may 'copy-paste' the marked section below and/or download the code
The layout of the rather simple wiring will be published here soon.
Code for the electronic remote shutter release timer for a NIKON D300 by Hans Loepfe is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 2.5 Switzerland License.
Based on a work at newyorkpanorama.com.
Permissions beyond the scope of this license may be available at https://www.halo-photographs.com/info/obtain-license.html.
/*
This program allows controlled bracketing specially suited for long exposures > 1/6 second.
Measure the maximum und minimum exposre time, select the corresponding values on RSRT which calcultes and displays what it's goint to.
Basically just fire away.
-----
Arduino long exposure bracketing
Parts of the LCD menu and interrupt timer are taken from the nokia demo application at nuelectronics.com
-----
2009 Joergen Geerds, V0.32 released as a creative commons open source license, please give/leave credit
download and more info at
http://newyorkpanorama.com/2009/01/21/long-exposure-night-hdr-photography-with-arduino/
-----
modified by Hans Loepfe (2009/05/12) and re-released under a creative commons BY-NC-SA license,
the code is available at: https://www.halo-photographs.com/remote-shutter-release-timer/Arduino/Nikon-RSRT-052.7zip
Version V0.52-HALO
-----
Some modification and other notes:
- First I have rewritten the firing sequence to accomodate to a NIKON D300 and introduced an additional digital signaling pin.
- Also the 'Bracket Dance' has been adapted using a different approach.
The Bracketwidth became the Bracketstep. From a base exposure (center) the sequence simply follows up and down the register
of 'exptime[]' by increments defined in the 'EV settings' for as many shots (uneven numbers) as calculated.
- The menus show a bit more information and the shooting sequence shows more values. Those I have used as and aid for getting
the code do what I want it to do.
- I had to adjust the timing values for the NIKON D300 that requires exactly 600ms in addition to the acutal exposure time.
This was neccessary for me because when shooting bracketed shots, I always set the Mirror-up function to ON. This creates a 600ms delay.
- I call this program 'RSRT' (aka remote-shutter-rellease-timer) - what else - run it off a small 9V Battery and carry it allover the place
to shot panoramic HDRIs.
- Unfortunately sometimes, when flipping through the settings pages, the code crashes, but quickly restarts.
I tried to figure out the cause, but did not succeed. I assume it has something to do with the addl. variables I introduced (see line 76-86).
Or possibly with the memory available for the display. I don't know.
When someone finds the answers, please be so kind and post the results back to me, thanks.
Turning 'Noise-Reduction' OFF
If one uses a NIKON D300 with 'Noise-Reduction for long exposures' turned on, then the D300 displays 'Job Nr' for as long as the previous exposure (sarting at 20 secs).
Therefore the bracketing sequence and the fire() must wait (brktwait) for the exposure period of the previous shot (b) before it can continue with the next shot.
The code lines below (on lines 387)take this into account.
If one prefers to turn OFF 'Noise-Reduction for long exposures', then the lines marked '// *ON' below become obsolete
If one prefers to turn ON 'Noise-Reduction for long exposures', then the lines marked '// **OFF below become obsolete
Expect this part of the code to be changed as a case selection in the NENU.
- Now use the code, improve and enjoy it.
...and don't forget to use it according to the Creative Commons license BY-NC-SA.
*/
#include "Nokia_lcd.h"
//keypad debounce parameter
#define DEBOUNCE_MAX 15
#define DEBOUNCE_ON 10
#define DEBOUNCE_OFF 3
#define NUM_KEYS 5
// joystick number
#define U_K 3 // up
#define L_K 0 // left
//#define C_K 1 // center, not used
#define D_K 2 // down
#define R_K 4 // right
// general wait timing between focus, mirror-up and shot. Used in the 'fire()' sequence only
int INITfocus = 2000; // wait 2 secondes for the camera to get focus and into the 'ready' state
int INITfire = 400; // this actually releases the shutter (400)
int SHUTTERPIN = 4; // the pin the shutter release is connected to?
int FOCUS = 6; // Camera 'ready' (FOCUS)
int RELEASE = 7; // pushbutton pin
int EVMIN = 0; // min 1/10 second (11)
int EVMAX = 44; // max 120 minutes
int t1 = 25; // temporary delay after joystick activity
int t2 = 25; // temporary delay before write to display
// exposure value table in 0.5 EV steps in milliseconds (600ms added to compensate the camera shutter lag)
unsigned long exptime[] = {602, 603, 604, 606, 608, 611, 617, 622, 633, 650, 667, 700, 728, 767, 850, 933, 1100, 1267, 1600, 2100, 2600, 3600, 4600, 6600, 8600, 10600, 15600, 20600, 30600, 40600, 60600, 90600, 120600, 180600, 240600, 360600, 480600, 600600, 900600, 1200600, 1800600, 2400600, 3600600, 4800600, 7200600, 14401200};
char* expstr[] = {"1/500", "1/350s", "1/250s", "1/180s", "1/125s", "1/90s", "1/60s", "1/45s", "1/30s", "1/20s", "1/15s", "1/10s", "1/8s", "1/6s", "1/4s", "1/3s", "1/2s", "2/3s", "1sec", "1.5sec", "2sec", "3sec", "4sec", "6sec", "8sec", "10sec", "15sec", "20sec", "30sec", "40sec", "1min", "1.5min", "2min", "3min", "4min", "6min", "8min", "10min", "15min", "20min", "30min", "40min", "60min", "80min", "120min", "240min"};
unsigned long brktwait[] = {1000, 2500, 5000, 10000, 15000, 20000};
char* brktstr[] = {"1s", "2.5s", "5s", "10s", "15s", "20s"};
// default values for exposure bracketing
byte b = 18; // base exposure, 1sec from exptime[] (18)
byte w = 2; // bracket steps EV/2 , default 1EV
byte n = 5; // # of bracketed shots, 5
byte c = 1; // wait time before next shot, optional, default='2.5s', (needed if 'Noise-Reduction for long exposures' is set to 'ON' - see also at the end of the 'fire()' sequence.
byte s = 0; // # of shots taken during firing sequence
byte ev_min = 11; // shortest exposure time, measured & entered by user
byte ev_max = 30; // longest exposure time, measured & entered by user
byte ev_base; // base exposure time, calculated
byte x; // used to calculate the # of shots above and below the base shot
byte i; // generic counter
// string variables
char tmpstr[8]; // generic string
// char tmpstr0[6]; // designated string for exposuretime b
// adc preset value, represent top value,incl. noise & margin,that the adc reads, when a key is pressed
// set noise & margin = 30 (0.15V@5V)
int adc_key_val[NUM_KEYS] = {30, 128, 260, 374, 515};
byte button_count[NUM_KEYS]; // debounce counters
byte button_status[NUM_KEYS]; // button status - pressed/released
byte button_flag[NUM_KEYS]; // button on flags for user program
// Display Settings, write position top-left
#define MN_X 5
#define MN_Y 5
// seemingly not needed
void main_menu(void);
void menu_expmax(void); //menu item inserted - enter max exposure
void menu_expmin(void); //menu item inserted - enter min exposure
void menu_bracketstep(void);
void menu_brktwait(void); //menu item inserted - time delay between shots, if desired
Nokia_lcd lcd=Nokia_lcd();
void InitPort(){
DDRB=0x2F;
}
void setup(void){
// setup interrupt-driven keypad arrays
// reset button arrays
for(i=0; i<NUM_KEYS; i++){
button_count[i]=0;
button_status[i]=0;
button_flag[i]=0;
}
// Setup timer2 -- Prescaler/256
TCCR2A &= ~((1<<WGM21) | (1<<WGM20));
TCCR2B &= ~(1<<WGM22);
TCCR2B = (1<<CS22)|(1<<CS21);
ASSR |=(0<<AS2);
// Use normal mode
TCCR2A =0;
//Timer2 Overflow Interrupt Enable
TIMSK2 |= (0<<OCIE2A);
TCNT2=0x6; // counting starts from 6;
TIMSK2 = (1<<TOIE2);
SREG|=1<<SREG_I;
InitPort();
LCD_BACKLIGHT(1);
lcd.cLCD_Init();
pinMode(RELEASE, INPUT);
}
void loop(void){
button_flag[i]=0; // reset button flag
main_menu(); // make main menu
while(true){ // repeat forever
for(i=0; i<NUM_KEYS; i++){ // wait for anything to happen
if(digitalRead(RELEASE) == LOW){ // red button on pin RELEASE is pressed (goes LOW)
bracket(); // start taking shots
}
if(button_flag[i] !=0){
button_flag[i]=0; // reset button flag
switch(i){
case L_K:
delay(t1);
menu_brktwait();
// menu_bracketstep();
break;
case R_K:
delay(t1);
menu_expmax();
break;
}
}
}
}
}
void main_menu(void){
ev_base=round((ev_max+ev_min)/2);
b=ev_base;
x = (round((ev_base-ev_min)/2)); //calculating # of shots above and below the base shot
n = 1 + (2 * x);
delay(t2);
lcd.cLCD_Box(0,0, 131,131, FILL, WHITE); // clear screen
lcd.cLCD_String("Ready...", MN_X, MN_Y, GREEN, BLACK);
lcd.cLCD_String("Press Button", MN_X, MN_Y+10, GREEN, BLACK);
lcd.cLCD_String("Exposures:", MN_X, MN_Y+20, BLACK, WHITE);
lcd.cLCD_String("Base:", MN_X, MN_Y+30, BLACK, WHITE);
lcd.cLCD_String(itoa(ev_base, tmpstr, 10), MN_X+40, MN_Y+30, RED, WHITE);
lcd.cLCD_String(expstr[b], MN_X+65, MN_Y+30, RED, WHITE);
lcd.cLCD_String("Max:", MN_X, MN_Y+40, BLACK, WHITE);
lcd.cLCD_String(itoa(ev_max, tmpstr, 10), MN_X+40, MN_Y+40, RED, WHITE);
lcd.cLCD_String(expstr[ev_max], MN_X+65, MN_Y+40, RED, WHITE);
lcd.cLCD_String("Min:", MN_X, MN_Y+50, BLACK, WHITE);
lcd.cLCD_String(itoa(ev_min, tmpstr, 10), MN_X+40, MN_Y+50, RED, WHITE);
lcd.cLCD_String(expstr[ev_min], MN_X+65, MN_Y+50, RED, WHITE);
lcd.cLCD_String("up/down:", MN_X, MN_Y+60, BLACK, WHITE);
lcd.cLCD_String(itoa(x, tmpstr, 10), MN_X+65, MN_Y+60, RED, WHITE);
lcd.cLCD_String("Total:", MN_X, MN_Y+70, BLACK, WHITE);
lcd.cLCD_String(itoa(n, tmpstr, 10), MN_X+65, MN_Y+70, RED, WHITE);
lcd.cLCD_String("Bracketstep(s):", MN_X, MN_Y+80, BLACK, WHITE);
lcd.cLCD_String(" /2 EV", MN_X+25, MN_Y+90, BLACK, WHITE);
lcd.cLCD_String(itoa(w, tmpstr, 10), MN_X+25, MN_Y+90, RED, WHITE);
lcd.cLCD_String("Bracket wait:", MN_X, MN_Y+100, BLACK, WHITE);
lcd.cLCD_String(brktstr[c], MN_X+25, MN_Y+110, RED, WHITE);
}
void menu_expmax(void){
b=ev_max;
button_flag[i]=0; // reset button flag
delay(t2);
lcd.cLCD_Box(0,0, 131,131, FILL, WHITE); // clear screen
lcd.cLCD_String("Select", MN_X, MN_Y, BLUE, LIGHTBLUE);
lcd.cLCD_String("Longest Exposure:", MN_X, MN_Y+10, BLUE, LIGHTBLUE);
lcd.cLCD_String(" ", MN_X+20, MN_Y+25, RED, WHITE);
lcd.cLCD_String(expstr[b], MN_X+20, MN_Y+25, RED, WHITE);
lcd.cLCD_String("Millisecs:", MN_X, MN_Y+60, BLACK, WHITE);
lcd.cLCD_String(" ", MN_X, MN_Y+70, RED, WHITE);
// lcd.cLCD_String(ultoa(exptime[b], tmpstr0, 10), MN_X, MN_Y+70, RED, WHITE);
lcd.cLCD_String(ultoa(exptime[b], tmpstr, 10), MN_X, MN_Y+70, RED, WHITE);
lcd.cLCD_String("Register:", MN_X, MN_Y+80, BLACK, WHITE);
lcd.cLCD_String(" ", MN_X+80, MN_Y+80, RED, WHITE);
lcd.cLCD_String(itoa(b, tmpstr, 10), MN_X+80, MN_Y+80, RED, WHITE); //print current register# in array
while(true){
for(i=0; i<NUM_KEYS; i++){ // wait for anything to happen
if(button_flag[i] !=0){
button_flag[i]=0; // reset button flag
switch(i){
case U_K:
delay(t1);
if (b<= EVMAX-1) b=b+1;
lcd.cLCD_String(" ", MN_X+20, MN_Y+25, RED, WHITE);
lcd.cLCD_String(expstr[b], MN_X+20, MN_Y+25, RED, WHITE);
lcd.cLCD_String(" ", MN_X, MN_Y+70, RED, WHITE);
// lcd.cLCD_String(ultoa(exptime[b], tmpstr0, 10), MN_X, MN_Y+70, RED, WHITE);
lcd.cLCD_String(ultoa(exptime[b], tmpstr, 10), MN_X, MN_Y+70, RED, WHITE);
ev_max=b;
lcd.cLCD_String(" ", MN_X+80, MN_Y+80, RED, WHITE);
lcd.cLCD_String(itoa(b, tmpstr, 10), MN_X+80, MN_Y+80, RED, WHITE); //print current register# in array
break;
case D_K:
delay(t1);
if (b>=EVMIN+1) b=b-1;
lcd.cLCD_String(" ", MN_X+20, MN_Y+25, RED, WHITE);
lcd.cLCD_String(expstr[b], MN_X+20, MN_Y+25, RED, WHITE);
lcd.cLCD_String(" ", MN_X, MN_Y+70, RED, WHITE);
// lcd.cLCD_String(ultoa(exptime[b], tmpstr0, 10), MN_X, MN_Y+70, RED, WHITE);
lcd.cLCD_String(ultoa(exptime[b], tmpstr, 10), MN_X, MN_Y+70, RED, WHITE);
ev_max=b;
lcd.cLCD_String(" ", MN_X+80, MN_Y+80, RED, WHITE);
lcd.cLCD_String(itoa(b, tmpstr, 10), MN_X+80, MN_Y+80, RED, WHITE); //print current register# in array
break;
case L_K:
delay(t1);
loop();
case R_K:
delay(t1);
menu_expmin();
}
}
}
}
}
void menu_expmin(void){
b=ev_min;
button_flag[i]=0; // reset button flag
delay(t2);
lcd.cLCD_Box(0,0, 131,131, FILL, WHITE); // clear screen
lcd.cLCD_String("Select", MN_X, MN_Y, BLUE, LIGHTBLUE);
lcd.cLCD_String("Shortest Exposure:", MN_X, MN_Y+10, BLUE, LIGHTBLUE);
lcd.cLCD_String(" ", MN_X+20, MN_Y+25, RED, WHITE);
lcd.cLCD_String(expstr[b], MN_X+20, MN_Y+25, RED, WHITE);
lcd.cLCD_String("Millisecs:", MN_X, MN_Y+60, BLACK, WHITE);
lcd.cLCD_String(" ", MN_X, MN_Y+70, RED, WHITE);
// lcd.cLCD_String(ultoa(exptime[b], tmpstr0, 10), MN_X, MN_Y+70, RED, WHITE);
lcd.cLCD_String(ultoa(exptime[b], tmpstr, 10), MN_X, MN_Y+70, RED, WHITE);
lcd.cLCD_String("Register:", MN_X, MN_Y+80, BLACK, WHITE);
lcd.cLCD_String(" ", MN_X+80, MN_Y+80, RED, WHITE);
lcd.cLCD_String(itoa(b, tmpstr, 10), MN_X+80, MN_Y+80, RED, WHITE); //print current register# in array
while(true){
for(i=0; i<NUM_KEYS; i++){ // wait for anything to happen
if(button_flag[i] !=0){
button_flag[i]=0; // reset button flag
switch(i){
case U_K:
delay(t1);
if (b<= EVMAX-1) b=b+1;
lcd.cLCD_String(" ", MN_X+20, MN_Y+25, RED, WHITE);
lcd.cLCD_String(expstr[b], MN_X+20, MN_Y+25, RED, WHITE);
lcd.cLCD_String(" ", MN_X, MN_Y+70, RED, WHITE);
// lcd.cLCD_String(ultoa(exptime[b], tmpstr0, 10), MN_X, MN_Y+70, RED, WHITE);
lcd.cLCD_String(ultoa(exptime[b], tmpstr, 10), MN_X, MN_Y+70, RED, WHITE);
ev_min=b;
lcd.cLCD_String(" ", MN_X+80, MN_Y+80, RED, WHITE);
lcd.cLCD_String(itoa(b, tmpstr, 10), MN_X+80, MN_Y+80, RED, WHITE); //print current register# in array
break;
case D_K:
delay(t1);
if (b>=EVMIN+1) b=b-1;
lcd.cLCD_String(" ", MN_X+20, MN_Y+25, RED, WHITE);
lcd.cLCD_String(expstr[b], MN_X+20, MN_Y+25, RED, WHITE);
lcd.cLCD_String(" ", MN_X, MN_Y+70, RED, WHITE);
// lcd.cLCD_String(ultoa(exptime[b], tmpstr0, 10), MN_X, MN_Y+70, RED, WHITE);
lcd.cLCD_String(ultoa(exptime[b], tmpstr, 10), MN_X, MN_Y+70, RED, WHITE);
ev_min=b;
lcd.cLCD_String(" ", MN_X+80, MN_Y+80, RED, WHITE);
lcd.cLCD_String(itoa(b, tmpstr, 10), MN_X+80, MN_Y+80, RED, WHITE); //print current register# in array
break;
case L_K:
delay(t1);
menu_expmax();
case R_K:
delay(t1);
menu_bracketstep();
}
}
}
}
}
void menu_bracketstep(void){
delay(t2);
button_flag[i]=0; // reset button flag
lcd.cLCD_Box(0,0, 131,131, FILL, WHITE); // clear screen
lcd.cLCD_String("Select", MN_X, MN_Y, BLUE, LIGHTBLUE);
lcd.cLCD_String("Bracketstep(s):", MN_X, MN_Y+10, BLUE, LIGHTBLUE);
lcd.cLCD_String(" /2 EV", MN_X+10, MN_Y+25, BLACK, WHITE);
lcd.cLCD_String(itoa(w, tmpstr, 10), MN_X+10, MN_Y+25, RED, WHITE);
while(true){
for(i=0; i<NUM_KEYS; i++){ // wait for anything to happen
if(button_flag[i] !=0){
button_flag[i]=0; // reset button flag
switch(i){
case U_K:
delay(t1);
if (w<12) w++; //+-12 EV should be enough
lcd.cLCD_String(" ", MN_X+10, MN_Y+25, RED, WHITE);
lcd.cLCD_String(itoa(w, tmpstr, 10), MN_X+10, MN_Y+25, RED, WHITE);
break;
case D_K:
delay(t1);
if (w>1) w--;
lcd.cLCD_String(" ", MN_X+10, MN_Y+25, RED, WHITE);
lcd.cLCD_String(itoa(w, tmpstr, 10), MN_X+10, MN_Y+25, RED, WHITE);
break;
case L_K:
delay(t1);
menu_expmin();
case R_K:
delay(t1);
menu_brktwait();
// loop();
}
}
}
}
}
void menu_brktwait(void){
delay(t2);
button_flag[i]=0; // reset button flag
lcd.cLCD_Box(0,0, 131,131, FILL, WHITE); // clear screen
lcd.cLCD_String("Select", MN_X, MN_Y, BLUE, LIGHTBLUE);
lcd.cLCD_String("Bracket wait:", MN_X, MN_Y+10, BLUE, LIGHTBLUE);
lcd.cLCD_String(" ", MN_X+20, MN_Y+25, RED, WHITE);
lcd.cLCD_String(brktstr[c], MN_X+20, MN_Y+25, RED, WHITE);
while(true){
for(i=0; i<NUM_KEYS; i++){ // wait for anything to happen
if(button_flag[i] !=0){
button_flag[i]=0; // reset button flag
switch(i){
case U_K:
delay(t1);
if (c<5) c++; // 6 options (1s, 2.5s, 5s, 10s, 15s, 20s)
lcd.cLCD_String(" ", MN_X+20, MN_Y+25, RED, WHITE);
lcd.cLCD_String(brktstr[c], MN_X+20, MN_Y+25, RED, WHITE);
break;
case D_K:
delay(t1);
if (c>0) c--;
lcd.cLCD_String(" ", MN_X+20, MN_Y+25, RED, WHITE);
lcd.cLCD_String(brktstr[c], MN_X+20, MN_Y+25, RED, WHITE);
break;
case L_K:
delay(t1);
menu_bracketstep();
case R_K:
delay(t1);
loop();
}
}
}
}
}
// start bracket shooting
void bracket(){
int ev;
s = 0;
lcd.cLCD_Box(0,0, 131,131, FILL, WHITE); // clear screen
lcd.cLCD_String("Shot #:", MN_X, MN_Y+10, BLACK, WHITE);
lcd.cLCD_String(" ", MN_X+75, MN_Y+10, RED, WHITE);
lcd.cLCD_String("wait next:", MN_X, MN_Y+20, BLACK, WHITE);
lcd.cLCD_String(" ", MN_X+75, MN_Y+20, RED, WHITE);
lcd.cLCD_String("Exposing:", MN_X, MN_Y+35, BLACK, WHITE);
lcd.cLCD_String(" ", MN_X+20, MN_Y+45, RED, WHITE); // clear
lcd.cLCD_String(expstr[b], MN_X+20, MN_Y+45, RED, WHITE); // print current exposure time, here the base EV
lcd.cLCD_String("Millisecs:", MN_X, MN_Y+65, BLACK, WHITE);
lcd.cLCD_String(" ", MN_X+75, MN_Y+65, RED, WHITE);
// lcd.cLCD_String(ultoa(exptime[b], tmpstr0, 10), MN_X+75, MN_Y+65, RED, WHITE);
lcd.cLCD_String(ultoa(exptime[b], tmpstr, 10), MN_X+75, MN_Y+65, RED, WHITE);
lcd.cLCD_String("Register:", MN_X, MN_Y+75, BLACK, WHITE);
ev = b;
lcd.cLCD_String(itoa(ev, tmpstr, 10), MN_X+75, MN_Y+75, RED, WHITE); //print register# in array, 1st instance appears in 'bracket dance'
s = s + 1; //counting the shots taken
lcd.cLCD_String(itoa(s, tmpstr, 10), MN_X+75, MN_Y+10, RED, WHITE); // print # of shot in sequence
fire(exptime[b]); // take the centershot
// Do the EV Bracketing
ev = b+(((n-1)/2)*w); //EV max. / bracketing on the long side
for (byte i=(n-1)/2; i>=1; i--){
s = s + 1; //counting the shots taken
lcd.cLCD_String(itoa(s, tmpstr, 10), MN_X+75, MN_Y+10, RED, WHITE); // print # of shot in sequence
lcd.cLCD_String(" ", MN_X+20, MN_Y+45, RED, WHITE); // clear
lcd.cLCD_String(expstr[ev], MN_X+20, MN_Y+45, RED, WHITE); // print current exposure time
lcd.cLCD_String(" ", MN_X+75, MN_Y+65, RED, WHITE);
lcd.cLCD_String(ultoa(exptime[ev], tmpstr, 10), MN_X+75, MN_Y+65, RED, WHITE); // print exposure in milliseconds
lcd.cLCD_String(" ", MN_X+75, MN_Y+75, RED, WHITE);
lcd.cLCD_String(itoa(ev, tmpstr, 10), MN_X+75, MN_Y+75, RED, WHITE); //print register# in array
fire(exptime[ev]);
ev=ev-w;
}
ev = b-(((n-1)/2)*w); //EV min. / bracketing on the short side
for (byte i=(n-1)/2; i>=1; i--){
s = s + 1; //counting the shots taken
lcd.cLCD_String(itoa(s, tmpstr, 10), MN_X+75, MN_Y+10, RED, WHITE); // print # of shot in sequence
lcd.cLCD_String(" ", MN_X+20, MN_Y+45, RED, WHITE); // clear
lcd.cLCD_String(expstr[ev], MN_X+20, MN_Y+45, RED, WHITE); // print current exposure time
lcd.cLCD_String(" ", MN_X+75, MN_Y+65, RED, WHITE);
lcd.cLCD_String(ultoa(exptime[ev], tmpstr, 10), MN_X+75, MN_Y+65, RED, WHITE); // print exposure in milliseconds
lcd.cLCD_String(" ", MN_X+75, MN_Y+75, RED, WHITE);
lcd.cLCD_String(itoa(ev, tmpstr, 10), MN_X+75, MN_Y+75, RED, WHITE); //print register# in array
fire(exptime[ev]);
ev=ev+w;
}
// end EV Bracketing (shots are in the box)
main_menu();
}
// The shutter relase function. May be adjusted for specific camera model.
// open shutter for 't' milliseconds
void fire(unsigned long t){
pinMode(FOCUS, OUTPUT); // outpin 6 gives output
pinMode(SHUTTERPIN, OUTPUT); // outpin 4 gives output
digitalWrite(FOCUS, HIGH); // initiate focus and camera ready ('r6' for the Nikon D300)
delay(INITfocus); // give time till camera 'beeps' the ready signal
digitalWrite(SHUTTERPIN, HIGH); // initiate exposure, activate mirror-up / on Nikon D300 set d9=on, results in a 600ms delay till the actual exposure starts
delay(INITfire); // there must be a short delay so the circuit has just enough time to trigger the shutter release
digitalWrite(SHUTTERPIN, LOW); // mirror is up and shutter has been released, the Shutterpin has no more effect can be set to LOW
delay(t); // this is the actual exposure
digitalWrite(FOCUS, LOW); // end the exposure delayed by 't'
/*
lcd.cLCD_String(brktstr[c], MN_X+75, MN_Y+20, RED, WHITE); // *ON Noise-Reduction ON
delay(brktwait[c]); // *ON Noise-Reduction ON - delay for as long as the last exposure till the next shot
*/
lcd.cLCD_String(brktstr[c], MN_X+75, MN_Y+20, RED, WHITE); // **OFF Noise-Reduction OFF
delay(brktwait[c]); // **OFF Noise-Reduction OFF - delay for as per selection in menu
}
/*
The following are interrupt-driven keypad reading
which includes DEBOUNCE ON/OFF mechanism, and continuous pressing detection
Best is to leave as is
*/
// Convert ADC value to key number
char get_key(unsigned int input)
{
char k;
for (k = 0; k < NUM_KEYS; k++)
{
if (input < adc_key_val[k])
{
return k;
}
}
if (k >= NUM_KEYS)
k = -1; // No valid key pressed
return k;
}
void update_adc_key(){
int adc_key_in;
char key_in;
byte i;
adc_key_in = analogRead(0);
key_in = get_key(adc_key_in);
for(i=0; i<NUM_KEYS; i++)
{
if(key_in==i) //one key is pressed
{
if(button_count[i]<DEBOUNCE_MAX)
{
button_count[i]++;
if(button_count[i]>DEBOUNCE_ON)
{
if(button_status[i] == 0)
{
button_flag[i] = 1;
button_status[i] = 1; //button debounced to 'pressed' status
}
}
}
}
else // no button pressed
{
if (button_count[i] >0)
{
button_flag[i] = 0;
button_count[i]--;
if(button_count[i]<DEBOUNCE_OFF){
button_status[i]=0; //button debounced to 'released' status
}
}
}
}
}
// Timer2 interrupt routine -
// 1/(160000000/256/(256-6)) = 4ms interval
ISR(TIMER2_OVF_vect) {
TCNT2 = 6;
update_adc_key();
}
contact HALO-Photographs |