I am trying to get my Arduino UNO to output certain text lines when certain pins are LOW and given a serial input. As recommended on a previous post, I am using the serial monitor to give inputs when the program is running. For greater context, I want to use this program to control a stepper motor. I am also using a driver board called A4988. My issue is that although it seems to accept inputs (Does not throw an error), it does not output any text when it is supposed to. I already made sure the correct voltages were being applied to the correct inputs. Moreover, I don't think there is anything wrong with the board because the example codes I upload to it work also (However, they do not rely on pins being LOW/HIGH so maybe that could be a potential problem). I read through all the serial commands and their details on the site and looked through the example codes recommended to me but still am unable to figure it out. The following code does compile.
// Include the Arduino Stepper Library
#include <Stepper.h>
// Define Constants
// User Inputs (Changes based on motor and application)
// Set default frequency of motor when there is no user input
const int defaultfreq = 25; // In Hz
// Assign threaded bar measurements to each variable (Inputs here will determine accuracy of actuator movement!)
const int barthreadclearance = 0.1; // Distance between each thread (In cm)
// Define either the number of steps the specified motor takes per revolution or its minimum step angle and comment the other one out (Can find this information on motor's data sheet)
// const int stepsperrev = 400; // Unitless
const float stepangleperrev = 1.8; // In degrees
// Calculate values based on user inputs
const float stepsperrev = 360/stepangleperrev; // Define # of steps per revolution
const float disperstep = (barthreadclearance*stepangleperrev)/360; // Define distance travelled per step
// Connections to A4988
const int motor1dirPin = 2; // Motor 1 direction
const int motor1stepPin = 3; // Motor 1 movement
// Connections to User Interface
const int numposmove = 10; // Nuemrical Input Positive Movement
const int numnegmove = 11; // Numerical Input Negative Movement
const int motorsetrpm = A0; // Set RPM for Pk266-01A and Pk266-01B (Input should be a voltage between 0 and 5 V) [RPM/Hz range: 0 to 4500/750] Recomend ~150 RPM or 25 Hz
const int motor1ID = A1; // ID pin for motor 1
const int emergencystop = A4; // Emergency stop used to break any loop/motor rotations
void setup() {
// Designate Output Pins
pinMode(motor1stepPin,OUTPUT);
pinMode(motor1dirPin,OUTPUT);
// Designate Input Pins
pinMode(motor1ID,INPUT_PULLUP);
pinMode(motorsetrpm,INPUT_PULLUP);
pinMode(emergencystop,INPUT_PULLUP);
pinMode(numposmove,INPUT_PULLUP);
pinMode(numnegmove,INPUT_PULLUP);
// Initialize serial and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // Wait for serial port to connect. Needed for native USB
}
}
// Stepper Motor Program Begins and Loops
void loop() {
// Use this for speed in motor testing
float setspeedfreq = defaultfreq/(1E6); // Sets the freq in to default when no user input
// To control all motors positive movements via numerical input (Input must be in untis of cm)
if (digitalRead(motor1ID) == LOW) { // ID motor 1
if (analogRead(numposmove) == LOW) {
// Send data only when you receive data greater than or equal to the minimum distance motor can move
if (Serial.available() > 0) { // If there is a serial available, read it
// read the incoming byte:
float posmoveinput = Serial.parseFloat();
Serial.print("I received: "); // Output numerical input (For testing purposes)
Serial.println(posmoveinput,DEC);
float distostep = posmoveinput/disperstep;
digitalWrite(motor1dirPin,HIGH); // Set motor rotation direction
if (abs(posmoveinput) < 0.001) { // 0.001 cm
Serial.println("Error! Cannot input a number less than the minimum step distance set by the program. If you think this is a mistake, check/change the step angle/microstep size accordingly in the constants defined by the driver board's hardware.");
}
else if (Serial.read() == '\n') {
for (int substep = 0; substep = distostep; substep++) {
Serial.print("Motor 1 Running to input dstance (cm): ");
Serial.println(posmoveinput,DEC);
digitalWrite(motor1stepPin,LOW);
// The following define speed which was either restricted by the user or set to default
delayMicroseconds(1/(2*setspeedfreq));
digitalWrite(motor1stepPin,HIGH);
delayMicroseconds(1/(2*setspeedfreq));
if (analogRead(emergencystop) == LOW) {
Serial.print("Emergency Stop Activated");
break;
}
}
}
}
}
}
}
Any ideas from a quick glance at the code why it may not be outputting any of the text I want it to?
Your program is trying to mix up different things - like a bowl of muesli or a fruit cake. For programming life is much easier if you keep the raisins and the grains and the other fruits in separate piles. In programming those piles are called functions.
Have a look at how the code is organized in Planning and Implementing a Program. By breaking the code into several short single-purpose functions it will be much easier to develop, test, debug and maintain.
You program does not use the Stepper library so there is no need to mention it, and the Stepper library is not appropriate for an A4988 stepper driver that just takes step and direction inputs. If you want to use a library use the AccelStepper library. However it is not difficult to control an A4988 without a library. Have a look at this Simple Stepper Code
Your system for receiving serial data is not robust and, because it is mingled with all the other stuff it will be a nightmare to debug. Have a look at the examples in Serial Input Basics - simple reliable ways to receive data. There is also a parse example to illustrate how to extract numbers from the received text.
@Robin2 Thanks for the answer and resources. Thanks for pointing out that library import. I originally was using it for a previous version but took out that code and forgot to remove the import command too. I took a glance at the guide and from my logic for this program is as follows:
User sets direction
User inputs distance
Program calculates number of substeps needed to achieve this distance and implements for loop
Emergency stop button available for user in case of mistaken input (Can be taken out to simplify program further for debugging)
Program resets
I can take out the first two if statements and the ones for the emergency stop and minimum input value error to simplify it further however after that I feel my code is as simple as it gets for what is needed. Unless that is what you are referring to in terms of simplifications and separation.
@MorganS You are right because that is not supposed to be an analogRead but digitalRead! Thanks for pointing that out. However, that leads to another question because I went back to reread the "Digital Pins" info page and realized that if I want to use the built in pull up resistors, I would need to issue the commands:
pinMode(pin, INPUT); // set pin to input
digitalWrite(pin, HIGH); // turn on pullup resistors
This concerns me because from the resource page on "digitalWrite" it says it recommends to use the "INPUT_PULLUP" command for pinMode() to turn on the pull up. Also, wouldn't using digitalWrite() to turn on those resistors affect the receiving signal to that pin (The pin won't be able to read if an input signal is LOW or HIGH), or since reading is a different command than writing, then there is no affect?
tkeaton: @Robin2 Thanks for the answer and resources. Thanks for pointing out that library import. I originally was using it for a previous version but took out that code and forgot to remove the import command too. I took a glance at the guide and from my logic for this program is as follows:
User sets direction
User inputs distance
Program calculates number of substeps needed to achieve this distance and implements for loop
Emergency stop button available for user in case of mistaken input (Can be taken out to simplify program further for debugging)
Program resets
I can take out the first two if statements and the ones for the emergency stop and minimum input value error to simplify it further however after that I feel my code is as simple as it gets for what is needed. Unless that is what you are referring to in terms of simplifications and separation.
I was not commenting on the length of the code, or even on its "simplicity". I was talking about the fact that code for getting serial data is mixed up with code for figuring out numbers of steps which is mixed up with code to make a motor move. Did you read my link Planning and Implementing a Program?
All those different activities should be in separate functions. Yes, of course you can get a program to work without using functions. But when you run into problems code that is created as a collection of short single purpose functions is much easier to debug. It is also easier to add extra capabilities to it later.
By the way, getting user input is often the most complicated and lengthy part of a program. There is a simple user input example in Planning and Implementing a Program.
@Robin2 I understand what you mean now and you are correct. I read through the guide and your guide you made for Serial Input and rewrote an entire new piece of code that involves just that. I posted a new topic on the forum with that code since it's very different than the one posted here. I did not exactly do as you did in terms of user input from your guide because it seemed like there would be more code to write but I wanted to try something very simple with the serial read before. I will change it to be more similar to the examples you provided if there doesn't seem to be an "easy" fix for the issue I am having with the new code.