Hi,
New user and new to arduino. I have an issue which is probably really simple but I seem to have cooked my brain learning all this and the answer isn't clear to me. I'm building a controller to drive a stepper connected to a microscope fine focus for use for focus stacking macro images. Here's the setup if of interest (sorry it's taken on a phone):
With the way it's geared, one step should equal a movement of the camera of about one micron. What I want to be able to do with the controller is choose the number of pictures I want to take and how many steps to move between each picture. Then I want to push a button and leave it to get on with it.
I'm using the following hardware:
Arduino Uno
easydriver v4.3
stepper motor with timing belt
serial lcd 16x2
momentary push button switch
sparkfun rotary encoder with button
opocouplers for camera control
I patched the code together from various sources (thank you everyone I've borrowed from). Here it is:
#include <SLCD.h> // lcd library
//2x16 char display
#define numRows 2 // Display has two rows
#define numCols 16 // Display has 16 columnsSLCD lcd = SLCD(numRows, numCols);
//Rotary encoder
#define ENC_A A0
#define ENC_B A1
#define ENC_PORT PINCstatic uint8_t steps = 0;
static uint8_t numPictures = 0;int pushButton = 2; // Pin 2 = Start/ Stop Button
int rotaryButton = 3;
int focus = 6; // Pin 6 = Focus the camera
int shutter = 7; // Pin 7 = Take a picture
int dir = 8; // Pin 5 = Stepper motor direction
int doStep = 9; // Pin 8 = Move stepper motor
int sleep = 10; // Pin 12 = Cut power to stepper motor when not in use
int ms1 = 11; // Pin 9 = Use with MS1 to enable/ disable microstepping (default disabled)
int ms2 = 12; // Pin 10 = Use with MS2 to enable/ disable microstepping (default disabled)
int toggleLed = 13; // Pin 13 = Switch onboard LED on/off depending on status of toggle button//pushButton toggle
int buttonState = HIGH; // the current state of the output pin
int reading; // the current reading from the input pin
int previous = LOW; // the previous reading from the input pin
long time = 0; // the last time the output pin was toggled
long debounce = 200; // the debounce time, increase if the output flickers//rotaryButton toggle
int rbbuttonState = HIGH; // the current state of the output pin
int rbreading; // the current reading from the input pin
int rbprevious = LOW; // the previous reading from the input pin
long rbtime = 0; // the last time the output pin was toggled
long rbdebounce = 200; // the debounce time, increase if the output flickersvoid setup()
{
lcd.init(); // Start lcd display
Serial.begin (9600);
attachInterrupt(0, buttonChange, CHANGE); // Button on interrupt 0 - pin 2
attachInterrupt(1, rotaryButtonChange, CHANGE); // Rotary encoder on interrupt 1 - pin 3pinMode(pushButton, INPUT);
pinMode(ENC_A, INPUT);
pinMode(ENC_B, INPUT);
pinMode(dir, OUTPUT);
pinMode(doStep, OUTPUT);
pinMode(ms1, OUTPUT);
pinMode(ms2, OUTPUT);
pinMode(focus, OUTPUT);
pinMode(shutter, OUTPUT);
pinMode(toggleLed, OUTPUT);digitalWrite(ms1, LOW); // Set states of MS1 and MS2 to LOW to disable microstepping
digitalWrite(ms2, LOW); // Set states of MS1 and MS2 to LOW to disable microstepping
digitalWrite(focus, LOW);
digitalWrite(shutter, LOW);
digitalWrite(ENC_A, HIGH);
digitalWrite(ENC_B, HIGH);}
void loop(){
if (buttonState == HIGH){
if (rbbuttonState == HIGH){static uint8_t steps = 0; //this variable will be changed by encoder input
int8_t tmpdata;
/**/
tmpdata = read_encoder();
if( tmpdata ) {
steps += tmpdata;
}lcd.print("Num steps: ", 0, 1);
Serial.print (numPictures, DEC);
lcd.print("Step size: ", 1, 1);
Serial.print (steps, DEC);}
else{
static uint8_t numPictures = 0; //this variable will be changed by encoder input
int8_t tmpdata;
/**/
tmpdata = read_encoder();
if( tmpdata ) {
numPictures += tmpdata;
}lcd.print("Num steps: ", 0, 1);
Serial.print (numPictures, DEC);
lcd.print("Step size: ", 1, 1);
Serial.print (steps, DEC);}
}else{
for (int h = 0; h < numPictures; h++){ // loop for number of times dictated by var numPictures
lcd.clear();
lcd.print("Moving forward", 0, 1);
lcd.print(">> ", 1, 1);
Serial.print (steps);
Serial.print (" microns");
delay(1500); // Delay required for text above to have time to appear on the screen{
digitalWrite(dir, LOW); // Set the stepper direction to clockwise
delay(100);for (int i = 0; i <= steps; i++) // Iterate doStep for number of steps dictated by var encoder0Pos
{
digitalWrite(doStep, LOW); // This LOW to HIGH change is what creates the
digitalWrite(doStep, HIGH); // "Rising Edge" so the easydriver knows to when to step
delayMicroseconds(2000); // Delay time between steps, too fast and motor stalls}
{
lcd.clear();
lcd.print("Settling", 0, 1);
lcd.print("1.5 secs", 1, 1);delay(1500); // Allow any vibrations from movement to cease before taking a picture
lcd.clear();
lcd.print("Taking picture", 0, 1);
lcd.print("5 secs", 1, 1);digitalWrite(focus, HIGH); // Trigger camera autofocus - camera may not take picture in some modes if this is not triggered first
digitalWrite(shutter, HIGH); // Trigger camera shutterdelay(500); // Small delay needed for camera to process above signals
digitalWrite(shutter, LOW); // Switch off camera trigger signal
digitalWrite(focus, LOW); // Switch off camera focus signaldelay(4500); //Pause to allow for camera to take picture with 2 sec mirror lockup and to allow flashes to recharge before next shot
lcd.clear();
}
}
}lcd.print("Stack finished", 0, 1);
delay(2000);
buttonState = HIGH;
}}
void buttonChange(){
reading = digitalRead(pushButton);
if (reading == HIGH && previous == LOW && millis() - time > debounce) {
if (buttonState == HIGH)
buttonState = LOW;
else
buttonState = HIGH;time = millis();
}digitalWrite(toggleLed, buttonState);
previous = reading;
}void rotaryButtonChange(){
rbreading = digitalRead(rotaryButton);
if (rbreading == HIGH && rbprevious == LOW && millis() - rbtime > rbdebounce) {
if (rbbuttonState == HIGH)
rbbuttonState = LOW;
else
rbbuttonState = HIGH;time = millis();
}digitalWrite(toggleLed, rbbuttonState);
rbprevious = rbreading;
}/* returns change in encoder state (-1,0,1) */
int8_t read_encoder()
{
static int8_t enc_states[] = {
0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0 };
static uint8_t old_AB = 0;
/**/
old_AB <<= 2; //remember previous state
old_AB |= ( ENC_PORT & 0x03 ); //add current state
return ( enc_states[( old_AB & 0x0f )]);
}
The idea is the loop defaults to the 'setup area' where you select your variables and then when pushButton is toggled it then runs the main part of the loop before returning to setup.
Within setup the rotary encoder pushbutton (rotaryButton) toggles between selecting numPictures and steps.
This bit isn't working properly though -
1/ when the toggle button is clicked it does switch inputs but it often makes the previous number 'jump' to another random figure.
2/ the numbers input also don't seem to get passed to the main part of the loop as it finishes instantly, suggesting numPictures and steps are still set to 0 - I'm misundertanding how to pass information up to global variables?
3/ rotary encoder feedback is not very good, numbers go up erratically but don't seem keen to come down again. The code (http://www.circuitsathome.com/mcu/reading-rotary-encoder-on-arduino) worked brilliantly by itself in a test sketch but the way I've implemented it seems to have damaged its functionality.
Can anyone point out the places where I've gone completely wrong please and if possible suggest a better way of implementing the rotary encoder code?