User Tools

Site Tools


projects:nikon_remote_snaper:home

Nikon remote snaper

~~META:description abstract=Base circuit/firmware for a nikon remote controller~~ microcontroller nikon camera remote

Base circuit/firmware for a nikon remote controller

Features

  • Can only trigger snap (for now …)
  • Battery operated
  • Manual operation (remote controlled snap)
  • Automatic operation from 1 second to 64 hours interval (intervalometer)
  • Complex modes allowed using USB connexion to a computer …
  • May add a “learning mode” where the delay between the 2 first triggers is repeated endlessly
  • May add a “delayed snap” mode
  • Extend UI with +/-/mode push-buttons and 2 x 7seg + leds (s, m, h, learn + interv/delay/manual) + 3 x 8 bit shift reg

Receipe

snap_command_waveform.svg

Ressources

Electronics

schematic.svg

Source code

main.c
#define F_CPU 12000000
 
// Use V-USB stack
// IR modulation @ 39kHz
 
// Trigger on PD1
// Output on OC0A (PD6)
 
#define TRIGGER Bit(PORTD).bit1
#define IR_LED Bit(PORTD).bit0
#define STATUS Bit(PORTB).bit7
 
#define MODE Bit(PORTB).bit5
#define TIMEBASE (PORTB & 0x18) >> 3
#define TIME ((PORTD & 0x70) >> 4) | ((PORTB && 0x07) << 3)
 
#define MOD_FREQ 0.039 //MHz
#define PULSE_HP 12 //us = 1000000 / (2 * Fmod) - pin_set_time, validate with scope
 
#define SEC_IRQ SIG_TIMER1_COMPAREA
 
//global
volatile uint8_t running = 0;
volatile struct {
	uint8_t h;
	uint8_t m;
	uint8_t s;
	uint8_t p;
} Tcounter;
Tcounter counter;
Tcounter recorded;
 
//init
void init(void) {
	// Inputs
	PORTB = 0x3f; // Pull-up on PB[0..5]
	PORTD = 0x72; // Pull-up on PD[1 + 4..6]
 
	// Outputs
	sbi(DDRD, PD0); // IR led
	sbi(DDRB, PB7); // Status led
 
	//Timer 1
	TCCR1A = 0x00; // No PWM
	TCCR1B = 0x04; // Presc. = 256
	OCR1A = 0x249f; // 9375 * 256 @ 12MHz = 0.2s
	TIMSK = 0x40; // Compare irq enabled
 
	status_pulse();
}
 
// Interrupts
SIGNAL(SEC_IRQ) {
	TCNT1 = 0x0000;
	if(!TIMEBASE) return;
	if(counter.p) {
		counter.p--;
		STATUS = 0;
	}else if(counter.s) {
		counter.p = 5;
		counter.s--;
		STATUS = 1;
	}else if(counter.m) {
		counter.p = 5;
		counter.s = 60;
		counter.m--;
	}else if(counter.h)
		counter.p = 5;
		counter.s = 60;
		counter.m = 60;
		counter.h--;
	}else{ // All empty, take action
		if(running) snap();
		if(!MODE) running = 0;
		reset_counter();
	}
}
 
// Utilities
void status_pulse(void) {
	STATUS = 1;
	_delay_ms(250);
	STATUS = 0;
}
 
void ir_pulse(uint16_t duration) { // duration in us
	for(duration=duration*MOD_FREQ; duration>0; duration--) {
		IR_LED = 1;
		_delay_us(PULSE_HP);
		IR_LED = 0;
		_delay_us(PULSE_HP);
	}
}
 
void snap(void) { // Send "snap" command
	ir_pulse(2000);
	_delay_us(27830);
	ir_pulse(390);
	_delay_us(1580);
	ir_pulse(410);
	_delay_us(3580);
	ir_pulse(400);
}
 
void reset_counter(void) {
	if(MODE && !TIMEBASE) {
		counter.p = recorded.p;
		counter.s = recorded.s;
		counter.m = recorded.m;
		counter.h = recorded.h;
	}
	if(TIMEBASE == 1) {
		counter.p = 0;
		counter.s = TIME + 1;
		counter.m = 0;
		counter.h = 0;
	}
	if(TIMEBASE == 2) {
		counter.p = 0;
		counter.s = 0;
		counter.m = TIME + 1;
		counter.h = 0;
	}
	if(TIMEBASE == 3) {
		counter.p = 0;
		counter.s = 0;
		counter.m = 0;
		counter.h = TIME + 1;
	}
}
 
// Main
int main(void) {
	init();
 
	while(1) {
		if(!TRIGGER) {
			if(!running) {
				if(MODE || !TIMEBASE) { // intervalometer or remote mode
					status_pulse();
					snap();
				}
 
				if(TIMEBASE) { // delayed or fixed intervalometer snap schedule
					reset_counter();
					running = 1;
				}
 
				if(MODE && !TIMEBASE) { // Learning intervalometer
					counter.p = 5;
					counter.s = 60;
					counter.m = 60;
					counter.h = 255;
 
					while(!TRIGGER); // Wait for trigger release
					_delay_ms(100); // Debounce
					while(TRIGGER); // Wait for second trigger push
 
					recorded.p = 5 - counter.p; // Record time
					recorded.s = 60 - counter.s;
					recorded.m = 60 - counter.m;
					recorded.h = 255 - counter.h;
 
					status_pulse(); // Take seconf snap
					snap();
 
					reset_counter(); // Schedule next snap
					running = 1;
				}
			}else running = 0;
			_delay_ms(100); // Debounce
		}
	}
 
	return 0;
}
projects/nikon_remote_snaper/home.txt · Last modified: 2022/06/30 21:13 by 127.0.0.1