Exiting Loop With Serial Input From Keyboard

I have an Arduino MKR1000 attached via USB to my computer and attached via the serial port to another board that I want to read some information from into the serial terminal of my computer.

I have a program that reads in this works to read in this information right that I will copy below. This may seem excessive for what I am trying to do but I have an expanded version that reads from many devices sequentially that I did not include because it would only complicate the question.

I would like to add the ability for the user to type an escape key (such as x) at any point in the process and start the loop over.

How should I best accomplish this?

Here is my code:

#include <Arduino.h>
#include <wiring_private.h>

// Serial2 pin and pad definitions (in Arduino files Variant.h & Variant.cpp)
#define PIN_SERIAL2_RX       (1ul)                // Pin description number for PIO_SERCOM on D1
#define PIN_SERIAL2_TX       (0ul)                // Pin description number for PIO_SERCOM on D0
#define PAD_SERIAL2_TX       (UART_TX_PAD_0)      // SERCOM pad 0 TX
#define PAD_SERIAL2_RX       (SERCOM_RX_PAD_1)    // SERCOM pad 1 RX

Uart Serial2(&sercom3, PIN_SERIAL2_RX, PIN_SERIAL2_TX, PAD_SERIAL2_RX, PAD_SERIAL2_TX);

const byte numPins = 4;
byte pins[] = {5, 4, 3, 2};
byte num_devices = 0;
char myChar = 0;

void setup() {
  Serial.begin(115200);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Native USB only
  }

  Serial2.begin(115200);
  
  pinPeripheral(0, PIO_SERCOM);   // Assign pins 0 & 1 SERCOM functionality
  pinPeripheral(1, PIO_SERCOM);

  //Set control Pins as outputs
  for (byte i=0; i<numPins; i++){
    pinMode(pins[i], OUTPUT);
  }

  //Serial.println("Setup Complete");
}

void loop() {

    Serial.println ("Retreiving from single device");
    Serial.println ("Press x at any point to exit this process");
    Serial.println ("Please enter device position (0 - 9)");
    Serial.println();

    while(!Serial.available()); //Wait for user to enter device position
    num_devices = Serial.read(); //Read the device position
    while (Serial.read() >= 0); //Clear Rx buffer
    

    Serial.println("Position | Device ID");
    Serial.print((char) num_devices); //Show entered device position as confirmation
    Serial.print(" | ");

    Set_Mux_Pin(num_devices); //Set the pins of the mux based on the entered device position
    //Serial.println("...Checking...");
    
    while (Serial2.read() >= 0); //Clear Rx buffer
    
    while (!Serial2.available()); //Wait until data is present in the Rx buffer
    
    if (Serial2.available()){
        while (myChar != '\n'){  //Read the buffer until new line character is transmitted
          myChar = Serial2.read();
          Serial.print(myChar);
          delay(3);
        }
        Serial.print(myChar);
    }
    myChar = 0;
}

void Set_Mux_Pin(byte number){
  //Serial.print("Pin state = ");
  
  for (byte i = 0; i < numPins; i++){
    byte state = bitRead(number, i);
    digitalWrite(pins[i], state);
    //Serial.print(state);
  }
}

void SERCOM3_Handler()    // Interrupt handler for SERCOM3
{
  Serial2.IrqHandler();
}

Look over Robin2's serial input basics. Specifically that part dealing with end markers.

Karma for first-post code tags.

Here is a sketch with some test data for Serial2
See Text I/O for the Real World for more details

// install SafeString V3 from Arduino Library manager
#include <SafeStringReader.h>
#include <SafeStringStream.h>

// see Text I/O for the Real World   https://www.forward.com.au/pfod/ArduinoProgramming/Serial_IO/index.html
createSafeStringReader(sfReader, 5, "\n"); // read text line upto 5chars terminated by '\n'

createSafeStringReader(sfReader2, 5, "\n"); // read a 1 char text line terminated by '\n'

cSF(serial2Data, 33);
SafeStringStream serial2Stream(serial2Data);

const byte numPins = 4;
byte pins[] = {5, 4, 3, 2};
int num_devices = 0;
char myChar = 0;

void setup() {
  Serial.begin(115200);
  for (int i = 10; i > 0; i--) {
    Serial.print(i); Serial.print(' ');
    delay(500);
  }
  Serial.println();
  //SafeString::setOutput(Serial); //uncomment this to enable error msgs
  sfReader.connect(Serial);
  sfReader.echoOn();

  // set up the Serial2 data
  serial2Data = "1\n2\n3\n4\n5\n6\n7\n8\n9\n0\n";

  sfReader2.connect(serial2Stream);
  sfReader2.echoOn(); // loop the chars read back to be re-read again
  //Serial2.begin(115200);

  //Set control Pins as outputs
  for (byte i = 0; i < numPins; i++) {
    pinMode(pins[i], OUTPUT);
  }

  Serial.println ("Retreiving from single device");
  Serial.println ("Press x at any point to exit this process");
  Serial.println ("Please enter device position (0 - 9)");
  Serial.println();
  //Serial.println("Setup Complete");
  serial2Stream.begin(); // start releasing data
}

int devNum = 0; // not set
bool readingChar = false; // this set to true once we have a position, then false when we get the char from Serial2

void reset() {
  Serial.println(" Exiting to Restart");
  readingChar = false;
  // other reset stuff here
}

bool processPosition(SafeString &input) {
  // device num // convert to int
  // check devNum not already set
  if (readingChar) {
    Serial.println(" Invalid input, already have Position");
    return false;
  } else {
    if (input.toInt(num_devices)) {
      // got a valid int
      if ((num_devices < 0) || (num_devices > 9)) {
        Serial.println(" device number out of range.");
        return false;
      } else {
        devNum = num_devices;
        return true;
      }
    } else {
      Serial.println(" Invalid device number");
      return false;
    }
  }
  return false;
}

void printSetting(int pos, char c) {
  Serial.println("Position | Device ID");
  Serial.print(pos); Serial.print(" | ");  Serial.print(c); Serial.println();
}

void loop() {
  if (sfReader.read()) {
    if (sfReader == 'x') {
      reset();
    } else {
      if (!readingChar) { // waiting for position
        if (processPosition(sfReader)) {
          // got valid position
          // set the mux
          readingChar = true; // reading char now
          sfReader2.skipToDelimiter(); // skip to next /n
        }
      }
    }
  }

  if (readingChar) {
    //serial2Data.debug();
    if (sfReader2.read()) {
      // got something one delimited by \n after skipping
      if (sfReader2.isEmpty()) { // input overflowed more then 1char and \n
        // ignore
      } else {
        myChar = sfReader2.charAt(0);
        printSetting(devNum, myChar);
        readingChar = false;
      }
    }
  }

  // other code here runs without being blocked
}

Here is some sample output

Retreiving from single device
Press x at any point to exit this process
Please enter device position (0 - 9)

7
Position | Device ID
7 | 2
x
 Exiting to Restart

This is exactly what I am looking for except when I try to compile it for my Arduino MK1000 Board it gives this error (shortened to meet character limit)

arduino error fatal error: avr/pgmspace.h: No such file or directory #include <avr/pgmspace.h>

I tried using adding this code to the header file as I have seen on other forums but it did not solve the problem

#if defined(__AVR__ )
#include <avr/pgmspace.h>
#else
#include <pgmspace.h>
#endif

I then tried copying the pgmspace.h file into a folder called avr in the directory where it was looking for it and I got a new error as follows (I had to shorten it significantly to meet the character limit):

In file included from /Users/justinandrew/Library/Arduino15/packages/arduino/tools/CMSIS-Atmel/1.2.0/CMSIS/Device/ATMEL/samd21/include/samd21.h:69:0,
                 from /Users/justinandrew/Library/Arduino15/packages/arduino/tools/CMSIS-Atmel/1.2.0/CMSIS/Device/ATMEL/samd.h:105,
                 from /Users/justinandrew/Library/Arduino15/packages/arduino/hardware/samd/1.8.10/cores/arduino/Arduino.h:34,
                 from /Users/justinandrew/Documents/FreshAir/FA2/Arduino/FA2_ID_Retrieval_test2_20210107/FA2_ID_Retrieval_test2_20210107.ino:1:
/Users/justinandrew/Library/Arduino15/packages/arduino/tools/CMSIS-Atmel/1.2.0/CMSIS/Device/ATMEL/samd21/include/samd21g18a.h:226:0: warning: "LITTLE_ENDIAN" redefined
 #define LITTLE_ENDIAN          1
 
***this part what repeated many times but had to be delated because of character limit***

In file included from /Users/justinandrew/Documents/Arduino/libraries/SafeString/src/SafeStringReader.h:13:0,
                 from /Users/justinandrew/Documents/FreshAir/FA2/Arduino/FA2_ID_Retrieval_test2_20210107/FA2_ID_Retrieval_test2_20210107.ino:5:
/Users/justinandrew/Documents/Arduino/libraries/SafeString/src/SafeString.h:135:7: note: candidates are: class __FlashStringHelper
 class __FlashStringHelper;

       ^~~~~~~~~~~~~~~~~~~
In file included from /Users/justinandrew/Library/Arduino15/packages/arduino/hardware/samd/1.8.10/cores/arduino/api/IPAddress.h:24:0,
                 from /Users/justinandrew/Library/Arduino15/packages/arduino/hardware/samd/1.8.10/cores/arduino/api/ArduinoAPI.h:30,
                 from /Users/justinandrew/Library/Arduino15/packages/arduino/hardware/samd/1.8.10/cores/arduino/Arduino.h:23,
                 from /Users/justinandrew/Documents/FreshAir/FA2/Arduino/FA2_ID_Retrieval_test2_20210107/FA2_ID_Retrieval_test2_20210107.ino:1:
/Users/justinandrew/Library/Arduino15/packages/arduino/hardware/samd/1.8.10/cores/arduino/api/String.h:44:7: note:                 class arduino::__FlashStringHelper
 class __FlashStringHelper;
       ^~~~~~~~~~~~~~~~~~~
exit status 1
Error compiling for board Arduino MKR1000.

Any ideas on what this means or how to solve this problem?

Ahh, the joys of writing libraries for Arduino, Write once and check on every possible board.
Remove the changes you have made and try replacing the SafeString.h header file with this version.
I don't have an MKR1000 here so let me know if that works for your

SafeString.h (41.6 KB)

That fixed my issue! Thank you so much for your help!

Ok keep an eye out for SafeString V3.0.1 that will include that fix

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