2 * Arduino Intervalometer
6 enum {INTERVAL, BULB, INTERVALBULB, TRIGGER};
14 int triggerInput = 2; // Feedback for trigger reset
16 int encoderButton = 3; // Encoder pushbutton
17 int buttonA = 4; // Left pushbutton
18 int buttonB = 5; // Right pushbutton
22 int cameraShutter = 0; // Pulse low for shutter release
24 int encoderPinA = 2; // HW interrupt
25 int encoderPinB = 3; // HW interrupt
28 int lcdDataBus[] = { 4, 5, 6, 7 };
32 int triggerReset = 12;
34 int potSelect = 10; // SPI (SS) for digital pots
35 int potData = 11; // SPI (MOSI) for digital pots
36 int potClock = 13; // SPI (SCK) for digital pots
38 /////////////////////////////
40 int currentMode = INTERVAL, selected = 0;
43 // Debouncing time variables
44 unsigned long lastToggleRunning = 0;
45 unsigned long lastModeUpdate = 0;
46 unsigned long lastSelectedUpdate = 0;
48 unsigned long lastShutter = 0;
50 int updateHeader = 1, updateEncoder = 1;
52 volatile long exposureTime = 0, lapseTime = 0;
53 int exposureRepresentation = 0, lapseRepresentation = 0;
56 * Higher level hardware functions
59 void pulsePin(int pin, int value)
61 digitalWrite(pin, !value);
63 digitalWrite(pin, value);
65 digitalWrite(pin, !value);
70 * LCD Control Functions
73 void lcdCommandWrite(int value)
80 for (i = lcdDataBus[0]; i <= lcdDataInt; i++)
82 digitalWrite(i,value1 & 01);
86 pulsePin(lcdEnable, HIGH);
89 for (i = lcdDataBus[0]; i <= lcdDataBus[3]; i++)
91 digitalWrite(i, value & 01);
97 for (i = lcdDataClock; i <= lcdDataInt; i++)
99 digitalWrite(i, value & 01);
103 pulsePin(lcdEnable, HIGH);
106 void lcdDataWrite(int value)
111 digitalWrite(lcdDataInt, HIGH);
112 digitalWrite(lcdDataClock, LOW);
116 for (i=lcdDataBus[0]; i <= lcdDataBus[3]; i++)
118 digitalWrite(i,value1 & 01);
122 pulsePin(lcdEnable, HIGH);
125 digitalWrite(lcdDataInt, HIGH);
126 digitalWrite(lcdDataClock, LOW);
128 for (i=lcdDataBus[0]; i <= lcdDataBus[3]; i++)
130 digitalWrite(i,value & 01);
134 pulsePin(lcdEnable, HIGH);
137 void lcdNumberWrite(int nr)
140 int n2 = (nr - n1 * 100) / 10;
143 lcdCommandWrite(560 + n2);
145 nr = nr - n1 * 100 - n2 * 10;
146 lcdCommandWrite(560 + nr);
149 void lcdHome(int row)
151 lcdCommandWrite(0x02);
156 lcdCommandWrite(0xC0);
163 lcdCommandWrite(0x01);
168 * Hardware initialization functions
175 for (i = lcdEnable; i <= lcdDataInt; i++)
178 // there's a chance that when we drop to not running
179 // on top of the arduino bootloader, we'll need a somewhat
180 // significant delay here (called for in the spec, but the bl is slow)
182 lcdCommandWrite(0x03); delay(64);
183 lcdCommandWrite(0x03); delay(50);
184 lcdCommandWrite(0x03); delay(50);
185 lcdCommandWrite(0x02); delay(50);
186 lcdCommandWrite(0x2C); delay(20);
187 lcdCommandWrite(0x06); delay(20);
188 lcdCommandWrite(0x0C); delay(20);
189 lcdCommandWrite(0x01); delay(100);
190 lcdCommandWrite(0x80); delay(30);
195 pinMode(encoderPinA, INPUT);
196 digitalWrite(encoderPinA, HIGH);
197 pinMode(encoderPinB, INPUT);
198 digitalWrite(encoderPinB, HIGH);
200 attachInterrupt(0, doEncoderA, CHANGE);
201 attachInterrupt(1, doEncoderB, CHANGE);
206 pinMode(cameraShutter, OUTPUT);
207 digitalWrite(cameraShutter, HIGH);
209 pinMode(triggerReset, OUTPUT);
210 // keep the reset low except when in trigger mode, so we don't accidentally trigger!
211 digitalWrite(triggerReset, LOW);
217 void incrementValue()
221 if(lapseRepresentation == 0)
228 if(exposureRepresentation == 0)
233 if(exposureTime > lapseTime)
234 lapseTime = exposureTime;
238 void decrementValue()
242 if(lapseRepresentation == 0 || lapseTime == 60) // careful around transition; thanks, nate
252 if(exposureRepresentation == 0 || exposureTime == 60)
268 delayMicroseconds(3000); // maximum bounce time, accd. to spec.
269 // should we use optical encoders instead?
270 if (digitalRead(encoderPinA) == HIGH)
272 if (digitalRead(encoderPinB) == LOW)
279 if (digitalRead(encoderPinB) == HIGH)
286 lapseRepresentation = 1;
288 lapseRepresentation = 0;
290 if(exposureTime >= 60)
291 exposureRepresentation = 1;
293 exposureRepresentation = 0;
305 delayMicroseconds(3000);
306 if (digitalRead(encoderPinB) == HIGH)
308 if (digitalRead(encoderPinA) == HIGH)
315 if (digitalRead(encoderPinA) == LOW)
322 lapseRepresentation = 1;
324 lapseRepresentation = 0;
326 if(exposureTime >= 60)
327 exposureRepresentation = 1;
329 exposureRepresentation = 0;
337 unsigned long diff = (millis() - lastModeUpdate);
339 if(diff < 300) // careful about the overflow...
341 lastModeUpdate = millis();
345 lastModeUpdate = millis();
351 if(currentMode == BULB)
356 if(currentMode == TRIGGER)
357 digitalWrite(triggerReset, HIGH);
359 digitalWrite(triggerReset, LOW);
365 void switchSelected()
367 if(currentMode == INTERVALBULB)
369 unsigned long diff = (millis() - lastSelectedUpdate);
371 if(diff < 300) // careful about the overflow...
373 lastSelectedUpdate = millis();
377 lastSelectedUpdate = millis();
379 selected = !selected;
387 unsigned long diff = (millis() - lastToggleRunning);
389 if(diff < 300) // careful about the overflow...
391 lastToggleRunning = millis();
395 lastToggleRunning = millis();
401 void drawTimecode(int secs, int rep)
405 lcdNumberWrite(secs);
410 lcdNumberWrite(secs/60);
415 int timecodeLength(int secs, int rep)
423 int n2 = (secs - n1 * 100) / 10;
431 char *modeHeader[4] = {"Interval", " Bulb", "Interval Bulb", "Trigger"};
440 for (count = 0; modeHeader[currentMode][count] != 0; count++)
441 lcdDataWrite(modeHeader[currentMode][count]);
442 for (; count < 16; count++)
453 if(currentMode != BULB)
454 drawTimecode(lapseTime, lapseRepresentation);
458 if(currentMode != BULB)
459 width += timecodeLength(lapseTime, lapseRepresentation);
460 if(currentMode != INTERVAL && currentMode != TRIGGER)
461 width += timecodeLength(exposureTime, exposureRepresentation);
465 lcdDataWrite(' '); width++;
466 lcdDataWrite(127); width++;
473 for(int i = 16; i > width; i--)
482 if(currentMode != INTERVAL && currentMode != TRIGGER)
483 drawTimecode(exposureTime, exposureRepresentation);
488 if(analogRead(buttonA) == 0)
493 lcdCommandWrite(0xD3); // /should/ shift us to middle of bottom row
494 lcdDataWrite('*'); // animated?
496 if(currentMode == TRIGGER)
498 // do special trigger stuff
500 if(analogRead(triggerInput) < 100) // 100 might change with different resistors, make sure it works!
502 digitalWrite(triggerReset, HIGH);
503 delay(100); // this should probably be at least the time of the delay...
504 digitalWrite(triggerReset, LOW);
506 digitalWrite(triggerReset, HIGH);
512 unsigned long diff = millis() - lastShutter;
514 int adjustedLapseTime = lapseTime;
515 if(currentMode != INTERVAL)
516 adjustedLapseTime -= exposureTime;
518 if(diff > (adjustedLapseTime * 1000)) // careful about the overflow...
520 digitalWrite(cameraShutter, LOW);
522 if(currentMode == INTERVAL)
525 delay(exposureTime * 1000); //delay for length of exposure
527 digitalWrite(cameraShutter, HIGH);
528 lastShutter = millis();
530 if(currentMode == BULB)
536 if(analogRead(buttonB) == 0)
539 if(analogRead(encoderButton) == 0)