LCD Causing Stepper motor to pause

Building a circuit with a stepper motor and a variable speed with an optical sensor as a turn counter to wind a tesla coil, but I am having issues with my code currently.

It worked fine up until I decided to add the turn counter with LCD and now whenever I write something to the LCD the stepper motor does a small stutter/jerk and then keeps going.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

int turns = 0;
int optoPin = A1;
int optoStateA = 0;
int optoStateB = 0;
int value;
int speed = A0;
const int on = 2;
int motorSpeed = 0;
int step = 13;
int direction = 9;
int pin = 6;
int buttonState = 0;
int state = HIGH;   
int reading;           
int previous = LOW;  
long time = 0;    
long debounce = 200; 
LiquidCrystal_I2C lcd(0x27,20,4);

void setup() {                
  lcd.init();
  lcd.backlight();
  lcd.clear();
  lcd.setCursor(2,0);
  lcd.print("Winding Counter");
  lcd.setCursor(6,2);
  lcd.print("Turns:");
  lcd.setCursor(8,3);
  lcd.print(0);
  pinMode(step, OUTPUT); 
  pinMode(direction, OUTPUT); 
  pinMode(speed, INPUT);
  pinMode(on, INPUT);
  pinMode(optoPin, INPUT);
  pinMode(pin, OUTPUT);
}

void loop() {
 optoStateA = digitalRead(optoPin); 
 buttonState = digitalRead(on);
 if (optoStateA && optoStateA != optoStateB) {
  turns = turns +1;
  count();
}
if (buttonState == HIGH && previous == LOW && millis() - time > debounce) {
 if (state == HIGH)
   state = LOW;
 else
 state = HIGH;
 time = millis();    
 }

if (state == HIGH) {
  digitalWrite(pin, HIGH);  
  digitalWrite(direction, HIGH);
  int spd = analogRead(speed);
  digitalWrite(step, HIGH); 
  digitalWrite(step, LOW); 
  delay(spd/24+2);
} else { digitalWrite(pin, LOW); }
 
previous = reading;
optoStateB = optoStateA;
}

void count() {
  lcd.clear();
  lcd.setCursor(2,0);
  lcd.print(F("Winding Counter"));
  lcd.setCursor(6,2);
  lcd.print(F("Turns:"));
  lcd.setCursor(6,3);
  lcd.print(turns);
}

The code is a little messy. Still have a ways to go before I finalize it and clean it up.

I’ve tried removing stuff from the LCD code just down to “lcd.print(turns);” and it still jerks but noticeably less.

If I delete or comment out the call to count(); the turns still count up but the LCD display is left blank and the jerking stops. I have also tried leaving it in the loop with same results.

And I know it would have been much simpler to use a DC motor and control it with PWM, but I don’t have any geared DC motors on hand, but I have a bunch of Nema17 Steppers and a bunch of Pololu A4988 Stepper drivers.

You could get rid of the delay() statement and instead use that time to print to the LCD.

jremington:
You could get rid of the delay() statement and instead use that time to print to the LCD.

Can't get rid of the delay, that is the speed control for the stepper

You need to get rid of the delay() and use millis() to manage the timing instead. See the demo several things at a time.

This will allow the stepper steps to happen at the correct time and the LCD to be updated in the interval.

Also see the second example in this simple stepper demo.

...R

The code is a little messy. Still have a ways to go before I finalize it and clean it up.

Stop right now. Clean up the code. No professional, in any trade, works in a messy situation. The first thing you learn in any profession is to clean-as-you-go.

Knowing that the code is a mess, and failing to do anything about it, is a recipe for failure.

Consistent naming convention usage is good. It's hard to tell from your code which variables represent pin numbers and which represent pin states. Without that, it's hard to be sure that you are using the variables correctly.

Using const on some variables that are supposed to be constant, but not on others that are not supposed to change is not a good thing. I'll admit that I am terrible at remembering to do that. But, I use Pin in the name of all variables that represent pins, and State in the name of all variables that represent state. That way, I never inadvertently overwrite a pin variable.

  pinMode(pin, OUTPUT);

That's just pathetic.

Cleaned up the code a bit,
Changed the delay to a millis()

Same problem, but slightly less pronounced.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

int speedPin = A0;
int optoPin = A1;
int powerPin = 2;
int sleepPin = 6;
int directionPin = 9;
int stepPin = 13;
int stepperSpeed;
int optoStateA = 0;
int optoStateB = 0;
int buttonState = 0;
int powerState = HIGH;   
int buttonReading;           
int buttonPrevious = LOW;  
int turnCount = 0;
unsigned long buttonTime = 0;    
unsigned long buttonDebounce = 200; 
unsigned long curMillis;
unsigned long prevStepMillis = 0;
unsigned long millisBetweenSteps;
LiquidCrystal_I2C lcd(0x27,20,4);

void setup() {                
  pinMode(speedPin, INPUT);
  pinMode(powerPin, INPUT);
  pinMode(optoPin, INPUT);
  pinMode(stepPin, OUTPUT); 
  pinMode(directionPin, OUTPUT); 
  pinMode(sleepPin, OUTPUT);
  lcd.init();
  lcd.backlight();
  lcd.clear();
  lcd.setCursor(2,0);
  lcd.print("Winding Counter");
  lcd.setCursor(6,2);
  lcd.print("Turns:");
  lcd.setCursor(8,3);
  lcd.print(0);
}

void loop() {
 optoStateA = digitalRead(optoPin); 
 buttonState = digitalRead(powerPin);
 curMillis = millis();
 millisBetweenSteps = (analogRead(speedPin)/24+2);
 singleStep();

if (optoStateA && optoStateA != optoStateB) {
    turnCount = turnCount +1;
    lcdCount();
}

  if (buttonState == HIGH && buttonPrevious == LOW && millis() - buttonTime > buttonDebounce) {
    if (powerState == HIGH)
     powerState = LOW;
    else
     powerState = HIGH;
     buttonTime = millis();    
    }

  if (powerState == HIGH) {
    digitalWrite(sleepPin, HIGH);  
    digitalWrite(directionPin, HIGH);
  } else {
    digitalWrite(sleepPin, LOW);  
}
 
 buttonPrevious = buttonReading;
 optoStateB = optoStateA;
 
}

void singleStep() {
    if (curMillis - prevStepMillis >= millisBetweenSteps) {
        prevStepMillis += millisBetweenSteps;
        digitalWrite(stepPin, HIGH);
        digitalWrite(stepPin, LOW);
    }
}

void lcdCount() {
  lcd.clear();
  lcd.setCursor(2,0);
  lcd.print("Winding Counter");
  lcd.setCursor(6,2);
  lcd.print("Turns:");
  lcd.setCursor(7,3);
  lcd.print(turnCount);
}

Do you REALLY need to do all that stuff in lcdCount()? lcd.clear() takes a fair amount of time. What that is trying to accomplish is to blank out the last value(s) written to the LCD.

Instead, if you write the same width value every time, or the value and some spaces, you’ll accomplish the same objective without having to erase anything.

You correctly put the non changing commands to the lcd in set up

lcd.init();
  lcd.backlight();
  lcd.clear();
  lcd.setCursor(2,0);
  lcd.print("Winding Counter");
  lcd.setCursor(6,2);
  lcd.print("Turns:");
  lcd.setCursor(8,3);
  lcd.print(0);

The lcd controller has its own memory, and you do not have to repeat the command in the lcdCount function. It can be reduced to

void lcdCount() {
  lcd.setCursor(7,3);
  lcd.print(turnCount);
}

How fast is the counter incrementing? What do you do with the information on the LCD? You can put the call to the function lcdCount on its own timer, to update the display once per second or longer, instead of every time through the loop.

cattledog:
You correctly put the non changing commands to the lcd in set up

lcd.init();

lcd.backlight();
  lcd.clear();
  lcd.setCursor(2,0);
  lcd.print("Winding Counter");
  lcd.setCursor(6,2);
  lcd.print("Turns:");
  lcd.setCursor(8,3);
  lcd.print(0);




The lcd controller has its own memory, and you do not have to repeat the command in the lcdCount function. It can be reduced to



void lcdCount() {
  lcd.setCursor(7,3);
  lcd.print(turnCount);
}




How fast is the counter incrementing? What do you do with the information on the LCD? You can put the call to the function lcdCount on its own timer, to update the display once per second or longer, instead of every time through the loop.

That definitely improved it a lot. It's barely noticeable now, but it still does happen. I tried something that worked up until the count made it to 10. I called lcdCount(); out of the if statement and it counted just fine with no jerks, but as soon as the count hit 10 the motor slowed down to about half the normal speed.

OsiViper:
That definitely improved it a lot. It's barely noticeable now, but it still does happen.

Please post your latest code. There is no point in me examining the stuff that has now been updated.

...R

I tried something that worked up until the count made it to 10. I called lcdCount(); out of the if statement and it counted just fine with no jerks, but as soon as the count hit 10 the motor slowed down to about half the normal speed.

If you want help with that, you will need to post the code which showed that behaviour.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

int speedPin = A0;
int optoPin = A1;
int powerPin = 2;
int sleepPin = 6;
int directionPin = 9;
int stepPin = 13;
int stepperSpeed;
int optoStateA = 0;
int optoStateB = 0;
int buttonState = 0;
int powerState = HIGH;   
int buttonReading;           
int buttonPrevious = LOW;  
int turnCount = 0;
unsigned long buttonTime = 0;    
unsigned long buttonDebounce = 200; 
unsigned long curMillis;
unsigned long prevStepMillis = 0;
unsigned long millisBetweenSteps;
LiquidCrystal_I2C lcd(0x27,20,4);

void setup() {                
  pinMode(speedPin, INPUT);
  pinMode(powerPin, INPUT);
  pinMode(optoPin, INPUT);
  pinMode(stepPin, OUTPUT); 
  pinMode(directionPin, OUTPUT); 
  pinMode(sleepPin, OUTPUT);
  lcd.init();
  lcd.backlight();
  lcd.clear();
  lcd.setCursor(2,0);
  lcd.print("Winding Counter");
  lcd.setCursor(6,2);
  lcd.print("Turns:");
  lcd.setCursor(7,3);
  lcd.print(0);
}

void loop() {
 optoStateA = digitalRead(optoPin); 
 buttonState = digitalRead(powerPin);
 curMillis = millis();
 millisBetweenSteps = (analogRead(speedPin)/24+2);
 singleStep();
 lcdCount();
 
  if (optoStateA && optoStateA != optoStateB) {
    turnCount = turnCount +1;
    //lcdCount();
  }

  if (buttonState == HIGH && buttonPrevious == LOW && millis() - buttonTime > buttonDebounce) {
    if (powerState == HIGH)
     powerState = LOW;
    else
     powerState = HIGH;
     buttonTime = millis();    
  }

  if (powerState == HIGH) {
    digitalWrite(sleepPin, HIGH);  
    digitalWrite(directionPin, HIGH);
  } else {
    digitalWrite(sleepPin, LOW);  
  }
 
 buttonPrevious = buttonReading;
 optoStateB = optoStateA;
 
}


void singleStep() {
    if (curMillis - prevStepMillis >= millisBetweenSteps) {
        prevStepMillis += millisBetweenSteps;
        digitalWrite(stepPin, HIGH);
        digitalWrite(stepPin, LOW);
    }
}


void lcdCount() {
  lcd.setCursor(7,3);
  lcd.print(turnCount);
}

Sorry, I forgot to attach it. This works exactly as intended until the count hits 10 then it slows the motor down, not jerky or rough, just slows down. Checked it again and let it go until 100 and it slowed down even more. so it seems to be based on how much it is writing to the LCD.

You are updating the LCD far too often. Add a mills() based delay to that function so it only updates the LCD once per second, or maybe once per 200 msecs.

Rather than read the millis() function in several places I would just use the value in currentMillis - that will save a small amount of time in each loop()

...R

I do not believe that the slowing down has anything to do with the LCD.

You have used the stepper delay code from Robins demo

void singleStep() {
    if (curMillis - prevStepMillis >= millisBetweenSteps) {
        prevStepMillis += millisBetweenSteps;
        digitalWrite(stepPin, HIGH);
        digitalWrite(stepPin, LOW);

But this code was written for a fixed value of millisBetweenSteps.

You are getting this value from

millisBetweenSteps = (analogRead(speedPin)/24+2);

You haven't explained the hardware,and what is connected to A0, and what the readings are. I would suspect there there is some sort of unintended feedback loop slowing the step rate down.

If you actually need the step rate to be controlled by the analogRead, then I would suggest some sort of serial print debug of millisBetweenSteps to see what is going on.

Otherwise try the code with a fixed value for millisBetweenSteps which gives you the correct turn rate.

cattledog:
I do not believe that the slowing down has anything to do with the LCD.

You have used the stepper delay code from Robins demo

void singleStep() {

if (curMillis - prevStepMillis >= millisBetweenSteps) {
        prevStepMillis += millisBetweenSteps;
        digitalWrite(stepPin, HIGH);
        digitalWrite(stepPin, LOW);




But this code was written for a fixed value of millisBetweenSteps.

You are getting this value from


millisBetweenSteps = (analogRead(speedPin)/24+2);




You haven't explained the hardware,and what is connected to A0, and what the readings are. I would suspect there there is some sort of unintended feedback loop slowing the step rate down.

If you actually need the step rate to be controlled by the analogRead, then I would suggest some sort of serial print debug of millisBetweenSteps to see what is going on. 

Otherwise try the code with a fixed value for millisBetweenSteps which gives you the correct turn rate.

Same result regardless of fixed or variable. The hardware is just a potentiometer attached to A0 to control the speed. I guess Ill just leave it and deal with the minor jerk now. It's hardly noticeable.

Indeed, you should follow the suggestions to put the lcdCount function on its own timer so it is not called every time through the loop.

What I hear you saying is that when the lcdCount is called from within the if statement which controls the index

if (optoStateA && optoStateA != optoStateB) {
    turnCount = turnCount +1;
    //lcdCount();
  }

The motor slows down.

But, if lcdCount is called from the loop, the motor does not slow down.

The if statement only triggers when the optical sensor triggers so it only would do the LCD print every 1 revolution. But if i put the lcdCount(); straight in the loop. the motor slows down based on how many digit's its writing to the LCD.

I tried putting a mili delay on it and tried it. I tried every second, every 5 seconds and every 10 seconds. And sure enough the motor jerked for a fraction of a second whenever the update was sent to the LCD. But when the motor jerks, it does not stop, it just slows down, basically the exact slow down I was experiencing when it was called from the loop statement, but this time its intermittently. Whether it be on a timer, or whenever the optical sensor sees it.

OsiViper:
I guess Ill just leave it and deal with the minor jerk now. It's hardly noticeable.

Did you read Reply #12 ?

...R

Yea, I stated that in my previous post that I tried putting a millis delay on the update to the LCD, but it still jerked whenever the update was sent. But its normally not sending the update too often when the call for it is in the if statement for the optical sensor, so it only sends it once a revolution.

It has the same jerk whether I send it when it passes the sensor or whether I send it on a timer.

OsiViper:
Yea, I stated that in my previous post that I tried putting a millis delay on the update to the LCD

I didn't (don't) see that, but never mind.

I can't recall if you have said what is the range of intervals you want between stepper steps?

...R