CNI widgets
Serial port scan trigger device
We are using a [Teensy board] programmed using a simple [teensyduino] sketch. The basic sketch is
/* * CNI_trigger sketch for Arduino. * * * A simple sketch to generate TTl pulses when told to do so through a serial * port command. * * When running this sketch on a Teensy, be sure to set the "USB Type" to * "Serial" (under the Arduino Tools menu). * * This sketch will also listen for input pulses and send out a serial port * character whenever one is detected. It uses an external interrupt, so it * can reliably detect very brief pulses. We use this to detect the GE 3.3v * scope trigger pulses (~4 usec pulse duration). * * * Copyright 2011 Robert F. Dougherty. * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You might have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * * HISTORY: * 2011.03.28 RFD (bobd@stanford.edu) finished a working version. * 2011.05.24 RFD: cleaned up source & comments, removed down-counter code, * and added a serial message upon every input pulse that's detected. */ #define VERSION "1.0" // Flash library is available from http://arduiniana.org/libraries/Flash/ #include <Flash.h> #include <Messenger.h> #define BAUD 57600 #define DEFAULT_OUT_PULSE_MSEC 5 #define DEFAULT_IN_PULSE_STATE 0 // The approximate duration of the output pulse, in milliseconds. // Note that we don't account for delays in the code, so it will // always be a bit longer than this. unsigned int g_outPulseDuration = DEFAULT_OUT_PULSE_MSEC; // The input pin should be the pin mapped to INT0, unless you change // the interrupt number below. The output pin can be any digital pin. // Teensy2.0 has LED on pin 11 and INT0 on pin 5 (D0) #define INTERRUPT 0 const byte g_outPin = 11; const byte g_inPin = 5; byte g_inPulseEdge = FALLING; volatile byte g_outPinOn = false; volatile unsigned long g_outPulseStart; // Instantiate Messenger object used for serial port communication. Messenger g_message = Messenger(',','[',']'); // Create the Message callback function. This function is called whenever a complete // message is received on the serial port. void messageReady() { int val[10]; byte i = 0; if(g_message.available()) { // get the command byte char command = g_message.readChar(); switch(command) { case '?': // display help text Serial << F("CNI Trigger Device\n"); Serial << F("Sends TTL pulses out on pin ") << (int)g_outPin << F(".\n"); Serial << F("Listens for pulses in on pin ") << (int)g_inPin << F(".\n"); Serial << F("\nCommands:\n"); Serial << F("[t] will send a trigger pulse. This also disables the input pulse\n"); Serial << F(" detection. Send a [p] command to re-enable it.\n\n"); Serial << F("[o,N] set the output pulse duration to N milliseconds. Send with\n"); Serial << F(" no argument to show the current pulse duration.\n\n"); Serial << F("[p] enable input pulse detection. Send a [t] to disable.\n\n"); Serial << F("[r] reset default state.\n\n"); break; case 'o': // Set out-pulse duration (msec) while(g_message.available()) val[i++] = g_message.readInt(); if(i>1){ Serial << F("ERROR: Set output pulse duration requires no more than one param.\n"); }else if(i==1){ g_outPulseDuration = val[0]; } Serial << F("Output pulse duration is set to ") << g_outPulseDuration << F(" msec.\n"); break; case 't': // force output trigger // First force the pin low, in case it was already on. This will ensure that // we get a change on the pin no matter what state we were in. if(g_outPinOn) digitalWrite(g_outPin, LOW); triggerOut(); // Automatically disable input pulse detection setInPulseState(0); break; case 'p': // turn on input pulse detection //Serial << F("Enabling input pulses\n"); setInPulseState(1); break; case 'r': // reset setInPulseState(DEFAULT_IN_PULSE_STATE); g_outPulseDuration = DEFAULT_OUT_PULSE_MSEC; digitalWrite(g_outPin, LOW); break; default: Serial << F("[") << command << F("]\n"); Serial << F("ERROR: Unknown command.\n\n"); } // end switch } // end while } void setup(){ Serial.begin(BAUD); Serial << F("*********************************************************\n"); Serial << F("* CNI Trigger firmware version ") << VERSION << F("\n"); Serial << F("* Copyright 2011 Bob Dougherty <bobd@stanford.edu>\n"); Serial << F("* http://cniweb.stanford.edu/wiki/CNI_widgets\n"); Serial << F("*********************************************************\n\n"); // This probably isn't necessary- external interrupts work even in OUTPUT mode. pinMode(g_inPin, INPUT); pinMode(g_outPin, OUTPUT); digitalWrite(g_outPin, LOW); setInPulseState(DEFAULT_IN_PULSE_STATE); // Attach the callback function to the Messenger g_message.attach(messageReady); Serial << F("CNI Trigger Ready. Send the ? command ([?]) for help.\n\n"); } void loop(){ // Reset the output, if needed: if(g_outPinOn){ // Turn off the output pin after the requested duration. // Detect and correct counter wrap-around: if(millis()<g_outPulseStart) g_outPulseStart += 4294967295UL; if(millis()-g_outPulseStart > g_outPulseDuration) digitalWrite(g_outPin, LOW); } // Handle Messenger's callback: if(Serial.available()) g_message.process(Serial.read()); } void setInPulseState(byte state){ // Turn on the internal pull-up resistor if we want to detect falling edges. if(g_inPulseEdge==FALLING) digitalWrite(g_inPin, HIGH); else digitalWrite(g_inPin, LOW); // Attach or detach the interrupt if(state) attachInterrupt(INTERRUPT, triggerIn, g_inPulseEdge); else detachInterrupt(INTERRUPT); } // The following is an interrupt routine that is run each time the // a pulse is detected on the trigger input pin. void triggerIn(){ Serial << F("p"); } void triggerOut(){ digitalWrite(g_outPin, HIGH); g_outPinOn = true; g_outPulseStart = millis(); //Serial << F("OUT\n"); }
GE physiological data monitor
Circuit tidbits
RS232 level converter
We need a little circuit to take the scanner data stream (-12v to +12v) and allow it to be safely ready by our 5v microprocessor. We just took the Tx part of this simple RS232 level converter. We used a 2N3904 transistor with emitter to ground, collector to the UART Rx pin on the microcontroller with a 10k pull-up resistor to the 5v line, and the base connected to the Tx line coming from the scanner via a 4.7K resistor, with a 4.7k pull-down to ground.