Calculating Cycles complete from frequency and time of a stepper motor

Hello all,

So for this project, I need to spin a stepper motor a minimum of 100 cycles and then display how many cycles at the end. However, when I display this number, I always get a zero. The stepper is spun using a tone function and then stopped when an IR detector detects a change.

I have cut down my code to make this easier for you. The relevant parts are below.

Research leads me to think the problem might have to do with the types of variables I am using but I don’t know where I am going wrong or even how to remedy it.

const int stepPin = 8;   //pin to pulse for steps
const int button1Pin = 4;  // the pin number of button 1
const int button2Pin = 7;  // the pin number of button 2
int freq = 100;
int timeout = 50;
long int lastDebounceTime;
int countdown = 1;
int period = 0;

void setup() {
  // put your setup code here, to run once:
  while (countdown == 1) {
    //debounce button 2
    int button2State = digitalRead(button2Pin);
    long int currentTime = millis();    //get the current time
    if (button2State == LOW) {
      lastDebounceTime = currentTime;
    }
    if (((currentTime - lastDebounceTime) > timeout)) {
      freq = freq + 50;
      if (freq == 350) {
        freq = 100;
      }
    }
    if (digitalRead(button1Pin) == HIGH) {
      countdown = countdown - 1 ;
      period = 400 * (1 / freq);  //stepper takes 400 pulses of LOW and HIGH to spin 360 degrees
    }
  }
  tone(8, 50);
  delay(600);
  for (int y = 55; y < freq; y = y + 5) {
    tone(8, y);
    delay(400);
  }
   digitalWrite(vibPin, HIGH);          //turn on the vibration
}

void loop() {
  // put your main code here, to run repeatedly:
  unsigned long startTime = millis();
  if (powder > (initPowder + 100)) {  //If IR detects change *this works*
    unsigned long endTime = millis();
    flowTime = endTime - startTime;
    flowTime = flowTime / 1000;
    unsigned long rev = floor((flowTime) / (period));
    display.println(rev); //display the number of cycles completed at the end
    display.display();
    digitalWrite(vibPin, 0);
    noTone(8);
    for (;;);
  }
}

It's hard to be sure from an incomplete sketch, but in loop, you set startTime to millis. Then you have an if, which if true sets endTime to millis and you calculate revs based on the difference between start & end.

Start and end are likely exactly the same or at most will differ by 1ms. So rev will always be zero as you observe. Either make startTime static, or make it global and set it at the end of setup.

wildbill:
Either make startTime static, or make it global and set it at the end of setup.

Ahh yes, that is one mistake, thank you

Well, I made it global and I am still getting a zero. Any other suggestions?

Here is my entire sketch:

const int stepPin = 8;   //pin to pulse for steps
const int button1Pin = 4;  // the pin number of button 1
const int button2Pin = 7;  // the pin number of button 2
int freq = 100;
int timeout = 50;
long int lastDebounceTime;
int vibPin = 3;             //vibration pin connected through mosfet
int IRpin = A0;               // IR photodiode on analog pin A0
int IRemitter = 10;            // IR emitter LED on digital pin 2
int ambientIR;                // variable to store the IR coming from the ambient
int obstacleIR;               // variable to store the IR coming from the object
int value[10];                // variable to store the IR values
int powder;                 // variable that will tell if there is an obstacle or not
int rev = 0;
int initPowder;
int countdown = 1;
unsigned long flowTime = 0;
int period = 0;
unsigned long startTime;

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET     -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

void setup() {
  //setup pins
  pinMode(stepPin, OUTPUT);
  pinMode(button1Pin, INPUT);
  pinMode(button2Pin, INPUT);
  pinMode(vibPin, OUTPUT);
  digitalWrite(vibPin, 0);
  pinMode(IRemitter, OUTPUT); // IR emitter LED on digital pin 2
  digitalWrite(IRemitter, LOW); // setup IR LED as off

  Serial.begin(9600);
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
    Serial.println(F("SSD1306 allocation failed"));
    for (;;);
  }
  display.display();
  //  delay(2000);
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(1);
  display.setCursor(15, 20);
  display.println("Ready to   Riffle");
  display.display();
  delay(2000);

  while (countdown == 1) {
    //debounce the button
    int button2State = digitalRead(button2Pin);
    long int currentTime = millis();    //get the current time
    if (button2State == LOW) {
      lastDebounceTime = currentTime;
    }
    if (((currentTime - lastDebounceTime) > timeout)) {
      freq = freq + 50;
      if (freq == 350) {
        freq = 100;
      }
    }
    switch (freq) {
      case 300:           // menu for the low freq setting *needs calibration*
        display.clearDisplay();
        display.setCursor(0, 0);
        display.setTextSize(1);
        display.println("How Much Powder?");
        display.display();
        display.setTextSize(3);
        display.setCursor(0, 20);
        display.println("  100   Grams");
        display.display();
        delay(750);
        break;
      case 250:           // menu for the low freq setting *needs calibration*
        display.clearDisplay();
        display.setCursor(0, 0);
        display.setTextSize(1);
        display.println("How Much Powder?");
        display.display();
        display.setTextSize(3);
        display.setCursor(0, 20);
        display.println("  200   grams");
        display.display();
        delay(750);
        break;
      case 200:           // menu for the low freq setting *needs calibration*
        display.clearDisplay();
        display.setCursor(0, 0);
        display.setTextSize(1);
        display.println("How Much Powder?");
        display.display();
        display.setTextSize(3);
        display.setCursor(0, 20);
        display.println("  300   Grams");
        display.display();
        delay(750);
        break;
      case 150:     // menu for the  medium setting *needs calibration*
        display.clearDisplay();
        display.setCursor(0, 0);
        display.setTextSize(1);
        display.println("How Much Powder?");
        display.display();
        display.setTextSize(3);
        display.setCursor(0, 20);
        display.println("  400   Grams");
        display.display();
        delay(750);
        break;
      case 100:     // menu for the high freq setting *needs calibration*
        display.clearDisplay();
        display.setCursor(0, 0);
        display.setTextSize(1);
        display.println("How Much Powder?");
        display.display();
        display.setTextSize(3);
        display.setCursor(0, 20);
        display.println("  500   Grams");
        display.display();
        delay(750);
        break;
    }
    if (digitalRead(button1Pin) == HIGH) {
      countdown = countdown - 1 ;
      period = 400 * (1 / freq); //stepper takes 400 pulses of LOW and HIGH to spin360 degrees
    }
  }
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(1);
  display.setCursor(15, 20);
  display.println("Riffler   Start Up");
  display.display();
  tone(8, 50);
  delay(600);
  for (int y = 55; y < freq; y = y + 5) {
    tone(8, y);
    delay(400);
  }
  display.clearDisplay();
  display.setCursor(15, 20);
  display.println(" Riffler   Running");
  display.display();
  initPowder = readIR(5);               //take initial powder IR reading for later comparison
  Serial.println(initPowder);
  //digitalWrite(vibPin, HIGH);          //turn on the vibration
  startTime = millis();
}

void loop() {
  //Serial.println((flowTime/1000)/(period*400));
  powder = readIR(5);                                     // Reread the IR sensor
  //  Serial.println(powder);
  delay(500);
  if (powder > (initPowder + 100)) {
    unsigned long endTime = millis();
    flowTime = endTime - startTime;
    display.clearDisplay();
    display.setCursor(10, 0);
    display.setTextSize(1.5);
    display.println("Cycles Completed:");
    display.display();
    display.setCursor(37, 23);
    display.setTextSize(3);
    flowTime = flowTime / 1000;
    int rev = floor((flowTime) / (period));
    display.println(rev); //display the number of cycles completed at the end
    display.display();
    digitalWrite(vibPin, 0);
    noTone(8);
    for (;;);
  }
}
int readIR(int times) {
  for (int x = 0; x < times; x++) {
    digitalWrite(IRemitter, LOW);    //turning the IR LEDs off to read the IR coming from the ambient
    delay(1);                        // minimum delay necessary to read values
    ambientIR = analogRead(IRpin);   // storing IR coming from the ambient
    digitalWrite(IRemitter, HIGH);   //turning the IR LEDs on to read the IR coming from the obstacle
    delay(1);                        // minimum delay necessary to read values
    obstacleIR = analogRead(IRpin);  // storing IR coming from the obstacle
    value[x] = ambientIR - obstacleIR; // calculating changes in IR values and storing it for future average
  }

  for (int x = 0; x < times; x++) {  // calculating the average based on the "accuracy"
    powder += value[x];
  }
  return (powder / times);         // return the final value
}

I have narrowed the problem down to the period. For some reason, this returns zero.

int period = 400 * (1 / freq);

the flowtime is both accurate and precise

freq is initialized at 100 globally and then in the setup is changed to a value between 100-300. something is going over my head here :confused:

That’s doing integer division, so the fractional part you’re expecting is lost. Try:

int period = 400.0 * (1.0 / freq);