Can not add line feed to string - arduino

I have an Arduino Leonardo and trying to use it as a serial to USB converter. On Serial1 I have a string ending on a number. This number I'm trying to get via USB to the PC. It works very fine but I need a '\n' at the end and I don't know how. When I try it in the line Keyboard.println or Keyboard.write, I get a various number of lines with the expected number in splitted.
#include <Keyboard.h>
String myEAN ="";
const int myPuffergrosse = 50;
char serialBuffer[myPuffergrosse];
void setup() {
Keyboard.begin();
Serial1.begin(9600);
delay(1000);
}
String getEAN (char *stringWithInt)
// returns a number from the string (positive numbers only!)
{
char *tail;
// skip non-digits
while ((!isdigit (*stringWithInt))&&(*stringWithInt!=0)) stringWithInt++;
return(stringWithInt);
}
void loop() {
// Puffer mit Nullbytes fuellen und dadurch loeschen
memset(serialBuffer,0,sizeof(myPuffergrosse));
if ( Serial1.available() ) {
int incount = 0;
while (Serial1.available()) {
serialBuffer[incount++] = Serial1.read();
}
serialBuffer[incount] = '\0'; // puts an end on the string
myEAN=getEAN(serialBuffer);
//Keyboard.write(0x0d); // that's a CR
//Keyboard.write(0x0a); // that's a LF
}
}

Since myEAN is a String, simply add the character...
myEAN += '\n';
Or, for a full carriage return/line feed combination:
myEAN += "\r\n";
See the doc: https://www.arduino.cc/en/Tutorial/StringAppendOperator
I suggest you use String in your getEAN function as well...
String getEAN(String s)
{
// returns the first positive integer found in the string.
int first, last;
for (first = 0; first < s.length(); ++first)
{
if ('0' <= s[first] && s[first] <= '9')
break;
}
if (first >= s.length())
return "";
// remove trailing non-numeric chars.
for (last = first + 1; last < s.length(); ++last)
{
if (s[last] < '0' || '9' < s[last])
break;
}
return s.substring(first, last - 1);
}

Related

Arduino for loop not running

What I am trying to do is to convert a string from the serial input into individual words by detecting spaces between the words:
String input;
char split[]{};
String output;
String product;
int inputSize;
void setup() {
Serial.begin(9600);
Serial.println("ready");
}
void loop() {
if (Serial.available() > 0) {
input = Serial.readString();
input.toCharArray(split, 8);
inputSize = sizeof(input);
for (int i = 0; i < inputSize; i++){
if (isSpace(split[i])) {
product = output;
output = "";
Serial.println(product);
}else{
output = output + split[i];
}
}
}
}
I am trying to do is to convert a string from the serial input into
individual words by detecting spaces between the words it should
print all words sent to the serial monitor separated into different
strings.
However sometimes it sends one word from the input string and
sometimes it doesn't send and it piles up and sends multiple words
without spaces at once
Use the following code, you will get the string split into the words
String output;
void setup() {
Serial.begin(9600);
Serial.println("ready");
}
void loop() {
if (Serial.available() > 0) {
char input = Serial.read();
if((input == ' ')){
Serial.println(output);
output = "";
}else
output+=input;
}
}

Reading multiple lines from serial

I'm trying to get up to 64 lines of max 16 characters to display on an LCD screen via serial. These lines have to be given during startup. I've got the following, which works in most cases:
unsigned char textMatrix[64][17];
unsigned char lineCount = 0;
void readLines(){
Serial.println("Send up to 64 lines of up to 16 characters. Send an empty line to stop sending lines. Make sure to use \\n (newline) as line terminator!");
Serial.setTimeout(10000);
bool receiving = true;
while (receiving){
if(Serial.available() > 0) {
textMatrix[lineCount][0] = '\0';
char res = Serial.readBytesUntil('\n',textMatrix[lineCount],16);
if (res == 0){
if (textMatrix[lineCount][0] != '\0'){
continue;
}
Serial.println("Received empty line");
receiving = false;
break;
}
textMatrix[lineCount][16] = '\0';
Serial.print("Received line: ");
Serial.println((const char*)textMatrix[lineCount]);
lineCount++;
if (lineCount >= 63){
receiving = false;
}
}
}
}
The problem occurs when I send the following line:
Okay, that's one
This line is exactly 16 characters long. I'm assuming that this causes readBytesUntil to trigger twice, causing it to be the same as pressing enter twice. I don't seem to be able to find a difference between seriously sending an empty line or sending a line of exactly 16 characters. What would be the best way to resolve this?
When you send the line
Okay, that's one
That's not 16 character but 17, because there is \n character in the end. What Serial.readBytesUntil('\n',textMatrix[lineCount],16); does in this case is it takes out first 16 characters out of the buffer. After that operation, the only thing left there, is the new line \n, which in the next iteration of the loop is read as an empty line.
To counter that, you can check res variable, and if you see that it equals 16, discard the next read. Or do some more checks in case there is a string longer than 16 + new line.
Here's one way... just read the chars yourself:
unsigned char textMatrix[64][17];
const uint8_t MAX_WIDTH = sizeof( textMatrix[0] );
const uint8_t MAX_LINES = sizeof( textMatrix ) / MAX_WIDTH;
unsigned char lineCount = 0;
void readLines(){
uint32_t startTime = millis();
uint8_t column = 0;
do {
if (Serial.available()) {
char c = Serial.read();
if (c == '\n') {
if ((lineCount >= MAX_LINES) || (column == 0))
break; // too many lines or empty line
textMatrix[ lineCount ] [ column ] = '\0'; // NUL-terminate
lineCount++; // start accumulating a new line
column = 0;
} else if (column < MAX_WIDTH-1) {
// room for another char on this line
textMatrix[ lineCount ] [ column ] = c;
column++;
} // else
// ignore rest of line
}
} while (millis() - startTime < 10000UL); // TIMEOUT == 10s
} // readLines

ARDUINO UNO+SIM808(GPS/GSM) SYNCHRONISATION

I started a project quite recently were I intend to combine the arduino uno and the sim808 module which has gps/gsm/gprs all together in one.
Using just the gps functionality works fine, just the gsm both receiving and sending messages also works good. but combining them for what i intend makes the entire system falls apart.
I intend to be able to have some coordinates registered let's say position A position B and position c, and the system i intend to design is put on a moving, let's say car, now anyone on either of the positions will send a message with the alphabet denoting the position to a number lets say "A TO +23*******98 , AND WOULD get a reply of the cars current time from that position.
With all parts combined the program would sometimes not even indicate receiving any message or even if it did the gps part won't even work.
Is there something I am doing wrong or is it not just feasible with what the components I am using pls help as I am very confused right now.
`#include <SoftwareSerial.h>
SoftwareSerial GPRS(7, 8); // RX, TX
String BUSNUM="A"; // THIS SIM IS TO BE INSTALLED ON BUS A
static String sendersnumber;
char* key;
char MESSAGE[280];
String latitude;
String longitude;
String Speed;
enum _parseState
{
PS_DETECT_MSG_TYPE,
PS_IGNORING_COMMAND_ECHO,
PS_READ_CMTI_STORAGE_TYPE,
PS_READ_CMTI_ID,
PS_DETECT_MSG_TYPE2,
PS_IGNORING_COMMAND_ECHO2,
PS_READ_CMGR_STATUS2,
PS_READ_CMGR_CONTENT2,
PS_READ_CMGR_DATE2,
PS_READ_CMGR_STATUS,
PS_READ_CMGR_NUMBER2,
PS_READ_CMGR_NUMBER,
PS_READ_CMGR_SOMETHING,
PS_READ_CMGR_DATE,
PS_READ_CMGR_CONTENT,
PS_READ_VIDEO_CONTENT,
PS_READ_VIDEO2_CONTENT,
PS_READ_CMGR_SOMETHING2,
PS_READ_VIDEO_CONTENT2,
};
byte state = PS_DETECT_MSG_TYPE; // KEEP TRACK OF WHAT STATE WE ARE IN RIGHT NOW
char buffer[100]; // WHAT WE ARE READING INTO
byte pos = 0; //WHAT POSITION WE ARE AT IN THAT BUFFER
int lastReceivedSMSId = 0; // LAST RECIEVED SMS ID
boolean validSender = false; //SOO NOT JUST ANYONE HAS ACESS TO SEND A COMMAND
void resetBuffer()
{
memset(buffer, 0, sizeof(buffer));
pos = 0;
}//BASICALLY TO RESET THE BUFFER
void setup()
{
GPRS.begin(9600);
Serial.begin(9600);
GPRS.println("AT+CGNSPWR=1");
delay(290);
GPRS.println("AT+CGNSURC=0");
delay(300);
GPRS.println("AT");
delay(300);
GPRS.println("AT+CMGF=1"); // INITIALIZE SMS
delay(300);
for (int i = 1; i <= 15; i++)
{
GPRS.print("AT+CMGD=");
GPRS.println(i);
delay(300);
// Not really necessary but prevents the serial monitor from dropping any input SINCE WE KNOW LIMIT TO STORE IS 15, THIS JUST DELETES IT CLEARS IT
while(GPRS.available())
Serial.write(GPRS.read());
}
delay(2000);
GPRS.println("AT+CGNSURC=1");
}
void loop()
{
while(GPRS.available()) //ONLY WHEN THERE IS SOMETHING AVAILABLE,
{
GSM_NUM1(GPRS.read());
//delay(50);
GPRS.println("AT+CGNSINF");
// delay(40);
GPSAnalyzer(GPRS.read());
sendSMS();
}
}
// END OF VOID LOOP
void GSM_NUM1(byte b)
{
buffer[pos++] = b;
if ( pos >= sizeof(buffer) )
resetBuffer(); // just to be safe
switch (state)
{
case PS_DETECT_MSG_TYPE:
{
if ( b == '\n' )
resetBuffer();
else {
if ( pos == 3 && strcmp(buffer, "AT+") == 0 ) {
state = PS_IGNORING_COMMAND_ECHO;
}
else if ( pos == 6 ) {
//Serial.print("Checking message type: ");
//Serial.println(buffer);
if ( strcmp(buffer, "+CMTI:") == 0 ) {
Serial.println("Received CMTI");
state = PS_READ_CMTI_STORAGE_TYPE;
}
else if ( strcmp(buffer, "+CMGR:") == 0 ) {
Serial.println("Received CMGR");
state = PS_READ_CMGR_STATUS;
}
resetBuffer();
}
}
}
break;
case PS_IGNORING_COMMAND_ECHO:
{
if ( b == '\n' ) {
//Serial.print("Ignoring echo: ");
//Serial.println(buffer);
state = PS_DETECT_MSG_TYPE;
resetBuffer();
}
}
break;
case PS_READ_CMTI_STORAGE_TYPE:
{
if ( b == ',' ) {
Serial.print("SMS storage is ");
Serial.println(buffer);
state = PS_READ_CMTI_ID;
resetBuffer();
}
}
break;
case PS_READ_CMTI_ID:
{
if ( b == '\n' ) {
lastReceivedSMSId = atoi(buffer);
Serial.print("SMS id is ");
Serial.println(lastReceivedSMSId);
GPRS.print("AT+CMGR=");
GPRS.println(lastReceivedSMSId);
//delay(500); don't do this!
state = PS_DETECT_MSG_TYPE;
resetBuffer();
}
}
break;
case PS_READ_CMGR_STATUS:
{
if ( b == ',' ) {
Serial.print("CMGR status: ");
Serial.println(buffer);
state = PS_READ_CMGR_NUMBER;
resetBuffer();
}
}
break;
case PS_READ_CMGR_NUMBER:
{
if ( b == ',' ) {
Serial.print("CMGR MSSG SENDERS Number: ");
Serial.println(buffer);
String sendersnumber=buffer;
// Uncomment these two lines to check the sender's cell number
//validSender = false;
//if ( strcmp(buffer, "\"+0123456789\",") == 0 )
validSender = true;
state = PS_READ_CMGR_SOMETHING;
resetBuffer();
}
}
break;
case PS_READ_CMGR_SOMETHING:
{
if ( b == ',' ) {
Serial.print("CMGR something A.K.A SENDER'S NAME: ");
Serial.println(buffer);
state = PS_READ_CMGR_DATE;
resetBuffer();
}
}
break;
case PS_READ_CMGR_DATE:
{
if ( b == '\n' ) {
Serial.print("CMGR date: ");
Serial.println(buffer);
state = PS_READ_CMGR_CONTENT;
resetBuffer();
}
}
break;
case PS_READ_CMGR_CONTENT:
{
if ( b == '\n' ) {
Serial.print("CMGR MESSAGE Content: ");
Serial.print(buffer);
String key=buffer;
// sendSMS();
// GPSAnalyzer();
GPRS.print("AT+CMGD=");
GPRS.println(lastReceivedSMSId);
//delay(500); don't do this!
state = PS_DETECT_MSG_TYPE;
resetBuffer();
}
}
break;
}
}
void GPSAnalyzer(byte b)
{
buffer[pos++] = b;
if ( pos >= sizeof(buffer) )
resetBuffer();// just to be safe
switch (state)
{
case PS_DETECT_MSG_TYPE2:
{
if ( b == '\n' )
resetBuffer();
else {
if ( pos == 9 ) {
// Serial.print("Checking message type: ");
// Serial.println(buffer);
if ( strcmp(buffer, "+UGNSINF:") == 0 ) {
Serial.println("Received CGNSINF:");
state = PS_READ_CMGR_STATUS2;
}
resetBuffer();
}
}
}
break;
//CHECK
case PS_IGNORING_COMMAND_ECHO2:
{
if ( b == '\n' ) {
//Serial.print("Ignoring echo: ");
//Serial.println(buffer);
state = PS_DETECT_MSG_TYPE2;
resetBuffer();
}
}
break;
//THIS WOULD READ FROM +CGNSINF: (TO THE COMMA),
case PS_READ_CMGR_STATUS2:
{
if ( b == ',' ) {
Serial.print("RUN STATUS: ");
Serial.println(buffer);
String runstatus=buffer;
state = PS_READ_CMGR_NUMBER2;
resetBuffer();
}
}
break;
case PS_READ_CMGR_NUMBER2:
{
if ( b == ',' ) {
Serial.print("FIX STATUS : ");
Serial.println(buffer);
String fixstatus=buffer;
fixstatus.replace(","," ");
validSender = true;
state = PS_READ_CMGR_SOMETHING2;
resetBuffer();
}
}
break;
// this is DATE AND TIME i dont need this
case PS_READ_CMGR_SOMETHING2:
{
if ( b == ',' ) {
Serial.print("DATE AND TIME : ");
Serial.println(buffer);
String dateandtime=buffer;
state = PS_READ_CMGR_DATE2;
resetBuffer();
}
}
break;
case PS_READ_CMGR_DATE2:
{
if ( b == ',' ) {
Serial.print("LATITUDE: ");
Serial.println(buffer);
latitude=buffer;
latitude.replace(","," ");
state = PS_READ_CMGR_CONTENT2;
resetBuffer();
}
}
break;
case PS_READ_CMGR_CONTENT2:
{
if ( b == ',' ) {
Serial.print("LONGITUDE: ");
Serial.println(buffer);
longitude=buffer;
longitude.replace(","," ");
state = PS_READ_VIDEO_CONTENT2;
resetBuffer();
//delay(500); don't do this!
}
}
break;
case PS_READ_VIDEO_CONTENT2:
{
if ( b == ',' ) {
Serial.print("ALTITUDE: ");
Serial.println(buffer);
String Altitude=buffer;
state = PS_READ_VIDEO2_CONTENT;
resetBuffer();
//delay(500); don't do this!
}
}
break;
case PS_READ_VIDEO2_CONTENT:
{
if ( b == ',' ) {
Serial.print("SPEED(KM/HR): ");
Serial.println(buffer);
String Speed=buffer;
Speed.replace(","," ");
state =PS_DETECT_MSG_TYPE2;
resetBuffer();
}
}
break;
//use goto to put it at sms begining
}
}
void sendSMS()
{
if ( strcmp(key,"A") == 0 )
{
float lati=7.200970;
float longi=5.181782;
float Speed1 = atof(Speed.c_str());
float latituded = atof(latitude.c_str());
float longituded = atof(longitude.c_str());
float Distance = HaverSine(lati,longi,latituded,longituded);
float duration=Distance/Speed1;
const int StrLen = 10;
char * duration_new ;
double Value = duration;
(void) dtostrf (Value, StrLen, 6, duration_new);
String MESSAGE="BUS A";
MESSAGE+=duration_new ;
Serial.print("THE MESSAGE SENT IS ");
Serial.println(MESSAGE);
}
else if ( strcmp(key,"B") == 0 )
{
float lati=7.290970;
float longi=5.141782;
float Speed1 = atof(Speed.c_str());
float latituded = atof(latitude.c_str());
float longituded = atof(longitude.c_str());
float Distance = HaverSine(lati,longi,latituded,longituded);
float duration=Distance/Speed1;
const int StrLen = 10;
char * duration_new ;
double Value = duration;
(void) dtostrf (Value, StrLen, 6, duration_new);
String MESSAGE="BUS B";
MESSAGE+=duration_new ;
Serial.print("THE MESSAGE SENT IS ");
Serial.println(MESSAGE);
}
delay(300);
GPRS.print("AT+CMGF=1\r\n");
delay(100);
GPRS.println("AT+CMGS=\""+sendersnumber+"\"\r\n");
delay(100);
GPRS.println(MESSAGE);
delay(100);
GPRS.println((char)26);
delay(100);
GPRS.println();
delay(100);
}
float HaverSine(float lat1,float lon1,float lat2,float lon2)
{
String fixstatus;
float ToRad = PI / 180.0;
float R = 6371; // radius earth in Km
float dLat = (lat2-lat1) * ToRad;
float dLon = (lon2-lon1) * ToRad;
float a = sin(dLat/2) * sin(dLat/2) +
cos(lat1 * ToRad) * cos(lat2 * ToRad) *
sin(dLon/2) * sin(dLon/2);
String o= fixstatus + "8";
float c = 2 * atan2(sqrt(a), sqrt(1-a));
float d = R * c;
return d;
}
EXPLANATION After all declarations and initializations the first active part of the entire code is the for loop that just deletes all former messages from the sim card memory.it runs 15 times
for (int i = 1; i <= 15; i++) { GPRS.print("AT+CMGD="); GPRS.println(i); delay(300); while(GPRS.available()) Serial.write(GPRS.read()); }
Now, having functions GSM_NUM1(); GPSAnalyzer(); sendSMS(); Which are defined below in the code
GSM_NUM1(); GPSAnalyzer(); both work similarly they extract needed data which come in separated by commas. For the gps which comes in , in the form
+UGNSINF: ,,,,, ,,, ,,,,,,, ,,,,
lathitude, speed and any other important parameter is extracted.
For GSM_NUM1(); it gets the senders message and number into variable.
sendSMS(); this just does some calculation based on the message received and send a certain result to the number who requested it.
OBERVATIONS
When the program starts nothing happens which is good cause nothing is supposed to until something new comes in. Hence the void loop() { while(GPRS.available()) //ONLY WHEN THERE IS SOMETHING AVAILABLE, { GSM_NUM1(GPRS.read());
//delay(50); GPRS.println("AT+CGNSINF"); // delay(40);
GPSAnalyzer(GPRS.read()); sendSMS(); } Now this is were things go bad, as the first function works good, it waits gets the message and extracts the senders number and message"key" into variables but immediately after that I wantjust one return of the gps info shown below that's why I used ("AT+CGNSINF"); instead of ("AT+CGNSURC=1"); as the later gives continuous gps data such as
+UGNSINF: ,,,,, ,,, ,,,,,,, ,,,,
BUT instead of one line of the gps data to be gotten from were lathitude and some other parameters are extracted into variables "THE PROGRAM HANGS/STOPS for some unknown reason.
SUSPICIONS
Since the SIM808 possess gps/gsm on the same module. It makes it kind of tricky to separate them in the sense that.
IF I WANT THE GPS TO BE ON BUT NOT READ IN ANY DATA UNTIL A VALID REQUEST COMES IN , IN FORM OF AN SMS THEN THE NECESSARY GPS INFORMATION IS PARSED AND SOME CALCULATIONS ARE DONE TO GET A PARAMETER THAT WOULD BE SENT TO THE SAME NUMBER THAT REQUESTED IT.
PERSONNALY, I FEEL THAT GETTING THE GPS AND GSM TO WORK HAND IN HAND WITHOUT CANCELLING EACH OTHER OUT IN SOME WAY,SUCESSFULLY WOULD BE THE END OF MY PROBLEM. AND I THINK IT COMES DOWN TO THE POSITION OF THE AT COMMAND
GPRS.println("AT+CGNSURC=1"); AND/OR GPRS.println("AT+CGNSINF"); AS the former spits out the gps data every GNSS FIX continuously when called once and LATER spits it out just once per one command.
the attached picture just shows the continous nature of the output of ("AT+CGNSURC=1"); , just as ("AT+CGNSINF"); spits out just one line with +CGNSINF: at the begining instead
Please check that is not in overflow SRAM , that produces stranger things when you execute the program. This occur when you declare so much variables, you can use this library to check the use of sram.
I ran into this similar issue with trying to get GPS data from a module over serial but figured it out after painstaking hours. Essentially you need to validate every response from every command and flush the serial port before every write.
Flushing the serial port buffer before you write any command will ensure that you don't accidentally read left over characters from a previous command when you are trying to get the output of the one you just ran. Most TAs (Terminal Adapters) use EOL characters like OK which translates into "\r\nOK\r\n". If you do not read them all, they can hang around and interfere with the next command you send/ read a response from.
use GPRS.flush() to get rid of extra garbage characters in the serial buffer before sending commands.
Also, creating a generic command function to pass all AT commands and validate their output will save you a lot of sleep.
something like
int sendCommand(int fd, char* message, char* eol, char* response){
int wlen, rlen;
char buf[1024];
tcflush(fd, TCIOFLUSH); //flush the serial port to remove anything left over
wlen = write(fd, message, strlen(message)); //write command to terminal
tcdrain(fd); //delay until 1st readable character is written by modem
delay(100); //delay a little longer until all characters are written(hopefully)
rdlen = read(fd, buf, sizeof(buf) - 1); //read from serial port
if(rdlen > 0){ //if readable characters
if(strstr(buf, eol) != NULL){ //if my end of line character is present then
int i = 0; //output from TA is complete
while(buf[i] != '\0'){ //while buffer has more characters
response[i] = buf[i]; //copy string into the string I passed, char by char
}
return 1; //return 1 (i.e.true aka success)
}
}
return 0; //return 0 (i.e. false aka failure)
}
I wrote this for a communicating to a simcom5320 but I didnt use software serial so it'll be a little different for you. Use this function for all your at commands to ensure everything actually succeed like:
char commandReply[512];
if(sendCommand(myFileDescriptor, "AT+CGNSINF\r", "\r\nOK\r\n", commandReply)){
//do something with commandReply or not
} else {
//command failed
//do something else
}
Hope this helps!

Arduino 1 not reading correctly the string from Serial Monitor

I am having a problem with the serial monitor on Arduino Uno.
Basically I want to write some commands on the Serial Monitor, read the string and according to the string do something.
The problem is the following: supposing I type the command 'read 4' in the Serial Monitor, sometimes the string is read correctly, sometimes it is read like: 'ead 4', missing the first character.
I even put a delay between two readings from the Serial Monitor. Does anyone have an explanation?
For completeness I post my code (basically it reads/writes from/to the EEPROM: for example 'read 5' will read the 5 block of EEPROM, 'write 4 5' will write the value 5 to the 4th block of memory).
#define MAX_STRING_LENGTH 14
#include <ctype.h>
#include <EEPROM.h>
//The function initializes the string to spaces
void initString(char* mystr, char strLength);
//The function returns true if it is a read operation, false otherwise
boolean isReadEEPROM(char *myStr, char strLength);
//The function returns true if it is a write operation, false otherwise
boolean isWriteEEPROM(char *myStr, char strLength);
//The function returns the EEPROM address from the string
unsigned int findAddress(char *myStr, char strLength);
char findValue(char *myStr, char strLength);
//Check the address range
boolean isAddressOk(unsigned int address);
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
}
void loop() {
char pos = 0;
bool newDataFound = false;
char serialStr[MAX_STRING_LENGTH];
unsigned int address = 0;
char val = 0;
while(Serial.available()){
val = Serial.read();
}
val = 0;
initString(&serialStr[0], (char) MAX_STRING_LENGTH);
while(Serial.available() && pos < MAX_STRING_LENGTH){
serialStr[pos] = Serial.read();
pos ++;
newDataFound = true;
delay(200);
}
if (newDataFound){
Serial.print("New Command found: ");
Serial.println(serialStr);
address = 0;
address = findAddress(&serialStr[0], MAX_STRING_LENGTH);
if (isReadEEPROM(&serialStr[0], MAX_STRING_LENGTH) && isAddressOk(address)){
Serial.println("Reading from EEPROM");
Serial.print("Address is ");
Serial.println(address);
val = EEPROM.read(address);
Serial.print("Value is: ");
Serial.println( (uint8_t) val );
Serial.println(" ");
}
else if (isWriteEEPROM(&serialStr[0], MAX_STRING_LENGTH) && isAddressOk(address)){
Serial.println("Writing to EEPROM");
Serial.print("Address is ");
Serial.println(address);
Serial.println(" ");
val = findValue(&serialStr[0], MAX_STRING_LENGTH);
EEPROM.write(address, val);
}
else{
if (!isAddressOk(address)){
Serial.write(address);
Serial.println("Address out of range");
Serial.println("");
}
Serial.println("Not recognized operation\n");
}
delay(2000);
}
}
void initString(char* mystr, char strLength){
for(char ii=0; ii<strLength; ii++){
(*mystr) = ' ';
mystr++;
}
}
//The function returns true if it is a read operation, false otherwise
boolean isReadEEPROM(char *myStr, char strLength){
//The string should contain first the 'read' operation
char expected[] = "read";
int ii =0;
while (ii<4){
if ( *(myStr + ii) != expected[ii]){
return false;
Serial.println("Not a Read Operation\n");
}
ii++;
}
return true;
Serial.println("Read Operation");
}
//The function returns true if it is a write operation, false otherwise
boolean isWriteEEPROM(char *myStr, char strLength){
//The string should contain first the 'read' operation
char expected[] = "write";
int ii =0;
while (ii<5){
if ( *(myStr + ii) != expected[ii]){
return false;
}
ii++;
}
return true;
}
//The function returns the EEPROM address from the string
unsigned int findAddress(char *myStr, char strLength){
unsigned int address;
char tmpStr[strLength];
char strAddress[] = " ";
int ii = 0;
while(ii< strLength){
tmpStr[ii] = *(myStr+ii);
ii++;
}
Serial.print("The address found is: ");
Serial.println(strAddress);
ii= 0;
if (isReadEEPROM(myStr, strLength)){
while (ii<=4){
if (isdigit(*(myStr + 5 + ii))){
strAddress[ii] = *(myStr + 5 + ii);
}
else{
break;
}
ii++;
}
address = atoi(strAddress);
}
else if(isWriteEEPROM(myStr, strLength)){
while (ii<=4){
if (isdigit(*(myStr + 6 + ii))){
strAddress[ii] = *(myStr + 6 + ii);
}
else{
break;
}
ii++;
}
address = atoi(strAddress);
}
else{
address = 0;
//Serial.println("Address not available in function 'findAddress'");
}
return address;
}
//The function returns the value to be written to the EEPROM from the string
char findValue(char *myStr, char strLength){
char val;
char tmpStr[strLength];
char strVal[] = " ";
int ii, idx = 0;
while(ii< strLength){
tmpStr[ii] = *(myStr+ii);
ii++;
}
ii= 0;
// first found the first digits corresponding to the address
while (ii<=4){
if (isdigit(*(myStr + 6 + ii))){
;//strAddress[ii] = *(myStr + 6 + ii);
}
else{
ii++;
break;
}
ii++;
}
// now find the value
while (ii<=4+3){
Serial.println(*(myStr + 6 + ii));
if (isdigit(*(myStr + 6 + ii))){
strVal[idx] = *(myStr + 6 + ii);
}
else{
break;
}
ii++;
idx++;
}
Serial.print("original string: ");
Serial.println(tmpStr);
Serial.print("Value found: ");
Serial.println(strVal);
val = (char)atoi(strVal);
return val;
}
boolean isAddressOk(unsigned int address){
if (address < 1024 && address >= 0){
return true;
}
else{
return false;
}
}
This snippet:
char val=0;
while(Serial.available()){
val = Serial.read();
}
val = 0;
Is just consuming any characters that may be left in the input buffer. You could also do:
while (Serial.avaialble())
Serial.read();
The next while loop does not wait for the entire command. Sometimes, it gets the 'r', and then doesn't get the 'ead...' in time. They will be there the next time loop executes, so it looks like the 'r' is missing. It was just consumed in the previous loop.
Things sent over the USB (from the Serial Monitor window) can have odd delays in them.
To gather up a complete line, you should save characters until a '\n' is received:
for (;;) {
if (Serial.available()) {
char c = Serial.read();
if (c == '\n')
break;
if (pos < MAX_LINE_LENGTH) {
serialStr[pos] = c;
pos ++;
}
newDataFound = true;
}
}
The delay call is totally unnecessary, because the for loop waits until a '\n' character is received (be sure that in the Serial Monitor pull down menu either 'New Line' or 'both NL & CR' is selected). Then you know you've read all the characters in the line.

Convert serial.read() into a usable string using Arduino

I'm using two Arduinos to sent plain text strings to each other using NewSoftSerial and an RF transceiver.
Each string is perhaps 20-30 characters in length. How do I convert Serial.read() into a string so I can do if x == "testing statements", etc.?
Unlimited string readed:
String content = "";
char character;
while(Serial.available()) {
character = Serial.read();
content.concat(character);
}
if (content != "") {
Serial.println(content);
}
From Help with Serial.Read() getting string:
char inData[20]; // Allocate some space for the string
char inChar = -1; // Where to store the character read
byte index = 0; // Index into array; where to store the character
void setup() {
Serial.begin(9600);
Serial.write("Power On");
}
char Comp(char* This) {
while (Serial.available() > 0) // Don't read unless there
// you know there is data
{
if(index < 19) // One less than the size of the array
{
inChar = Serial.read(); // Read a character
inData[index] = inChar; // Store it
index++; // Increment where to write next
inData[index] = '\0'; // Null terminate the string
}
}
if (strcmp(inData, This) == 0) {
for (int i=0; i<19; i++) {
inData[i] = 0;
}
index = 0;
return(0);
}
else {
return(1);
}
}
void loop()
{
if (Comp("m1 on") == 0) {
Serial.write("Motor 1 -> Online\n");
}
if (Comp("m1 off") == 0) {
Serial.write("Motor 1 -> Offline\n");
}
}
You can use Serial.readString() and Serial.readStringUntil() to parse strings from Serial on the Arduino.
You can also use Serial.parseInt() to read integer values from serial.
int x;
String str;
void loop()
{
if(Serial.available() > 0)
{
str = Serial.readStringUntil('\n');
x = Serial.parseInt();
}
}
The value to send over serial would be my string\n5 and the result would be str = "my string" and x = 5
I was asking the same question myself and after some research I found something like that.
It works like a charm for me. I use it to remote control my Arduino.
// Buffer to store incoming commands from serial port
String inData;
void setup() {
Serial.begin(9600);
Serial.println("Serial conection started, waiting for instructions...");
}
void loop() {
while (Serial.available() > 0)
{
char recieved = Serial.read();
inData += recieved;
// Process message when new line character is recieved
if (recieved == '\n')
{
Serial.print("Arduino Received: ");
Serial.print(inData);
// You can put some if and else here to process the message juste like that:
if(inData == "+++\n"){ // DON'T forget to add "\n" at the end of the string.
Serial.println("OK. Press h for help.");
}
inData = ""; // Clear recieved buffer
}
}
}
This would be way easier:
char data [21];
int number_of_bytes_received;
if(Serial.available() > 0)
{
number_of_bytes_received = Serial.readBytesUntil (13,data,20); // read bytes (max. 20) from buffer, untill <CR> (13). store bytes in data. count the bytes recieved.
data[number_of_bytes_received] = 0; // add a 0 terminator to the char array
}
bool result = strcmp (data, "whatever");
// strcmp returns 0; if inputs match.
// http://en.cppreference.com/w/c/string/byte/strcmp
if (result == 0)
{
Serial.println("data matches whatever");
}
else
{
Serial.println("data does not match whatever");
}
The best and most intuitive way is to use serialEvent() callback Arduino defines along with loop() and setup().
I've built a small library a while back that handles message reception, but never had time to opensource it.
This library receives \n terminated lines that represent a command and arbitrary payload, space-separated.
You can tweak it to use your own protocol easily.
First of all, a library, SerialReciever.h:
#ifndef __SERIAL_RECEIVER_H__
#define __SERIAL_RECEIVER_H__
class IncomingCommand {
private:
static boolean hasPayload;
public:
static String command;
static String payload;
static boolean isReady;
static void reset() {
isReady = false;
hasPayload = false;
command = "";
payload = "";
}
static boolean append(char c) {
if (c == '\n') {
isReady = true;
return true;
}
if (c == ' ' && !hasPayload) {
hasPayload = true;
return false;
}
if (hasPayload)
payload += c;
else
command += c;
return false;
}
};
boolean IncomingCommand::isReady = false;
boolean IncomingCommand::hasPayload = false;
String IncomingCommand::command = false;
String IncomingCommand::payload = false;
#endif // #ifndef __SERIAL_RECEIVER_H__
To use it, in your project do this:
#include <SerialReceiver.h>
void setup() {
Serial.begin(115200);
IncomingCommand::reset();
}
void serialEvent() {
while (Serial.available()) {
char inChar = (char)Serial.read();
if (IncomingCommand::append(inChar))
return;
}
}
To use the received commands:
void loop() {
if (!IncomingCommand::isReady) {
delay(10);
return;
}
executeCommand(IncomingCommand::command, IncomingCommand::payload); // I use registry pattern to handle commands, but you are free to do whatever suits your project better.
IncomingCommand::reset();
Here is a more robust implementation that handles abnormal input and race conditions.
It detects unusually long input values and safely discards them. For example, if the source had an error and generated input without the expected terminator; or was malicious.
It ensures the string value is always null terminated (even when buffer size is completely filled).
It waits until the complete value is captured. For example, transmission delays could cause Serial.available() to return zero before the rest of the value finishes arriving.
Does not skip values when multiple values arrive quicker than they can be processed (subject to the limitations of the serial input buffer).
Can handle values that are a prefix of another value (e.g. "abc" and "abcd" can both be read in).
It deliberately uses character arrays instead of the String type, to be more efficient and to avoid memory problems. It also avoids using the readStringUntil() function, to not timeout before the input arrives.
The original question did not say how the variable length strings are defined, but I'll assume they are terminated by a single newline character - which turns this into a line reading problem.
int read_line(char* buffer, int bufsize)
{
for (int index = 0; index < bufsize; index++) {
// Wait until characters are available
while (Serial.available() == 0) {
}
char ch = Serial.read(); // read next character
Serial.print(ch); // echo it back: useful with the serial monitor (optional)
if (ch == '\n') {
buffer[index] = 0; // end of line reached: null terminate string
return index; // success: return length of string (zero if string is empty)
}
buffer[index] = ch; // Append character to buffer
}
// Reached end of buffer, but have not seen the end-of-line yet.
// Discard the rest of the line (safer than returning a partial line).
char ch;
do {
// Wait until characters are available
while (Serial.available() == 0) {
}
ch = Serial.read(); // read next character (and discard it)
Serial.print(ch); // echo it back
} while (ch != '\n');
buffer[0] = 0; // set buffer to empty string even though it should not be used
return -1; // error: return negative one to indicate the input was too long
}
Here is an example of it being used to read commands from the serial monitor:
const int LED_PIN = 13;
const int LINE_BUFFER_SIZE = 80; // max line length is one less than this
void setup() {
pinMode(LED_PIN, OUTPUT);
Serial.begin(9600);
}
void loop() {
Serial.print("> ");
// Read command
char line[LINE_BUFFER_SIZE];
if (read_line(line, sizeof(line)) < 0) {
Serial.println("Error: line too long");
return; // skip command processing and try again on next iteration of loop
}
// Process command
if (strcmp(line, "off") == 0) {
digitalWrite(LED_PIN, LOW);
} else if (strcmp(line, "on") == 0) {
digitalWrite(LED_PIN, HIGH);
} else if (strcmp(line, "") == 0) {
// Empty line: no command
} else {
Serial.print("Error: unknown command: \"");
Serial.print(line);
Serial.println("\" (available commands: \"off\", \"on\")");
}
}
String content = "";
char character;
if(Serial.available() >0){
//reset this variable!
content = "";
//make string from chars
while(Serial.available()>0) {
character = Serial.read();
content.concat(character);
}
//send back
Serial.print("#");
Serial.print(content);
Serial.print("#");
Serial.flush();
}
If you want to read messages from the serial port and you need to deal with every single message separately I suggest separating messages into parts using a separator like this:
String getMessage()
{
String msg=""; //the message starts empty
byte ch; // the character that you use to construct the Message
byte d='#';// the separating symbol
if(Serial.available())// checks if there is a new message;
{
while(Serial.available() && Serial.peek()!=d)// while the message did not finish
{
ch=Serial.read();// get the character
msg+=(char)ch;//add the character to the message
delay(1);//wait for the next character
}
ch=Serial.read();// pop the '#' from the buffer
if(ch==d) // id finished
return msg;
else
return "NA";
}
else
return "NA"; // return "NA" if no message;
}
This way you will get a single message every time you use the function.
Credit for this goes to magma. Great answer, but here it is using c++ style strings instead of c style strings. Some users may find that easier.
String string = "";
char ch; // Where to store the character read
void setup() {
Serial.begin(9600);
Serial.write("Power On");
}
boolean Comp(String par) {
while (Serial.available() > 0) // Don't read unless
// there you know there is data
{
ch = Serial.read(); // Read a character
string += ch; // Add it
}
if (par == string) {
string = "";
return(true);
}
else {
//dont reset string
return(false);
}
}
void loop()
{
if (Comp("m1 on")) {
Serial.write("Motor 1 -> Online\n");
}
if (Comp("m1 off")) {
Serial.write("Motor 1 -> Offline\n");
}
}
If you're using concatenate method then don't forget to trim the string if you're working with if else method.
Use string append operator on the serial.read(). It works better than string.concat()
char r;
string mystring = "";
while(serial.available()){
r = serial.read();
mystring = mystring + r;
}
After you are done saving the stream in a string(mystring, in this case), use SubString functions to extract what you are looking for.
I could get away with this:
void setup() {
Serial.begin(9600);
}
void loop() {
String message = "";
while (Serial.available())
message.concat((char) Serial.read());
if (message != "")
Serial.println(message);
}
Many great answers, here is my 2 cents with exact functionality as requested in the question.
Plus it should be a bit easier to read and debug.
Code is tested up to 128 chars of input.
Tested on Arduino uno r3 (Arduino IDE 1.6.8)
Functionality:
Turns Arduino onboard led (pin 13) on or off using serial command input.
Commands:
LED.ON
LED.OFF
Note: Remember to change baud rate based on your board speed.
// Turns Arduino onboard led (pin 13) on or off using serial command input.
// Pin 13, a LED connected on most Arduino boards.
int const LED = 13;
// Serial Input Variables
int intLoopCounter = 0;
String strSerialInput = "";
// the setup routine runs once when you press reset:
void setup()
{
// initialize the digital pin as an output.
pinMode(LED, OUTPUT);
// initialize serial port
Serial.begin(250000); // CHANGE BAUD RATE based on the board speed.
// initialized
Serial.println("Initialized.");
}
// the loop routine runs over and over again forever:
void loop()
{
// Slow down a bit.
// Note: This may have to be increased for longer strings or increase the iteration in GetPossibleSerialData() function.
delay(1);
CheckAndExecuteSerialCommand();
}
void CheckAndExecuteSerialCommand()
{
//Get Data from Serial
String serialData = GetPossibleSerialData();
bool commandAccepted = false;
if (serialData.startsWith("LED.ON"))
{
commandAccepted = true;
digitalWrite(LED, HIGH); // turn the LED on (HIGH is the voltage level)
}
else if (serialData.startsWith("LED.OFF"))
{
commandAccepted = true;
digitalWrite(LED, LOW); // turn the LED off by making the voltage LOW
}
else if (serialData != "")
{
Serial.println();
Serial.println("*** Command Failed ***");
Serial.println("\t" + serialData);
Serial.println();
Serial.println();
Serial.println("*** Invalid Command ***");
Serial.println();
Serial.println("Try:");
Serial.println("\tLED.ON");
Serial.println("\tLED.OFF");
Serial.println();
}
if (commandAccepted)
{
Serial.println();
Serial.println("*** Command Executed ***");
Serial.println("\t" + serialData);
Serial.println();
}
}
String GetPossibleSerialData()
{
String retVal;
int iteration = 10; // 10 times the time it takes to do the main loop
if (strSerialInput.length() > 0)
{
// Print the retreived string after looping 10(iteration) ex times
if (intLoopCounter > strSerialInput.length() + iteration)
{
retVal = strSerialInput;
strSerialInput = "";
intLoopCounter = 0;
}
intLoopCounter++;
}
return retVal;
}
void serialEvent()
{
while (Serial.available())
{
strSerialInput.concat((char) Serial.read());
}
}
This always works for me :)
String _SerialRead = "";
void setup() {
Serial.begin(9600);
}
void loop() {
while (Serial.available() > 0) //Only run when there is data available
{
_SerialRead += char(Serial.read()); //Here every received char will be
//added to _SerialRead
if (_SerialRead.indexOf("S") > 0) //Checks for the letter S
{
_SerialRead = ""; //Do something then clear the string
}
}
}

Resources