I am using this code to retrieve data from a Thingspeak channel in a JSON format. I am using an ESP8266 along with an Arduino Nano 33 BLE. The Nono 33 BLE Arduino board is not compatible with Thingspeak library and it doesn’t support SoftwareSerial. Alternatively, I am using serial1 to communicate with the ESP8266 and REST API method to get the data from Thingspeak as it is shown in the code. However, I cannot get it to work. It is worth noting that Serial1.available() always gives zero even after adding delays.
I have used the same code to send data to the same Thingspeak channel and it works perfectly. I have no clue why it is not reading from the channel. I would really appreciate any help with this problem
Thanks in advance.
String AP ="xxxxxxxxxxx";
String PASS ="xxxxxxxxxxxxxx";
String PORT = "80";
String field = "Id";
int countTrueCommand;
int countTimeCommand;
boolean found = false;
String Data ="";
void setup() {
Serial.begin(9600);
Serial1.begin(115200);
sendCommand("AT",5,"OK",false);
Serial1.println("AT+UART_DEF=9600,8,1,0,0");
delay(1000);
Serial1.end();
Serial1.begin(9600);
ConnectToWifi();
}
void loop() {
String getData="GET https://api.thingspeak.com/channels/1335558/fields/1?api_key=7XFZKXEGOV5HY4TQ";
sendCommand("AT+CIPMUX=1",5,"OK",false);
sendCommand("AT+CIPSTART=4,\"TCP\",\""+ HOST +"\","+ PORT,15,"OK",false);
sendCommand("AT+CIPSEND=4," +String(getData.length()+4),4,">",false);
sendCommand(getData,20,"OK",true);
delay(1500);
countTrueCommand++;
sendCommand("AT+CIPCLOSE=0",5,"OK",false);
}
bool ConnectToWifi(){
for (int a=0; a<15; a++)
{
sendCommand("AT",5,"OK",false);
sendCommand("AT+CWMODE=1",5,"OK",false);
boolean isConnected = sendCommand("AT+CWJAP=\""+ AP +"\",\""+ PASS +"\"",20,"OK",false);
if(isConnected)
{
return true;
}
}
}
bool sendCommand(String command, int maxTime, char readReplay[],boolean isGetData) {
boolean result=false;
//Test Purpose
Serial.print(countTrueCommand);
Serial.print(". at command => ");
Serial.print(command);
Serial.print(" ");
while(countTimeCommand < (maxTime*1))
{
Serial1.println(command);
if(Serial1.find(readReplay))//ok
{
if(isGetData)
{
if(Serial1.find(readReplay))
{
Serial.println("Success : Request is taken from the server");
}
while(Serial1.available())
{
char character = Serial1.read()
Data.concat(character); /
if (character == '\n')
{
Serial.print("Received: ");
Serial.println(Data);
delay(50);
Data = "";
}
}
}
result = true;
break;
}
countTimeCommand++;
}
if(result == true)
{
Serial.println("Success");
countTrueCommand++;
countTimeCommand = 0;
}
if(result == false)
{
Serial.println("Fail");
countTrueCommand = 0;
countTimeCommand = 0;
}
found = false;
return result;
Related
Easy to handle received data with BLE but can't send data.
I'm using ESP32 BLE Uart code.
It's easy to get data from RxCharateristic but I don't know how to send data.
I'm trying to use TxCharacteristic to send data with BLE.
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
BLEServer *pServer = NULL;
BLECharacteristic * pTxCharacteristic;
bool deviceConnected = false;
bool oldDeviceConnected = false;
uint8_t txValue = 0;
// See the following for generating UUIDs:
// https://www.uuidgenerator.net/
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
};
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
}
};
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string rxValue = pCharacteristic->getValue();
if (rxValue.length() > 0) {
Serial.println("*********");
Serial.print("Received Value: ");
for (int i = 0; i < rxValue.length(); i++){
Serial.print(rxValue[i]);
}
}
}
};
void setup() {
Serial.begin(115200);
// Create the BLE Device
BLEDevice::init("TheOneSystem");
// Create the BLE Server
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
// Create the BLE Service
BLEService *pService = pServer->createService(SERVICE_UUID);
// Create a BLE Characteristic
pTxCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_TX,
BLECharacteristic::PROPERTY_NOTIFY
);
pTxCharacteristic->addDescriptor(new BLE2902());
BLECharacteristic * pRxCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_RX,
BLECharacteristic::PROPERTY_WRITE
);
pRxCharacteristic->setCallbacks(new MyCallbacks());
// Start the service
pService->start();
// Start advertising
pServer->getAdvertising()->start();
Serial.println("Waiting a client connection to notify...");
}
void loop() {
if (deviceConnected) {
pTxCharacteristic->setValue(&txValue, 1);
pTxCharacteristic->notify();
txValue++;
delay(10); // bluetooth stack will go into congestion, if too many packets are sent
}
// disconnecting
if (!deviceConnected && oldDeviceConnected) {
delay(500); // give the bluetooth stack the chance to get things ready
pServer->startAdvertising(); // restart advertising
Serial.println("start advertising");
oldDeviceConnected = deviceConnected;
}
// connecting
if (deviceConnected && !oldDeviceConnected) {
// do stuff here on connecting
oldDeviceConnected = deviceConnected;
}
}
I can easily handle received data with this part of code
class MyCallbacks: public BLECharacteristicCallbacks {
String bleData;
void onWrite(BLECharacteristic *pCharacteristic) {
std::string rxValue = pCharacteristic->getValue();
if (rxValue.length() > 0) {
Serial.println("*********");
Serial.print("Received Value: ");
for (int i = 0; i < rxValue.length(); i++){
//Serial.print(rxValue[i]);
bleData=bleData+rxValue[i];
}
Serial.println();
Serial.println(bleData);
Serial.println("*********");
int first = bleData.indexOf(",");
String bleSSID = bleData.substring(0, first);
String blepw = bleData.substring(first+1, bleData.length());
Serial.println("Wifi : " + bleSSID + "," + "Password : " + blepw);
bleData="";
}
}
};
How to send data by using TxCharacteristic?
In my receiving code, I'm using this function to use callback.
if(pTxCharacteristic->canNotify()) {
pTxCharacteristic->registerForNotify(notifyCallback);
}
And here is my notifyCallback function i got from Google.
static void notifyCallback(
BLERemoteCharacteristic* pBLERemoteCharacteristic,
uint8_t* pData,
size_t length,
bool isNotify){
Serial.println(data);
}
It seems like i have to add a little function in notifyCallback.
However errors continue to occur. I can't get data. Tnx for help.
I am writing an Arduino code to receive SMS from a SIM800 module and then send the same message back to the sender. My code is as follows:
#include<SoftwareSerial.h>
SoftwareSerial mySerial(9, 10);//Connect to pin 9&10 on GSM module
const byte numChars = 128; //character size
char receivedChars[numChars]; // Store data read from SMS
boolean newData = false; //flag to check if new data has arrived
void setup() {
Serial.begin(9600);
mySerial.begin(9600);
Serial.println("<Arduino is ready>");
mySerial.println("AT");
mySerial.println("AT+CMGF=1"); //text mode
mySerial.println("AT+CNMI=1,2,0,0,0");
mySerial.println("AT+CSQ"); //Check signal strength
while (Serial.available())
{
mySerial.write(Serial.read());//Forward what Serial received to Software Serial Port
}
while(mySerial.available())
{
Serial.write(mySerial.read());//Forward what Software Serial received to Serial Port
}
}
void loop() {
//code for checking sms
scanSMS();
//Print if a new data arrived
showNewData();
delay(25000);
}
void scanSMS() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '#'; //Start and end markers. Eg. SMS body will be sent as #status#
char endMarker = '#';
char rc;
while (Serial.available())
{
mySerial.write(Serial.read());//Forward what Serial received to Software Serial Port
}
while (mySerial.available() > 0 && newData == false) {
Serial.write(mySerial.read());//Forward what Software Serial received to Serial Port
rc = mySerial.read();
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
}
else if (rc == startMarker) {
recvInProgress = true;
}
}
}
/*PRINT IF THERE IS A NEW DATA*/
void showNewData() {
if (newData == true) {
SendMessage(receivedChars);
newData = false;
}
}
/*SEND BACK WHATEVER SMS IS RECEIVED*/
void SendMessage(String receivedChars)
{
Serial.print("here");
mySerial.println("AT+CMGS=\"+xxxxxxxxxx\"\r"); // Replace x with mobile number
mySerial.println("Humidity Alert!");// The SMS text you want to send
mySerial.print(receivedChars);
mySerial.println((char)26);// ASCII code of CTRL+Z
}
The issue is that the module seems to receive only alternate characters instead of the whole message. For example, if I send the text #program#, the Arduino will only print porm or rga. Am I missing something here? Any help is highly appreciated.
You are calling mySerial.read() twice in the while loop.
while (mySerial.available() > 0 && newData == false) {
Serial.write(mySerial.read());//Forward what Software Serial received to Serial Port
rc = mySerial.read();
I think that is why you are not seeing the whole string. read reads the first byte in the buffer and advances.
You want to store a returned value and pass it to the write call like this.
while (mySerial.available() > 0 && newData == false) {
rc = mySerial.read();
Serial.write(rc);//Forward what Software Serial received to Serial Port
....
}
I am new to Arduino and GSM shield. I have been working with SMS, and I have a problem to read the SMS's text contents from the modem.
Here is the setting for the Arduino and the GSM.
#include <SoftwareSerial.h>
SoftwareSerial sim900(7, 8);
#define BUFF_SIZE 400
char buffer[BUFF_SIZE];
bool GSMconnected = false;
//functions
bool copyResponse(int* size);
void printBuff(int size);
bool readlnbuffer(int* start, int* nextline, int* size);
bool isResponseOK(int start, int endofline);
bool checkConnection();
bool checkMessage(int index);
bool checkString(int start, int end, String command);
bool checkSMS(int start, int nextline);
bool newMessage();
void setup() {
sim900.begin(9600);
Serial.begin(9600);
delay(100);
pinMode(relayIN, OUTPUT);
delay(100);
while (!GSMconnected) {
checkConnection();
delay(10000);
}
int rsize;
//text mode
sim900.print("AT+CMGF=1\r");
delay(1000);
//store message in SIM card
sim900.print("AT+CPMS=\"SM\"\r");
delay(1000);
sim900.print("AT+CMGD=0,4\r\n");
delay(1000);
copyResponse(&rsize);
printBuff(rsize);
/*
0: do not show header values
1: show the values in result codes
*/
sim900.print("AT+CSDH=1\r");
delay(1000);
//receive mode +CMTI:"SM", 1
sim900.print("AT+CNMI=2,2,0,0,0 \r");
delay(1000);
copyResponse(&rsize);
printBuff(rsize);
sim900.print("AT+CSMP=17,167,0,0\r\n");
delay(10000);
copyResponse(&rsize);
printBuff(rsize);
Serial.println("GSM is ready");
I want to check the SMS message when there is a new SMS. So I simply call the function when the GSM is available.
void loop() {
if(sim900.available()) {
newMessage();
}
}
newMessage() checks the index of the new SMS stored in the SIM card.
bool newMessage() {
int responseSize;
if (!copyResponse(&responseSize)) {
return false;
}
//+CMTI: “SM”,1
//read a line and check if there is a SMS
int start = 0;
int nextline = 0;
int index;
while (readlnbuffer(&start, &nextline, &responseSize)) {
String command = "+CMTI: \"SM\",";
if (checkString(start, start + 12, command)) {
Serial.println("SMS found");
index = int(buffer[start + 12]);
break;
}
start = nextline;
}
//debug
printBuff(responseSize);
delay(10000);
if (checkMessage(index)) {
//delete message
sim900.print("AT+CMGD=");
sim900.print(char(index));
sim900.println("\r");
delay(100);
return true;
} else {
return false;
}
checkMessage() reads SMS message and should print SMS text data.
bool checkMessage(int index) {
//listing
//sim900.print("AT+CMGL=\"REC UNREAD\"\r\n");
//reading
sim900.print("AT+CMGR=");
sim900.print(char(index));
sim900.print("\r\n");
delay(5000);
int responseSize;
if (!copyResponse(&responseSize)) {
return false;
}
delay(100);
//debug, to check what is in the buffer
printBuff(responseSize);
//read a line and check if there is a SMS
int start = 0;
int nextline = 0;
bool isSMS = false;
while (!isSMS) {
start = nextline;
if (!readlnbuffer(&start, &nextline, &responseSize)) {
Serial.println("no SMS found");
return false;
}
String command = "+CMGR:";
if (checkString(nextline, nextline + 6, command)) {
Serial.println("SMS checking");
isSMS = true;
}
}
//debug
if (!readlnbuffer(&start, &nextline, &responseSize)) {
Serial.println("cannot read the sms info");
return false;
}
Serial.println("SMS message: ");
for (int i = start; i < nextline; i++) {
//debug
Serial.print(buffer[i]);
}
Serial.println("");
}
When I run the code, it looks like the response for AT+CMGR cannot be copied completely. Here is what the Serial monitor shows.
checking the network
AT+CREG?
+CREG: 0,1
OK
AT+CMGF=1
OK
AT+CPMS="SM"
+CPMS: 1,30,1,30,1,30
OK
AT+
AT+CSDH=1
OK
AT+CNMI=2,1,0,0,0
OK
AT+CSMP=17,167,0,0
OK
GSM is ready
SMS found
+CMTI: "SM",1
AT+CMGR=1
> +CMGR: "REC UNREAD","+123456789","","17/11/26,11
SMS checking
SMS message:
AT+CMGD=1
OK
I think I went wrong with copying the response in the buffer. I am also a beginner of writing code and I need some help. Can anyone advise me on why I am getting this problem?
Thank you!
I think the problem is that you are aborting the command by using delay which you should never, never, ever do as a substitute for reading and parsing the responses from the mopdem.
For hints on removing delay usage see the linked answer (and for details on aborting command you can see V.250).
I am using an Arduino mega2560 and an EZO EC(Electrical Conductivity) and am trying to send a command using the Serial.print() function. I am using the Arduino IDE 1.6.7.
I have some code that seems to work fine which I found online. But I want to know why my code will not work. The EC sensor does not seem to get the data I am sending. No data seems to being sent.
I know it is not my connection as I have tested the setup with the code that works it runs fine and as expected.
Here is the code I found online that works:
String inputstring = "";
String sensorstring = "";
boolean input_string_complete = false;
boolean sensor_string_complete = false;
void setup() {
Serial.begin(9600);
Serial3.begin(9600);
inputstring.reserve(10);
sensorstring.reserve(30);
}
void serialEvent() {
inputstring = Serial.readStringUntil(13);
input_string_complete = true;
}
void serialEvent3() {
sensorstring = Serial3.readStringUntil(13);
sensor_string_complete = true;
}
void loop() {
float wt = 28.9;
String tempCal = "T,";
tempCal += wt;
if (input_string_complete == true) {
Serial3.print(inputstring);
Serial3.print("\r");
inputstring = "";
input_string_complete = false;
}
if (sensor_string_complete == true) {
if (isdigit(sensorstring[0]) == false) {
Serial.println(sensorstring);
}
else
print_EC_data();
}
sensorstring = "";
sensor_string_complete = false;
}
}
void print_EC_data(void) {
char sensorstring_array[30];
char *EC;
char *TDS;
char *SAL;
char *GRAV;
float f_ec;
sensorstring.toCharArray(sensorstring_array, 30);
EC = strtok(sensorstring_array, ",");
TDS = strtok(NULL, ",");
SAL = strtok(NULL, ",");
GRAV = strtok(NULL, ",");
Serial.print("EC:");
Serial.println(EC);
Serial.print("TDS:");
Serial.println(TDS);
Serial.print("SAL:");
Serial.println(SAL);
Serial.print("GRAV:");
Serial.println(GRAV);
Serial.println();
//f_ec= atof(EC);
}
Here is my code:
void setup() {
Serial.begin(9600);
Serial3.print(9600);
}
void loop() {
Serial3.print("R/r");
Serial.print("R/r");
delay(2000);
}
The Serial3.print just doesn't get sent to the sensor. But the other code also sends a string using the Serial3.print() function an it works fine. I do not know what I am doing wrong.
I understand that I need to write a procedure to take in anything that comes in from the sensor. But nothing seems to be even sent to the sensor in the first place!
Any help would be greatly appreciated. Thank you
You're using slash, not backslash. Change this
Serial3.print("R/r");
to this:
Serial3.print("R\r");
And don't use the String class. It'll mess you up. :) Just use char arrays, and fill them up as characters are available in loop. When the \r finally arrives, process the array:
char inputString[16];
int inputStringIndex = 0;
void loop()
{
if (Serial.available()) {
char c = Serial.read();
if (c == '\r') {
inputString[ inputStringIndex ] = '\0'; // NUL-terminate string
inputStringIndex = 0; // reset for next time
Serial3.print( inputString );
Serial3.print( '\r' );
} else if (inputStringIndex < sizeof(inputString)-1) {
inputString[ inputStringIndex++ ] = c;
}
}
Do something similar for the response line. This will also avoid blocking inside a SerialEvent. :P
You have an error in your setup() block: before you can send data over a serial connection you need to configure the connection with a begin() statement:
Serial3.begin(9600)
But in the code in your question you have
Serial3.print(9600)
And make sure that you have the EZO connected to the correct pins for Serial3 (14,15).
Also you need to use the "\" for printing control characters.
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
}
}
}