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
50 /////////////////////////////
54 int currentMode = INTERVAL, selected = 0;
56 // Debouncing time variables
57 unsigned long lastToggleRunning = 0;
58 unsigned long lastModeUpdate = 0;
59 unsigned long lastSelectedUpdate = 0;
60 unsigned long lastShutter = 0;
64 volatile int updateHeader = 1, updateEncoder = 1, running = 0;
66 // Exposure and Timelapse durations
67 volatile long exposureTime = 0, lapseTime = 0;
68 volatile int exposureRepresentation = 0, lapseRepresentation = 0;
71 * Higher level hardware functions
74 void pulsePin(int pin, int value)
76 digitalWrite(pin, !value);
78 digitalWrite(pin, value);
80 digitalWrite(pin, !value);
84 void parallelShiftOut(int firstPin, int lastPin, int & value)
87 for(i = firstPin; i <= lastPin; i++)
89 digitalWrite(i, value & 0x01);
95 * Digital Pot Control Functions
98 char spi_transfer(volatile char data)
101 while (!(SPSR & (1<<SPIF))) {};
105 void digitalPotInit()
109 pinMode(potData, OUTPUT);
110 pinMode(potClock,OUTPUT);
111 pinMode(potSelect,OUTPUT);
112 digitalWrite(potSelect,HIGH);
113 SPCR = (1<<SPE)|(1<<MSTR);
121 byte write_pot(int address, int value)
123 digitalWrite(potSelect,LOW);
124 spi_transfer(address);
126 digitalWrite(potSelect,HIGH);
130 * LCD Control Functions
133 void lcdDataWrite(byte a)
136 shiftOut(lcdData, lcdClock, LSBFIRST, 0x20 + ((a >> 4) & 0xF));
137 digitalWrite(lcdEnable, HIGH);
138 delayMicroseconds(1);
139 digitalWrite(lcdEnable, LOW);
143 shiftOut(lcdData, lcdClock, LSBFIRST, 0x20 + (a & 0xF));
144 digitalWrite(lcdEnable, HIGH);
145 delayMicroseconds(1);
146 digitalWrite(lcdEnable, LOW);
152 void lcdCommandWrite(int a)
155 shiftOut(lcdData, lcdClock, LSBFIRST, (a >> 4) & 0xF);
156 digitalWrite(lcdEnable, HIGH);
157 delayMicroseconds(1);
158 digitalWrite(lcdEnable, LOW);
162 shiftOut(lcdData, lcdClock, LSBFIRST, a & 0xF);
163 digitalWrite(lcdEnable, HIGH);
164 delayMicroseconds(1);
165 digitalWrite(lcdEnable, LOW);
171 void lcdNumberWrite(int nr)
174 int n2 = (nr - n1 * 100) / 10;
177 lcdDataWrite('0' + n2);
179 nr = nr - n1 * 100 - n2 * 10;
180 lcdDataWrite('0' + nr);
183 void lcdHome(int row)
185 lcdCommandWrite(0x02);
190 lcdCommandWrite(0xC0);
197 lcdCommandWrite(0x01);
202 * Hardware initialization functions
209 pinMode(lcdEnable, OUTPUT);
210 pinMode(lcdData, OUTPUT);
211 pinMode(lcdClock, OUTPUT);
213 digitalWrite(lcdClock,LOW);
214 digitalWrite(lcdData,LOW);
215 digitalWrite(lcdEnable,LOW);
217 // there's a chance that when we drop to not running
218 // on top of the arduino bootloader, we'll need a somewhat
219 // significant delay here (called for in the spec, but the bl is slow)
221 lcdCommandWrite(0x03); delay(5);
222 lcdCommandWrite(0x03); delay(1);
223 lcdCommandWrite(0x03); delay(1);
224 lcdCommandWrite(0x02); delay(4);
225 lcdCommandWrite(0x06); delay(1);
226 lcdCommandWrite(0x0C); delay(1);
227 lcdCommandWrite(0x01); delay(4);
228 lcdCommandWrite(0x80); delay(1);
230 pinMode(lcdPower, OUTPUT);
231 digitalWrite(lcdPower, LOW);
236 pinMode(encoderPinA, INPUT);
237 digitalWrite(encoderPinA, HIGH);
238 pinMode(encoderPinB, INPUT);
239 digitalWrite(encoderPinB, HIGH);
241 attachInterrupt(0, doEncoderA, CHANGE);
242 attachInterrupt(1, doEncoderB, CHANGE);
247 pinMode(cameraShutter, OUTPUT);
248 digitalWrite(cameraShutter, HIGH);
250 pinMode(triggerReset, OUTPUT);
251 // keep the reset high except when in trigger mode, so we don't accidentally trigger!
252 digitalWrite(triggerReset, LOW);
259 void incrementValue()
263 if(lapseRepresentation == 0)
270 if(exposureRepresentation == 0)
275 if(exposureTime > lapseTime)
276 lapseTime = exposureTime;
280 void decrementValue()
284 if(lapseRepresentation == 0 || lapseTime == 60) // careful around transition; thanks, nate
294 if(exposureRepresentation == 0 || exposureTime == 60)
304 void updateTimeRepresentations()
307 lapseRepresentation = 1;
309 lapseRepresentation = 0;
311 if(exposureTime >= 60)
312 exposureRepresentation = 1;
314 exposureRepresentation = 0;
325 delayMicroseconds(3000); // maximum bounce time, accd. to spec.
327 if (digitalRead(encoderPinA) == HIGH)
329 if (digitalRead(encoderPinB) == LOW)
336 if (digitalRead(encoderPinB) == HIGH)
342 updateTimeRepresentations();
354 delayMicroseconds(3000);
355 if (digitalRead(encoderPinB) == HIGH)
357 if (digitalRead(encoderPinA) == HIGH)
364 if (digitalRead(encoderPinA) == LOW)
370 updateTimeRepresentations();
378 unsigned long diff = (millis() - lastModeUpdate);
380 if(diff < 300) // careful about the overflow...
382 lastModeUpdate = millis();
386 lastModeUpdate = millis();
392 if(currentMode == BULB)
397 if(currentMode == TRIGGER)
398 digitalWrite(triggerReset, HIGH);
400 digitalWrite(triggerReset, LOW);
406 void switchSelected()
408 if(currentMode == INTERVALBULB)
410 unsigned long diff = (millis() - lastSelectedUpdate);
412 if(diff < 300) // careful about the overflow...
414 lastSelectedUpdate = millis();
418 lastSelectedUpdate = millis();
420 selected = !selected;
428 unsigned long diff = (millis() - lastToggleRunning);
430 if(diff < 300) // careful about the overflow...
432 lastToggleRunning = millis();
436 lastToggleRunning = millis();
443 void drawTimecode(int secs, int rep)
447 lcdNumberWrite(secs);
452 lcdNumberWrite(secs/60);
457 int timecodeLength(int secs, int rep)
465 int n2 = (secs - n1 * 100) / 10;
473 char *modeHeader[4] = {"Interval", " Bulb", "Interval Bulb", "Trigger"};
489 write_pot(5,--pot / 3.0);
498 for (count = 0; modeHeader[currentMode][count] != 0; count++)
499 lcdDataWrite(modeHeader[currentMode][count]);
500 for (; count < 16; count++)
511 if(currentMode != BULB)
512 drawTimecode(lapseTime, lapseRepresentation);
516 if(currentMode != BULB)
517 width += timecodeLength(lapseTime, lapseRepresentation);
518 if(currentMode != INTERVAL && currentMode != TRIGGER)
519 width += timecodeLength(exposureTime, exposureRepresentation);
523 lcdDataWrite(' '); width++;
524 lcdDataWrite(127); width++;
531 for(int i = 16; i > width; i--)
540 if(currentMode != INTERVAL && currentMode != TRIGGER)
541 drawTimecode(exposureTime, exposureRepresentation);
546 if(!digitalRead(buttonA))
551 digitalWrite(lcdPower, HIGH);
553 if(currentMode == TRIGGER)
555 if(analogRead(triggerInput) < 100) // 100 might change with different resistors, make sure it works!
557 digitalWrite(triggerReset, HIGH);
558 delay(100); // this should probably be at least the time of the delay from signal (in the 555)...
559 digitalWrite(triggerReset, LOW);
561 digitalWrite(triggerReset, HIGH);
567 unsigned long diff = millis() - lastShutter;
569 int adjustedLapseTime = lapseTime;
570 if(currentMode != INTERVAL)
571 adjustedLapseTime -= exposureTime;
573 if(diff > (adjustedLapseTime * 1000)) // careful about the overflow...
575 digitalWrite(cameraShutter, LOW);
577 if(currentMode == INTERVAL)
580 delay(exposureTime * 1000); //delay for length of exposure
581 // biggest problem with this is that you can't stop a bulb (of either type)
582 // in the middle... you have to power off the intervalometer; same as you would have
583 // to do with a camera, I suppose, so people might be used to it.
584 // however, we can get around this by looping and checking millis()...
586 digitalWrite(cameraShutter, HIGH);
587 lastShutter = millis();
589 if(currentMode == BULB)
595 digitalWrite(lcdPower, LOW);
597 if(!digitalRead(buttonB))
600 if(!digitalRead(encoderButton))