// Serial-controlled stepper motor
// Based on:
//
// https://wokwi.com/projects/327823888123691604
// Arduinozyme from https://github.com/WardCunningham/Txtzyme
// stepper code from https://forum.arduino.cc/t/want-to-control-stepper-motor-angle-via-serial/1096201
//
// https://github.com/WardCunningham/Txtzyme/blob/master/Arduinozyme/Arduinozyme.ino
// Note the 32:1 gear ratio on Wokwi's diagram.json

unsigned int x = 0; // general purpose value
long int d = 13;    // pin register
const unsigned int bufsize = 128; // 2048 is too large for Arduino Uno

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 ) --<<<<<<<<<<<<<<<<<<<<< 
uint32_t stepDelay = 500;
//-----------------------------------------------(   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;    

void doHelp(){
  Serial.print(F("0-9: Accumulate digits into a x. p: print number\n"
  "d: copy number to d. i:pinmode(d,INPUT), I: pinMode(d,INPUT_PULLUP), s: x=analogRead(d) r: digitalRead(d)\n"
  "o: output x digital, O: output x analog\n"
  "T: tone(d,x). m: delay(x). {...}: loop k=x times. k: copy k to x \n"
  "A: step to angle x, f: step(+x): b: step(-x), D: delayMicros(x) between steps \n"
  "try: 10{_k:_kpf1500m} loop down from 10, printing and stepping, and pause between motions.\n"
  "or try: 180A 5{45b 1000m 500D 90f 1000m 5000D _boop_}\n"
  ));
}


void setup() {
  //txtEval("10d10T 1000m 2T 1000m 0T 0o\r\n"); // hint for a startup command
  pinMode (PUL, OUTPUT);  // set out pins 
  pinMode (DIR, OUTPUT);
  pinMode (ENA, OUTPUT);
  digitalWrite(ENA,LOW);  // disable on start 
  Serial.begin(9600);   
  Serial.println("Txtzyme h?diIoOmprTksAbf{}+ ");

}

void loop() {
  char buf[bufsize];
  txtRead(buf, bufsize);  // wait for commands
  txtEval(buf);
}

void txtRead (char *p, unsigned int n) {
  unsigned int i = 0;
  while (i < (n - 1)) {
    while (!Serial.available());  // loop while waiting for input
    char ch = Serial.read();
    if (ch == '\r' || ch == '\n') break;
    if (ch >= ' ' && ch <= '~') {
      *p++ = ch;
      i++;
    }
  }
  *p = 0;
}

void txtEval (char *buf) {
  unsigned int k = 0;
  char *loop;
  char ch;
  while ((ch = *buf++)) {
    switch (ch) {
      case '0':
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case '9':
        x = ch - '0';
        while (*buf >= '0' && *buf <= '9') {
          x = x * 10 + (*buf++ - '0');
        }
        break;
      case 'p':
        Serial.println(x);
        break;
      case 'd':
        d = x;
        break;
      case 'i':
        pinMode(d, INPUT);
      case 'I':
        pinMode(d, INPUT_PULLUP);
      case 'r':
        x = digitalRead(d);
        break;
      case 'o':
        pinMode(d, OUTPUT);
        digitalWrite(d, x % 2);
        break;
      case 'O': // write analog
        pinMode(d, OUTPUT);
        analogWrite(d, x);
        break;
        // Teensy 3.1 and 3.0 specifc code
#if defined(__MK20DX256__)|| defined(__MK20DX128__)
      case 'F':  // See https://www.pjrc.com/teensy/td_pulse.html
        analogWriteFrequency(d, x);
        break;
      case 'R':  // Teensy3 bits of resolution 2-16 default was 8
        analogWriteResolution(x);
        break;
#endif
      case 'T':
        if (x == 0 )
          noTone(d);
        else
          tone(d, x);
        break;
      case 'm':
        delay(x);
        break;
      case '{':
        k = x;
        loop = buf;
        while ((ch = *buf++) && ch != '}') {
        }
      case '}':
        if (k) {
          k--;
          buf = loop;
        }
        break;
      case 'k':
        x = k;
        break;
      case '_':
        while ((ch = *buf++) && ch != '_') {
          Serial.print(ch);
        }
        Serial.println();
        break;
      case 's':
        x = analogRead(x);
        break;
      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;
        case 'h':
        case '?':
          doHelp();
    }
  }
}



int doStep(int8_t direction) {
  if (direction > 0) {
    digitalWrite(DIR, HIGH);
    ++cur_step;
  } else {
    digitalWrite(DIR, LOW);
    --cur_step;
  }
  //digitalWrite(ENA, HIGH);
  digitalWrite(PUL, HIGH);
  delayMicroseconds(5);            // no less than 50 ( under torque issue.. nema 23 works )
  digitalWrite(PUL, LOW);
  delayMicroseconds(stepDelay);
}





A4988