Pololu Robotics & Electronics
Menu
My account Comments or questions? About Pololu Contact Ordering information Distributors

Pololu Forum

Arduino Uno + 36v4 + timers

Hi,
I am trying to write code that allows for an Arduino Uno to read several buttons pins, run a bipolar stepper motor via the Pololu 36v4 driver and finally trigger a camera shutter in time with each 360° revolution of the motor. I successfully wrote a version that did all these using delay functions but the camera wasn’t getting triggered on time reliably and the motor was running very loudly and jerkily. IT just didn’t seem right. So I’ve tried re-writing my sketch using only timers to avoid blocking functions, but I can’t get it to work. Now the buttons are completely unresponsive. Does anyone see where I’ve gone wrong?

//========= LIBRARIES ===============================================================
#include <SPI.h>
#include <HighPowerStepperDriver.h>

//======== CONSTANTS ================================================================
// 36v4 pins (motor driver)
const uint8_t DirPin = 9;
const uint8_t StepPin = 10;
const uint8_t CSPin = 8;
const int RESpin = 6;
const int SLEpin = 7;
const int FLTpin = 5;
HighPowerStepperDriver sd;

// constant intervals
const int buttonInterval = 500000; // number of millisecs between button readings
const int StepDelayInterval = 3; // compare this to micros 
const int GH5_interval = 3000; // adjust based on GH5 trigger response time
unsigned long print_interval = 500000;

const uint16_t StepPeriodUs = 200; // controls speed of stepper motor
const int StepsPerRev = 2000; // maybe try setting this the effective gear ratio of one frame?

// telecine/camera controls
const int motorStartPin = 4;
const int motorDirPin = 3;
const int cameraTriggerPin = 2;

//======== VARIABLES ================================================================
unsigned long currentMicros = 0;
unsigned long previousMotorStartMicros = 0; // time when button press last checked
unsigned long previousDirMicros = 0; // time when button press last checked
unsigned long previousPrintMicros = 0;

unsigned long StepTime_a = 0;
unsigned long StepTime_b = 0;
unsigned long TriggerTime_a = 0;
unsigned long TriggerTime_b = 0;

byte cameraTrigger_State = LOW;
byte motor_State = LOW;
byte dir_State = LOW;
unsigned long stepCount = 0;
unsigned long frameCount = 0;
unsigned long triggerCount = 0;

//===================================================================

void setup() {
  
  SPI.begin();
  sd.setChipSelectPin(CSPin);
  Serial.begin(9600);
  
  pinMode(StepPin, OUTPUT);
  digitalWrite(StepPin, LOW);
  pinMode(DirPin, OUTPUT);
  digitalWrite(DirPin, LOW);
  pinMode(cameraTriggerPin, OUTPUT);
  digitalWrite(cameraTriggerPin, LOW);
  
  pinMode(SLEpin, OUTPUT);
  digitalWrite(SLEpin, HIGH);
  pinMode(RESpin, OUTPUT);
  digitalWrite(RESpin, LOW);
  pinMode(FLTpin, INPUT);
  pinMode(motorStartPin, INPUT_PULLUP);
  pinMode(motorDirPin, INPUT_PULLUP);
  
  delay(1);

  sd.resetSettings();
  sd.clearStatus();
  sd.setDecayMode(HPSDDecayMode::AutoMixed);
  sd.setCurrentMilliamps36v4(1700);
  sd.setStepMode(HPSDStepMode::MicroStep8); 
  sd.enableDriver();

}

void loop() {
  
  currentMicros = micros();
  
  readMotorToggle();
  readDirToggle();
  setDir();
  advanceOneFrame();
  triggerCamera();
  updateFrameCount();
  printInfo();
}

//Action functions bellow (called in the loop above)
//===================================================================

void readMotorToggle() {
  
  if (micros() - previousMotorStartMicros >= buttonInterval) {
    if (digitalRead(motorStartPin) == LOW) {
      motor_State = HIGH;
      previousMotorStartMicros = micros();
    }
  }
else {
    if (digitalRead(motorStartPin) == HIGH) {
    motor_State = LOW;
  }
 }
}

//===================================================================

void readDirToggle() {
   
   if (micros() - previousDirMicros >= buttonInterval) {
    if (digitalRead(motorDirPin) == LOW) {
      dir_State = HIGH;
      previousDirMicros = micros();
    }
  }
else {
  if (digitalRead(motorDirPin) == HIGH) {
    dir_State = LOW;
  }
 }
}

//===================================================================

void setDir() {

  if(dir_State == HIGH) {
    setDirection(0);
  }
  else {
    if(dir_State == LOW) {
      setDirection(1);
    }
   
  }
  
}

//===================================================================

void setDirection(bool dir) {

  delayMicroseconds(1);
  digitalWrite(DirPin, dir);
  delayMicroseconds(1);
}


//===================================================================

void advanceOneFrame()  {
 
 if (motor_State == HIGH) {
   for(int x = 0; x < StepsPerRev; x++){ //change value of StepsPerRev to be one frame
    StepTime_a = micros();
    digitalWrite(StepPin, HIGH); 
    stepCount ++;                     
    while(micros() - StepTime_a < StepDelayInterval){
    // do nothing
    }
    StepTime_b = micros();    
    digitalWrite(StepPin, LOW);
    while(micros() - StepTime_b < StepDelayInterval + StepPeriodUs){
    // do nothing
    }
   }
  }
 }

//===================================================================
 
void triggerCamera() {
 
 if (motor_State == HIGH) {
      TriggerTime_a = micros();
      digitalWrite(cameraTriggerPin, HIGH);
      triggerCount ++;                    
    while(micros() - TriggerTime_a <= GH5_interval){
      
    }
    TriggerTime_b = micros();    
    digitalWrite(cameraTriggerPin, LOW);
    while(micros() - TriggerTime_b <= GH5_interval){
    
    }
  }
}


//===================================================================

void updateFrameCount() {
  
  frameCount = stepCount/StepsPerRev;

}


//===================================================================

void printInfo() {
  
  if (micros()-previousPrintMicros >= print_interval) {

    Serial.print("Motor State:   ");
    Serial.println(motor_State);
    Serial.print("Direction:     ");
    Serial.println(dir_State);
    Serial.print("Frames:        ");
    Serial.println(frameCount);
    Serial.print("Trigger Count: ");
    Serial.println(triggerCount);
    Serial.println();
    previousPrintMicros = micros();
  }  else {
    if (micros()-previousPrintMicros < print_interval) {
    }
  }
}



//======================================== END ===========================

Hello, Ceee.Esss.Beee.

One of the problems you might be having is that your buttonInterval is declared as a const int and it is being set to a value higher than an int can be. You might try seeing if it works how you expect when it is an unsigned long.

If you are still not getting the behavior you want, can you clarify what you are trying to do with the timers when reading the buttons? The way your current code is, it looks like you are only trying to check if motorStartPin and motorDirPin are LOW, only if half a second has passed since the last time they were pressed.

By the way, if you do not need the extra resolution of microseconds, you can use millis() instead of micros() to get the time in milliseconds.

Brandon

Ah, thanks for these tips! I will try making some changes and report back. For some reason I thougt I needed more resoluiton and went for micros() instead of millis() but I’ll play with that too.
Thanks!