Search code examples
arduinoarduino-unoarduino-ide

How to solve issue with my program getting stuck and repeating itself?


The program

I have an Arduino project that controls a stepper motor for automated testing.

The program should wait for user input, execute some code based on the input, and allow the user to change the task part way through by sending a new command.

Some of the tasks to be performed require a function that will hold the program until the next quarter hour interval ie, 10:00, 10:15, 10:30, etc.

The issues

There are 3 commands that do not result in the execution of a task, they mostly just print some stuff and are done. If one of these commands is the first command sent, the program will print out what it is suppose to and will not accept any new commands.

Additionally, when any other command is run any prints in the switch statement will be printed twice.

My conclusion is that for some reason the switch statement gets ran through twice every time a command is sent, thus the double prints (the default switch will run the previously run command) and the program halting (Those particular functions do not set a previous cmd to remember. The reason for the previous cmd variable is in case a user wants to see the menu they don't have to interrupt their test.).

I have tried changing the architecture so that loop no handles characters coming in from serial port and made a separate function for time keeping (originally this was in loop()).

I have also tried calling the serial handling function from loop and in the Command() function.

The code

void setup() 
{
    Serial.begin(9600);
    AFMS.begin();                   //start motor object
    myStepper1->setSpeed(300);      //set motor speed

    Serial.print("Starting AutoArduino V0.7 ...\n");
    Serial.print("Press H for help\n");
    Serial.print("\n");

    lastTime = -1;  // make sure lastTime is initialized to something that 
                    // is not 0 and not a multiple of 15.

 }

 void TimeKeeper() 
 { 
  while(Serial.available() <= 0){
    now = rtc.now();
    if (now.minute() != lastTime && now.minute() % 15 == 0){

        interval++;
        intervalTotal++;
        lastTime = now.minute();
        return; // this is where you want to exit loop() if you do not want
                // execution beyond this point. 
    }
  }
 }

void loop(){
    while (Serial.available() > 0) Command(Serial.read());
}


void Command(int cmd){ 
  myStepper1->release();
  if(prevCmd!=cmd) interval=0;

    switch (cmd) {                             //Switch stament will execute any code that matchs a received character. Data sent over serial is asynchronous, thus the single charaters.

     case 'B':
     case 'b':
        prevCmd = cmd;
        delay(100);
        Serial.print("Starting backwards flow... \n");
        BackwardFlow();
       break;

     case 'C':
     case 'c':
        prevCmd = cmd;
        delay(100);
        Serial.print("Incrementing... \n");
        delay(10);
        Increment();
       break;

     case 'D':
     case 'd':
        prevCmd = cmd;
        delay(100);
        Serial.print("Decrementing... \n");
        Decrement();
       break;

     case 'H':
     case 'h':
        delay(100);
        Serial.print("\n");
        Serial.print("B: Continuous backward flow\n");
        Serial.print("C: Increment every interval\n");
        Serial.print("D: Decriment every interval\n");
        Serial.print("F: Continuous forward flow\n");
        Serial.print("R: Reverse flow\n");
        Serial.print("X: Cancels current test\n");
        Serial.print("\n");
        return;
       break;

     case 'F':
     case 'f':
        prevCmd = cmd;
        delay(100);
        Serial.print("Starting forward flow... \n");
        ForwardFlow();
       break;

     case 'R':
     case 'r':
        interval =0;
        prevCmd = cmd;
        delay(100);
        Serial.print("Starting Reverse flow simulator... \n");
        ReverseFlowSim();
       break;

     case 'T':
     case 't':
        now = rtc.now();

        Serial.println("Current Date & Time: ");
        Serial.print(now.year(), DEC);
        Serial.print('/');
        Serial.print(now.month(), DEC);
        Serial.print('/');
        Serial.print(now.day(), DEC);
        Serial.print(" (");
        Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
        Serial.print(") ");
        Serial.print(now.hour(), DEC);
        Serial.print(':');
        Serial.print(now.minute(), DEC);
        Serial.print(':');
        Serial.print(now.second(), DEC);
        Serial.println();
       break;

     case 'X':
     case 'x':                         
        delay(100);
        Serial.print("Stopping all tests \n");
        prevCmd = empty;
        cmdID = empty;
       break;

     default:
        delay(100);
        //Serial.print("Continuing: " + cmdID);
        Command(prevCmd);
      break;
    }
}

void ForwardFlow(){
  while(Serial.available() <= 0){
    myStepper1->step(512, FORWARD, SINGLE);   //512 steps per revolution
  }
    myStepper1->release();
}

void BackwardFlow(){
  while(Serial.available() <= 0){
    myStepper1->step(512, BACKWARD, SINGLE);   //512 steps per revolution
  }
    myStepper1->release();  
}

void Increment(){
    while(Serial.available() <= 0){
      TimeKeeper();
      for(int i=0; i < 1; i++){
        //if(Serial.available() > 0) Serialhandler();
        myStepper1->step(512, FORWARD, SINGLE);
      }
    }  
}

void Decrement(){
    while(Serial.available() <= 0){
      TimeKeeper();
      for(int i=0; i < 43; i++){
        //if(Serial.available() > 0) SerialHandler();
        myStepper1->step(512, BACKWARD, SINGLE);
      }
    }  
}

I expect the program to allow me to change commands at will and allow the user to receive the help menu without halting the program, currently the help menue will casue the program to stop working until the device is rebooted.


Solution

  • Check your Serial Monitor's line ending setting. My guess is that you are sending CR or NL. So, when you send a letter that sets prevCmd, a following CR/NL prints the same thing. And a letter that does not set prevCmd puts your program into infinite loop because Command(prevCmd); is called infinitely.

    If you expect CR or NL, you better ignore them. Evaluate a returned value from Serial.read() before you send it to Command(int cmd).

    int cmd = Serial.read();
    if (cmd != '\n' && cmd != '\r') {
        Command(cmd);
    }