{"id":775,"date":"2015-02-20T12:41:05","date_gmt":"2015-02-20T01:41:05","guid":{"rendered":"http:\/\/bandetech.com\/blog\/?page_id=775"},"modified":"2015-03-25T17:10:36","modified_gmt":"2015-03-25T06:10:36","slug":"remote-shutter-release-arduino-code","status":"publish","type":"page","link":"https:\/\/bandetech.com\/blog\/remote-shutter-release-arduino-code\/","title":{"rendered":"Remote shutter release &#8212; Arduino code"},"content":{"rendered":"<p>The Arduino code and schematic for the <a title=\"Remote camera shutter release project\" href=\"http:\/\/bandetech.com\/blog\/2015\/02\/remote-camera-shutter-release\/\">Remote camera shutter release<\/a> project is included here.<\/p>\n<p>This is written for use on a MicroView, which includes a 64 x 48 pixel OLED display. Comments are included in the code and the schematic is below, but for the most part you&#8217;ll have to work out what&#8217;s going on for yourself (or leave a comment below, and I&#8217;ll get back to you).<\/p>\n<p><a href=\"http:\/\/bandetech.com\/blog\/remote-shutter-release-arduino-code\/remote-camera-shutter-project01\/\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-832 size-full\" src=\"http:\/\/bandetech.com\/blog\/wp-content\/uploads\/remote-camera-shutter-project01.png\" alt=\"\" width=\"621\" height=\"685\" srcset=\"https:\/\/bandetech.com\/blog\/wp-content\/uploads\/remote-camera-shutter-project01.png 621w, https:\/\/bandetech.com\/blog\/wp-content\/uploads\/remote-camera-shutter-project01-272x300.png 272w\" sizes=\"auto, (max-width: 621px) 100vw, 621px\" \/><\/a><\/p>\n<p>This project shows\u00a0a flagrant disregard for debouncing switch input, but it works and saved me the effort of being rigorous about it. Variable range checking isn&#8217;t high on the list of things to do either. My apologies if either offends you, but pragmatism wins. \ud83d\ude09<\/p>\n<pre class=\"brush: arduino; title: ; notranslate\" title=\"\">\r\n\r\n#include &lt;7segment.h&gt;\r\n#include &lt;font5x7.h&gt;\r\n#include &lt;font8x16.h&gt;\r\n#include &lt;fontlargenumber.h&gt;\r\n#include &lt;MicroView.h&gt;\r\n#include &lt;Servo.h&gt;\r\n\r\n#define servoPIN 6\r\n#define buttonPIN 2\r\n#define potPIN A1\r\n\r\n\/*\r\nUse uView to remotely activate camera shutter, via servo arm\r\n\r\n- On first boot, read switch pin, if held down, enable Interval mode\r\n- Setup: read Analog pot, adjust to set autofocus rotation for Neutral, Half press &amp; Full\r\n- Enter loop to wait for click &amp; then activate position1, then position2\r\n\r\nv0.6\r\nv0.65 corrected variable type for maxIdleTime (was int)\r\n*\/\r\n\r\nServo myservo; \/\/ create servo object\r\n\r\nboolean snap = false, interval = false;\r\nint pNeutral, pFocus, pShutter, vr1, count=0;\r\nunsigned long milliVar, snapTime, wiggleTime;\r\nconst unsigned long maxIdleTime = 60000; \/\/ millis between keepAlive presses\r\n\r\nvoid setup() {\r\nmyservo.attach(servoPIN);\r\nmyservo.write(90); \/\/ set servo to mid position\r\npinMode(buttonPIN, INPUT_PULLUP);\r\npinMode(potPIN, INPUT);\r\n\r\nuView.begin(); \/\/ begin MicroView\r\nuView.clear(ALL); \/\/ erase hardware memory inside the OLED controller\r\nuView.display(); \/\/ display the content in the buffer memory, by default it is the uView logo\r\ndelay(1000);\r\n\r\nfor (int i=0; i&lt;10; i++) { \/\/ loop a few times, checking to see if button has been held down at boot\r\nif (!digitalRead(buttonPIN)) { \/\/ pin is active LOW\r\ninterval = true; \/\/ if button was down, activate interval timer mode\r\nbreak;\r\n}\r\ndelay(10);\r\n}\r\nif (interval) { \/\/ interval mode?\r\nmyservo.write(80); \/\/ wiggle servo to acknowledge\r\ndelay(100);\r\nmyservo.write(100);\r\ndelay(100);\r\nmyservo.write(80);\r\ndelay(100);\r\nmyservo.write(100);\r\ndelay(100);\r\nuView.clear(PAGE); \/\/ write message confirming interval mode\r\nuView.setFontType(0); \/\/ use 1 for 8x16 font, 0 for 5x7\r\nuView.setCursor(8,13);\r\nuView.print(&quot;Interval&quot;);\r\nuView.setCursor(20,23);\r\nuView.print(&quot;mode&quot;);\r\nuView.setCursor(11,33);\r\nuView.print(&quot;enabled&quot;);\r\nuView.display();\r\ndelay(2000);\r\n}\r\n\r\n\/\/ calibration process, part 1 - set position where camera button not active\r\nuView.clear(PAGE);\r\nuView.setFontType(0); \/\/ use 1 for 8x16 font, 0 for 5x7\r\nuView.setCursor(1,1); \/\/ drop to lower half of display\r\nuView.print(&quot;Calibrate&quot;);\r\nuView.line(0,9,56,9);\r\nuView.setCursor(1,12);\r\nuView.print(&quot;Set zero&quot;);\r\nuView.setCursor(1,20);\r\nuView.print(&quot;position,&quot;);\r\nuView.setCursor(1,28);\r\nuView.print(&quot;then press&quot;);\r\nuView.setCursor(1,36);\r\nuView.print(&quot;button.&quot;);\r\nuView.display(); \/\/ display the content in the buffer memory, by default it is the uView logo\r\npNeutral = readServo(); \/\/ neutral is the last position of the servo before click\r\ndelay(1000);\r\n\r\n\/\/ calibration process, part 2 - set position where camera button half pressed\r\nuView.clear(PAGE);\r\nuView.setFontType(0); \/\/ use 1 for 8x16 font, 0 for 5x7\r\nuView.setCursor(1,1); \/\/ drop to lower half of display\r\nuView.print(&quot;Calibrate&quot;);\r\nuView.line(0,9,56,9);\r\nuView.setCursor(1,12);\r\nuView.print(&quot;Set 1st&quot;);\r\nuView.setCursor(1,20);\r\nuView.print(&quot;position,&quot;);\r\nuView.setCursor(1,28);\r\nuView.print(&quot;then press&quot;);\r\nuView.setCursor(1,36);\r\nuView.print(&quot;button.&quot;);\r\nuView.display();\r\npFocus = readServo(); \/\/ focus active is the last position of the servo before click\r\ndelay(1000);\r\n\r\n\/\/ calibration process, part 3 - set position where camera button fully pressed\r\nuView.clear(PAGE);\r\nuView.setFontType(0); \/\/ use 1 for 8x16 font, 0 for 5x7\r\nuView.setCursor(1,1); \/\/ drop to lower half of display\r\nuView.print(&quot;Calibrate&quot;);\r\nuView.line(0,9,56,9);\r\nuView.setCursor(1,12);\r\nuView.print(&quot;Set 2nd&quot;);\r\nuView.setCursor(1,20);\r\nuView.print(&quot;position,&quot;);\r\nuView.setCursor(1,28);\r\nuView.print(&quot;then press&quot;);\r\nuView.setCursor(1,36);\r\nuView.print(&quot;button.&quot;);\r\nuView.display();\r\npShutter = readServo(); \/\/ save the last position of the servo before click\r\ndelay(1000);\r\n\r\nmyservo.write(pNeutral); \/\/ back to neutral\r\nattachInterrupt(0,pushButton,FALLING); \/\/ start interrupt handler for switch input\r\n\r\n\/\/ Interval mode?\r\nif (interval) { doInterval(); }\r\n\r\n\/\/ Ready to go. Display message, set timer\r\nsnapTime = millis();\r\nuView.clear(PAGE);\r\nuView.setFontType(1);\r\nuView.setCursor(9,2);\r\nuView.print(&quot;Ready&quot;);\r\nuView.line(8,17,54,17);\r\nuView.display(); \/\/ display the content in the buffer memory, by default it is the uView logo\r\nwiggleTime = millis() + maxIdleTime;\r\n\r\n} \/\/ end setup\r\n\r\nvoid loop() {\r\n\r\nmilliVar = millis();\r\n\r\nuView.setFontType(0); \/\/ use 1 for 8x16 font, 0 for 5x7\r\nuView.setCursor(9,20);\r\nuView.print(&quot;n=&quot;); \/\/ display count of images taken\r\nuView.print(count);\r\nuView.setCursor(9,30);\r\nuView.print(&quot;t=&quot;); \/\/ display time since last shutter press\r\nuView.print((milliVar-snapTime)\/1000);\r\nuView.print(&quot; &quot;);\r\nuView.display(); \/\/ display the content in the buffer memory, by default it is the uView logo\r\n\r\nif(snap) { \/\/ Button interrupt been called?\r\ntakePic(); \/\/ take photo\r\ncount++; \/\/ increment counter\r\nsnap = false; \/\/ reset interrupt\r\nmilliVar = millis();\r\nwiggleTime = milliVar + maxIdleTime; \/\/ run keepAlive motion again in maxIdleTime millis\r\n}\r\n\r\nif(milliVar &gt; wiggleTime) { \/\/ half press button every maxIdleTime millis to keep camera awake\r\ndelay(50);\r\nmyservo.write(pFocus);\r\ndelay(500);\r\nmyservo.write(pNeutral);\r\nwiggleTime = milliVar + maxIdleTime; \/\/ run keepAlive motion again in maxIdleTime millis\r\n}\r\ndelay(250); \/\/ just to slow the loop down a bit\r\n\r\n} \/\/ end of main loop\r\n\r\n\/\/ Interrupt Service Routine for remote shutter button\r\nvoid pushButton() {\r\nsnap = true;\r\n} \/\/ end pushbutton\r\n\r\n\/\/ Move servo to pFocus, delay, then pShutter, delay, then back to pNeutral\r\nvoid takePic() {\r\ndelay(50);\r\nmyservo.write(pFocus);\r\ndelay(1000);\r\nmyservo.write(pShutter);\r\ndelay(750);\r\nmyservo.write(pNeutral);\r\nsnapTime = millis();\r\n} \/\/ end takePic\r\n\r\n\/\/ Move servo around, based on analogue input from pot.\r\nint readServo(){ \/\/ read from potentiometer, rotate servo in sync with pot. Return servo angle when button is pressed\r\nint angle;\r\n\r\nwhile(digitalRead(buttonPIN)) {\r\nvr1 = analogRead(potPIN);\r\nangle = map(vr1,0,1023,45,135); \/\/ mapping 45 degrees either side of the 90 degree position\r\nmyservo.write(angle);\r\ndelay(50);\r\n}\r\nreturn angle;\r\n} \/\/ end readServo\r\n\r\n\/\/ Interval timer mode -- setup, then run infinite loop\r\nvoid doInterval(){\r\nunsigned long snapTime, timeLeft;\r\nint sInt;\r\n\r\nuView.clear(PAGE);\r\nuView.setFontType(0); \/\/ use 1 for 8x16 font, 0 for 5x7\r\nuView.setCursor(1,1);\r\nuView.print(&quot;Timing&quot;);\r\nuView.line(0,9,38,9);\r\nuView.setCursor(1,12);\r\nuView.print(&quot;Set interval&quot;);\r\nuView.setCursor(1,20);\r\nuView.print(&quot;then press&quot;);\r\nuView.setCursor(1,28);\r\nuView.print(&quot;button.&quot;);\r\nuView.display(); \/\/ display the content in the buffer memory, by default it is the uView logo\r\n\r\nwhile(digitalRead(buttonPIN)) { \/\/ read pot and display delay time, save value when button pressed\r\nvr1 = analogRead(potPIN);\r\nsInt = map(vr1,5,1020,240,5); \/\/ mapping interval to between 5 and 240 seconds\r\nuView.setCursor(1,36);\r\nuView.print(sInt);\r\nuView.print(&quot;s &quot;);\r\nuView.display(); \/\/ display the content in the buffer memory, by default it is the uView logo\r\ndelay(75);\r\n}\r\nsInt = sInt * 1000; \/\/ convert seconds to millis\r\ndelay(1000);\r\nuView.clear(PAGE);\r\nuView.setFontType(0); \/\/ use 1 for 8x16 font, 0 for 5x7\r\nuView.setCursor(8,2);\r\nuView.print(&quot;Interval&quot;);\r\nuView.line(7,11,57,11);\r\nuView.display(); \/\/ display the content in the buffer memory, by default it is the uView logo\r\n\r\nsnapTime = millis() + sInt;\r\nsnap = false; \/\/ just make sure the interrupt is cleared\r\n\/\/ set up complete -- begin interval mode\r\n\r\n\/\/ start interval photos, never exit this loop\r\nwhile (true) {\r\ntimeLeft = (snapTime - millis())\/1000;\r\n\r\nif (snap) { \/\/ if the button was pressed, and there's time to take a photo...\r\nif (timeLeft &gt; 2) {\r\ntakePic();\r\ncount++;\r\n}\r\nsnap = false;\r\n}\r\n\r\nuView.setFontType(0); \/\/ use 1 for 8x16 font, 0 for 5x7\r\nuView.setCursor(9,20);\r\nuView.print(&quot;n=&quot;);\r\nuView.print(count);\r\nuView.setCursor(9,30);\r\nuView.print(&quot;t=&quot;);\r\nuView.print(timeLeft);\r\nuView.print(&quot; &quot;);\r\nuView.display(); \/\/\r\nif(timeLeft &lt;= 0) {\r\ntakePic();\r\ncount++;\r\nsnapTime = millis() + sInt;\r\n}\r\ndelay(300);\r\n}\r\n\r\n} \/\/ doInterval\r\n\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>The Arduino code and schematic for the Remote camera shutter release project is included here. This is written for use on a MicroView, which includes a 64 x 48 pixel OLED display. Comments are included in the code and the &hellip; <a href=\"https:\/\/bandetech.com\/blog\/remote-shutter-release-arduino-code\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":823,"parent":0,"menu_order":0,"comment_status":"open","ping_status":"open","template":"","meta":{"jetpack_post_was_ever_published":false,"footnotes":""},"class_list":["post-775","page","type-page","status-publish","has-post-thumbnail","hentry"],"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/P8H2X3-cv","_links":{"self":[{"href":"https:\/\/bandetech.com\/blog\/wp-json\/wp\/v2\/pages\/775","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bandetech.com\/blog\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/bandetech.com\/blog\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/bandetech.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/bandetech.com\/blog\/wp-json\/wp\/v2\/comments?post=775"}],"version-history":[{"count":15,"href":"https:\/\/bandetech.com\/blog\/wp-json\/wp\/v2\/pages\/775\/revisions"}],"predecessor-version":[{"id":841,"href":"https:\/\/bandetech.com\/blog\/wp-json\/wp\/v2\/pages\/775\/revisions\/841"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/bandetech.com\/blog\/wp-json\/wp\/v2\/media\/823"}],"wp:attachment":[{"href":"https:\/\/bandetech.com\/blog\/wp-json\/wp\/v2\/media?parent=775"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}