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 = 16; // 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 int updateHeader = 1, updateEncoder = 1, running = 0;
66 // Exposure and Timelapse durations
67 volatile long exposureTime = 0, lapseTime = 0;
68 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)
100 SPDR = data; // Start the transmission
101 while (!(SPSR & (1<<SPIF))) // Wait the end of the transmission
104 return SPDR; // return the received byte
107 void digitalPotInit()
111 pinMode(potData, OUTPUT);
112 pinMode(potClock,OUTPUT);
113 pinMode(potSelect,OUTPUT);
114 digitalWrite(potSelect,HIGH);
115 SPCR = (1<<SPE)|(1<<MSTR);
123 byte write_pot(int address, int value)
125 digitalWrite(potSelect,LOW);
127 spi_transfer(address);
129 digitalWrite(potSelect,HIGH); //release chip, signal end transfer
133 * LCD Control Functions
136 void lcdDataWrite(byte a)
139 shiftOut(lcdData, lcdClock, LSBFIRST, 0x20 + ((a >> 4) & 0xF));
140 digitalWrite(lcdEnable, HIGH);
141 delayMicroseconds(1);
142 digitalWrite(lcdEnable, LOW);
146 shiftOut(lcdData, lcdClock, LSBFIRST, 0x20 + (a & 0xF));
147 digitalWrite(lcdEnable, HIGH);
148 delayMicroseconds(1);
149 digitalWrite(lcdEnable, LOW);
155 void lcdCommandWrite(int a)
158 shiftOut(lcdData, lcdClock, LSBFIRST, (a >> 4) & 0xF);
159 digitalWrite(lcdEnable, HIGH);
160 delayMicroseconds(1);
161 digitalWrite(lcdEnable, LOW);
165 shiftOut(lcdData, lcdClock, LSBFIRST, a & 0xF);
166 digitalWrite(lcdEnable, HIGH);
167 delayMicroseconds(1);
168 digitalWrite(lcdEnable, LOW);
174 void lcdNumberWrite(int nr)
177 int n2 = (nr - n1 * 100) / 10;
180 lcdDataWrite('0' + n2);
182 nr = nr - n1 * 100 - n2 * 10;
183 lcdDataWrite('0' + nr);
186 void lcdHome(int row)
188 lcdCommandWrite(0x02);
193 lcdCommandWrite(0xC0);
200 lcdCommandWrite(0x01);
205 * Hardware initialization functions
212 pinMode(lcdEnable, OUTPUT);
213 pinMode(lcdData, OUTPUT);
214 pinMode(lcdClock, OUTPUT);
216 digitalWrite(lcdClock,LOW);
217 digitalWrite(lcdData,LOW);
218 digitalWrite(lcdEnable,LOW);
220 // there's a chance that when we drop to not running
221 // on top of the arduino bootloader, we'll need a somewhat
222 // significant delay here (called for in the spec, but the bl is slow)
224 lcdCommandWrite(0x03); delay(5);
225 lcdCommandWrite(0x03); delay(1);
226 lcdCommandWrite(0x03); delay(1);
227 lcdCommandWrite(0x02); delay(4);
228 lcdCommandWrite(0x06); delay(1);
229 lcdCommandWrite(0x0C); delay(1);
230 lcdCommandWrite(0x01); delay(4);
231 lcdCommandWrite(0x80); delay(1);
233 pinMode(lcdPower, OUTPUT);
234 digitalWrite(lcdPower, LOW);
239 pinMode(encoderPinA, INPUT);
240 digitalWrite(encoderPinA, HIGH);
241 pinMode(encoderPinB, INPUT);
242 digitalWrite(encoderPinB, HIGH);
244 attachInterrupt(0, doEncoderA, CHANGE);
245 attachInterrupt(1, doEncoderB, CHANGE);
250 pinMode(cameraShutter, OUTPUT);
251 digitalWrite(cameraShutter, HIGH);
253 pinMode(triggerReset, OUTPUT);
254 // keep the reset high except when in trigger mode, so we don't accidentally trigger!
255 digitalWrite(triggerReset, LOW);
262 void incrementValue()
266 if(lapseRepresentation == 0)
273 if(exposureRepresentation == 0)
278 if(exposureTime > lapseTime)
279 lapseTime = exposureTime;
283 void decrementValue()
287 if(lapseRepresentation == 0 || lapseTime == 60) // careful around transition; thanks, nate
297 if(exposureRepresentation == 0 || exposureTime == 60)
307 void updateTimeRepresentations()
310 lapseRepresentation = 1;
312 lapseRepresentation = 0;
314 if(exposureTime >= 60)
315 exposureRepresentation = 1;
317 exposureRepresentation = 0;
328 delayMicroseconds(3000); // maximum bounce time, accd. to spec.
330 if (digitalRead(encoderPinA) == HIGH)
332 if (digitalRead(encoderPinB) == LOW)
339 if (digitalRead(encoderPinB) == HIGH)
345 updateTimeRepresentations();
357 delayMicroseconds(3000);
358 if (digitalRead(encoderPinB) == HIGH)
360 if (digitalRead(encoderPinA) == HIGH)
367 if (digitalRead(encoderPinA) == LOW)
373 updateTimeRepresentations();
381 unsigned long diff = (millis() - lastModeUpdate);
383 if(diff < 300) // careful about the overflow...
385 lastModeUpdate = millis();
389 lastModeUpdate = millis();
395 if(currentMode == BULB)
400 if(currentMode == TRIGGER)
401 digitalWrite(triggerReset, HIGH);
403 digitalWrite(triggerReset, LOW);
409 void switchSelected()
411 if(currentMode == INTERVALBULB)
413 unsigned long diff = (millis() - lastSelectedUpdate);
415 if(diff < 300) // careful about the overflow...
417 lastSelectedUpdate = millis();
421 lastSelectedUpdate = millis();
423 selected = !selected;
431 unsigned long diff = (millis() - lastToggleRunning);
433 if(diff < 300) // careful about the overflow...
435 lastToggleRunning = millis();
439 lastToggleRunning = millis();
446 void drawTimecode(int secs, int rep)
450 lcdNumberWrite(secs);
455 lcdNumberWrite(secs/60);
460 int timecodeLength(int secs, int rep)
468 int n2 = (secs - n1 * 100) / 10;
476 char *modeHeader[4] = {"Interval", " Bulb", "Interval Bulb", "Trigger"};
488 write_pot(5,--pot / 3.0);
499 for (count = 0; modeHeader[currentMode][count] != 0; count++)
500 lcdDataWrite(modeHeader[currentMode][count]);
501 for (; count < 16; count++)
512 if(currentMode != BULB)
513 drawTimecode(lapseTime, lapseRepresentation);
517 if(currentMode != BULB)
518 width += timecodeLength(lapseTime, lapseRepresentation);
519 if(currentMode != INTERVAL && currentMode != TRIGGER)
520 width += timecodeLength(exposureTime, exposureRepresentation);
524 lcdDataWrite(' '); width++;
525 lcdDataWrite(127); width++;
532 for(int i = 16; i > width; i--)
541 if(currentMode != INTERVAL && currentMode != TRIGGER)
542 drawTimecode(exposureTime, exposureRepresentation);
547 //if(!digitalRead(buttonA))
552 digitalWrite(lcdPower, HIGH);
554 if(currentMode == TRIGGER)
556 if(!digitalRead(triggerInput)) // 100 might change with different resistors, make sure it works!
558 digitalWrite(triggerReset, HIGH);
559 delay(100); // this should probably be at least the time of the delay from signal (in the 555)...
560 digitalWrite(triggerReset, LOW);
562 digitalWrite(triggerReset, HIGH);
568 unsigned long diff = millis() - lastShutter;
570 int adjustedLapseTime = lapseTime;
571 if(currentMode != INTERVAL)
572 adjustedLapseTime -= exposureTime;
574 if(diff > (adjustedLapseTime * 1000)) // careful about the overflow...
576 digitalWrite(cameraShutter, LOW);
578 if(currentMode == INTERVAL)
581 delay(exposureTime * 1000); //delay for length of exposure
582 // biggest problem with this is that you can't stop a bulb (of either type)
583 // in the middle... you have to power off the intervalometer; same as you would have
584 // to do with a camera, I suppose, so people might be used to it.
585 // however, we can get around this by looping and checking millis()...
587 digitalWrite(cameraShutter, HIGH);
588 lastShutter = millis();
590 if(currentMode == BULB)
596 digitalWrite(lcdPower, LOW);
598 //if(!digitalRead(buttonB))
601 //if(!digitalRead(encoderButton))