I would like to display a countdown timer that shows the time in seconds until a stepper motor is due to make its next move.
I have two bits of code that function independently. I'm wondering if they can be merged together to achieve the above objective. I'm not sure if this is the right approach. I am hoping some can steer me in the right direction?
The two codes are posted below.
Code 1: Stepper motor
Code 2: Countdown timer
int smDirectionPin = 2; //Direction pin
int smStepPin = 3; //Stepper pin
int smEnablePin = 7; //Motor enable pin
void setup(){
/*Sets all pin to output; the microcontroller will send them(the pins) bits, it will not expect to receive any bits from thiese pins.*/
pinMode(smDirectionPin, OUTPUT);
pinMode(smStepPin, OUTPUT);
pinMode(smEnablePin, OUTPUT);
digitalWrite(smEnablePin, HIGH); //Disbales the motor, so it can rest untill it is called uppond
Serial.begin(9600);
}
void loop(){
/*Here we are calling the rotate function to turn the stepper motor*/
rotate(800, 0.1); //The motor rotates 800 steps clockwise with a speed of 0.1 (slow)
delay(30000);
rotate(1600, 0.5); //The motor rotates 1600 steps clockwise with a speed of 0.5 (medium)
delay(40000);
rotate(-1600, 1); //The motor rotates 1600 steps counter clockwise with a speed of 1 (fast)
delay(20000);
}
/*The rotate function turns the stepper motor. Tt accepts two arguments: 'steps' and 'speed'*/
void rotate(int steps, float speed){
digitalWrite(smEnablePin, LOW); //Enabling the motor, so it will move when asked to
/*This section looks at the 'steps' argument and stores 'HIGH' in the 'direction' variable if */
/*'steps' contains a positive number and 'LOW' if it contains a negative.*/
int direction;
if (steps > 0){
direction = HIGH;
}else{
direction = LOW;
}
speed = 1/speed * 70; //Calculating speed
steps = abs(steps); //Stores the absolute value of the content in 'steps' back into the 'steps' variable
digitalWrite(smDirectionPin, direction); //Writes the direction (from our if statement above), to the EasyDriver DIR pin
/*Steppin'*/
for (int i = 0; i < steps; i++){
digitalWrite(smStepPin, HIGH);
delayMicroseconds(speed);
digitalWrite(smStepPin, LOW);
delayMicroseconds(speed);
}
digitalWrite(smEnablePin, HIGH); //Disbales the motor, so it can rest untill the next time it is called uppond
}
TIMER CODE BELOW:
unsigned long previousMillis = 0; // will store last time LED was updated
const long interval = 1000; // interval at which to blink (milliseconds)
int timer = 40; // Set the timer to 5 seconds
void setup() {
Serial.begin(9600);
}
void loop() {
unsigned long currentMillis = millis();
// for (int i = timer; i >= 0; i--) { // Set i to timer; test if timer is greater equal to 0; decrement timer
if (currentMillis - previousMillis >= interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
//Serial.println(i); // print i to the serial monitor
Serial.println(timer);
timer--;//decrease timer count
if (timer == -1)
{
timer = 40;
}
}
}
Thanks Idahowalker. I have changed the delay function to millis() as you suggested.
However, my attempt to merge the codes results in the timer acting like a loop counter rather than counting the seconds until the stepper's next move.
Is an interrupt the right way to go to merge the two codes?
int smDirectionPin = 2; //Direction pin
int smStepPin = 3; //Stepper pin
const unsigned long period1 = 5000; //the value is a number of milliseconds
const unsigned long period2 =10000; //the value is a number of milliseconds
const unsigned long period3 = 15000; //the value is a number of milliseconds
unsigned long startMillis; //some global variables available anywhere in the program
unsigned long currentMillis;
unsigned long previousMillis = 0; // will store last time update
const long interval = 1000; // interval at which to blink (milliseconds)
int timer = 10; // Set the timer to 10 seconds
void setup() {
/*Sets all pin to output; the microcontroller will send them(the pins) bits, it will not expect to receive any bits from thiese pins.*/
pinMode(smDirectionPin, OUTPUT);
pinMode(smStepPin, OUTPUT);
Serial.begin(9600);
startMillis = millis(); //initial start time
}
void loop() {
currentMillis = millis(); //get time in milliseconds since the program started
// Stepper - first move:
if (currentMillis - startMillis == period1) //test whether the period has elapsed
{
Countdown();
/*Here we are calling the rotate function to turn the stepper motor*/
rotate(1600, 0.5); //The motor rotates 1600 steps counter clockwise with a speed of 0.5 (medium)
}
// Stepper - second move:
currentMillis = millis(); //get time in milliseconds since the program started
if (currentMillis - startMillis == period2) //test whether the period has elapsed
{
Countdown();
/*Here we are calling the rotate function to turn the stepper motor*/
rotate(-1600, 1); //The motor rotates 400 steps clockwise with a speed of 0.001 (slow)
}
// Stepper - third move:
currentMillis = millis(); //get time in milliseconds since the program started
if (currentMillis - startMillis == period3) //test whether the period has elapsed
{
Countdown();
/*Here we are calling the rotate function to turn the stepper motor*/
rotate(-3200, 1); //The motor rotates 800 steps clockwise with a speed of 0.1 (fast)
startMillis = currentMillis; //IMPORTANT to save the start time.
}
}
void Countdown() {
unsigned long currentMillis = millis();
// for (int i = timer; i >= 0; i--) { // Set i to timer; test if timer is greater equal to 0; decrement timer
if (currentMillis - previousMillis >= interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
//Serial.println(i); // print i to the serial monitor
Serial.println(timer);
timer--;//decrease timer count
if (timer == -1)
{
timer = 10;
}
}
}
/*The rotate function turns the stepper motor. Tt accepts two arguments: 'steps' and 'speed'*/
void rotate(int steps, float speed) {
/*This section looks at the 'steps' argument and stores 'HIGH' in the 'direction' variable if */
/*'steps' contains a positive number and 'LOW' if it contains a negative.*/
int direction;
if (steps > 0) {
direction = HIGH;
} else {
direction = LOW;
}
speed = 1 / speed * 70; //Calculating speed
steps = abs(steps); //Stores the absolute value of the content in 'steps' back into the 'steps' variable
digitalWrite(smDirectionPin, direction); //Writes the direction (from our if statement above), to the EasyDriver DIR pin
/*Steppin'*/
for (int i = 0; i < steps; i++) {
digitalWrite(smStepPin, HIGH);
delayMicroseconds(speed);
digitalWrite(smStepPin, LOW);
delayMicroseconds(speed);
}
}
I hope to run the stepper using Millis() and no blocking delays.
In the code below I am trying to move the stepper 100 steps using millis() inside a For Loop, however the stepper just keeps turning and doesn't stop at 100.
The For Loop works fine with a delay() but not millis(). Should I be taking a different approach?
Wildbill, you are quite right. Thanks for pointing that out.
In the code below I used a for loop inside a millis hoping to create a 5 second pause between stepper moves, but no luck. The stepper just clicks every 5 secs, but doesn't move.
Maybe I could use the loop() function with a counter to keep count of each stepper move?
Any suggestions would be appreciated.
byte directionPin = 2;
byte stepPin = 3;
int numberOfSteps = 200;
unsigned long curMillis;
unsigned long curMicros;
unsigned long millisPrevMove = 0;
unsigned long microsPrevPulse = 100;
unsigned long millisInterval = 5000; // interval between stepper moves (milliseconds)
unsigned long microsPulseWidth = 100; // interval between High-Low pulses (microseconds)
void setup()
{
pinMode(directionPin, OUTPUT);
pinMode(stepPin, OUTPUT);
digitalWrite(directionPin, HIGH);
}
void loop()
{
unsigned long curMillis = millis();
unsigned long curMicros = micros();
if (curMillis - millisPrevMove >= millisInterval)
{
for(int j = 0; j <= numberOfSteps; j++)
{
if (curMicros - microsPrevPulse >= microsPulseWidth)
{ digitalWrite(stepPin, HIGH);
digitalWrite(stepPin, LOW);
microsPulseWidth = curMicros;
}
}
millisPrevMove = curMillis;
}
}
Actually, the compiler did tell me about my mistake so I changed the variable type thinking that had fixed it. There is something I'm missing here. How did you know the variable was wrong?
I was suspicious of your old code because it had no delay between setting the step pin high and low. Usually there is a brief delay there, but it was working for you in the earlier code. Might be worth changing as a test.
The other difference I see is that you haven't set the direction pin, although I don't expect that to matter either.
I could not get millis() working inside a for loop so I ended up using a counter++ instead.
For loops are blocking anyway, so best avoided where timing is concerned.
The timer in this sketch uses only millis and no delays, whereas the code for the stepper is still blocking. Blocking occurs between timing events so does not appear to be an issue.
For my purposes the sketch below achieves what I set out to do, ie countdown the remaining time until the next move of a stepper motor.
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
int smDirectionPin = 2; //Direction pin
int smStepPin = 3; //Stepper pin
int stepperMoveCount = 192;
int count = 0;
int timer = 936; // Set the timer 93.6 seconds
unsigned long stepperPrevMillis = 0;
unsigned long timePrevMillis = 0;
unsigned long curMillis;
unsigned long interval = 93600; //inverval betweeen stepper motor moves (milliseconds)
void setup() {
/*Sets all pin to output; the microcontroller will send them(the pins) bits, it will not expect to receive any bits from thiese pins.*/
pinMode(smDirectionPin, OUTPUT);
pinMode(smStepPin, OUTPUT);
// initialize the LCD
lcd.begin();
lcd.clear();
Serial.begin(9600);
}
void loop() {
curMillis = millis();
// Stepper instructions:
if (curMillis - stepperPrevMillis >= interval)
{ stepperPrevMillis = curMillis;
count++; // on every loop,adds 1 to the count int
if (count <= stepperMoveCount) {
rotate(6, 0); // The motor rotates 6 steps clockwise with a speed of 0 (slowest)
}
else {
rotate(-1152, 0.1); // The motor rotates 1152 steps counter clockwise with a speed of 0.1 (slow)
count = 0;
}
}
// Timer instructions:
if ((millis() - timePrevMillis >= 100) && (timer >= 0))
{ timePrevMillis = millis();
lcd.backlight();
lcd.print(timer);
lcd.print(" ");
lcd.setCursor(0, 0); // set cursor to 1st character position.
timer--;
if (timer <= 0)
timer = 936 - 1; // reset timer to 93.6 seconds.. less 0.01sec calibration
}
}
/*The rotate function turns the stepper motor. Tt accepts two arguments: 'steps' and 'speed'*/
void rotate(int steps, float speed) {
/*This section looks at the 'steps' argument and stores 'HIGH' in the 'direction' variable if */
/*'steps' contains a positive number and 'LOW' if it contains a negative.*/
int direction;
if (steps > 0) {
direction = HIGH;
} else {
direction = LOW;
}
speed = 1 / speed * 70; //Calculating speed
steps = abs(steps); //Stores the absolute value of the content in 'steps' back into the 'steps' variable
digitalWrite(smDirectionPin, direction); //Writes the direction (from our if statement above), to the EasyDriver DIR pin
/*Steppin'*/
for (int i = 0; i < steps; i++) {
digitalWrite(smStepPin, HIGH);
delayMicroseconds(speed);
digitalWrite(smStepPin, LOW);
delayMicroseconds(speed);
}
}