;=================================================================== ; ; Nikon D70 infra-red remote shutter control ; using the PIC12F509 ; ; Originally developed by Jan Wagner for use with PIC12F675 ; http://users.tkk.fi/~jwagner/electr/d70remote/main.asm ; ; Modified to compile on PIC12F509 by tech@vedella ; http://tech.vedella.com/control_IR_Nikon_D70 ;=================================================================== ; Code info: ; ; Compiles with Microchip's free MPLAB IDE, www.microchip.com ; or gpasm under linux ; ; Uses the PIC12F509 (PIC12C509 should work too) ; ; IR command sequence for AF & shutter release : ; - starting pulse 2250us (IR on) OR: 2ms on ; - pause 27600us (IR off) 28ms off ; - 650us pulse 0.5ms on ; - pause 13750us 1.5ms off ; - 575us pulse 0.5ms on ; - pause 3350us 3.5ms off ; - pulse 650us 0.5ms on ; - pause 63msec 60ms off pause ; - repeat the above sequence one time ; ; The IR on-pulses need to be gated/modulated with 40kHz, ; i.e. on for 12.5us off for 12.5us ; ; The PIC runs on its 4MHz internal oscillator, so one ; instruction cycle takes 1.0us (1/4th of clock) ; ;=================================================================== ; Schematic: ; ; +2.4..3.3V (coin cell) ; | _______ _______ ; | PUSH | \/ | ; +--BUTTON-----+ 1 Vdd Vss 8 +-----| Vss (GND, ICD_GND) ; | | ; GP5 --+ 2 7 +-- GP0 ICD_DATA ; | | ; GP4 --+ 3 6 +-- GP1 ICD_CLK ; | | IR LED ; !MCLR --+ 4 5 +-- GP2 ----RRRR---|>------|GND ; Vprogram | PIC12F509 | 220 ; +----------------+ ; ; parts: PIC12F509, pushbutton switch (closing type), ; IR LED ("remote control" type), ; 220 Ohm 1/4W resistor, CR2032 coin cell and cell holder ;=================================================================== list p=12F509 include "p12f509.inc" radix dec ; config: ; !MCLR pin off, no code-protect, watchdog off ; internal 4MHz clock with no output __CONFIG _MCLRE_OFF & _IntRC_OSC & _CP_OFF & _WDT_OFF ;------------- ISR VECTORS org 0x000 ; startup movwf OSCCAL ; calibrate goto main ;------------- VARS : variables into file register bank cblock 0x10 ; (bank 0 0x20-0x5f are free for use) pulsecntr ; 0x20 counter for main pulses (pulselen = 25us * pulsecounter) waitcntr ; 0x21 counter for pauses (pauselen = 25us * waitcntr * pulsecntr) waittmp ; 0x22 temporary storage for waitcntr maincntr ; 0x23 how many times the sequence has been sent endc LED_BIT equ 2 ; IR LED placed on pin 5 (GP2) ;------------- FUNCTIONS ; ; Function doLedToggling ; ; IR LED toggler, toggle once at 40kHz i.e. with 25us period ; ; Input: W contains counter (>0) with the number of toggles ; to perform ; Return: nothing ; Time: W*25us + 2us ; doLedToggling movwf pulsecntr ; store argument W into pulsecounter doLedToggLoop ; ON for 13us bsf GPIO,LED_BIT ; 1/13us GPx high to enable IR LED nop ; 2/13us just use NOPs instead of complicated loop, nop ; might even be a bit less powerhungry nop nop ; 5/13us nop nop nop nop nop ; 10/13us nop nop nop ; 13/13us ; OFF for 12us total bcf GPIO,LED_BIT ; 1/12us GPx low to disable IR LED nop ; 2/12us nop nop nop ; 5/12us nop nop nop nop ; 9/12us decfsz pulsecntr,F ; 10/12us (or +2us on exit) goto doLedToggLoop ; 11&12/12us (+2us) return ; (+2us) ; ; Function do25usPauses ; ; Do a longer pause, duration is approximately in multiples of 25us ; ; Input: W contains outer counter ('pulsecounter'), >0 ; waitcntr contains inner counter, >0 ; ; Return: nothing ; Time: (25us*waitcntr + 3us)*W + 4us ; do25usPauses movwf pulsecntr ; store argument W into pulsecounter movf waitcntr,W ; load waitcntr argument to W movwf waittmp ; place waitcntr into actual temp counter do25outer do25inner ; delay for 25us nop nop nop nop nop ; 5us nop nop nop nop nop ; 10us nop nop nop nop nop ; 15us nop nop nop nop nop ; 20us nop nop ; 22us decfsz waittmp,F ; +1us (+2us on end) goto do25inner ; +2us movwf waittmp ; put back waitcntr into actual counter ; (also +1us on end so condition check always takes 3us) decfsz pulsecntr,F goto do25outer return ;------------- MAIN main clrwdt ; init GPIO pins clrf GPIO ; init GPIO state to 0 movlw 0 tris 6 ; all pins as output option initOneFullSeq movlw 2 ; send same sequence twice movwf maincntr performSequences decfsz maincntr,W ; if maincntr==1, do a longer pause goto doOneSeq ; skip pause, send directly ; long pause of 63000us between first and second time sending ; (25us*waitcntr + 3us)*W + 4us : (25*15+3)*167+4=63130us movlw 15 movwf waitcntr movlw 167 call do25usPauses ; send the sequence ; ON 2250us = 90 * 25us doOneSeq movlw 90 call doLedToggling ; Off 27600us-(ON call 3us + w/f 3us + OFF call 2us)=27592us ; (25us*waitcntr + 3us)*W + 4us : (25*15+3)*73+4=27598 movlw 15 movwf waitcntr movlw 73 call do25usPauses ; ON 650us = 26 * 25us movlw 26 call doLedToggling ; Off 1375us-(3us+3us+2us)=1367us : (25*18+3)*3+4=1363 movlw 18 movwf waitcntr movlw 3 call do25usPauses ; ON 575us = 21 * 25us movlw 21 call doLedToggling ; Off 3350us-(3us+3us+2us)=3342us : (25*2+3)*63+4=3343 movlw 2 movwf waitcntr movlw 63 call do25usPauses ; ON 650us = 26 * 25us movlw 26 call doLedToggling decfsz maincntr,F goto performSequences ; to completely stop: ;sleep ; or, to run in continuos shooting mode, do ; first a quite long pause... movlw 20 movwf waitcntr movlw 167 call do25usPauses ; ...and then restart goto initOneFullSeq end