/* Stepper Scanner by Tony Wills Slighty modified version of Shapespeare Scanner by Whitney Potter This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. Controls SELECT: Start/Stop automatic scan. LEFT: Step through post shutter delay times. RIGHT: Step one unit clockwise without triggering camera. DOWN: Step one unit counter clockwise without triggering camera. UP: Cycle through options for number of exposures per revolution. Version AJW 2.0 */ #include #include #include #include "multiCameraIrControl.h" const int stepsPerRevolution = 200; // change this to fit the number of steps per revolution for your motor Stepper myStepper(stepsPerRevolution, A1, A2, A3, A4 ); // initialize stepper LiquidCrystal lcd(8, 9, 4, 5, 6, 7); //pin assignments for SainSmart LCD Keypad Shield DFR_Key keypad; // initialize keypad int localKey = 0; int lastKey = 0; int keyChange = 1; // set true when key is released. Prevents double triggers. int stepChoices [] = {25, 40, 50, 66, 100, 200}; // different numbers of exposures per revolution which may be selected. Higher number = smaller angle change // will only step by int(stepsPerRevolution/stepChoices[i]) per step, so won't do a complete revolution for non integer results int stepIndex = 0; // step choices selection int numStepChoices = 0; //number of step choices, this variable is initialised in the setup code int runFlag = 0; // whether scanner running int stepCount = 1; // count of exposures starting at 1 long delayChoices [] = {0, 500, 1000, 2000, 4000, 5000, 6000}; // different post shot delays available int delayIndex = 1; // delay choices selection int numDelayChoices = 0; // number of delay choices, this variable is initialised in the setup code unsigned long startWait; // time we start the wait timer unsigned long currentTime; // current time const long preWait = 500; // pre exposure pause in millis(). Allows the specimen to settle before exposure. unsigned long postWait = 0; // post exposure pause in millis(). Allows time for the exposure to finish before moving. int waitFlag = 0; // 0=ready to move 1=pre-exposure wait 2=post-exposure wait //Nikon Camera(2); // change Nikon to any other supported brand //CanonWLDC100 Camera(2); Olympus Camera(2); void setup() { Serial.begin(9600); // Open debugging output lcd.begin(16, 2); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Stepper Scanner"); lcd.setCursor(0, 1); lcd.print("version AJW 2.0"); delay(2500); lcd.clear(); // set number of choices based on the actual number of choices found in the respective arrays numStepChoices = (sizeof(stepChoices) / sizeof(stepChoices[0])); numDelayChoices = (sizeof(delayChoices) / sizeof(delayChoices[0])); // set the speed at 10 rpm: myStepper.setSpeed(10); // not actually using motor enable/disable so these bits are commented out throughout the program // pinMode(19, OUTPUT); //enable pin // digitalWrite(19, HIGH); } void loop() { postWait = delayChoices[delayIndex]; lcd.setCursor(0, 0); lcd.print("Steps:"); lcd.setCursor(6, 0); lcd.print(stepChoices[stepIndex]); lcd.print(","); lcd.print(delayChoices[delayIndex]); lcd.print("ms "); lcd.setCursor(0, 1); if (runFlag == 1) { lcd.print("run "); } else { lcd.print("stop "); } // poll keypad to see if any commands given // The polling based time delay allows us to still receive keypad input during the delay // so we can manually step and change post wait delay even while stepping is in progress localKey = keypad.getKey(); // read keypad // Serial.println(localKey); if (localKey != SAMPLE_WAIT) { if (localKey == 0) // key has been released { keyChange = 1; // the next key data represents a new key press } if (localKey == 1 && keyChange == 1) //select=start sequence { if (runFlag == 0 && keyChange == 1) { runFlag = 1; waitFlag = 0; keyChange = 0; if (stepCount > stepChoices[stepIndex]) //the revolution is complete. { stepCount = 1; //reset stepCount if auto scan is complete, to start another scan. } } if (runFlag == 1 && keyChange == 1) { runFlag = 0; keyChange = 0; } } if (localKey == 2 && keyChange == 1) // left=post shot delay select { keyChange = 0; // digitalWrite(19, LOW); // activate stepper driver // digitalWrite(19, HIGH); // deactivate stepper driver to save power, heat and noise if (delayIndex < numDelayChoices - 1) { delayIndex ++; } else { delayIndex = 0; } } if (localKey == 3 && keyChange == 1 && runFlag == 0) //up=cycle through steps per revolution choices { stepCount = 1; keyChange = 0; if (stepIndex < numStepChoices - 1) { stepIndex ++; } else { stepIndex = 0; } } if (localKey == 4 && keyChange == 1) //down=1 step counter clockwise { keyChange = 0; lcd.setCursor(0, 1); lcd.print("CCW step"); // digitalWrite(19, LOW); myStepper.step(-stepsPerRevolution / stepChoices[stepIndex]); // digitalWrite(19, HIGH); } if (localKey == 5 && keyChange == 1) //right=1 step clockwise { keyChange = 0; lcd.setCursor(0, 1); lcd.print("CW step "); // digitalWrite(19, LOW); myStepper.step(stepsPerRevolution / stepChoices[stepIndex]); // digitalWrite(19, HIGH); } } if (runFlag == 1) //sequence is running { if (stepCount > stepChoices[stepIndex]) //the revolution is complete. { runFlag = 0; // stop sequence lcd.setCursor(9, 1); lcd.print("Done "); } else { currentTime = millis(); // Serial.print("current : "); // Serial.println(currentTime); // if not waiting for anything then take next step if (waitFlag == 0) // advance stepper and start wait timer { startWait = millis(); waitFlag = 1; // start preshutter wait lcd.setCursor(9, 1); lcd.print("Exp#: "); lcd.setCursor(13, 1); lcd.print(stepCount); // digitalWrite(19, LOW); //activate stepper driver // Serial.println("move"); Serial.println(stepsPerRevolution / stepChoices[stepIndex]); myStepper.step(stepsPerRevolution / stepChoices[stepIndex]); //advance stepper // digitalWrite(19, HIGH); //deactivate stepper driver } // when preshutter wait expires, trigger shutter if (waitFlag == 1) { if ((currentTime - startWait) >= preWait) //wait time has expired { // Serial.println("click"); Camera.shutterNow(); // trigger shutter startWait = millis(); // restart wait timer currentTime = millis(); waitFlag = 2; // initiate post shutter wait stepCount ++; } } // when post wait expires just reset flag if (waitFlag == 2) // wait after triggering shutter before moving motor { if ((currentTime - startWait) >= postWait) //wait time has expired { // Serial.println("done, next"); waitFlag = 0; //done waiting } } } } }