calling functions in the serial monitor

Hello there. This is my first time asking for help on this forum. I will, therefore, be as specific as I can. I am working on a project that calls different functions through the serial monitor using a two letter input. I have done my research and can’t for the life of me get something to work. I have tried to use the code from this website and have not been able to get something to work.

https://www.norwegiancreations.com/2017/12/arduino-tutorial-serial-inputs/

I can only call each individual function separately within the code without using the serial monitor. I would like to use an input in the serial monitor to call/run a corresponding function.

Any and all help would be appreciated with this. I am looking forward to seeing what you guys can come up with.

Here is the section of code of interest:

///serial input void loop section 11-4-9:01pm
   if(Serial.available()){
    command = Serial.readStringUntil('\n');

    if(command.equals(casting_forward("cf")){
      casting_forward();
    }
    else if(command.equals(casting_backward("cb")){
      casting_backward();
    }
    else if(command.equals(home_flick_rod("hr")){
      home_flick_rod();
    }
    else if(command.equals(line_flick_backward("lb")){
      line_flick_backward();
    }
    else if(command.equals(line_flick_forward("lf")){
      line_flick_forward();
    }
  else if(command.equals(carriage_forward_flick("cg")){
  carriage_forward_flick();
  }
}

I will attach the entire code file if that is needed for reference.

forum11-5.ino (7.72 KB)

So what doesn't work in the section of code that you posted ?
What have you got the Line Ending set to in the Serial monitor ?

readStringUntil() is a blunt instrument. Read Serial Input Basics

readStringUntil() is a blunt instrument.

Blunt, but it works

String command;

void setup()
{
  Serial.begin(115200);
  Serial.println();
}

void loop()
{
  if (Serial.available())
  {
    command = Serial.readStringUntil('\n');
  }
  if (command == "one")
  {
    one();
  }
  else if (command == "two")
  {
    two();
  }
  command = "";
}

void one()
{
  Serial.println("function one");
}

void two()
{
  Serial.println("function two");
}

Plenty of scope for improvement

Wow, I really appreciate all the responses this has gotten! Thank you guys so much! Alright, so this one first.

UKHeliBob:
So what doesn't work in the section of code that you posted ?
What have you got the Line Ending set to in the Serial monitor ?

I am not sure what you mean by "line ending set in the serial monitor". If you mean have I ran this in the serial monitor then the answer is I have not. The system that this control is in a shop that I need to wait to get access to, I can at noon mountain time so in the next few hours.

The error I am getting is saying that " 'casting_forward' was not declared in the scope". I have gotten this error a million times and I keep forgetting what I did to correct it in other instances. I will try the code that UKHeliBob has posted here in just a few hours and see what's going on. I have a feeling I am just not using the "readStringUntil()" correctly. I will update you guys shortly.

Also, yes I have read the serial input basics post but still can't for the life of me understand this. I am very new to coding and basically have taught myself this by banging my head against the wall.

Thank you guys again so much for the help with this.

This is a more condensed version of gathering serial input:

const byte maxMsgLen = 16;

const byte cbLF = 10;
const byte cbCR = 13;

void setup() {
  Serial.begin(250000);
  Serial.println(F("TwoLetterCommands cf cb hr lb lf cg"));
}

void loop() {
  handleSerial();
}

void oneLineReceived(const char * buffer) {
  if (!strcmp_P(buffer, PSTR("cf"))) {
    casting_forward();
  } else if (!strcmp_P(buffer, PSTR("cb"))) {
    casting_backward();
  } else if (!strcmp_P(buffer, PSTR("hr"))) {
    home_flick_rod();
  } else if (!strcmp_P(buffer, PSTR("lb"))) {
    line_flick_backward();
  } else if (!strcmp_P(buffer, PSTR("lf"))) {
    line_flick_forward();
  } else if (!strcmp_P(buffer, PSTR("cg"))) {
    carriage_forward_flick();
  } else {
    Serial.print(F("don't know  '"));
    Serial.print(buffer);
    Serial.println(F("'."));
  }
}

void handleSerial() {
  static uint8_t bIndex;
  static uint8_t buffer[maxMsgLen + 1];
  bool lineReady = false;
  if (Serial.available()) {
    uint8_t inChar = Serial.read();
    if (inChar != cbLF) {
      if (inChar == cbCR) {
        lineReady = true;
      } else {
        buffer[bIndex++] = inChar;
        lineReady = (bIndex == maxMsgLen);
      }
      if (lineReady) {
        buffer[bIndex] = 0;
        oneLineReceived((const char*)buffer);
        bIndex = 0;
      }
    }
  }
}

void casting_forward() {
  Serial.println(F("casting_forward"));
}
void casting_backward() {
  Serial.println(F("casting_backward"));
}
void home_flick_rod() {
  Serial.println(F("home_flick_rod"));
}
void line_flick_backward() {
  Serial.println(F("line_flick_backward"));
}
void line_flick_forward() {
  Serial.println(F("line_flick_forward"));
}
void carriage_forward_flick() {
  Serial.println(F("carriage_forward_flick"));
}

Select Tools=>Auto Format in the IDE and you’ll notice that the function casting_forward() is indented, meaning that you’re missing a curly brace somewhere (end of lopp(), I think).

Also you might want to include Wire.h.

Also I don’t think this line will work:

if(command.equals(casting_forward("cf"))

since you’re passing equals() something that’s not a string, probably better to accept just “cf” from the serial monitor and compare to that.

Also casting_forward() expects to be called with two floats and you’re calling it with no arguments.

///all functions code//

//setup tic
#include <Tic.h>

TicI2C tic;

//encoder setup
// setup encoder libraries and variables

#include <SPI.h>
 
#define CS 3 //Chip or Slave select 
 
uint16_t ABSposition = 0;
uint16_t ABSposition_last = 0;
uint8_t temp[2];    //This one.
 
float deg = 0.00;
float tempDeg;
char x;

//wiper bounds in degrees
float home1 = 180.00;
float stop1 = 240.00;
float stop2 = 120.00;

//serial monitor setup
String command;

///void setup setup section
void setup()
{
  ///tic setup
  // Set up I2C.
  Wire.begin();

  // Give the Tic some time to start up.
  delay(20);

  // Set the Tic's current position to 0, so that when we command
  // it to move later, it will move a predictable amount.
  tic.haltAndSetPosition(0);

  // Tells the Tic that it is OK to start driving the motor.  The
  // Tic's safe-start feature helps avoid unexpected, accidental
  // movement of the motor: if an error happens, the Tic will not
  // drive the motor again until it receives the Exit Safe Start
  // command.  The safe-start feature can be disbled in the Tic
  // Control Center.
  tic.exitSafeStart();

 //encoder setup
    
 Serial.begin(250000);
  pinMode(CS,OUTPUT);//Slave Select
  digitalWrite(CS,HIGH);
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE0);
  SPI.setClockDivider(SPI_CLOCK_DIV32);
  Serial.begin(115200);
  Serial.println("starting");
  Serial.flush();
  delay(2000);
  SPI.end();


//dc motor setup
 pinMode(8, OUTPUT); //set direction pin as output, dir
 pinMode(11, OUTPUT); //set enable pin as output, pwm 

 //serial input command setup 11-4-9:31pm
 Serial.begin(9600);
 
}

// Sends a "Reset command timeout" command to the Tic.  We must
// call this at least once per second, or else a command timeout
// error will happen.  The Tic's default command timeout period
// is 1000 ms, but it can be changed or disabled in the Tic
// Control Center.
void resetCommandTimeout()
{
  tic.resetCommandTimeout();
}

// Delays for the specified number of milliseconds while
// resetting the Tic's command timeout so that its movement does
// not get interrupted by errors.
void delayWhileResettingCommandTimeout(uint32_t ms)
{
  uint32_t start = millis();
  do
  {
    resetCommandTimeout();
  } while ((uint32_t)(millis() - start) <= ms);
}

// Polls the Tic, waiting for it to reach the specified target
// position.  Note that if the Tic detects an error, the Tic will
// probably go into safe-start mode and never reach its target
// position, so this function will loop infinitely.  If that
// happens, you will need to reset your Arduino.
void waitForPosition(int32_t targetPosition)
{
  do
  {
    resetCommandTimeout();
  } while (tic.getCurrentPosition() != targetPosition);
}


// more encoder setup

  uint8_t SPI_T (uint8_t msg)    //Repetive SPI transmit sequence
{
   uint8_t msg_temp = 0;  //vairable to hold recieved data
   digitalWrite(CS,LOW);     //select spi device
   msg_temp = SPI.transfer(msg);    //send and recieve
   digitalWrite(CS,HIGH);    //deselect spi device
   return(msg_temp);      //return recieved byte
}





/////call functions void loop
void loop(){


   uint8_t recieved = 0xA5;    //just a temp vairable
   ABSposition = 0;    //reset position vairable
   
   SPI.begin();    //start transmition
   digitalWrite(CS,LOW);
   
   SPI_T(0x10);   //issue read command
   
   recieved = SPI_T(0x00);    //issue NOP to check if encoder is ready to send
   
   while (recieved != 0x10)    //loop while encoder is not ready to send
   {
     recieved = SPI_T(0x00);    //cleck again if encoder is still working 
     delay(2);    //wait a bit
   }
   
   temp[0] = SPI_T(0x00);    //Recieve MSB
   temp[1] = SPI_T(0x00);    // recieve LSB
   
   digitalWrite(CS,HIGH);  //just to make sure   
   SPI.end();    //end transmition
   
   temp[0] &=~ 0xF0;    //mask out the first 4 bits
    
   ABSposition = temp[0] << 8;    //shift MSB to correct ABSposition in ABSposition message
   ABSposition += temp[1];    // add LSB to ABSposition message to complete message
    
   if (ABSposition != ABSposition_last)    //if nothing has changed dont wast time sending position
   {
     ABSposition_last = ABSposition;    //set last position to current position
     deg = ABSposition;
     deg = deg * 0.08789;// aprox 360/4096
     Serial.println(deg);     //send position in degrees
    //Serial.println(encoder_read);     //send position in degrees
   
return(deg);
   delay(10);    //wait a bit till next check

   }

   ///serial input void loop section 11-4-9:01pm
   if(Serial.available()){
    command = Serial.readStringUntil('\n');

    if(command.equals(casting_forward("cf")){
      casting_forward();
    }
    else if(command.equals(casting_backward("cb")){
      casting_backward();
    }
    else if(command.equals(home_flick_rod("hr")){
      home_flick_rod();
    }
    else if(command.equals(line_flick_backward("lb")){
      line_flick_backward();
    }
    else if(command.equals(line_flick_forward("lf")){
      line_flick_forward();
    }
   }
  else if(command.equals(carriage_forward_flick("cg")){
  carriage_forward_flick();

}


 

//////functions
//////carriage_forward_flick function
  void carriage_forward_flick(){
  // Tell the Tic to move to position 10000, and wait until it gets
  // there.
  tic.setTargetVelocity(25000); //motor vel in 10000 pulses per second
  tic.setTargetPosition(10000);// in steps
  waitForPosition(1000);//ms
  }

//////carriage_backward_flick function
  void carriage_backward_flick(){
  // Tell the Tic to move to position -10000, and wait until it gets
  // there.
  tic.setTargetVelocity(25000); //motor vel in 10000 pulses per second
  tic.setTargetPosition(-10000);// in steps
  waitForPosition(1000);//ms
  return;
  }

//////function for home flick
void home_flick_rod(float home1,float encoder, float stop1, float stop2) { 
  Serial.println("end home flick");
  
if (encoder > home1){
  digitalWrite (8,HIGH); //dir cw low ccw
  analogWrite (11,30);}
  else { digitalWrite (8,LOW);
  analogWrite (11,30);}
  if (abs(encoder - home1) < 5){
  analogWrite (11,0);}
  return;
  Serial.println("at home");
  Serial.read();
}

///////function for rod_forward_flick
void rod_forward_flick(float stop1,float deg) {
  //Serial.println("end forward flick");
  digitalWrite (8,LOW); //dir cw low ccw
if (deg < stop1){
  analogWrite (11,30);
  }
  else {
  analogWrite (11,0);}
  return;
}

//////functon for rod_back_flick
void rod_back_flick(float stop2,float deg) {
  //Serial.println("end backward flick");
  digitalWrite (8,HIGH); //dir cw low ccw
if (deg > stop2){
  analogWrite (11,30);}
  else {
  analogWrite (11,0);}
  return;
}

//11-4-8:35pm
//////function for casting rod forward
  void casting_forward(float stop2, float deg){
    for (int i = 0; 6; i++)
    rod_forward_flick(stop2, deg);
    delay(10);
    carriage_forward_flick();
    delay(10);
    return;
  }

  //////function for casting rod backward
  void casting_backward(float stop1, float deg){
    for (int i = 0; 6; i++)
    rod_back_flick(stop1, deg);
    delay(10);
    carriage_backward_flick();
    delay(10);
    return;
  }

  /////function for flicking rod forward (flick line out)
   void line_flick_forward(float stop2, float deg){
    rod_forward_flick(stop2, deg);
    delay(10);
    carriage_forward_flick();
    delay(10);
    return;
   }

  /////function for flicking rod backward (flick line back)
   void line_flick_backward(float stop1, float deg){
    rod_back_flick(stop1, deg);
    delay(10);
    carriage_backward_flick();
    delay(10);
    return;
   }
}

I am not sure what you mean by "line ending set in the serial monitor"

The code you posted has this line in it

   command = Serial.readStringUntil('\n');

Basically, this reads the serial input until it receives a Newline character.

The Serial monitor into which you type the command has an option at the bottom of the screen to set the line ending character that will be sent when you press Return, which in this case needs to be Newline.

Ok. So I got UKHeliBob’s code to work. For me, it looks like this.

//11-5 11:55am
if (Serial.available())
{
  command = Serial.readStringUntil('\n');
}
if (command == "cff")
{
  carriage_forward_flick();
}
else if(command == "cbf")
{
  carriage_backward_flick();
}
command = "";

This is just the code snippet within the void loop. It can work with both commands “cff” and “cbf” but only one or the other and only once. How can I be able to input these commands multiple times within the serial monitor? eg. I enter cff once and it runs that once then i enter cbf and it runs cbf once but i can also just enter cff multiple times and it runs multiple times.

Also, it will only let one command to be entered and then it does nothing until i reupload the code. Eg. enter cff once, runs it once, but will not run it again until i reupload the code.

Thank you so very much guys. This is incredibly helpful.

if you use Serial.readStringUntil('\n') function, you SHOULD select “newline” option in Serial Monitor.

You can refer to an example of turning led ON/OFF by sending command via Serial Monitor

IoT_hobbyist:
if you use Serial.readStringUntil('\n') function, you SHOULD select “newline” option in Serial Monitor.

You can refer to an example of turning led ON/OFF by sending command via Serial Monitor

Isn't the newline option already selected in serial monitor? What I mean is that isn't newline the standard selection? I might be completely wrong. Thank you so much! I will have to check when I have access to the system tomorrow.