Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pietroartoni/943137046d610120658b to your computer and use it in GitHub Desktop.
Save pietroartoni/943137046d610120658b to your computer and use it in GitHub Desktop.
Spectrumino: an Arduino Due based tool for spectroscopy
/*This sketch is for Arduino Due and is made for getting fast spectra in vivo.
The software asks for the first wavelength of the spectrum, the wavelength step, the length of the spectrum and for the laser intensity during the spectrum.
Imaging is triggered by the ECG signal, to be in phase with the heartbeat.
Feel free to fork it! Comments and suggestions are appreciated.
*/
//global variables
double alpha;
int nframes = 10; //number of frames to be mediated for each wavelength
int lambdamin; //first lambda
int deltalambda; //lambda step
int n_scansioni; //number of wavelengths
int LEDred = 12; //activity led (busy)
int LEDgreen = 13; //activity led (free)
double potmisuratamW; //instantaneous measured power in mW
double potmisuratadouble;
double mediapotmisuratamW;//mediated measured power in mW
double epsilonS;
int TRIGGER_prairie = 3;
int SHUTTER = 4; //shutter of the microscope
int CHAMELEON = 9; //shutter of the chameleon laser
int i = 0;
int k = 0;
int epsilon = 5;
//boolean control flow variables
boolean pippo = false ;
boolean pippo2 = false ;
boolean pippo3 = true ;
boolean pippo4 = true ;
boolean pippo5 = true ;
boolean pippo6 = true ;
boolean pippo7 = true ;
//analog I/O
int pinpotmisurata = A0; //indicates the measured power
int heartbeat = A3;
int pinpotimposta = DAC0;
int potimposta;
int potmisurata;
double targetpower;
int powermax = 4090; //maximum voltage allowed by the pockels cell amplifier, is 2.00v but can be boosted to 2.25v. 16 bit value
int memo910 = 0;
int t0;
int t1;
double ratio; //ratio between measured power and target power
//setup section, this happens only once
void setup() {
//serial initialization
Serial.begin(19200); //debug
Serial1.begin(19200); //serial communication with the pc (termite serial monitor)
Serial3.begin(19200); //serial communication with the laser
//digital and analog pin definition
pinMode(potmisurata, INPUT);
pinMode(heartbeat, INPUT);
pinMode(TRIGGER_prairie, OUTPUT);
pinMode(SHUTTER, OUTPUT);
pinMode(CHAMELEON, OUTPUT);
pinMode(LEDred, OUTPUT);
pinMode(LEDgreen, OUTPUT);
pinMode(pinpotimposta, OUTPUT);
digitalWrite(CHAMELEON, HIGH);
}
//heartbeat synchronization function
void synchroheartbeat(void)
{
int data = 0;
int trigger = 300;
int nbeat = 0;
int nbeatmax = 2;
bool pippolo = false;
delay(100);
while (nbeat < (nbeatmax + 1)) {
// dataold=data;
data = analogRead(heartbeat);
Serial.println(data);
if ((data > trigger) && (pippolo == false))
{ nbeat++;
pippolo = true;
digitalWrite(LEDgreen, HIGH);//switch on the green led
delay(15);
}
if (data <= trigger) {
digitalWrite(LEDgreen, LOW);
//switch off the green led
pippolo = false;
}
}
digitalWrite(LEDgreen, LOW);
digitalWrite(CHAMELEON, HIGH);
digitalWrite(TRIGGER_prairie, HIGH); //send the trigger to the microscope
delayMicroseconds (20);
digitalWrite(TRIGGER_prairie, LOW);
delay (360); //time necessary for scanning + time necessary for measurements
digitalWrite(CHAMELEON, LOW);
}
//loop section, this happens continuosly
void loop() {
epsilonS = 0.002;
//12 bit resolution for reading and writing through A/D and D/A converters
analogReadResolution(12);
analogWriteResolution(12);
digitalWrite(LEDred, LOW);
digitalWrite(LEDgreen, LOW);
digitalWrite(SHUTTER, LOW);
analogWrite(pinpotimposta, 0);
if (pippo == true) {
t0 = millis();
delay (100);
digitalWrite(TRIGGER_prairie, LOW);
digitalWrite(LEDred, HIGH);
digitalWrite(LEDgreen, LOW);
digitalWrite(SHUTTER, LOW);
potimposta = 0;
analogWrite(pinpotimposta, potimposta);
Serial1.println("Start spectrum (type q to stop acquisition)");
for (i = 0; i < n_scansioni; i++)
{
Serial1.print("\nlambda ");
Serial1.print(lambdamin + i * deltalambda);
Serial3.print("VW=");
Serial3.println(lambdamin + i * deltalambda);
delay (2000); //time needed by the laser to change the wavelength
if (i == 0) {
potimposta = 0;
mediapotmisuratamW = 0;
analogWrite(pinpotimposta, potimposta);
}
else {
//power measurement
mediapotmisuratamW = 0;
for (k = 0; k < 200; k++)
{
potmisurata = analogRead(pinpotmisurata);
potmisuratadouble = potmisurata;
potmisuratamW = potmisuratadouble * 30 / 1186;
mediapotmisuratamW = potmisuratamW + mediapotmisuratamW;
}
mediapotmisuratamW = mediapotmisuratamW / 200;
Serial.println(mediapotmisuratamW);
}
alpha = 1;
if (lambdamin + i * deltalambda >= 900) {
alpha = 2 * (lambdamin + i * deltalambda - 900) / 100 + 1;
}
while ((abs(mediapotmisuratamW - targetpower) / targetpower) > epsilonS)
{
//3 step algorithm for setting the power of the laser
ratio = mediapotmisuratamW / targetpower;
//decreases the power if too high
if ((ratio >= 1.0) && (ratio < 1.1))
{
potimposta = potimposta - alpha * 5;
}
if ((ratio >= 1.1) && (ratio < 1.40))
{
potimposta = potimposta - alpha * 10;
}
if (ratio >= 1.40)
{
potimposta = potimposta - alpha * 50;
}
//increases the power if too low
if (ratio < 0.6)
{
potimposta = potimposta + alpha * 50;
}
if ((ratio >= 0.6) && (ratio < 0.9))
{
potimposta = potimposta + alpha * 10;
}
if ((ratio >= 0.9) && (ratio < 1.0))
{
potimposta = potimposta + alpha * 5;
}
delay (50);
analogWrite(pinpotimposta, potimposta);
delay (100); //let the power meter do the measurement
//give 50 ms extra for the voltage rise, due to the low pass filter
//power measurement
mediapotmisuratamW = 0;
for (k = 0; k < 200; k++)
{
potmisurata = analogRead(pinpotmisurata);
potmisuratadouble = potmisurata;
potmisuratamW = potmisuratadouble * 30 / 1186;
mediapotmisuratamW = potmisuratamW + mediapotmisuratamW;
}
mediapotmisuratamW = mediapotmisuratamW / 200;
Serial.println(mediapotmisuratamW);
//end of power measurement
if (potimposta > powermax) {
targetpower = 0; //for Pockels cell protection
Serial1.println("Error - too high power on the pockel cell");
//exits the loop
}//exit from the if
if (Serial1.read() == 'q') {
Serial1.print("\nstopped ");
i = n_scansioni;
} //if the loop doensn't converge
}//exit from while
if ((lambdamin + i * deltalambda) == 900) {
memo910 = potimposta;
}
digitalWrite(SHUTTER, HIGH);
delay(200);
Serial1.print("frame n ");
for (int conta = 0; conta < nframes; conta++) {
synchroheartbeat(); //synchronization to the heartbeat, and image triggering
delay(300);
Serial1.print("");
Serial1.print(conta + 1);
}
Serial1.println("");
digitalWrite(CHAMELEON, HIGH);
Serial1.print(" - power = ");
Serial1.print(mediapotmisuratamW);
Serial1.println(" mW");
digitalWrite(SHUTTER, LOW);
// event, if something is not right and the user wants to exit the scan
if (Serial1.read() == 'q') {
Serial1.print("\nstopped ");
i = n_scansioni;
} //exit from the if loop
} //exit from the for loop
digitalWrite(SHUTTER, LOW);
digitalWrite(LEDred, LOW);
digitalWrite(LEDgreen, HIGH);
potimposta = 0;
analogWrite(pinpotimposta, potimposta);
t1 = millis();
Serial1.print("\n\n...finished! \nTime elapsed = ");
Serial1.print((t1 - t0) / 60000);
Serial1.print(" min and ");
Serial1.print(((t1 - t0) % 60000) / 1000);
Serial1.print(" s \n");
pippo = false;
pippo2 = false;
pippo3 = true;
pippo4 = true;
pippo5 = true;
pippo6 = true;
pippo7 = true;
}
/*In this part of the sketch the Arduino Due asks the user for the parameters of the spectrum, and then gets the parameters
from the PC. The protocol used is the serial communication port 1 of the Arduino Due.
When the code is looped in these queries, waiting the parameters from the user,
the Arduino Due leaves the user taking control of the microscope,
seeking another field to image, for example. Wavelength is tuned at 910 nm automatically.
Termite, or any other software for serial communication, has to be run on the PC.
The settings for the serial communication are as follows:
port: comXX, or dev/ttyXX (the one used by the operative system, usually changes if different serial devices are connected)
Baud rate: 19200
data bits: 8
stop bits: 1
parity: none
flow control: none
forward: none
append: nothing
local echo: off.
*/
else {
digitalWrite(SHUTTER, HIGH);
digitalWrite(LEDred, LOW);
digitalWrite(LEDgreen, HIGH);
digitalWrite(TRIGGER_prairie, LOW); // just to be sure
analogWrite(pinpotimposta, memo910);
delay(200);
if (pippo7 == true) {
Serial3.println("VW=910");
}
pippo7 = false;
if (pippo2 == false) {
Serial1.println("Spectrum parameters");
Serial1.print("first lambda = ");
while (pippo3 == true) {
if (Serial1.available() > 0) {
int var4 = Serial1.parseInt();
if ((var4 >= 760) && (var4 <= 1039)) {
lambdamin = var4;
Serial1.println(lambdamin);
pippo3 = false;
}
}
}
Serial1.print("step nm = ");
while (pippo5 == true) {
if (Serial1.available() > 0) {
deltalambda = Serial1.parseInt();
Serial1.println(deltalambda);
pippo5 = false;
}
}
Serial1.print("number of wavelengths = ");
while (pippo4 == true) {
if ((Serial1.available() > 0)) {
int var2 = Serial1.parseInt();
if (lambdamin + (var2 - 1)*deltalambda < 1040) {
n_scansioni = var2;
Serial1.println(n_scansioni);
pippo4 = false;
}
}
}
Serial1.print("power (mW) = ");
while (pippo6 == true) {
if ((Serial1.available() > 0)) {
double var3 = Serial1.parseInt();
if (var3 <= 28) {
targetpower = var3;
Serial1.println(targetpower);
pippo6 = false;
}
}
}
Serial1.println("\nStart T-Series on Prarie, then, press s to start!");
Serial1.println("Press n for new parameters\n");
pippo2 = true;
}
char lettera = Serial1.read();
switch (lettera) {
case 's':
pippo = true;
break;
case 'n':
pippo = false;
pippo2 = false;
pippo3 = true;
pippo4 = true;
pippo5 = true;
pippo6 = true;
break;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment