Reading the first 3 characters of incoming string

Hi
I am new to Arduino and programming. I would like some help on a project.
what I want to do get the first 3 charterers of an incoming string.
eg:
data received through Rx is 123467890X
the data will typically be 11 digits long. and always end with an X.
all I want are the first 3 characters, (123)
while trawling through google I came across this code which prints all the data received.
how can this be modified, so I can only serial.print the first 3 characters.
Many thanks.

// zoomkat 8-6-10 serial I/O string test
// type a string in serial monitor. then send or enter
// for IDE 0019 and later

String readString;

void setup() {
      Serial.begin(9600);
        Serial.println("serial test 0021"); // so I can keep track of what is loaded
        }

void loop() {

        while (Serial.available()) {
        delay(10);  
          if (Serial.available() >0) {
        char c = Serial.read();
        readString += c;}
        }
        
      if (readString.length() >0) {
      Serial.println(readString);
      
      readString="";
      } 
   }

Gammon Forum : Electronics : Microprocessors : How to process incoming serial data without blocking will show you how to receive bytes from serial into a char array until an end of message byte is received. Once you have the chars in the array you can do what you need with them by reading them from the array.

Once you have the chars in the array you can do what you need with them by reading them from the array.

And, if all you are interested in is the first three characters, AFTER you receive the X, then put a NULL in the 4th element:

char serData[12];
byte index = 0;

   // Read and store the serial data in serData until the 'X' arrives, if there is room

    serData[3] = '\0';

    int serVal = atoi(serData);

If you send "132xxxyyyX", then serData should contain "132xxxyyy", when becomes "132" after the NULL is inserted. The atoi() call will convert "132" to 132, which is then stored in serVal.

I did this different in my recent project. Using the String class makes it easy.
While this is not the most efficient way of achieving this I was not coming anywhere near filling all the ram on my arduino uno.

First you need a global String

String readString;

this function will fill this string until no more characters are received

void serialRead() { 
  while (Serial.available()) {
  delay(10);  
  if (Serial.available() >0) {
    char c = Serial.read();
    readString += c;}
  }
}

then to get the first 3 characters i would do this

if (Serial.available() > 0) {
        readString = "";
        serialRead();
        String firstThree = readString.substring(0,3);
}

hope this helps

1 Like

Carlhacko's code compiled and produced results I wanted. now I could do some thing with the data. the first 3 characters are identifiers which I need to print on a thermal printer. but I do need to save the rest on an SD With a time stamp.I will try and and cobble a Sketch together and if I get stuck I know I can post here for more help as you guys are very helpful.
many Thanks to all of you for your replies,

String readString;
void setup() {
Serial.begin(9600);
Serial.println("Trial");
}
void serialRead() { 
  while (Serial.available()) {
  delay(10);  
  if (Serial.available() >0) {
    char c = Serial.read();
    readString += c;};
   }
}
void loop() {
if (Serial.available() > 0) {
        readString = "";
        serialRead();
        String firstThree = readString.substring(0,3);
        Serial.print(firstThree);
}
}

For heavens sake, make use of the fact that your serial input will always end in an X and read bytes from serial, put them into an array of chars until you get an X, then you know that your inbound message is complete and can deal with it.

I would be grateful if I can get more help because I have not made much progress . the date is being repeatedly printed and not much else is happening. How do I make the date print only once. and also how do I buffer data from serial and software serial before printing.
the project is to scan items using a barcode scanner enter the price and issue a receipt. the barcode scanner is connected to serial port and keypad and printer are connected via software serial. I am using a 3.5" tv as the display. the items can be identified by the first 3 digits of the barcode. I want to include the item names somewhere in the sketch and match and print them when the string starts with their number. I am very confused but hope this is making sense to you. T

//#include <TVout.h>
//#include <video_gen.h>

//ARDUINO 1.0 COMPATIBLE ONLY!
//ARDUINO 1.0 COMPATIBLE ONLY!
#include <Time.h>
#include <DS1307RTC.h>
#include <SoftwareSerial.h>
//#include <LiquidCrystal.h>
#include <Thermal.h>
#include <Wire.h>
//TVout TV;
int printer_RX_Pin = 3;
int printer_TX_Pin = 4;
int incomingByte = 0;
Thermal printer(printer_RX_Pin, printer_TX_Pin, 19200);

  String readString;    // a string to hold incoming data
//SoftwareSerial mySerial(10, 11);
void setup(){
//TV.begin(PAL,120,96);
 // TV.select_font(font6x8);
Serial.begin(9600);
 //mySerial.begin(9600);
   setSyncProvider(RTC.get);  
// if (timeStatus() != timeSet) 
    // Serial.println("Unable to sync with the RTC");
 // else
   //  Serial.println("RTC has set the system time"); 
//tv.print(scan item)  ???
//ITEM SCANNED GETS STORED INTO string.Readstring
//tv print (enter donation  Amount)
//INPUT FROM KEYPAD GETS STORED INTO  BUFFER1 (KEYPAD IS HOOKED UP TO SOFTWARE SERIAL PINS)
//THEN PRINTER PRINTS TITLE  (MAYBE BETTER TO WAIT FOR ALL INPUT BEFORE PRINTING)
printer.justify('C'); //sets text justification (right, left, center) accepts 'L', 'C', 'R'
 printer.setSize('L'); // set type size, accepts 'S', 'M', 'L'
  printer.println("School Feast "); //print line
  printer.setSize('M'); // set type size, accepts 'S', 'M', 'L'
  printer.println("My Stall"); //print line
  printer.println("My Town");
 printer.feed(); //advance one line
 printer.println(" My Country");
printer.feed(); //advance one line 
}
void serialRead() {
  
   while (Serial.available()) {
  delay(10);  
  if (Serial.available() >0) {
    char c = Serial.read();
    readString += c;};
   }
}
   void loop() {
     // THEN TIME GETS PRINTED 
    tmElements_t tm;
     
      if (RTC.read(tm)) {
    Serial.print(" ");
    print2digits(tm.Hour);
    Serial.write(':');
    print2digits(tm.Minute);
    Serial.write(':');
    print2digits(tm.Second);
    Serial.print("        ");
    Serial.print(tm.Day);
    Serial.write('/');
    Serial.print(tm.Month);
    Serial.write('/');
    Serial.print(tmYearToCalendar(tm.Year));
    Serial.println();
      printer.print(" ");
    
    print2digits(tm.Hour);
    printer.write(':');
    print2digits(tm.Minute);
    printer.write(':');
    print2digits(tm.Second);
    printer.print("        ");
    printer.print(tm.Day);
    printer.write('/');
    printer.print(tm.Month);
    printer.write('/');
    printer.print(tmYearToCalendar(tm.Year));
    printer.println();
  } else {
    if (RTC.chipPresent()) {
      Serial.println("The DS1307 is stopped.  Please run the SetTime");
      Serial.println("example to initialize the time and begin running.");
      Serial.println();
    } else {
      Serial.println("DS1307 read error!  Please check the circuitry.");
      Serial.println();
    }
    delay(9000);
  }
  delay(1000);
}

void print2digits(int number) {
  if (number >= 0 && number < 10) {
    Serial.write('0');
  }
  Serial.print(number);
if (Serial.available() > 0) {
        readString = "";
        serialRead();
        String Item = readString.substring(0,3);
//THEN ITEM PRINT( IDENTIFY ITEM BY FIRST 3 CHARACTERS OF STRING, HOW??)
        Serial.print(Item);
        printer.print(Item);
  Serial.println();{
//THEN PRINT DONATION AMOUNT(INPUT FROM SOFTWARE SERIAL)
//printer.print(software.serial buffer)
//printer. print("GBP"); 
//clear display
//tv.clear

}


}

}

what I want to do get the first 3 charterers of an incoming string.

Some simple code that might be of use.

//zoomkat 3-5-12 simple delimited 'X' string  
//from serial port input (via serial monitor)
//and print result out serial port

String readString;

void setup() {
  Serial.begin(9600);
  Serial.println("serial delimit test 1.0"); // so I can keep track of what is loaded
}

void loop() {

  //expect a string like 123467890X  

  if (Serial.available())  {
    char c = Serial.read();  //gets one byte from serial buffer
    if (c == 'X') {
      //do stuff
      Serial.println(readString); //prints captured string to serial port out     
      readString = readString.substring(0, 3); //get the first three characters
      Serial.print("First three characters are: ");
      Serial.println(readString); 
      readString=""; //clears variable for new input      
    }  
    else {     
      readString += c; //makes the string readString
    }
  }
}

I want to include the item names somewhere in the sketch and match and print them when the string starts with their number

I suspect that this requirement is going to stretch/exceed the available memory of most Arduinos unless the number of item names to be stored is very small. How many do you envisage storing and of what length?

Yes That is why I decided to go with the first 3 as opposed to reading the whole barcode.

cola will begin with 101- 300
chocobar with 301-500
muffin 501-700

A small set of strings like that will be OK. I assume that the first 3 characters indicate a category and the detail is in the rest of the barcode. You could, of course, save the whole barcode on an SD card or pass it to a PC for later analysis if you wanted to.

I am waiting on an openlog sd recorder. I could serial print barcode and time and it will get autologged.SparkFun OpenLog - DEV-13712 - SparkFun Electronics
when I open the serial monitor all I am getting is the time being printed over and over again. how do I stop this loop and print time only once per transaction. even though It is not practical, I want to assume there will be only one item per receipt. As I am not yet sure how to add multiple items.
basically the completed sketch should do
1 prompt for barcode data from user
store bar code number data buffer1
prompt for donation amount
store amount in data buffer2
print address
print time date
compare data in buffer 1 to item list
print item
print amount from buffer2
print thanks for donation
back to prompt.

Thank you zoomkat and UkheliBob for your replies.

I have discovered that The barcode scanner terminates with carriage return every time an item is scanned. which makes things easier?.
I was able to print the 3 digits before I added the stuff to get time from the RTC

The carriage return terminator will make things easier. Look at the link I posted in reply #1. Once the input is in an array of chars you can process it as you want.

Yes, you can do the same with SoftwareSerial, but I don't understand what you mean by having both in the array. Remember that serial data is asynchronous and you cannot guarantee when, or even if it will arrive.

Thanks UkheliBob ,barcode serial data will arrive via serial port. followed by keypad data via software serial.
here is the sketch and I believe I have the serial data in the array. how do I proceed to process this data and extract the first 3 digits and compare to item list.

PaulS has provided some information but I am not sure as how to work that into my sketch?

//#include <TVout.h>
//#include <video_gen.h>

//ARDUINO 1.0 COMPATIBLE ONLY!
//ARDUINO 1.0 COMPATIBLE ONLY!
#include <Time.h>
#include <DS1307RTC.h>
#include <SoftwareSerial.h>
//#include <LiquidCrystal.h>
#include <Thermal.h>
#include <Wire.h>
//TVout TV;
int printer_RX_Pin = 3;
int printer_TX_Pin = 4;
int incomingByte = 0;
Thermal printer(printer_RX_Pin, printer_TX_Pin, 19200);
const unsigned int MAX_INPUT = 12;

void setup(){
//TV.begin(PAL,120,96);
 // TV.select_font(font6x8);
Serial.begin(9600);
 //mySerial.begin(9600);
   setSyncProvider(RTC.get);  
// if (timeStatus() != timeSet) 
    // Serial.println("Unable to sync with the RTC");
 // else
   //  Serial.println("RTC has set the system time"); 
//tv.print(scan item)  ???
//ITEM SCANNED GETS STORED INTO array
//tv print (enter donation  Amount)
//INPUT FROM KEYPAD GETS STORED INTO  BUFFER1 (KEYPAD IS HOOKED UP TO SOFTWARE SERIAL PINS)
//THEN PRINTER PRINTS TITLE  (MAYBE BETTER TO WAIT FOR ALL INPUT BEFORE PRINTING)
printer.justify('C'); //sets text justification (right, left, center) accepts 'L', 'C', 'R'
 printer.setSize('L'); // set type size, accepts 'S', 'M', 'L'
  printer.println("School Feast "); //print line
  printer.setSize('M'); // set type size, accepts 'S', 'M', 'L'
  printer.println("My Stall"); //print line
  printer.println("My Town");
 printer.feed(); //advance one line
 printer.println(" My Country");
printer.feed(); //advance one line 
tmElements_t tm;
     
      if (RTC.read(tm)) {
    Serial.print(" ");
    print2digits(tm.Hour);
    Serial.write(':');
    print2digits(tm.Minute);
    Serial.write(':');
    print2digits(tm.Second);
    Serial.print("        ");
    Serial.print(tm.Day);
    Serial.write('/');
    Serial.print(tm.Month);
    Serial.write('/');
    Serial.print(tmYearToCalendar(tm.Year));
    Serial.println();
      printer.print(" ");
    
    print2digits(tm.Hour);
    printer.write(':');
    print2digits(tm.Minute);
    printer.write(':');
    print2digits(tm.Second);
    printer.print("        ");
    printer.print(tm.Day);
    printer.write('/');
    printer.print(tm.Month);
    printer.write('/');
    printer.print(tmYearToCalendar(tm.Year));
    printer.println();
  } else {
    if (RTC.chipPresent()) {
      Serial.println("The DS1307 is stopped.  Please run the SetTime");
      Serial.println("example to initialize the time and begin running.");
      Serial.println();
    } else {
      Serial.println("DS1307 read error!  Please check the circuitry.");
      Serial.println();
    }
    delay(9000);
  }
  delay(1000);
}

void print2digits(int number) {
  if (number >= 0 && number < 10) {
    Serial.write('0');
  }
  Serial.print(number);
}
void process_data (const char * data)
{
  Serial.println (data);
   
   }
void processIncomingByte (const byte inByte)
 {
  static char input_line [MAX_INPUT];
  static unsigned int input_pos = 0;

  switch (inByte)
    {

    case '\r':   // end of text
      input_line [input_pos] = 0;  // terminating null byte
      
      // terminator reached! process input_line here ...
      process_data (input_line);
      
      // reset buffer for next time
      input_pos = 0;  
      break;
      default:
      // keep adding if not full ... allow for terminating null byte
      if (input_pos < (MAX_INPUT - 1))
        input_line [input_pos++] = inByte;
      break;

    }  // end of switch
   
  } // end o
   void loop() {
     // THEN TIME GETS PRINTED 
     // if serial data available, process it
  if (Serial.available () > 0)
    processIncomingByte (Serial.read ());

  Serial.println();{
//THEN PRINT DONATION AMOUNT(INPUT FROM SOFTWARE SERIAL)
//printer.print(software.serial buffer)
//printer. print("GBP"); 
//clear display
//tv.clear

}


}

A step in the right direction for you.

Assuming that the process_data() function prints the whole of the data string correctly, try putting '\0' in data[3] and print it again. What do you get ?

UKHeliBob:
A step in the right direction for you.

Assuming that the process_data() function prints the whole of the data string correctly, try putting '\0' in data[3] and print it again. What do you get ?

process_data() function is not printing anything . what am I missing

process_data() function is not printing anything . what am I missing

You are missing a string in data !

Add a serial print of inByte at the start of processIncomingByte. Are you getting any bytes to add to the string ? Print delimiters, such as "<" and ">" around the print of data in process_data. Does the program ever get to that function and is there anything between the delimiters ?

Hi
It does not look like I get as far as that function. sketch prints the time and does not go any further. the following section of the sketch seems to work.

//#include <TVout.h>
//#include <video_gen.h>

//ARDUINO 1.0 COMPATIBLE ONLY!
//ARDUINO 1.0 COMPATIBLE ONLY!
#include <Time.h>
#include <DS1307RTC.h>
#include <SoftwareSerial.h>
//#include <LiquidCrystal.h>
#include <Thermal.h>
#include <Wire.h>
//TVout TV;
int printer_RX_Pin = 3;
int printer_TX_Pin = 4;
int incomingByte = 0;
Thermal printer(printer_RX_Pin, printer_TX_Pin, 19200);
const unsigned int MAX_INPUT = 12;

void setup(){
//TV.begin(PAL,120,96);
 // TV.select_font(font6x8);
Serial.begin(9600);
 //mySerial.begin(9600);
   setSyncProvider(RTC.get);  
// if (timeStatus() != timeSet) 
    // Serial.println("Unable to sync with the RTC");
 // else
   //  Serial.println("RTC has set the system time"); 
//tv.print(scan item)  ???
//ITEM SCANNED GETS STORED INTO array
//tv print (enter donation  Amount)
//INPUT FROM KEYPAD GETS STORED INTO  BUFFER1 (KEYPAD IS HOOKED UP TO SOFTWARE SERIAL PINS)
//THEN PRINTER PRINTS TITLE  (MAYBE BETTER TO WAIT FOR ALL INPUT BEFORE PRINTING)
printer.justify('C'); //sets text justification (right, left, center) accepts 'L', 'C', 'R'
 printer.setSize('L'); // set type size, accepts 'S', 'M', 'L'
  printer.println("School Feast "); //print line
  printer.setSize('M'); // set type size, accepts 'S', 'M', 'L'
  printer.println("My Stall"); //print line
  printer.println("My Town");
 printer.feed(); //advance one line
 printer.println(" My Country");
printer.feed(); //advance one line 
tmElements_t tm;
     
      if (RTC.read(tm)) {
    Serial.print(" ");
    print2digits(tm.Hour);
    Serial.write(':');
    print2digits(tm.Minute);
    Serial.write(':');
    print2digits(tm.Second);
    Serial.print("        ");
    Serial.print(tm.Day);
    Serial.write('/');
    Serial.print(tm.Month);
    Serial.write('/');
    Serial.print(tmYearToCalendar(tm.Year));
    Serial.println();
      printer.print(" ");
    
    print2digits(tm.Hour);
    printer.write(':');
    print2digits(tm.Minute);
    printer.write(':');
    print2digits(tm.Second);
    printer.print("        ");
    printer.print(tm.Day);
    printer.write('/');
    printer.print(tm.Month);
    printer.write('/');
    printer.print(tmYearToCalendar(tm.Year));
    printer.println();
  } else {
    if (RTC.chipPresent()) {
      Serial.println("The DS1307 is stopped.  Please run the SetTime");
      Serial.println("example to initialize the time and begin running.");
      Serial.println();
    } else {
      Serial.println("DS1307 read error!  Please check the circuitry.");
      Serial.println();
    }
    delay(9000);
  }
  delay(1000);
}

void print2digits(int number) {
  if (number >= 0 && number < 10) {
    Serial.write('0');
  }
  Serial.print(number);

and the following does not

void process_data (const char * data)
{
  Serial.println (data);
   
   }
void processIncomingByte (const byte inByte)
 {
  static char input_line [MAX_INPUT];
  static unsigned int input_pos = 0;

  switch (inByte)
    {

    case '\r':   // end of text
      input_line [input_pos] = 0;  // terminating null byte
      
      // terminator reached! process input_line here ...
      process_data (input_line);
      
      // reset buffer for next time
      input_pos = 0;  
      break;
      default:
      // keep adding if not full ... allow for terminating null byte
      if (input_pos < (MAX_INPUT - 1))
        input_line [input_pos++] = inByte;
      break;

    }  // end of switch
   
  } // end o
   void loop() {
     // THEN TIME GETS PRINTED 
     // if serial data available, process it
  if (Serial.available () > 0)
    processIncomingByte (Serial.read ());
Serial.print(inByte);
  Serial.println();{
//THEN PRINT DONATION AMOUNT(INPUT FROM SOFTWARE SERIAL)
//printer.print(software.serial buffer)
//printer. print("GBP"); 
//clear display
//tv.clear