2 * Arduino Intervalometer
6 enum {INTERVAL, BULB, INTERVALBULB, TRIGGER};
12 // Running/Shutter LEDs (through digital pots)
13 // Contrast adjustment (through digital pots/encoder)
15 // Speed up encoder more, later in the 'minute' range
16 // Slow down encoder in second range/normally
17 // Hour representation?
18 // Either need to support more digits, or arbitrarily limit durations
19 // Fix when trigger is triggered and someone (ROBB) stops it (and it keeps open)
20 // Why does trigger reset not get put back when we're done triggering!?
21 // External power supply?
27 int cameraShutter = 0; // Pulse low for shutter release
29 int triggerReset = 1; // Resets trigger latch on low pulse
30 // Prevents trigger if held low
32 int encoderPinA = 2; // HW interrupt
33 int encoderPinB = 3; // HW interrupt
35 int lcdPower = 4; // Pull low to power the LCD backlight
36 int lcdEnable = 7; // LCD Enable - pin 6 on LCD module
37 int lcdClock = 8; // Shift register clock
38 int lcdData = 9; // Shift register data
40 int potSelect = 10; // SPI (SS) for digital pots
41 int potData = 11; // SPI (MOSI) for digital pots
42 int badSPIpin = 12; // SPI (MISO) for nothing, unusable
43 int potClock = 13; // SPI (SCK) for digital pots
45 int triggerInput = 2; // Feedback for trigger reset
46 int encoderButton = 17; // Encoder pushbutton
47 int buttonA = 18; // Left pushbutton
48 int buttonB = 19; // Right pushbutton
51 * Digital Pot Assignment
61 /////////////////////////////
65 int currentMode = INTERVAL, selected = 0;
67 // Debouncing time variables
68 unsigned long lastToggleRunning = 0;
69 unsigned long lastModeUpdate = 0;
70 unsigned long lastSelectedUpdate = 0;
71 unsigned long lastShutter = 0;
75 volatile int updateHeader = 1, updateEncoder = 1, running = 0;
77 // Exposure and Timelapse durations
78 volatile long exposureTime = 0, lapseTime = 0;
79 volatile int exposureRepresentation = 0, lapseRepresentation = 0;
82 * Higher level hardware functions
85 void pulsePin(int pin, int value)
87 digitalWrite(pin, !value);
89 digitalWrite(pin, value);
91 digitalWrite(pin, !value);
95 void parallelShiftOut(int firstPin, int lastPin, int & value)
98 for(i = firstPin; i <= lastPin; i++)
100 digitalWrite(i, value & 0x01);
106 * Digital Pot Control Functions
109 char spi_transfer(volatile char data)
112 while (!(SPSR & (1<<SPIF))) {};
116 void digitalPotInit()
120 pinMode(potData, OUTPUT);
121 pinMode(potClock,OUTPUT);
122 pinMode(potSelect,OUTPUT);
123 digitalWrite(potSelect,HIGH);
124 SPCR = (1<<SPE)|(1<<MSTR);
132 byte write_pot(int address, int value)
134 digitalWrite(potSelect,LOW);
135 spi_transfer(address);
137 digitalWrite(potSelect,HIGH);
141 * LCD Control Functions
144 void lcdDataWrite(byte a)
147 shiftOut(lcdData, lcdClock, LSBFIRST, 0x20 + ((a >> 4) & 0xF));
148 digitalWrite(lcdEnable, HIGH);
149 delayMicroseconds(1);
150 digitalWrite(lcdEnable, LOW);
154 shiftOut(lcdData, lcdClock, LSBFIRST, 0x20 + (a & 0xF));
155 digitalWrite(lcdEnable, HIGH);
156 delayMicroseconds(1);
157 digitalWrite(lcdEnable, LOW);
163 void lcdCommandWrite(int a)
166 shiftOut(lcdData, lcdClock, LSBFIRST, (a >> 4) & 0xF);
167 digitalWrite(lcdEnable, HIGH);
168 delayMicroseconds(1);
169 digitalWrite(lcdEnable, LOW);
173 shiftOut(lcdData, lcdClock, LSBFIRST, a & 0xF);
174 digitalWrite(lcdEnable, HIGH);
175 delayMicroseconds(1);
176 digitalWrite(lcdEnable, LOW);
182 void lcdNumberWrite(int nr)
185 int n2 = (nr - n1 * 100) / 10;
188 lcdDataWrite('0' + n2);
190 nr = nr - n1 * 100 - n2 * 10;
191 lcdDataWrite('0' + nr);
194 void lcdHome(int row)
196 lcdCommandWrite(0x02);
201 lcdCommandWrite(0xC0);
208 lcdCommandWrite(0x01);
213 * Hardware initialization functions
220 pinMode(lcdEnable, OUTPUT);
221 pinMode(lcdData, OUTPUT);
222 pinMode(lcdClock, OUTPUT);
224 digitalWrite(lcdClock,LOW);
225 digitalWrite(lcdData,LOW);
226 digitalWrite(lcdEnable,LOW);
228 // there's a chance that when we drop to not running
229 // on top of the arduino bootloader, we'll need a somewhat
230 // significant delay here (called for in the spec, but the bl is slow)
232 lcdCommandWrite(0x03); delay(5);
233 lcdCommandWrite(0x03); delay(1);
234 lcdCommandWrite(0x03); delay(1);
235 lcdCommandWrite(0x02); delay(4);
236 lcdCommandWrite(0x06); delay(1);
237 lcdCommandWrite(0x0C); delay(1);
238 lcdCommandWrite(0x01); delay(4);
239 lcdCommandWrite(0x80); delay(1);
241 pinMode(lcdPower, OUTPUT);
242 digitalWrite(lcdPower, LOW);
247 pinMode(encoderPinA, INPUT);
248 digitalWrite(encoderPinA, HIGH);
249 pinMode(encoderPinB, INPUT);
250 digitalWrite(encoderPinB, HIGH);
252 attachInterrupt(0, doEncoderA, CHANGE);
253 attachInterrupt(1, doEncoderB, CHANGE);
258 pinMode(cameraShutter, OUTPUT);
259 digitalWrite(cameraShutter, HIGH);
261 pinMode(triggerReset, OUTPUT);
262 // keep the reset high except when in trigger mode, so we don't accidentally trigger!
263 digitalWrite(triggerReset, LOW);
270 void incrementValue()
274 if(lapseRepresentation == 0)
281 if(exposureRepresentation == 0)
286 if(exposureTime > lapseTime)
287 lapseTime = exposureTime;
291 void decrementValue()
295 if(lapseRepresentation == 0 || lapseTime == 60) // careful around transition; thanks, nate
305 if(exposureRepresentation == 0 || exposureTime == 60)
315 void updateTimeRepresentations()
318 lapseRepresentation = 1;
320 lapseRepresentation = 0;
322 if(exposureTime >= 60)
323 exposureRepresentation = 1;
325 exposureRepresentation = 0;
336 delayMicroseconds(3000); // maximum bounce time, accd. to spec.
338 if (digitalRead(encoderPinA) == HIGH)
340 if (digitalRead(encoderPinB) == LOW)
347 if (digitalRead(encoderPinB) == HIGH)
353 updateTimeRepresentations();
365 delayMicroseconds(3000);
366 if (digitalRead(encoderPinB) == HIGH)
368 if (digitalRead(encoderPinA) == HIGH)
375 if (digitalRead(encoderPinA) == LOW)
381 updateTimeRepresentations();
389 unsigned long diff = (millis() - lastModeUpdate);
391 if(diff < 300) // careful about the overflow...
393 lastModeUpdate = millis();
397 lastModeUpdate = millis();
403 if(currentMode == BULB)
408 if(currentMode == TRIGGER)
409 digitalWrite(triggerReset, HIGH);
411 digitalWrite(triggerReset, LOW);
417 void switchSelected()
419 if(currentMode == INTERVALBULB)
421 unsigned long diff = (millis() - lastSelectedUpdate);
423 if(diff < 300) // careful about the overflow...
425 lastSelectedUpdate = millis();
429 lastSelectedUpdate = millis();
431 selected = !selected;
439 unsigned long diff = (millis() - lastToggleRunning);
441 if(diff < 300) // careful about the overflow...
443 lastToggleRunning = millis();
447 lastToggleRunning = millis();
454 void drawTimecode(int secs, int rep)
458 lcdNumberWrite(secs);
463 lcdNumberWrite(secs/60);
468 int timecodeLength(int secs, int rep)
476 int n2 = (secs - n1 * 100) / 10;
484 char *modeHeader[4] = {"Interval", " Bulb", "Interval Bulb", "Trigger"};
493 write_pot(ledRPot, 20);
494 write_pot(ledGPot, 255);
495 write_pot(ledBPot, 255);
496 write_pot(timerPot, 255);
500 write_pot(contrastPot, --pot / 3.0);
509 for (count = 0; modeHeader[currentMode][count] != 0; count++)
510 lcdDataWrite(modeHeader[currentMode][count]);
511 for (; count < 16; count++)
522 if(currentMode != BULB)
523 drawTimecode(lapseTime, lapseRepresentation);
527 if(currentMode != BULB)
528 width += timecodeLength(lapseTime, lapseRepresentation);
529 if(currentMode != INTERVAL && currentMode != TRIGGER)
530 width += timecodeLength(exposureTime, exposureRepresentation);
534 lcdDataWrite(' '); width++;
535 lcdDataWrite(127); width++;
542 for(int i = 16; i > width; i--)
551 if(currentMode != INTERVAL && currentMode != TRIGGER)
552 drawTimecode(exposureTime, exposureRepresentation);
557 if(!digitalRead(buttonA))
562 digitalWrite(lcdPower, HIGH);
564 if(currentMode == TRIGGER)
566 if(analogRead(triggerInput) < 100) // 100 might change with different resistors, make sure it works!
568 digitalWrite(triggerReset, HIGH);
569 delay(100); // this should probably be at least the time of the delay from signal (in the 555)...
570 digitalWrite(triggerReset, LOW);
572 digitalWrite(triggerReset, HIGH);
578 unsigned long diff = millis() - lastShutter;
580 int adjustedLapseTime = lapseTime;
581 if(currentMode != INTERVAL)
582 adjustedLapseTime -= exposureTime;
584 if(diff > (adjustedLapseTime * 1000)) // careful about the overflow...
586 digitalWrite(cameraShutter, LOW);
588 if(currentMode == INTERVAL)
591 delay(exposureTime * 1000); //delay for length of exposure
592 // biggest problem with this is that you can't stop a bulb (of either type)
593 // in the middle... you have to power off the intervalometer; same as you would have
594 // to do with a camera, I suppose, so people might be used to it.
595 // however, we can get around this by looping and checking millis()...
597 digitalWrite(cameraShutter, HIGH);
598 lastShutter = millis();
600 if(currentMode == BULB)
606 digitalWrite(lcdPower, LOW);
608 if(!digitalRead(buttonB))
611 if(!digitalRead(encoderButton))