Changing variable values from pc via serial

I want to add serial control to my code, so i can set for example temperature from my PC for example with a command

temperature 250

would set variable named temperature to 250, i spent some time on the internet searching for some tips and example codes, but i couldn't find anything for my use case, i would need my code first to recognize to which variable to save value and then save the value to that variable.

i have this example code

#include "string.h"

String SerialData = "";

void SerialCommandReceive()
{
    char in_char = ' ';
    while (Serial.available() > 0)
    {
        in_char = Serial.read();
        if (int(in_char) != -1)
        {
            SerialData += in_char;
        }
    }
    if (in_char == '\n')
    {
        Serial.print("Text Entered: ");
        Serial.print(SerialData);

        SerialData = "";
    }
}

maybe with character analysis that would first recognise alphabetic characters , then whitespace and then the numeric.?

I also found this code for reference but it's pretty complex
https://github.com/reivax-boucoi/Electronic_Load/blob/master/firmware/SerialCommand.cpp

https://github.com/davehakkens/shredder-reverse/blob/master/Arduino%20Code/shredderControl.ino

Looks like it does pretty much what you need it to do.
So either learn how to use it, which admittedly is complex, or make it yourself, which is also complex but in a different way.

Sounds like a lot of work. As long as you stick to a clear protocol, it doesn't have to be very difficult. Start with this:

Does the command have to be 'temperature'? It might just as well be just 't'. Then a command like

t250

would set temperature to 250.

The only thing you then have to do is match the first character to 't' (which is ASCII 116) and parse the remainder of the input to an integer value using for instance atoi().

If you want to adhere to the command style you proposed, you could even parse the input into separate parts using strtok() and evaluate those separately, using the space (ASCII 32) as the separator.

Then once you've determined which command you're dealing with and what the parameter(s) is/are, you can perform the required function (e.g. set temperature to 250) using e.g. a swtich-case.

Thanks, for starters i will try the way you proposed without the whitespace, to make it a bit easier.

This is covered in the Serial Input Basics tutorial on this forum.

1 Like

I have a simpler parser, that allows things like:

  Serial.print(F("Enter command: "));
  int i = parseGetline();  // read a line of text

  do {
    enum {
      CMD_RED, CMD_GREEN, CMD_BLUE, CMD_RESET  // make sure this matches the string
    };
    cmd = parseKeyword(PSTR("red green blue reset")); // look for a command.

    if (cmd >= 0) {
      n = parseNumber();
    }
    switch (cmd) {
      case CMD_RED:
        red = n;
        break;
      case CMD_BLUE:
        blue = n;
        break;
      case CMD_GREEN:
        green = n;
        break;
      case CMD_RESET:
        red = green = blue = 0;
        break;
      case PARSER_EOL:
        Serial.print("RED = "); Serial.print(red);
        Serial.print(" GREEN = "); Serial.print(green);
        Serial.print(" BLUE= "); Serial.println(blue);
        break;
      default:
        Serial.println("Invalid command");
        break;
    }
  } while (cmd >= 0);
}

It hasn't really been published, or converted to proper library format, because there isn't enough there. But adding "enough" makes it more complicated :frowning:

1 Like

How is about the following sketch which accepts the above Newline terminated alphanumeric string from the InputBox of Serial Monitor, extracts the alphabetic substring, converts the digital substring into numeric value, and then assigns the numeric value to the variable (temperature).

char myData[30] = {0};
char myString[20] = {0};
int i = 0;
int temperature;

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  byte n = Serial.available();
  if (n != 0)
  {
    byte m = Serial.readBytesUntil('\n', myData, 30);//receive all
    myData[m] = '\0';
    //Serial.println(myData); //show received string
    //---------------------
    for (i = 0; i < m; i++)
    {
      if (isAlpha(myData[i]))//checking if it is a letter
      {
        myString[i] = myData[i];
      }
      else
      {
        break;  //exit for() loop is this is not a letter
      }
    }
    myString[i] = '\0';
    //Serial.println(myString);//show the alphabetic substring
    //------------------------
    if (strcmp(myString, "temperature") == 0)//check the substring
    {
      int y = strtoul(myData + i, NULL, 10);//convert to numeric value
      //Serial.println(y); //show the numeric value
      //--------------------------
      temperature = y; //assgn the numeric value to variable
      Serial.print("Temperature set at: ");
      Serial.println(temperature);
    }
  }
}

Output:

Temperature set at: 250
Temperature set at: 245
1 Like

Thanks for all of the help in replies, i decided to try the serial input basics example, but i have one more question i just added an if statement

 if (messageFromPC == "setTemp")
  {
    setTemperature = integerFromPC;
  }

But it doesn't work setTemperature doesn't change.

#include "Arduino.h"

const byte maxChars = 32;
char receivedChars[maxChars];
char tempChars[maxChars]; // temporary array for use when parsing

// variables to hold the parsed data
char messageFromPC[maxChars] = {0};
int integerFromPC = 0;
int setTemperature = 0;

boolean newData = false;

//============

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  SerialReceive();
}

void recvWithStartEndMarkers()
{
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;

  while (Serial.available() > 0 && newData == false)
  {
    rc = Serial.read();

    if (recvInProgress == true)
    {
      if (rc != endMarker)
      {
        receivedChars[ndx] = rc;
        ndx++;
        if (ndx >= maxChars)
        {
          ndx = maxChars - 1;
        }
      }
      else
      {
        receivedChars[ndx] = '\0'; // terminate the string
        recvInProgress = false;
        ndx = 0;
        newData = true;
      }
    }

    else if (rc == startMarker)
    {
      recvInProgress = true;
    }
  }
}

//============

void parseData()
{ // split the data into its parts

  char *strtokIndx; // this is used by strtok() as an index

  strtokIndx = strtok(tempChars, ","); // get the first part - the string
  strcpy(messageFromPC, strtokIndx);   // copy it to messageFromPC

  strtokIndx = strtok(NULL, ",");   // this continues where the previous call left off
  integerFromPC = atoi(strtokIndx); // convert this part to an integer

   if (messageFromPC == "setTemp")
  {
    setTemperature = integerFromPC;
  }
}

//============

void showParsedData()
{
  Serial.print("Message ");
  Serial.println(messageFromPC);
  Serial.print("Integer ");
  Serial.println(integerFromPC);
  Serial.println("setTemperature=");
  Serial.println(setTemperature);
}

void SerialReceive()
{
  recvWithStartEndMarkers();
  if (newData == true)
  {
    strcpy(tempChars, receivedChars);
    // this temporary copy is necessary to protect the original data
    //   because strtok() used in parseData() replaces the commas with \0
    parseData();
    showParsedData();
    newData = false;
  }
}

You cannot compare character strings in this way. You can use strcmp() to do so.
https://www.cplusplus.com/reference/cstring/strcmp/

Thanks, another question i defined multiple strings in an array so i have multiple aliases that work for setting the temperature, but i get an error saying cannot convert const char** to const char*, not sure how to make this work, also tried defining a string but also got errors, probably would need to convert to const char.

const char* alias[] = {"setTemp", "setTemperature"};

Serial_send_change_variables:80:43: error: cannot convert 'const char**' to 'const char*' for argument '1' to 'int strcmp(const char*, const char*)'
   int result = strcmp(alias, messageFromPC);
                                           ^
exit status 1
cannot convert 'const char**' to 'const char*' for argument '1' to 'int strcmp(const char*, const char*)'

int result = strcmp(alias, messageFromPC);

alias is an array. Which element of the array do you want to compare to messageFromPC?

You want to use a specific array index like
int result = strcmp(alias[0], messageFromPC); //test to see if messageFromPC is"setTemp"

You can iterate through the indexes in a for loop to test all the alias character strings against the messageFromPC.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.