// Ethan's Arduino Nikon Programmable Remote w/ Intervalometer (July 2009) #include #include #define TO_UPPER(x) (((x >= 'a') && (x <= 'z')) ? ((x) - ('a' - 'A')) : (x)) // Flow control variables boolean mainloopbool = true; boolean checkbool = false; boolean beganserial = false; // Pin assignments // IR LED pin assignment NikonRemote remote(12); // Status LED int statusPin = 13; // Pin assignment for each program LED int progOne = 2; int progTwo = 3; int progThree = 4; int progFour = 5; int progFive = 6; int progSix = 7; int progSeven = 8; // Pin assignements for each button int butLeft = 9; int butGo = 10; int butRight = 11; //The amount of time that the LEDs are all off to eliminate ambient light. int allOffMS = 300; // Keyboard buffer char* keyboardBuffer = "12345678901234567890123456789012345678901234567890123456789012345678901234567890"; //80 character int bufferLength = 0; // Starting default program = manual trigger mode int progNum = 6; // Time delays for each interval program (1-5) unsigned long milliOne = 5000; // five seconds unsigned long milliTwo = 30000; // thirty seconds unsigned long milliThree = 60000; // one minute unsigned long milliFour = 300000; // five minutes unsigned long milliFive = 840000; // fourteen minutes // Runs when the microcontroller boots void setup(){ // Power all pins to default values pinMode(statusPin, OUTPUT); pinMode(progOne, OUTPUT); pinMode(progTwo, OUTPUT); pinMode(progThree, OUTPUT); pinMode(progFour, OUTPUT); pinMode(progFive, OUTPUT); pinMode(progSix, OUTPUT); pinMode(progSeven, OUTPUT); pinMode(butLeft, INPUT); pinMode(butGo, INPUT); pinMode(butRight, INPUT); } // Main Loop - Runs immediately after setup() void loop(){ // Reset status LED to OFF digitalWrite(statusPin, LOW); interface(); // button selection logic LEDstate(); // power all LEDs to selected values delay(125); // One tenth second button debounce } // Terminate a program, resume the main loop void resumeLoop(){ digitalWrite(statusPin, HIGH); mainloopbool = false; checkbool = false; resetBuffer(); LEDstate(); } // button selection logic void interface(){ if (digitalRead(butGo)==LOW){ // Middle "GO" button to ground means it's pressed digitalWrite(statusPin, HIGH); mainloopbool = true; program(); // execute the selected program digitalWrite(statusPin, LOW); }else if (digitalRead(butLeft)==LOW){ // "Left" button pressed, decrement selected program digitalWrite(statusPin, HIGH); progNum-=1; digitalWrite(statusPin, LOW); }else if (digitalRead(butRight)==LOW){ // "Right" button pressed, increment selected program digitalWrite(statusPin, HIGH); progNum+=1; digitalWrite(statusPin, LOW); } // Keep program selection in range if (progNum > 7) { progNum = 1; } else if (progNum < 1) { progNum = 7; } /* uncomment for diagnostic code if (beganserial == false){ digitalWrite(statusPin, HIGH); Serial.begin(9600); beganserial = true; delay (50); digitalWrite(statusPin, LOW); } Serial.println(progNum); */ } // Run the selected program void program(){ while (mainloopbool == true){ switch (progNum){ case 1: intervalsnap(milliOne); break; case 2: intervalsnap(milliTwo); break; case 3: intervalsnap(milliThree); break; case 4: intervalsnap(milliFour); break; case 5: intervalsnap(milliFive); break; case 6: manualTrigger(); break; case 7: serialTrigger(); break; } } } // Manually trigger the camera void manualTrigger(){ if (digitalRead(butGo)==LOW){ // Trigger camera if GO is pressed snap(); digitalWrite(statusPin, HIGH); } else if ((digitalRead(butLeft)==LOW) || (digitalRead(butRight)==LOW)){ // If Left or Right are pressed, exit program back to main loop resumeLoop(); } } // Trigger the camera via Laptop serial port, etc. void serialTrigger(){ // Initialize serial one time only if (beganserial == false){ digitalWrite(statusPin, HIGH); Serial.begin(9600); beganserial = true; delay (50); digitalWrite(statusPin, LOW); } // Bypass if button is pressed if ((digitalRead(butLeft)==LOW) || (digitalRead(butRight)==LOW)){ resumeLoop(); return; } // Read all pending characters into our keyboard buffer boolean gotEndDelimiter = false; while (Serial.available() > 0) { char ch = Serial.read(); char serialByte = TO_UPPER(ch); keyboardBuffer[bufferLength++] = serialByte; if (bufferLength > 80){ Serial.println("Serial buffer overflow"); SerialError(); return; } if (serialByte == 'X'){ gotEndDelimiter = true; break; } } // If it is a full command, including the end delimiter, then execute it. if (gotEndDelimiter == true){ processSerialTriggerCommand(); } } // Trigger the camera via Laptop serial port, etc. // // Syntax for serial triggering: SSX void processSerialTriggerCommand() { int initialDelayMs = 0; int intervalMs = 0; int repetitionCount = 0; enum State { INITIAL=0, DELAY=1, REPEAT=2 }; int state = INITIAL; checkbool = true; //!!?? maybe move this? //Serial.println("Debug. Entering for loop..."); int i; for (i=0; i 0) delaycheck(intervalMs); } resetBuffer(); Serial.println("Successful exit"); return; //successSX } else { break; } //Serial.println("Debug: Done processing character."); }//end for SerialError(); } void resetBuffer(){ bufferLength = 0; } void SerialError(){ Serial.println("Error. Exit"); Serial.flush(); resetBuffer(); ErrorBlink(); if ((digitalRead(butLeft)==LOW) || (digitalRead(butRight)==LOW)){ resumeLoop(); } } void ErrorBlink(){ int i; for (i = 0; i < 5; i++){ digitalWrite(progOne, LOW); digitalWrite(progTwo, LOW); digitalWrite(progThree, LOW); digitalWrite(progFour, LOW); digitalWrite(progFive, LOW); digitalWrite(progSix, LOW); digitalWrite(progSeven, LOW); digitalWrite(statusPin, LOW); delaycheck(100); digitalWrite(progOne, HIGH); digitalWrite(progTwo, HIGH); digitalWrite(progThree, HIGH); digitalWrite(progFour, HIGH); digitalWrite(progFive, HIGH); digitalWrite(progSix, HIGH); digitalWrite(progSeven, HIGH); digitalWrite(statusPin, HIGH); delaycheck(100); } LEDstate(); } // Intervalometer - time delay determined by which program is selected void intervalsnap(unsigned long timeMS){ // If time to wait is longer than 8 seconds, the status blink will last 5 seconds // otherwise, the status blink lasts 2 seconds. unsigned long preStatusBlinkTime; int nBlinks; if (timeMS < 1000){ nBlinks = 1; preStatusBlinkTime = 500; }else if (timeMS < 8000){ nBlinks = 4; preStatusBlinkTime = timeMS - 2000; }else{ //anything longer nBlinks = 10; preStatusBlinkTime = timeMS - 5000; } //Take account of the time it takes to turn back on the LEDs during snap(); preStatusBlinkTime = preStatusBlinkTime - (allOffMS + 63); //Delay for specified number of milliseconds, quitting if any button is pressed delaycheck(preStatusBlinkTime); // Blink the status lights at half-second intervals for the remainder of the time if (checkbool == true){ int i; for(i=0; i < nBlinks; i++){ digitalWrite(statusPin, HIGH); delaycheck(400); digitalWrite(statusPin, LOW); delaycheck(100); } // Trigger the shutter snap(); } } // Delay for specified number of tenths of a second, quitting if any button is pressed void delaycheck(unsigned long delayMs){ int i = 0; checkbool = true; int hundredms = delayMs / 100; while(i < hundredms && checkbool == true){ delay(100); if ((digitalRead(butLeft)==LOW) || (digitalRead(butRight)==LOW)){ resumeLoop(); } i=i+1; } } // Trigger the shutter void snap(){ remote.Snap(); delay(63); remote.Snap(); allOff(); delay(allOffMS); LEDstate(); } // Called by main loop to power all LEDs to selected values void LEDstate(){ digitalWrite(statusPin, LOW); if (progNum == 1) { digitalWrite(progOne, HIGH); digitalWrite(progTwo, LOW); digitalWrite(progThree, LOW); digitalWrite(progFour, LOW); digitalWrite(progFive, LOW); digitalWrite(progSix, LOW); digitalWrite(progSeven, LOW); } if (progNum == 2) { digitalWrite(progOne, LOW); digitalWrite(progTwo, HIGH); digitalWrite(progThree, LOW); digitalWrite(progFour, LOW); digitalWrite(progFive, LOW); digitalWrite(progSix, LOW); digitalWrite(progSeven, LOW); } if (progNum == 3) { digitalWrite(progOne, LOW); digitalWrite(progTwo, LOW); digitalWrite(progThree, HIGH); digitalWrite(progFour, LOW); digitalWrite(progFive, LOW); digitalWrite(progSix, LOW); digitalWrite(progSeven, LOW); } if (progNum == 4) { digitalWrite(progOne, LOW); digitalWrite(progTwo, LOW); digitalWrite(progThree, LOW); digitalWrite(progFour, HIGH); digitalWrite(progFive, LOW); digitalWrite(progSix, LOW); digitalWrite(progSeven, LOW); } if (progNum == 5) { digitalWrite(progOne, LOW); digitalWrite(progTwo, LOW); digitalWrite(progThree, LOW); digitalWrite(progFour, LOW); digitalWrite(progFive, HIGH); digitalWrite(progSix, LOW); digitalWrite(progSeven, LOW); } if (progNum == 6) { digitalWrite(progOne, LOW); digitalWrite(progTwo, LOW); digitalWrite(progThree, LOW); digitalWrite(progFour, LOW); digitalWrite(progFive, LOW); digitalWrite(progSix, HIGH); digitalWrite(progSeven, LOW); } if (progNum == 7) { digitalWrite(progOne, LOW); digitalWrite(progTwo, LOW); digitalWrite(progThree, LOW); digitalWrite(progFour, LOW); digitalWrite(progFive, LOW); digitalWrite(progSix, LOW); digitalWrite(progSeven, HIGH); } /* //simple, overrated approach to the same thing as above. int pin; for (pin = 2; pin <= 8; pin++) { if (pin == progNum+1) { digitalWrite(pin, HIGH); } else { digitalWrite(pin, LOW); } } digitalWrite(statusPin, LOW); */ } //Turn off all LEDs void allOff(){ digitalWrite(progOne, LOW); digitalWrite(progTwo, LOW); digitalWrite(progThree, LOW); digitalWrite(progFour, LOW); digitalWrite(progFive, LOW); digitalWrite(progSix, LOW); digitalWrite(progSeven, LOW); digitalWrite(statusPin, LOW); }