2 * Arduino Intervalometer
6 enum {INTERVAL, BULB, INTERVALBULB, TRIGGER};
8 // There's currently a bug in arduino12 which breaks interrupts.
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?
22 // preferences: save if we want to use the LED, contrast, etc. in eeprom
30 int triggerInput = 2; // Feedback for trigger reset
34 int cameraShutter = 0; // Pulse low for shutter release
36 int triggerReset = 1; // Resets trigger latch on low pulse
37 // Prevents trigger if held low
39 int encoderPinA = 2; // HW interrupt
40 int encoderPinB = 3; // HW interrupt
42 int lcdPower = 4; // Pull low to power the LCD backlight
43 int lcdEnable = 7; // LCD Enable - pin 6 on LCD module
44 int lcdClock = 8; // Shift register clock
45 int lcdData = 9; // Shift register data
47 int potSelect = 10; // SPI (SS) for digital pots
48 int potData = 11; // SPI (MOSI) for digital pots
49 int badSPIpin = 12; // SPI (MISO) for nothing, unusable
50 int potClock = 13; // SPI (SCK) for digital pots
52 int encoderButton = 17; // Encoder pushbutton
53 int buttonA = 18; // Left pushbutton
54 int buttonB = 19; // Right pushbutton
57 * Digital Pot Assignment
67 /////////////////////////////
69 volatile int writing = 0;
71 int currentMode = INTERVAL, selected = 0, changeSelected = 0;
73 // Debouncing time variables
74 unsigned long lastToggleRunning = 0;
75 unsigned long lastModeUpdate = 0;
76 unsigned long lastSelectedUpdate = 0;
77 unsigned long lastShutter = 0;
81 volatile int updateHeader = 1, updateEncoder = 1, running = 0;
83 // Exposure and Timelapse durations
84 volatile long exposureTime = 0, lapseTime = 0;
85 volatile int exposureRepresentation = 0, lapseRepresentation = 0;
87 volatile int contrastValue = 1000;
90 * Higher level hardware functions
93 void pulsePin(int pin, int value)
95 digitalWrite(pin, !value);
97 digitalWrite(pin, value);
99 digitalWrite(pin, !value);
103 void parallelShiftOut(int firstPin, int lastPin, int & value)
106 for(i = firstPin; i <= lastPin; i++)
108 digitalWrite(i, value & 0x01);
114 * Digital Pot Control Functions
117 char spi_transfer(volatile char data)
120 while (!(SPSR & (1<<SPIF))) {};
124 void digitalPotInit()
128 pinMode(potData, OUTPUT);
129 pinMode(potClock,OUTPUT);
130 pinMode(potSelect,OUTPUT);
131 digitalWrite(potSelect,HIGH);
132 SPCR = (1<<SPE)|(1<<MSTR);
140 byte write_pot(int address, int value)
142 digitalWrite(potSelect,LOW);
143 spi_transfer(address);
145 digitalWrite(potSelect,HIGH);
149 * LCD Control Functions
152 void lcdDataWrite(byte a)
158 shiftOut(lcdData, lcdClock, LSBFIRST, 0x20 + ((a >> 4) & 0xF));
159 pulsePin(lcdEnable, HIGH);
161 shiftOut(lcdData, lcdClock, LSBFIRST, 0x20 + (a & 0xF));
162 pulsePin(lcdEnable, HIGH);
169 void lcdCommandWrite(int a)
175 shiftOut(lcdData, lcdClock, LSBFIRST, (a >> 4) & 0xF);
176 pulsePin(lcdEnable, HIGH);
178 shiftOut(lcdData, lcdClock, LSBFIRST, a & 0xF);
179 pulsePin(lcdEnable, HIGH);
186 void lcdNumberWrite(int nr)
189 int n2 = (nr - n1 * 100) / 10;
192 lcdDataWrite('0' + n2);
194 nr = nr - n1 * 100 - n2 * 10;
195 lcdDataWrite('0' + nr);
198 void lcdHome(int row)
200 lcdCommandWrite(0x02);
205 lcdCommandWrite(0xC0);
212 lcdCommandWrite(0x01);
217 * Hardware initialization functions
224 pinMode(lcdEnable, OUTPUT);
225 pinMode(lcdData, OUTPUT);
226 pinMode(lcdClock, OUTPUT);
228 digitalWrite(lcdClock,LOW);
229 digitalWrite(lcdData,LOW);
230 digitalWrite(lcdEnable,LOW);
232 // there's a chance that when we drop to not running
233 // on top of the arduino bootloader, we'll need a somewhat
234 // significant delay here (called for in the spec, but the bl is slow)
236 lcdCommandWrite(0x03); delay(5);
237 lcdCommandWrite(0x03); delay(1);
238 lcdCommandWrite(0x03); delay(1);
239 lcdCommandWrite(0x02); delay(4);
240 lcdCommandWrite(0x06); delay(1);
241 lcdCommandWrite(0x0C); delay(1);
242 lcdCommandWrite(0x01); delay(4);
243 lcdCommandWrite(0x80); delay(1);
245 pinMode(lcdPower, OUTPUT);
246 digitalWrite(lcdPower, HIGH);
251 pinMode(encoderPinA, INPUT);
252 digitalWrite(encoderPinA, HIGH);
253 pinMode(encoderPinB, INPUT);
254 digitalWrite(encoderPinB, HIGH);
256 attachInterrupt(0, doEncoderA, CHANGE);
257 attachInterrupt(1, doEncoderB, CHANGE);
262 pinMode(cameraShutter, OUTPUT);
263 digitalWrite(cameraShutter, HIGH);
265 pinMode(triggerReset, OUTPUT);
266 // keep the reset high except when in trigger mode, so we don't accidentally trigger!
267 digitalWrite(triggerReset, LOW);
274 write_pot(timerPot, 255);
277 void incrementValue()
288 if(lapseRepresentation == 0)
295 if(exposureRepresentation == 0)
300 if(exposureTime > lapseTime)
301 lapseTime = exposureTime;
305 void decrementValue()
316 if(lapseRepresentation == 0 || lapseTime == 60) // careful around transition; thanks, nate
326 if(exposureRepresentation == 0 || exposureTime == 60)
336 void updateTimeRepresentations()
339 lapseRepresentation = 1;
341 lapseRepresentation = 0;
343 if(exposureTime >= 60)
344 exposureRepresentation = 1;
346 exposureRepresentation = 0;
353 if(running || writing)
357 delayMicroseconds(3000); // maximum bounce time, accd. to spec.
359 if (digitalRead(encoderPinA) == HIGH)
361 if (digitalRead(encoderPinB) == LOW)
368 if (digitalRead(encoderPinB) == HIGH)
374 updateTimeRepresentations();
382 if(running || writing)
386 delayMicroseconds(3000);
388 if (digitalRead(encoderPinB) == HIGH)
390 if (digitalRead(encoderPinA) == HIGH)
397 if (digitalRead(encoderPinA) == LOW)
403 updateTimeRepresentations();
411 unsigned long diff = (millis() - lastModeUpdate);
413 if(diff < 300) // careful about the overflow...
416 lastModeUpdate = millis();
422 if(currentMode == BULB)
427 if(currentMode == TRIGGER)
428 digitalWrite(triggerReset, HIGH);
430 digitalWrite(triggerReset, LOW);
432 if(currentMode == TRIGGER)
433 writeLED(200, -1, 0);
434 else if(currentMode == BULB)
435 writeLED(0, -1, 128);
436 else if(currentMode == INTERVALBULB)
437 writeLED(0, -1, 128);
438 else if(currentMode == INTERVAL)
439 writeLED(0, -1, 128);
445 void switchSelected()
447 if(currentMode == INTERVALBULB)
449 unsigned long diff = (millis() - lastSelectedUpdate);
451 if(diff < 300) // careful about the overflow...
454 lastSelectedUpdate = millis();
464 unsigned long diff = (millis() - lastToggleRunning);
466 if(diff < 300) // careful about the overflow...
469 lastToggleRunning = millis();
475 writeLED(200, -1, -1);
480 if(currentMode == TRIGGER)
481 writeLED(200, -1, -1);
487 void drawTimecode(int secs, int rep)
491 lcdNumberWrite(secs);
496 lcdNumberWrite(secs/60);
501 int timecodeLength(int secs, int rep)
509 int n2 = (secs - n1 * 100) / 10;
517 char *modeHeader[4] = {"Interval", " Bulb", "Interval Bulb", "Trigger"};
521 void updateContrast()
523 write_pot(contrastPot, map(contrastValue, 0, 1000, 25, 60));
526 void writeLED(int r, int g, int b)
529 write_pot(ledRPot, map(255-r, 0, 255, 15, 150));
531 write_pot(ledGPot, map(255-g, 0, 255, 15, 150));
533 write_pot(ledBPot, map(255-b, 0, 255, 15, 150));
542 if((contrastValue -= 1) <= 0)
551 for (count = 0; modeHeader[currentMode][count] != 0; count++)
552 lcdDataWrite(modeHeader[currentMode][count]);
553 for (; count < 16; count++)
564 if(currentMode != BULB)
565 drawTimecode(lapseTime, lapseRepresentation);
569 if(currentMode != BULB)
570 width += timecodeLength(lapseTime, lapseRepresentation);
571 if(currentMode != INTERVAL && currentMode != TRIGGER)
572 width += timecodeLength(exposureTime, exposureRepresentation);
576 lcdDataWrite(' '); width++;
577 lcdDataWrite(127); width++;
584 for(int i = 16; i > width; i--)
593 if(currentMode != INTERVAL && currentMode != TRIGGER)
594 drawTimecode(exposureTime, exposureRepresentation);
599 if(!digitalRead(buttonA))
604 digitalWrite(lcdPower, LOW);
606 if(currentMode == TRIGGER)
608 if(analogRead(triggerInput) < 100) // 100 might change with different resistors, make sure it works!
610 writeLED(-1, 128, -1);
611 digitalWrite(triggerReset, HIGH);
612 delay(100); // this should probably be at least the time of the delay from signal (in the 555)...
613 digitalWrite(triggerReset, LOW);
615 digitalWrite(triggerReset, HIGH);
622 unsigned long diff = millis() - lastShutter;
624 int adjustedLapseTime = lapseTime;
625 if(currentMode != INTERVAL)
626 adjustedLapseTime -= exposureTime;
628 if(diff > (adjustedLapseTime * 1000)) // careful about the overflow...
630 writeLED(-1, 128, -1);
631 digitalWrite(cameraShutter, LOW);
633 if(currentMode == INTERVAL)
636 delay(exposureTime * 1000); //delay for length of exposure
637 // biggest problem with this is that you can't stop a bulb (of either type)
638 // in the middle... you have to power off the intervalometer; same as you would have
639 // to do with a camera, I suppose, so people might be used to it.
640 // however, we can get around this by looping and checking millis()...
642 digitalWrite(cameraShutter, HIGH);
643 lastShutter = millis();
645 if(currentMode == BULB)
653 digitalWrite(lcdPower, HIGH);
655 if(!digitalRead(buttonB))
658 if(!digitalRead(encoderButton))
660 else if(changeSelected)
662 selected = !selected;