Use the DIP compatible analog ports (SMT part has 2 more); keep reset low while not...
[arduino-intervalometer.git] / Intervalometer.pde
blob6a929f8ed4161c126d2e8f6201778568c8fb7719
1 /*
2  *  Arduino Intervalometer
3  *  Tim Horton, 2008
4  */
6 #define INTERVAL         0
7 #define BULB             1
8 #define INTERVALBULB 2
9 #define TRIGGER          3
12  *  Pin Assignment
13  */
15 // Analog Pins
16 int triggerInput =  2;
18 int encoderButton =     3;
19 int buttonA =           4; // Left pushbutton
20 int buttonB =           5; // Right pushbutton
22 // Digital Pins
24 int cameraShutter = 0; // Pulse low for shutter release
26 int encoderPinA =       2;
27 int encoderPinB =       3;
29 int lcdEnable =         1;
30 int lcdDataBus[] =      { 4, 5, 6, 7 };
31 int lcdDataClock =      8;
32 int lcdDataInt =        9;
34 int triggerReset =  12;
36 /////////////////////////////
38 int currentMode = INTERVAL, selected = 0;
39 int running = 0;
40 unsigned long lastToggleRunning = 0;
41 unsigned long lastModeUpdate = 0;
42 unsigned long lastSelectedUpdate = 0;
43 unsigned long lastShutter = 0;
46 int updateHeader = 1, updateEncoder = 1;
47 volatile long exposureTime = 0, lapseTime = 0;
48 int exposureRepresentation = 0, lapseRepresentation = 0;
49 int n = LOW;
52  *  Higher level hardware functions
53  */
55 void pulsePin(int pin, int value)
57         digitalWrite(pin, !value);
58         delay(1);
59         digitalWrite(pin, value);
60         delay(1);
61         digitalWrite(pin, !value);
62         delay(1);
66  *  lcd Control Functions
67  */
69 void lcdCommandWrite(int value)
71         int i = 0;
72         int value1 = value;
74         value1 >>= 4;
75         
76         for (i = lcdDataBus[0]; i <= lcdDataInt; i++)
77         {
78                 digitalWrite(i,value1 & 01);
79                 value1 >>= 1;
80         }
81         
82         pulsePin(lcdEnable, HIGH);
83         delay(1);
85         for (i = lcdDataBus[0]; i <= lcdDataBus[3]; i++)
86         {
87                 digitalWrite(i, value & 01);
88                 value >>= 1; 
89         }
90         
91         value >>= 4;
92         
93         for (i = lcdDataClock; i <= lcdDataInt; i++)
94         {
95                 digitalWrite(i, value & 01);
96                 value >>= 1;
97         }
98         
99         pulsePin(lcdEnable, HIGH);
102 void lcdDataWrite(int value)
104         int i = 0;
105         int value1 = value;
106         
107         digitalWrite(lcdDataInt, HIGH);
108         digitalWrite(lcdDataClock, LOW);
109         
110         value1 >>= 4;
111         
112         for (i=lcdDataBus[0]; i <= lcdDataBus[3]; i++)
113         {
114                 digitalWrite(i,value1 & 01);
115                 value1 >>= 1;
116         }
117         
118         pulsePin(lcdEnable, HIGH);
119         delay(1);
120         
121         digitalWrite(lcdDataInt, HIGH);
122         digitalWrite(lcdDataClock, LOW);
123         
124         for (i=lcdDataBus[0]; i <= lcdDataBus[3]; i++)
125         {
126                 digitalWrite(i,value & 01);
127                 value >>= 1;
128         }
129         
130         pulsePin(lcdEnable, HIGH);
133 void lcdNumberWrite(int nr)
135         // We don't need negatives, but if you do:
136         /*if(nr < 0)
137         {
138                 lcdCommandWrite(557);
139                 nr = abs(nr);
140         }
141         else
142         {
143                 lcdCommandWrite(544);
144         }*/
145         
146         int n1 = nr/100;
147         int n2 = (nr - n1 * 100) / 10;
148         
149         if(n2)
150                 lcdCommandWrite(560 + n2);
151         
152         nr = nr - n1 * 100 - n2 * 10;
153         lcdCommandWrite(560 + nr);
156 void lcdHome(int row)
158         lcdCommandWrite(0x02);
159         
160         delay(4);
161         
162         if(row == 1)
163                 lcdCommandWrite(0xC0);
164                 
165         delay(1);
168 void lcdClear()
170         lcdCommandWrite(0x01);
171         delay(4);
175  *  Hardware initialization functions
176  */
178 void lcdInit()
180         int i = 0;
181         
182         for (i = lcdEnable; i <= lcdDataInt; i++)
183                 pinMode(i, OUTPUT);
185         lcdCommandWrite(0x03); delay(64);
186         lcdCommandWrite(0x03); delay(50);
187         lcdCommandWrite(0x03); delay(50);
188         lcdCommandWrite(0x02); delay(50);
189         lcdCommandWrite(0x2C); delay(20);
190         lcdCommandWrite(0x06); delay(20);
191         lcdCommandWrite(0x0C); delay(20);
192         lcdCommandWrite(0x01); delay(100);
193         lcdCommandWrite(0x80); delay(30);
196 void encoderInit()
198         pinMode(encoderPinA, INPUT); 
199         digitalWrite(encoderPinA, HIGH);
200         pinMode(encoderPinB, INPUT); 
201         digitalWrite(encoderPinB, HIGH);
203         attachInterrupt(0, doEncoderA, CHANGE);
204         attachInterrupt(1, doEncoderB, CHANGE);
207 void setup (void)
209         pinMode(cameraShutter, OUTPUT);
210         digitalWrite(cameraShutter, HIGH);
212         lcdInit();
213         encoderInit();
214         
215         pinMode(triggerReset, OUTPUT);
216         digitalWrite(triggerReset, LOW);
219 void incrementValue()
221         if(selected == 0)
222         {
223                 if(lapseRepresentation == 0)
224                         lapseTime++;
225                 else
226                         lapseTime += 60;
227         }
228         else
229         {
230                 if(exposureRepresentation == 0)
231                         exposureTime++;
232                 else
233                         exposureTime += 60;
234                 
235                 if(exposureTime > lapseTime)
236                         lapseTime = exposureTime;
237         }
240 void decrementValue()
242         if(selected == 0)
243         {
244                 if(lapseRepresentation == 0 || lapseTime == 60) // careful around transition; thanks, nate
245                         lapseTime--;
246                 else
247                         lapseTime -= 60;
248                 
249                 if(lapseTime < 0)
250                         lapseTime = 0;
251         }
252         else
253         {
254                 if(exposureRepresentation == 0 || exposureTime == 60)
255                         exposureTime--;
256                 else
257                         exposureTime -= 60;
258                 
259                 if(exposureTime < 0)
260                         exposureTime = 0;
261         }
264 void doEncoderA()
266         if(running)
267                 return;
268                 
269         noInterrupts();
270         delayMicroseconds(3000);
271         if (digitalRead(encoderPinA) == HIGH)
272         { 
273                 if (digitalRead(encoderPinB) == LOW)
274                         incrementValue();
275                 else
276                         decrementValue();
277         }
278         else                                       
279         {
280                 if (digitalRead(encoderPinB) == HIGH)
281                         incrementValue();
282                 else
283                         decrementValue();
284         }
285         
286         if(lapseTime >= 60)
287                 lapseRepresentation = 1;
288         else
289                 lapseRepresentation = 0;
291         if(exposureTime >= 60)
292                 exposureRepresentation = 1;
293         else
294                 exposureRepresentation = 0;
295         
296         updateEncoder = 1;
297         interrupts();
300 void doEncoderB()
302         if(running)
303                 return;
304         
305         noInterrupts();
306         delayMicroseconds(3000);
307         if (digitalRead(encoderPinB) == HIGH)
308         {
309                 if (digitalRead(encoderPinA) == HIGH)
310                         incrementValue();
311                 else
312                         decrementValue();
313         }
314         else
315         {
316                 if (digitalRead(encoderPinA) == LOW)
317                         incrementValue();
318                 else
319                         decrementValue();
320         }
321         
322         if(lapseTime >= 60)
323                 lapseRepresentation = 1;
324         else
325                 lapseRepresentation = 0;
327         if(exposureTime >= 60)
328                 exposureRepresentation = 1;
329         else
330                 exposureRepresentation = 0;
331         
332         updateEncoder = 1;
333         interrupts();
336 void switchModes()
338         unsigned long diff = (millis() - lastModeUpdate);
339         
340         if(diff < 300) // careful about the overflow...
341         {
342                 lastModeUpdate = millis();
343                 return;
344         }
345         else
346                 lastModeUpdate = millis();
347         
348         currentMode++;
349         if(currentMode > 3)
350                 currentMode = 0;
351         
352         if(currentMode == BULB)
353                 selected = 1;
354         else
355                 selected = 0;
356         
357         if(currentMode == TRIGGER)
358                 digitalWrite(triggerReset, HIGH);
359         else
360                 digitalWrite(triggerReset, LOW);
361                 
362         
363         updateHeader = 1;
366 void switchSelected()
368         if(currentMode == INTERVALBULB)
369         {
370                 unsigned long diff = (millis() - lastSelectedUpdate);
371                 
372                 if(diff < 300) // careful about the overflow...
373                 {
374                         lastSelectedUpdate = millis();
375                         return;
376                 }
377                 else
378                         lastSelectedUpdate = millis();
380                 selected = !selected;
381         }
382         
383         updateEncoder = 1;
386 void toggleRunning()
388         unsigned long diff = (millis() - lastToggleRunning);
389         
390         if(diff < 300) // careful about the overflow...
391         {
392                 lastToggleRunning = millis();
393                 return;
394         }
395         else
396                 lastToggleRunning = millis();
397         
398         running = !running;
401 void drawTimecode(int secs, int rep)
403         if(rep == 0)
404         {
405                 lcdNumberWrite(secs);
406                 lcdDataWrite('"');
407         }
408         else
409         {
410                 lcdNumberWrite(secs/60);
411                 lcdDataWrite('\'');
412         }
415 int timecodeLength(int secs, int rep)
417         int count = 2;
418         
419         if(rep)
420                 secs = secs/60;
421         
422         int n1 = secs/100;
423         int n2 = (secs - n1 * 100) / 10;
425         if(n2)
426                 count++;
427         
428         return count;
431 char *modeHeader[4] = {"Interval", "            Bulb", "Interval    Bulb", "Trigger"};
433 void loop(void)
435         if(updateHeader)
436         {
437                 lcdHome(0);
438                 
439                 int count;
440                 for (count = 0; modeHeader[currentMode][count] != 0; count++)
441                         lcdDataWrite(modeHeader[currentMode][count]);
442                 for (; count < 16; count++)
443                         lcdDataWrite(' ');
444                 
445                 updateHeader = 0;
446                 updateEncoder = 1;
447         }
448                 
449         if(updateEncoder)
450         {       
451                 lcdHome(1);
452                 
453                 if(currentMode != BULB)
454                         drawTimecode(lapseTime, lapseRepresentation);
455                 
456                 int width = 0;
457                 
458                 if(currentMode != BULB)
459                         width += timecodeLength(lapseTime, lapseRepresentation);
460                 if(currentMode != INTERVAL && currentMode != TRIGGER)
461                         width += timecodeLength(exposureTime, exposureRepresentation);
462                         
463                 if(selected == 0)
464                 {
465                         lcdDataWrite(' '); width++;
466                         lcdDataWrite(127); width++;
467                 }
468                 else
469                 {
470                         width += 2;
471                 }
472                                 
473                 for(int i = 16; i > width; i--)
474                         lcdDataWrite(' ');
475                 
476                 if(selected == 1)
477                 {
478                         lcdDataWrite(126);
479                         lcdDataWrite(' ');
480                 }
481                 
482                 if(currentMode != INTERVAL && currentMode != TRIGGER)
483                         drawTimecode(exposureTime, exposureRepresentation);
485                 updateEncoder = 0;
486         }
487         
488         if(analogRead(buttonA) == 0)
489                 toggleRunning();
490         
491         if(running)
492         {
493                 if(currentMode == TRIGGER)
494                 {
495                         // do special trigger stuff
496                         
497                         if(analogRead(triggerInput) < 100) // 100 might change with different resistors, make sure it works!
498                         {
499                                 digitalWrite(triggerReset, HIGH);
500                                 delay(100); // this should probably be at least the time of the delay...
501                                 digitalWrite(triggerReset, LOW);
502                                 delay(10);
503                                 digitalWrite(triggerReset, HIGH);
504                         }
505                         
506                         return;
507                 }
508                 
509                 unsigned long diff = millis() - lastShutter;
510                 
511                 int adjustedLapseTime = lapseTime;
512                 if(currentMode != INTERVAL)
513                         adjustedLapseTime -= exposureTime;
514                 
515                 if(diff > (adjustedLapseTime * 1000)) // careful about the overflow...
516                 {
517                         digitalWrite(cameraShutter, LOW);
518                         
519                         if(currentMode == INTERVAL)
520                                 delay(100);
521                         else
522                                 delay(exposureTime * 1000); //delay for length of exposure
523                                 
524                         digitalWrite(cameraShutter, HIGH);
525                         lastShutter = millis();
526                         
527                         if(currentMode == BULB)
528                                 running = 0;
529                 }
530         }
531         else
532         {
533                 if(analogRead(buttonB) == 0)
534                         switchModes();
535                 
536                 if(analogRead(encoderButton) == 0)
537                         switchSelected();
538         }