1

This is not a duplicate of my other question. This question deals with reading specific data within a serial stream. The other question deals with reading and adding data into a manageable data string.

What I'm trying to do is send a command to serial, get the response, and put it into a string, and then break that string up into usable parts of data.

The problem I'm having, is there is a delay between the time the serial command is sent, and the response. meaning the serial data isn't being captured before the function moves onto the next line. Using delay() doesn't appear to work, as i believe it halts everything for that delay period.

What I'm hoping to do, is read the data from serial and if the character '<' is received, place it, and everything after it into the buffer until the character ">" is received. After the last character is received, and placed into the buffer, continue on with the script.

Unless of coarse someone has a better idea on how to approach this. i would also like to note that this is just a part of a larger project. If you need to see the entire project, please let me know and i will provide a link where you can download it.

The string i'm expecting as a response would be similar to this:

<Alarm,MPos:0.000,0.000,0.000,WPos:0.000,0.000,0.000>

Here is the code i have so far:

float mx;
float my;
float mz;
float wx;
float wy;
float wz;
String dAlarm;
char buffer;
void gPos() {
  Serial1.print("?\n");
  buffer = Serial1.read();
  char string[80];
  string[buffer];
  char *alarm = strtok(string, ",");
  char *mposX = strtok(NULL, ",");
  char *mposY = strtok(NULL, ",");
  char *mposZ = strtok(NULL, ",");
  char *wposX = strtok(NULL, ",");
  char *wposY = strtok(NULL, ",");
  char *wposZ = strtok(NULL, ">");
  alarm += 1;
  mposX += 5;
  wposX += 5;
  mx = strtod(mposX, NULL);
  my = strtod(mposY, NULL);
  mz = strtod(mposZ, NULL);
  wx = strtod(wposX, NULL);
  wy = strtod(wposY, NULL);
  wz = strtod(wposZ, NULL);

  if (strcmp(alarm, "Idle") == 0) {
    dAlarm = "Idle";
  } else if (strcmp(alarm, "Run") == 0) {
    // Something to do when Busy
    dAlarm = "Run";
  } else if (strcmp(alarm, "Hold") == 0) {
    // Something to do when Busy
    dAlarm = "Hold";
  } else if (strcmp(alarm, "Door") == 0) {
    // Something to do when Busy
    dAlarm = "Door";
  } else if (strcmp(alarm, "Home") == 0) {
    // Something to do when Busy
    dAlarm = "Home";
  } else if (strcmp(alarm, "Alarm") == 0) {
    // Something to do when Busy
    dAlarm = "ALARM!";
  } else if (strcmp(alarm, "Check") == 0) {
    // Something to do when Busy
    dAlarm = "Check";
  }
  dispPos();
}

void dispPos() {
  int state = 0;
  int x = analogRead (0);
  if (x < 800) {
    state = 1;
  }
  if (state == 1) {
    dPos = false;
  }

  if (dPos == true) {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("X");
    lcd.print(mx);
    lcd.setCursor(8, 0);
    lcd.print("Y");
    lcd.print(my);
    lcd.setCursor(0, 1);
    lcd.print("Z");
    lcd.print(mz);
    lcd.setCursor(8, 1);
    //lcd.print(" ");
    lcd.print(dAlarm);
    delay(3000);
  } else {
    mainMenu();
  }
}
  • possible duplicate of How would i capture and split serial data? – Nick Gammon Aug 30 '15 at 21:24
  • Sorry nick gammon, not a duplicate of that question. That question dealt with capturing and splitting the data. This deals with doing it for specific data only. The difference between the two is one asks how to capture and split, this one delves deeper and captures based upon certain criteria. – ArcAiN6 Aug 31 '15 at 0:35
  • You have lost me as to the difference between "capturing and splitting the data" and "for specific data". You are quoting the same data: <Alarm,MPos:0.000,0.000,0.000,WPos:0.000,0.000,0.000>. It's all very well do "delve deeper" but this is splitting the basic problem across two separate questions. One with, and one without, "certain criteria" I gather. – Nick Gammon Aug 31 '15 at 3:33
  • I guess i could go ahead and delete the question, but i have a feeling it would just be asked again, simply because it deals with a specific problem within a general subject. As far as i know, we aren't supposed to expand upon the initial question with another one. As i said, the first one deals promarily with general serial data collection, and processing. Where this question deals with a specific string within the serial stream. Just because i used the same example, doesn't mean the question is a duplicate, it offers other readers information not available in the first question's answer.. – ArcAiN6 Aug 31 '15 at 3:46
1

What you need to do here is implement a small finite state machine.

Basically you need to look at each character as it comes in and make a decision what to do with it depending on what state you're in at the moment.

Basically the operational decisions you need to make are:

  • Is the character a < and am I currently not reading a string?
    • Yes, start reading the string.
  • Is the character a > and am I currently reading a string?
    • Yes, finish reading the string and process it
  • Is it any other character and I am currently reading the string?
    • Yes, add it to the buffer.

So you can see there some common questions:

  • What is the character?
  • What am I doing at the moment?

So you need to have a simple state variable that remembers if you're reading the string or not, and something to say where in the buffer you are so you know where in the buffer to add any incoming characters.

boolean readingString = false;

A simple true/false will suffice to depict if we're reading the string or not. Start off not reading the string.

char buffer[80] = "";

A buffer to store the text - maximum of 80 characters (including the NULL terminating character)

int charPointer = 0;

Something to know where in the buffer are currently.

Now to read the characters:

First get the next character from the serial port:

loop() {
    if (Serial.available()) {
        int incoming = Serial.read();

Now decide what to do with it. We have a number of possible situations, some of which can be combined into single options. For instance, if we get a "<" while reading a string it's an error condition - but do we really care? It could be that we lost the end of the last string and have just started a fresh one - so we can just treat it as the start of a string regardless of what state we're in. Let's use a switch for this since it's nice and tidy:

        switch (incoming) {
            case '<':
                readingString = true; // Start reading string
                charPointer = 0; // Set the buffer pointer to the start
                buffer[0] = 0; // Make the string empty
                break;

            case '>':
                if (readingString) {
                    processBufferData(); // Do something with the buffer
                }
                readingString = false; // Finish reading
                break;

            default: // Anything that's not > or <
                // If we are reading the string and the buffer isn't full
                if (readingString && charPointer < 78) {
                    // Add the character to the buffer and increment the pointer
                    buffer[charPointer++] = incoming;
                    buffer[charPointer] = 0; // Don't forget to terminate the string
                }
        }
    }
}

So the reception of a < starts the string reading, the reception of a > stops it and triggers the processing of the string, and anything else (while we are reading the string) gets added to the buffer.

  • for some reason i'm not getting the result i expect. I think because elsewhere in the script i already have serial available, and perhaps it's interfering, or something else more drastic is happening. If you're willing to take a look. Perhaps you can spot, and explain what i've done wrong and where so others can learn from my mistakes. Also.. Please don't laugh too hard at me, it's only my second or third week using the arduino IDE I've uploaded my project to Here – ArcAiN6 Aug 30 '15 at 16:27
  • You must only consume the serial bytes in one place, otherwise who knows what'll happen. – Majenko Aug 30 '15 at 16:34
  • hrm.. well.. that kind of shoots my entire project down then. What i'm trying doing is sending data to an arduino Uno with GRBL, through an arduino mega with an LCDKeypad shield. That way i can display the POS on the LCD, have a menu system for common GRBL stuff. As well as use the PC (and at a later date SD) to send g-code to the uno. So the flow would be PC-> Mega+Keypad -> UNO | Uno -> Mega -> LCD+PC So far everything is working OK, but i've had to avoid using if(serial.available) as it's always available so it can send data from PC to UNO, and from UNO to PC. – ArcAiN6 Aug 30 '15 at 16:46
  • Just move the reading routine out of the timer and into the serialcomms routine, and print the characters in there instead. – Majenko Aug 30 '15 at 17:00
  • I Thought about that, and was working on it as you responded. I left the command in the timer that requests the status string from GRBL (the string we are processing) That way it can continue to update without interference. And i moved the reading of the string to the serial comms. Going to test it now :) – ArcAiN6 Aug 30 '15 at 17:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.