Skip to content

Making A Trigger Generator

jstanleyx edited this page Aug 23, 2019 · 6 revisions

← Previous topic: Triggers | Next topic: Testing Your Trigger Generator →

Making A Trigger Generator

A good external trigger generator for image collection would have several important properties.

  • Stable. Same pulse rate day in, day out.
  • Low power.
  • Programmable. If you want to change from 2 fps to something else...
  • Cheap.
  • Small.

A crystal-controlled microprocessor can have all of these. For example, an Arduino Nano. While the official Nano is rather expensive, Chinese versions of the device can be found online (Amazon) for less than $5 each. They may require a bit of soldering to install the pins so the device can be socketed, but you can always solder to the holes if you want to hardwire the connections.

Software

The code to create a simple, fixed 2fps pulse generator is very simple. The 1/2 second interval is provided by the two instances of the constant "500000" -- 500,000 microseconds. It is left to the reader as an exercise to determine how you would create a four fps trigger source.

    unsigned long now;

    void setup() {
  
      // put your setup code here, to run once:
      pinMode( 4, OUTPUT );
      pinMode( 5, OUTPUT );
      pinMode( 6, OUTPUT );
      pinMode( 13, OUTPUT );
      digitalWrite( 4, HIGH );
      digitalWrite( 5, HIGH );
      digitalWrite( 6, HIGH );
      digitalWrite( 13, LOW );

      now = micros();
  
    }


    void loop() {
  
      // put your main code here, to run repeatedly:
      digitalWrite( 4, HIGH );
      digitalWrite( 5, HIGH );
      digitalWrite( 6, HIGH );
      digitalWrite( 13, LOW );

      while( (micros() - now) < 500000 ) { };
      now += 500000;
  
      digitalWrite( 13, HIGH );
      digitalWrite( 4, LOW );
      digitalWrite( 5, LOW );
      digitalWrite( 6, LOW );
    
    }

The "setup" function configures the I/O pins to be output for D4, D5, and D6 and sets all three to "high". The "loop" function repeatedly sets the same pins high, waits for 500,000 microseconds, turns the output pins low. It immediately returns to the top of the loop and sets the outputs back to high. This creates a short (20ms or so) low pulse on the output pins. Pin 13 is the red LED on the Nano, which is pulsed "on" when the low trigger pulse is output.

Three outputs are pulsed so that you can distribute the load across multiple outputs. I.e., camera 1 goes to D4, camera 2 to D5, etc. This circuit will drive more than two cameras per pin.

Hardware

The Chinese version of the Nano is certainly the cheaper one, and the difference is, in large part, the use of a different USB to serial interface circuit. The Chinese Nano has a CH340, which is not found automatically by Windows Update (at least not for my version of Windows.) You can download the driver from here.

The wiring to the Nano is very simple. Here's a diagram.

Software Update

Well, I said it would be an interesting modification to change the trigger code to allow changing the trigger via serial (USB) input, and it is. Here's my version. It is a lot longer than the first one, but you can send the desired microsecond period out the COM port at 9600 baud followed by a newline and change the timing.

I've found that using a period of 500185 microseconds puts the timing almost dead on 2Hz. Your Arduino may be different.


// global variables
unsigned long now;
unsigned long interval;
unsigned long snap;
String inputString = "";
boolean stringComplete = false;
unsigned long temp;
int ports[] = {4,5,6,7,8,9,10,11,12,0};
int ii;

// initializations
void setup() {

  // open a 9600 baud serial link through USB
  Serial.begin( 9600 );
  while ( !Serial ) {
    ;
  }

  Serial.println("Hello, starting trigger loops...");

  // reserve 100 characters in my input string
  inputString.reserve(100);

  // set all digital pins to output
  for( ii=0; ports[ii]>0; ii++ ) {
    pinMode( ports[ii], OUTPUT );
    digitalWrite( ports[ii], HIGH );
  }
  // plus the on-board LED
  pinMode( 13, OUTPUT );

  // turn off LED
  digitalWrite( 13, LOW );

  // when is now?
  now = micros();
  // and default interval of 500,000 microseconds
  interval = 500259;

}


void loop() {

  // if we haven't reached out interval yet, nothing
  if ( (micros() - now) < interval ) {
    ;
  }
  // otherwise, send pulse
  else {

    // set next pulse time
    now += interval;

    // light the LED
    digitalWrite( 13, HIGH );

    // and send out our active low pulse
    for( ii=0; ports[ii]>0; ii++ )
      digitalWrite( ports[ii], LOW );

    // a temporary timer to set pulse length
    snap = micros();

    // wait 100 micros for trigger pulse
    while ( (micros() - snap) < 100 ) {
      ;
    }

    // and go back HIGH
    for( ii=0; ports[ii]>0; ii++ )
      digitalWrite( ports[ii], HIGH );

    // wait 5 ms for the LED flash
    while ( (micros() - snap) < 5000 ) {
      ;
    }

    // and turn it back off
    digitalWrite( 13, LOW );

  }

  // every loop, look for serial input
  while ( Serial.available() ) {

    // if there, read one char
    char inChar = (char)Serial.read();

    // add to input string
    inputString += inChar;

    // look for newline to end input
    if ( inChar == '\n' ) {
      stringComplete = true;
    }
  }

  // if we got a newline ...
  if ( stringComplete ) {

    // convert to integer and say string is not complete
    temp = inputString.toInt();
    stringComplete = false;

    // if we got anything but 0 for our conversion ...
    if ( temp ) {

      // report the change in case Poppa is listening
      Serial.print("Changing interval from ");
      Serial.print( interval );
      Serial.print(" to ");
      Serial.print( temp );
      Serial.println(" microseconds");

      // change the interval and clear the temp
      interval = temp;
      temp = 0;
    }
    // invalid input if 0
    else {
      Serial.print("Error: invalid interval: ");
      Serial.print( inputString );
    }

    // clear the input for the next time
    inputString = "";

  }

}



[[ ← Previous topic: Triggers | Triggers ]] | [[Next topic: Testing Your Trigger Generator → | Testing-Your-Trigger-Generator ]] 
Clone this wiki locally