Dear JC (and other expert). I made this project to be able to trigger my flash off the camera and at the same time time be able to control the power of the flash. It works really good, the range is also excellent and very reliable, but I have problem with the flash sync speed. Normally an SLR camera can sync the flash up to 1/250sec (even with a cheap "made in china" wireless flash trigger). With this project, (which i called SPOTduino, BTW), on my Canon EOS 40D, I cannot sync higher than 1/160sec. At 1/200sec got very thin dark area at the bottom and 1/250sec got half dark area (this is typical of out-of-sync flash problem). It is the same on my friend's Nikon D200, so I don't think the camera is the issue here. My project is very simple, just use two BCD rotary switches. The 1st BCD switch for choosing the flash group and the 2nd BCD for setting up the power/quench timing. And two optocouplers to trigger the flash (on RX unit) and to trigger the quench signal. Then I only transmit two bytes to trigger the flash and to set the flash power on the receiver end. I read from your article and HackADay, that Arduino's digitalRead and digitalWrite command is very slow, so after some google time, I found the C style replacement for these command, it works fine too in my SPOTduino, but unfortunately it still does not solve the problem with the sync speed. So I am back to scratching my head to find where the bottleneck is in the program. Pls check below my Arduino script, appreciate very much if somebody can help me solve this problem. Thanks a lot.
=====
//SPOTduino TX/RX Dual mode //RFM12B RF arduino library by JC, Jeelabs
//http://news.jeelabs.org/code/
//very easy to use HopeRF RFM12B arduino library, tks a lot JC.
#include //Macro C to replace Arduino's digitalRead and digitalWrite to speed
//things up
#define BITSET(REG, bit) ( REG |= (1UL << (bit) ) )
#define BITCLR(REG, bit) ( REG &= ~(1UL << (bit) ) )
#define BITTST(REG, bit, val) ( ( (REG & (1UL << (bit) ) ) == ( (val) << (bit) ) ) ) //TX RF unit ID (Anything outside A-I is fine)
#define TxID ('T') //two bytes command for flash sync (syncCmd) and flash power (vpCmd)
//second byte of vpCmd will be adjusted by the BCD rotary switch
byte syncCmd[2] = {
'X','S'};
byte vpCmd[2] = {
'V', 0};
// BCD Rotary Switch for flash group/RF group
const int fg8Pin = 14; //PC0
const int fg4Pin = 15; //PC1
const int fg2Pin = 16; //PC2
const int fg1Pin = 17; //PC3 // BCD Rotary Switch for flash power (quench time)
const int vp8Pin = 8; //PB0
const int vp4Pin = 7; //PD7
const int vp2Pin = 6; //PD6
const int vp1Pin = 5; //PD5 //output pin to fire/sync and quench flash using optocoupler
const int quenchPin = 18; //PC4
const int triggerFlashPin = 19; //PC5 //Sync Pin to fire the flash (connected camera hotshoe or camera sync
//connector)
const int syncPin = 3; //PD3 //VP Pin push button to set the flash power
const int vpPin = 4; //PD4 //toggle switch for TX or RX mode
const int modePin = 0; //PD0 //Led status Pin
const int ledPin = 9; //PB1 //variable to store the varipower/quench timing mS value, initial
//value at the highest possible in mS
//in my vivitar 285HV flash, 1350 mS is the full power quench time
int vp = 1350; //LED blinky subroutines
static void blink1() {
//digitalWrite(ledPin, HIGH);
BITSET( PORTB, 1);
delay(100);
//digitalWrite(ledPin, LOW);
BITCLR( PORTB, 1);
delay(100);
} static void blink2() {
//digitalWrite(ledPin, HIGH);
BITSET( PORTB, 1);
delay(100);
//digitalWrite(ledPin, LOW);
BITCLR( PORTB, 1);
delay(100);
//digitalWrite(ledPin, HIGH);
BITSET( PORTB, 1);
delay(100);
//digitalWrite(ledPin, LOW);
BITCLR( PORTB, 1);
delay(100);
} static void blink3() {
//digitalWrite(ledPin, HIGH);
BITSET( PORTB, 1);
delay(100);
//digitalWrite(ledPin, LOW);
BITCLR( PORTB, 1);
delay(100); //digitalWrite(ledPin, HIGH);
BITSET( PORTB, 1);
delay(100);
//digitalWrite(ledPin, LOW);
BITCLR( PORTB, 1);
delay(100); //digitalWrite(ledPin, HIGH);
BITSET( PORTB, 1);
delay(100);
//digitalWrite(ledPin, LOW);
BITCLR( PORTB, 1);
delay(100);
} //read rotary BCD switch for RF Group subroutine
//all input pin default pulled high internally from atmega328 or can
//also using 10K external Resistor
//BCD switch: convert binary to decimal, then to ASCII BCD1 -> A=65,
//BCD2 -> B=66, etc.,
//while BCD0 is broadcast mode
static byte getFGcmd () {
byte FG = 64;
//PC0
if (BITTST ( PINC, 0, 0 )) {
FG += 8;
}
//PC1
if (BITTST ( PINC, 1, 0 )) {
FG += 4;
}
//PC2
if (BITTST ( PINC, 2, 0 )) {
FG += 2;
}
//PC3
if (BITTST ( PINC, 3, 0 )) {
FG += 1;
}
if (FG == 64) {
FG = 0;
}
return FG;
} //read rotary BCD switch for flash power subroutine
//all input pin default pulled high internally from atmega328 or can
//also using 10K external Resistor
//BCD switch: convert binary to decimal 0-9, 0 is lowest power, 9 is
//the highest/full power.
static byte getVPcmd () {
byte VP = 0;
if (BITTST ( PINB, 0, 0 )) {
VP += 8;
}
if (BITTST ( PIND, 7, 0 )) {
VP += 4;
}
if (BITTST ( PIND, 6, 0 )) {
VP += 2;
}
if (BITTST ( PIND, 5, 0 )) {
VP += 1;
}
return VP;
} void setup() {
//all input pins are pulled high using external or internal 10K
//Resistor //RF Group BCD rotary switch
pinMode(fg8Pin, INPUT);
pinMode(fg4Pin, INPUT);
pinMode(fg2Pin, INPUT);
pinMode(fg1Pin, INPUT); //VariPower/quench timing BCD rotary switch
pinMode(vp8Pin, INPUT);
pinMode(vp4Pin, INPUT);
pinMode(vp2Pin, INPUT);
pinMode(vp1Pin, INPUT); //connect to hot shoe in the camera to trigger the flash
pinMode(syncPin, INPUT); //connect to push button to send the varipower/quench timing command
//to the receiver
pinMode(vpPin, INPUT); //toggle switch for TX or RX mode
pinMode(modePin, INPUT); //led status pin
pinMode(ledPin, OUTPUT); //trigger flash pin to connect to optocoupler1
pinMode(triggerFlashPin, OUTPUT); //quench pin to connect to optocoupler2
pinMode(quenchPin, OUTPUT); digitalWrite(ledPin, LOW);
digitalWrite(quenchPin, LOW);
digitalWrite(triggerFlashPin, LOW);
delay(500); //activate internal pull-up for all input pins, if using atmega328
//internal pull up resistor
digitalWrite(fg8Pin, HIGH);
digitalWrite(fg4Pin, HIGH);
digitalWrite(fg2Pin, HIGH);
digitalWrite(fg1Pin, HIGH);
digitalWrite(vp8Pin, HIGH);
digitalWrite(vp4Pin, HIGH);
digitalWrite(vp2Pin, HIGH);
digitalWrite(vp1Pin, HIGH);
digitalWrite(syncPin, HIGH);
digitalWrite(vpPin, HIGH);
delay(1000); //if mode toggle switch=LOW, is RX Mode On, choose RF group from the
//value of BCD rotary switch for RF Group
//if mode toggle switch=HIGH, is TX Mode On, choose RF group outside
//A-I group, use TxID value
//Note: this toggle switch must be set, before you turn on the
//SPOTduino device
if (BITTST ( PIND, 0, 0 )) {
rf12initialize(getFGcmd(), RF12915MHZ, 0x58); //RX Mode ON
}
else {
rf12initialize(TxID, RF12915MHZ, 0x58); //TX Mode ON
}
delay(500);
//give blinky 2x3 to give init status OK
blink3();
delay(200);
blink3();
//set RF unit alive
rf12recvDone();
delay(100);
} void loop() {
//TX subroutine
//if syncPin is LOW, send the syncCmd to all RX unit (broadcast) to
//fire the flash
//if (digitalRead(syncPin) == LOW && rf12canSend()) { //equiv in Arduino std cmd
if ( BITTST ( PIND, 3, 0 ) && rf12canSend()) {
rf12sendStart(0, syncCmd, 2); //Send syncCmd to all RX unit
delay(50);
blink1();
}
//if vpPin is LOW, get the first rotary BCD value for RF group
//or Flash Group
//also read second rotary BCD switch value for the flash power
//(quench time)
//then send the vpCmd to that specific RF group (Flash Group)
//if (digitalRead(vpPin) == LOW && rf12canSend()) { //equiv in Arduino std cmd
if ( BITTST ( PIND, 4, 0 ) && rf12canSend() ) {
vpCmd1; //set the 2nd byte of TX
//buffer from the value of BCD switch
//for varipower/quench timing
rf12sendStart(getFGcmd(), vpCmd, 2); //Send varipower/quench
//timing to specific RX RF unit group
//based on BCD switch for RF group
delay(50);
blink2();
}
//RX subroutine
if (rf12recvDone()) { //if RF buffer receive data...
if (rf12data0 {
//if RF RX buffer = 'XS' (means trigger flash command received)
//if trigger flash command received, turn on triggerFlashPin,
//then wait according to quench timing, then turn on the quench pin
//digitalWrite(triggerFlashPin, HIGH);
//sets the triggerFlashPin HIGH to trigger
//optocoupler1 to fire the flash
BITSET( PORTC, 5);
delayMicroseconds(vp);
// then wait for 'vp' mS before
//trigger the quench optocoupler
//digitalWrite(quenchPin, HIGH);
// sets the quenchPin HIGH to
//trigger optocoupler2 to short circuit flash quench pin to ground
BITSET( PORTC, 4);
delay(100);
//digitalWrite(quenchPin, LOW);
// sets the quench pin LOW again
BITCLR( PORTC, 4);
//digitalWrite(triggerFlashPin, LOW);
// sets the triggerFlashPin LOW again
BITCLR( PORTC, 5);
//LED blinky 1 time for sync
blink1();
}
//if set power/quench timing command received,
//set the quench pin delay time (vp var)
if (rf12data0 {
// if RF RX buffer 1st char = 'V'
//(means set power/quench timing command received)
switch (rf12data1 {
//check RF RX buffer 2nd char
//(value is 0 to 9), then set vp variable
//accordingly to the value received
// This section below is where you can modify the vp value
//accordingly to your flash brand and model,
// below is sample from my Vivitar 285HV
case 9:
vp = 1350;
//I think 1350mS quench is the real full power
//for my vivitar 285HV
break;
case 8:
vp = 1000;
//according to vivitar 285HV spec, 1000mS is
//full power, but I believe it is longer
break;
case 7:
vp = 800;
break;
case 6:
vp = 650; //1/2 power??
break;
case 5:
vp = 500;
break;
case 4:
vp = 350; // 1/4 power??
break;
case 3:
vp = 250;
break;
case 2:
vp = 125; // 1/8 power??
break;
case 1:
vp = 63; //1/16 power??
break;
case 0:
vp = 32; //1/32 power??
break;
default:
break;
}
//LED blinky 2 times for setting up the flash power
blink2();
}
}
}
