this code work normal but i want to change angle via serial not make it constant angle
int PUL =4; //define Pulse pin
int DIR =3; //define Direction pin
int ENA =2; //define Enable Pin
int steps_pr = 6400; //steps per revolution ( changable ) --<<<<<<<<<<<<<<<<<<<<< set based on stepper DIP config
int long target_ = 90; // move by degree ( changable ) --<<<<<<<<<<<<<<<<<<<<< test 2 function
int rotation_amt = 0; // rotation number ( changable ) --<<<<<<<<<<<<<<<<<<<<<
//-----------------------------------------------( test 1 functions only) rotation counter only )----------------------------
bool test_done = false; // test code finishes exicution
int step_ = 0; // current step
int rot_ = 0; // current rotation
// ----------------------------------------------( degree specification )--------------------------------------------------
float step_per_degree = 6400/360.0; // the number of steps in a degree
int long cur_step = 0; // the current step (holder) must be intiger
float calculated_step = step_per_degree * target_; // (180*17.7777~8 ) = 3,200.00~
int long rounded_step = abs(round(calculated_step)); // calc rounded
bool test2_done = false; // test code finishes exicution
void setup() {
pinMode (PUL, OUTPUT); // set out pins
pinMode (DIR, OUTPUT);
pinMode (ENA, OUTPUT);
digitalWrite(ENA,LOW); // dissable on start
Serial.begin(9600); // serial open
}
// example portion!
void test() {
if (step_ < steps_pr) {
step_++;
digitalWrite(DIR,LOW);
digitalWrite(ENA,HIGH);
digitalWrite(PUL,HIGH);
delayMicroseconds(50); // no less than 50 ( under torque issue.. nema 23 works )
digitalWrite(PUL,LOW);
delayMicroseconds(50);
}
if (step_ >= steps_pr){
rot_++;
step_ = 0;
Serial.println("rotation #: "); // serial read out
Serial.println(rot_);
}
if (rot_ >= rotation_amt ) {
test_done = true;
}
}
// example portion! -- specific degree
void test2() {
// handle - number case ( not the best way, but its a test )
if (target_ < 0 ) {
digitalWrite(DIR,HIGH);
}
if (target_ > 0 ) {
digitalWrite(DIR,LOW);
}
if ( cur_step < rounded_step ) {
cur_step++;
// digitalWrite(DIR,LOW);
digitalWrite(ENA,HIGH);
digitalWrite(PUL,HIGH);
delayMicroseconds(50); // no less than 50 ( under torque issue.. nema 23 works )
digitalWrite(PUL,LOW);
delayMicroseconds(50);
}
if (cur_step >= rounded_step){
test2_done = true;
}
}
// stop processes after completion!
void loop() {
if (test_done != true){
test();
}
if (test2_done != true && test_done == true ){
test2();
}
if (test2_done == true && test_done == true ){
digitalWrite(ENA,LOW); // disable after finish ( stops holding torque )
}
}
int doStep(int8_t direction){
if(direction > 0){
digitalWrite(DIR,LOW);
++cur_step;
} else {
digitalWrite(DIR,HIGH);
--cur_step;
}
digitalWrite(ENA,HIGH);
digitalWrite(PUL,HIGH);
delayMicroseconds(50); // no less than 50 ( under torque issue.. nema 23 works )
digitalWrite(PUL,LOW);
delayMicroseconds(50);
}
and then use it with the serial data parsed by Txtzyme:
case 'A': // step to Angle `x`
{
int32_t stepsToGo = x * step_per_degree - cur_step;
int8_t inc = stepsToGo > 0 ? 1 : -1;
while (stepsToGo) {
stepsToGo-=inc;
doStep(inc);
}
}
break;
case 'b': // step backward by Angle 'x'
case 'f': // step forward by Angle 'x'
{
int32_t stepsToGo = x * step_per_degree;
while (stepsToGo) {
--stepsToGo;
doStep(ch == 'f' ? 1 : -1);
}
}
break;
case 'D': // set Delay micros between steps
stepDelay = x;
break;
A demo-code where you type in <500>
the 500 is the value that will be received in the arduino the "<" and ">" were stripped off
and then the character-sequence "5" "0" "0" is converted into an integer-value
The demo-code uses this value to set the stepper-speed
at this place you have to modify the code to set the angle.
The code uses the mobatools-library which offers direct angle-setting
read the documentation of the mobatools
about the command
myStepper.write(angle)
// a comlex functionality doing multiple things "in parallel"
// requires quite a lot of lines of code
// at the end of this file the structure of the code is epxlained
#define ProjectName "MobaTools serial receive Speed Start Stop Bounce "
// define IO-states for inputs with pull-up-resistors
// pull-up-resistors invert the logig
#define unPressed HIGH
//#define pressed LOW
const byte ToggleButtonPin = 4;
const byte dirPin = 5;
const byte stepPin = 6;
// ( 1600 steps / revolution = 1/8 Microstep )
const int STEPS_REVOLUTION = 1600;
const long baudrate = 115200;
#include <MobaTools.h> // stepper-motor-library
MoToStepper myStepper( STEPS_REVOLUTION, STEPDIR );
const long targetPos = 8000; // stepper moves between 0 and targetpos
long nextPos;
//Array for storing serial received data
const unsigned int numChars = 128;
char receivedChars[numChars];
boolean newData = false;
unsigned int StepperSpeed = 1000;
bool activationMode = false;
void setup() {
Serial.begin(baudrate); // adjust baudrate in the serial monitor to match the number
Serial.println( F("Setup-Start") );
printFileNameDateTime();
pinMode (LED_BUILTIN, OUTPUT); // used for indicating logging active or not
digitalWrite(LED_BUILTIN, LOW);
// wire button between IO-pin and GND
// Pull-up-resistor inverts the logic
// unpressed: IO-pin detects HIGH
// pressed: IO-Pin detects LOW
pinMode(ToggleButtonPin, INPUT_PULLUP);
SetUpStepperMotor();
Serial.print( F("start / stop button must be conected to IO-PIN no ") );
Serial.println(ToggleButtonPin);
Serial.println( F("send speed-commands through serial monitor with <speed>") );
Serial.println( F("example <500>") );
Serial.println( F("press button to start / stop steppermotor") );
}
void loop () {
recvWithStartEndMarkers(); // non-blocking checking if serial data is received
// receive with Start- / Endmarker means the data must have
// a leading "<" and a trailing ">" for switching newData to true
if (newData) { // if a valid command is received
newData = false;
SetStepperMotorSpeed();
}
activationMode = GetToggleSwitchState(); // must be executed all the time
execute_if_Active(activationMode); // function that does what its name says
}
void SetUpStepperMotor() {
myStepper.attach( stepPin, dirPin );
//myStepper.attachEnable( enaPin, 10, LOW ); // Enable Pin aktivieren ( LOW=aktiv )
// the maximum steprate pulses per second is limited
// due to the kind of how the step-pulses are created with a timer-interrupt
// Arduino Uno, Mega Nano 2500 steps / second
// ESP8266 6250 steps / second
// STM32F103 20000 steps / second
// ESP32 30000 steps / second
Serial.print("myStepper.setSpeed( ");
Serial.print(StepperSpeed);
Serial.println(" );");
myStepper.setSpeed( StepperSpeed );
myStepper.setRampLen( 100 ); // Rampenlänge 100 Steps bei 20U/min
Serial.print( F("step-pin is IO-pin no ") );
Serial.println(stepPin);
Serial.print( F("dir-pin is IO-pin no ") );
Serial.println(dirPin);
}
bool GetToggleSwitchState() {
// "static" makes variables persistant over function calls
static bool toggleState = false;
static byte buttonStateOld = unPressed;
unsigned long buttonDebounceTime = 100;
unsigned long buttonDebounceTimer = 0;
byte buttonStateNew;
if ( TimePeriodIsOver(buttonDebounceTimer, buttonDebounceTime) ) {
// if more time than buttonDebounceTime has passed by
// this means let pass by some time until
// bouncing of the button is over
buttonStateNew = digitalRead(ToggleButtonPin);
if (buttonStateNew != buttonStateOld) {
// if button-state has changed
buttonStateOld = buttonStateNew;
if (buttonStateNew == unPressed) {
// if button is released
toggleState = !toggleState; // toggle state-variable
} // the attention-mark is the NOT operator
} // which simply inverts the boolean state
} // !true = false NOT true is false
// !false = true NOT false is true
return toggleState;
}
void SetStepperMotorSpeed() {
Serial.print( F("I received #") );
Serial.print(receivedChars);
Serial.println( F("#") );
StepperSpeed = atoi (receivedChars);
Serial.print("myStepper.setSpeed( ");
Serial.print(StepperSpeed);
Serial.println(" );");
if (StepperSpeed > 0) {
myStepper.setSpeed( StepperSpeed );
Serial.print( F("set speed to ") );
Serial.print(StepperSpeed);
Serial.println();
}
else {
Serial.println( F("no valid speed-data") );
}
}
void RunStepperMotor() {
// if steppermotor has reached target-position and
// does NOT move anymore
if ( !myStepper.moving() ) {
Serial.print( F("arrived at position ") );
Serial.println(myStepper.currentPosition() );
Serial.println();
if ( nextPos == 0 ) { // if is at startposition 0
nextPos = targetPos; // drive to position max
}
else { // if is at endposition
nextPos = 0; // drive to position zero
}
Serial.print( F("moving to position ") );
Serial.println(nextPos);
myStepper.moveTo( nextPos ); // start creating step-pulses
}
}
void execute_if_Active(bool p_IsActivated) {
if (p_IsActivated) {
RunStepperMotor();
}
else { // DE-activated
myStepper.stop();
}
PrintToSerialMonitor(p_IsActivated); // deactivate through commenting if not wanted
}
// helper-function ignore at first
void printFileNameDateTime() {
Serial.print( F("File : ") );
Serial.println( F(__FILE__) );
Serial.print( F("Date : ") );
Serial.println( F(__DATE__) );
Serial.print( F("Project: ") );
Serial.println( F(ProjectName) );
}
// ignore at first
// helper-function for easy to use non-blocking timing
boolean TimePeriodIsOver (unsigned long & expireTime, unsigned long TimePeriod) {
unsigned long currentMillis = millis();
if ( currentMillis - expireTime >= TimePeriod ) {
expireTime = currentMillis; // set new expireTime
return true; // more time than TimePeriod) has elapsed since last time if-condition was true
}
else return false; // not expired
}
// helper-function
void PrintToSerialMonitor(boolean p_IsActivated) {
static bool lastIsActivated;
// only in case the activation-mode has CHANGED print ONE time
if (p_IsActivated != lastIsActivated) {
// only if state of parameter p_logIsActivated has changed
if (p_IsActivated) {
Serial.println();
Serial.println( F("start executing") );
Serial.println();
digitalWrite(LED_BUILTIN, HIGH);
}
else { // not activated
Serial.println();
Serial.println( F("stopp executing") );
Serial.println();
digitalWrite(LED_BUILTIN, LOW);
}
lastIsActivated = p_IsActivated; // update variable lastSDlogActive
}
}
void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static unsigned int ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;
// If data is in the receive-buffer .available() > 0
// .available() returns how MANY bytes are in the receive-buffer
while (Serial.available() > 0 && newData == false) {
rc = Serial.read();
if (recvInProgress == true) { // if startmarker is found set flag to true
if (rc != endMarker) { // if the received byte is NOT the endmarker
receivedChars[ndx] = rc; // append the received byte at the end of char-array
ndx++; // increase array-index by 1
if (ndx >= numChars) { // if message is longer than max number of chars the arraybuffer can hold
ndx = numChars - 1; // reduce array-index => byte is trhown away
}
} // if (rc != endMarker) {
else { // it IS the endmarker
receivedChars[ndx] = '\0'; // terminate the string through adding a zero
recvInProgress = false; // receiving of command is finished
ndx = 0;
newData = true; // command is ready to be used
}
} // if (recvInProgress == true) {
else if (rc == startMarker) { // if the byte is the startmarker
recvInProgress = true; // set boolean flag receive in progress to true
}
} // while (Serial.available() > 0 && newData == false) {
}
/* OVERVIEW: ###################################################
this demo-code does quite a lot of things
the code has a hierachical structure
the code is organised in SUB-units where each SUB-unit is
doing a senseful unit of things like
- receive serial data
- Set StepperMotorSpeed
- check if start/stop-button is pressed
- depending on beeing in state "active" or "inactive"
drive stepper-motor or not
- create step-pulses to make the stepper-motor drive back and forth
- helper-functios for
- print source-code-filename to serial monitor
- measure how much time has passed by since a referencetime
(non-blocking timing)
- print info to serial monitor to make visible what the code is doing
in more Detail: ################################################
toggle-switch:
there is the function GetToggleSwitchState()
GetToggleSwitchState() returns a "true" or a "false"
this transforms a momentary pushbutton into a toggle-switch
press push-button => toggle-switch is in ON-position
press push-button => toggle-switch is in OFF-position
push-ON, Push-OFF, Push-ON, Push-OFF etc. etc.
In function loop the state of GetToggleSwitchState()
is checked ALL the time. Depending on variable activationMode
beeing true or false the
function execute_if_Active() is creating step-pulses
or just pausing -----------------------------------------------
receive serial data:
The function recvWithStartEndMarkers()
is checking for newly arrived serial data
it is doing this in a receive byte for byte
and NON-blocking manner.
NON-blocking is important that the code stays responsive to
button-presses ALL the time
If the code receives bytes that do not follow the pattern
leading startmarker "<" trailing endmarker ">" the received bytes
are just thrown away -------------------------------------------
set steppermotor speed:
If a complete command like "<500>" is received the variable newData
is set true and then the function SetStepperMotorSpeed()
processes the command.
In case the command is invalid the steppermotor-speed stays the same
in case the command is valid the stepper-motor-speed is changed
-----------------------------------------------------------------
some helper-functions:
*/