Arduino <-> Core: SoftwareSerial and Serial1

Dear all,

I’m writing since I’m getting a little bit confused…

What would like to do is the following communication between Core © and Arduino (A):
© --> (A) “:CT1!”
(A) --> © “:ANSWER1!”

Where :CT1! is a command (a string of 5 char) that starts with “:” and ends with “!”. Answers are variable length and always start and end in the same way.
I previously connected my Arduino to a RPi and via python script I was sending commands to Arduino and parsing the answer.

This was the original code for the Arduino:

String inputString = "";         // string for incoming command
boolean stringComplete = false;  // flag command complete

void setup() {
  Serial.begin(9600); 
  Serial.println("Start");
  inputString.reserve(200);
}

void serialEvent() {
  while (Serial.available())
  {
    char inChar = (char)Serial.read(); 
    if (inChar == ':') // Command begins
    {
      inputString = "";
    }
    inputString += inChar;
    if (inChar == '!') // Command ends
    {
      stringComplete = true;
    } 
  }
}


void loop() {
 
  if (stringComplete)
  {
    if ((inputString.length()==5) && (inputString.startsWith(":C")))
    {
      switch (inputString.charAt(2))
      {
        case 'P':
          Serial.println(":P:Arduino is live!");
          break;
        case 'T':
          Serial.println(ProduceAnswer(inputString.charAt(3)));
          break;
      }
    }

    // clear
    inputString = "";
    stringComplete = false;
  }
}

Now reading this http://community.spark.io/t/spark-3-3v-to-arduino-5v-serial-communication/3548

I did connected as follows my arduino 3.3v to the Core:

   (A)      (C)
   GND <--> GND
3.3Vin <--> 3.3Vout
    D6 <--> TX
    D7 <--> RX

For Arduino the code has been adapted:

#include <SoftwareSerial.h>
SoftwareSerial swSerial(6,7); // 6 RX, 7 TX

void setup() {
   swSerial.begin(9600);
   [...]
}

[...]

// Serial changed with swSerial

But now the serialEvent() function is no more available. I tried to create a swSerialEvent() and call it at the beginning of the loop() but it seems not to work.

The spark code:

String inputString = "";
boolean stringComplete = false;

void setup() {
	Serial.begin(9600);
	Serial1.begin(9600);
	Serial.println("SPARK: Start");
}

void loop() {
  
  if (Serial1.available() > 0)
  {
      Serial1.write(":CT0!"); // Send the command
      Serial.println("SPARK: sending CT0!");
  }
  
  // Read the answer
  while (Serial1.available())
  {
    char inChar = (char)Serial1.read(); 
    Serial.print("SPARK: receive single char: ");
    Serial.print(inChar);
    if (inChar == ':')
    {
      inputString = "";
    }
    inputString += inChar;
    if (inChar == '!')
    {
      stringComplete = true;
    } 
  }
  
  if (stringComplete)
  {
      Serial.print("SPARK: received: ");
      Serial.println(inputString);
  }
  else
  {
      Serial.println("SPARK: waiting");
  }
    // clear the string:
    inputString = "";
    stringComplete = false;
  
  delay(1000);
}

But it actually never mets the “if (Serial1.available() > 0)” …

Can anyone help me clarify?
Is there an alternative to serialEvent() function for software serial? Exists this for Core?
If I take off the FTDI connector from the arduino, I can use the original serial pins 0 RX and 1 TX… but how can I make the Core to wait to have the whole answer string back?

Thank you for your support.
dk

After reading through everything, it’s not clear to me how you propose to initiate this sequence from the Core:

What would like to do is the following communication between Core (C) and Arduino (A):
(C) --> (A) ":CT1!"
(A) --> (C) ":ANSWER1!"

I also don’t see :CT1! in your Core code… but I do see :CT0!

If you were intending on using the USB Serial of the Spark Core to initiate things, perhaps this block:

if (Serial1.available() > 0)

should be

if (Serial.available() > 0)

?

I'm not familiar with SoftSerial on Arduino, but I'd suppose that serialEvent is only called when the event occures on Serial - since I can't see where serialEvent gets hooked up to Serial or swSerial.
So I think it's an Arduino issue, rather than Core, but you could always try to transfer your serialEvent code into the Arduino loop.

And I assume, you have made sure that your Arduino is running stable on 3.3V only.
If so there should be no problem to have a 3.3V running Arduino HW Serial connected to the Cores RX/TX pins.
On the other hand you can try the 5V tolerant Serial2 pins (D0/D1) of the Core to do the communication with a 5V Arduino - but be careful with the wiring!

And about your question how to make the Core wait for the whole message to arrive, you can use your start (:) and stop (!) characters and drop the Cores delay(1000). With each "undelayed" iteration of loop you keep looking out for the first : to arrive which opens the door for subsequently arriving chars which you suck in by use of while(Serial1.available()) as many as are there already and if you don't receive the final ! you just leave the door open for the next iteration of loop, till you receive your !.


@BDub, I think the Arduino setup() code line

should be the GO! for the Core, so it might well stay as while(Serial1.available()) and the actual problem is independent of :CT0! or :CT1!.

@d82k et al, I found a great little serial command parser that could the job on both the Arduino and Spark sides here. It even supports SoftwareSerial on the Arduino side!! It needs a little adapting but it looks great :smile:

1 Like

Sometimes it pays to take a step back and start with something simpler. I would just put the Arduino in a loop so it sends :CT1! on the Software Serial TX line over and over every second.

Then get your connections straight…

And see if you can receive that data on the Core and echo it to the USB Serial port.

Once that’s working, do it in the opposite direction Spark Core -> Arduino.

Then put it all together :smile:

@BDub, if it pays, I’ll do THAT for a dollar :stuck_out_tongue:

BTW, I have the ArduinoSerialCommand library compile for both Spark and Arduino if anyone is interested.

4 Likes

Thank you all for your replies.
I admit I had to write the first post really quick, I apologize probably I was not clear enought.
The arduino I’m using is an Atmega328 (bootloader Arduino Pro 3.3V 8Mhz) which I program using my Uno.
I thought it would have been more easy… I’m trying to do one step a time.
Fist step: make arduino and spark communicate via serial (A) and serial1 ©:

   (A)      (C)
   GND <--> GND
3.3Vin <--> 3.3Vout
    D0 <--> TX
    D1 <--> RX

The arduino code is a simple loop with Serial.println(":P:Arduino is live!"); while the Core code is the following:

void setup() {
    Serial.begin(9600);
    Serial1.begin(9600);
}

void loop() {
    char inChar = (char)Serial1.read(); 
    Serial.print(inChar);
}

So I output on the Core serial what I read on Serial1. The first issue is that it partially works… this is the output:

:P:Arduino is live!
:P:Arduino is live!
:P:Arduino is liePuiv:dol
An ePuiv:dol
An !:uiv:d l
An !:uiv:d i
An !:uiv:d i
An !:iiv:d i
An !:isv:d i
rn !:isv:d i
rn !:ise:d i
ro !:ise:d i
ro !:isePd i
rol!:isePu i
rol!:isePu i
rol
:isePuii
rol
AisePuii
rol
AisePuiv
rol
AisePuiv
[...]

So the output is correct only for the first 2 messages, than I think the arduino is flooding the core wich makes confusion.

Than I tried to make the core send a string to arduino and have the arduino reply and turn on a led.
Core:

void setup() {
    Spark.function("serial", serialControl);
	Serial.begin(9600);
	
	while(!Serial.available()) SPARK_WLAN_Loop();
	Serial1.begin(9600);
}

void loop() {
  if (Serial1.available())
  {
    int inByte = Serial1.read();
    Serial.write(inByte);
  }  
}

int serialControl(String command)
{
	Serial.println("SPARK: serial input");
	Serial.println(command);
	Serial1.println(command);
   return 1;
}

Arduino:

String inputString = "";
boolean stringComplete = false;
boolean stringStart = false;

void setup() {
  pinMode(13, OUTPUT);
  Serial.begin(9600);
  digitalWrite(13, HIGH);
  delay(1000);
  digitalWrite(13, LOW);
  delay(1000);
}

void SerialEvent() {
  while (Serial.available())
  {
    char inChar = (char)Serial.read(); 
    if (inChar == ':')
    {
      inputString = "";
      stringStart = true;
    }
    if (stringStart == true && stringComplete != true)
    {
      inputString += inChar;
    }
    if (inChar == '!')
    {
      stringComplete = true;
    }
   
   Serial.println(inputString);
  }
}

void loop() {
  if (stringComplete)
  {
    if ((inputString.length()==5) && (inputString.startsWith(":C")))
    {
      digitalWrite(13, HIGH);
        
      switch (inputString.charAt(2))
      {
        case 'P':
          Serial.println(":P:Arduino is live!");
          break;
        case 'T':
          Serial.println(":Off!");
          digitalWrite(13, LOW);
          break;
      }
    }
    inputString = "";
    stringComplete = false;
    stringStart = false;
  }
}

and I send commands using curl https://api.spark.io/v1/devices/xxxx -d access_token=xxx -d params=:CP0! , the command is executed, but the serialEvent() seems not to work no Serial.println(inputString); (that should be sent back to the core).

any suggestions or advices?

@peekay123 thank you for the suggessition, I will have a look to the library!

thank you,
dk

@d82k, I can see some problem with your code there already, but haven’t got the time yet to elaborate more.
One thing I can say. The Core loop is not called as fast as the Arduino loop since it does some cloud keeping between iterations, so you should read the whole Serial1 buffer in a while loop as long bytes are available, otherwise you’ll run into buffer overflows.

Edit: Now I’ve got a bit of time again

Try this on the Core for your first test

void loop()
{
  int inByte; // .read() reads a byte but returns an int do indicate error by -1

  while (Serial1.available())  // read as long there is something to read
  {
    inByte = Serial1.read();
    Serial.write(inByte);  // write() the received byte as is, not fancy print() stuff
  }
}

I also think you should call your SerialEvent() more correctly serialEvent() - C is case sensitive.


BTW: What Arduino are you using?
I found an issue with the Arduino Due and it might be present in others too.
To see if your serialEvent() is called at all try to do something (e.g. blink) outside the if clause.

1 Like

Thank you for your reply @ScruffR
Yes you are right, was serialEvent() :wink:
I was using an Arduino Uno, but in order to get rid of the logic level converted I build a new one with an ATmega328 running at 3.3v and 8Mhz.

This is now the working for the Core:

String inputString = "";
boolean stringComplete = false;
boolean stringStart = false;

void setup() {
    Spark.function("serial", serialControl);
	Serial.begin(9600);
	
	//while(!Serial.available()) SPARK_WLAN_Loop();
	Serial1.begin(9600);
}


void loop()
{
    while (Serial1.available())
    {
        char inChar = (char)Serial1.read();
        if (inChar == '*')
        {
            inputString = "";
            stringStart = true;
        }
        if (stringStart == true && stringComplete != true)
        {
            inputString += inChar;
        }
        if (inChar == '#')
        {
            stringComplete = true;
        }
    }
    
    if (stringComplete)
    {
        if ((inputString.startsWith("*")))
        {
            switch (inputString.charAt(1))
            {
                case 'P':
                  Serial.print("Arduino answered to the ping: ");
                  Serial.println(inputString);
                  break;
                case 'O':
                  Serial.print("Arduino message: ");
                  Serial.println(inputString);
                  break;
            }
        }
        inputString = "";
        stringComplete = false;
        stringStart = false;
    }
}


int serialControl(String command)
{
    Serial.print("SPARK: command to be sent: ");
    Serial.println(command);
	
    char* buf = (char*) malloc(sizeof(char)*command.length()+1);
    command.toCharArray(buf, command.length()+1);
    if(Serial1.write(buf) > 0)
    {
        Serial.println("SPARK: command sent!");
        free(buf);
        return 1;
    }
    else
    {
        return -1;
        free(buf);
    }
    free(buf);
    return 1;
}  

and for the Arduino:

String inputString = "";
boolean stringComplete = false;
boolean stringStart = false;

void setup() {
  pinMode(13, OUTPUT);
  Serial.begin(9600);
  inputString.reserve(200);
  digitalWrite(13, HIGH);
  delay(1000);
  digitalWrite(13, LOW);
  delay(1000);
}

void serialEvent() {
  while (Serial.available())
  {
    char inChar = (char)Serial.read();
    if (inChar == '*')
    {
      inputString = "";
      stringStart = true;
    }
    if (stringStart == true && stringComplete != true)
    {
      inputString += inChar;
    }
    if (inChar == '#')
    {
      stringComplete = true;
    }
  }
}

void loop() {
  if (stringComplete)
  {
    if ((inputString.length()==4) && (inputString.startsWith("*C")))
    {
      switch (inputString.charAt(2))
      {
        case 'P':
          Serial.println("*PING#");
          digitalWrite(13, HIGH);
          break;
        case 'T':
          Serial.println("*Off#");
          digitalWrite(13, LOW);
          break;
      }
    }
    inputString = "";
    stringComplete = false;
    stringStart = false;
  }
}

I changed a bit the structure of messages: now commands start with * and ends with #.
Now using curl https://api.spark.io/v1/devices/xxxx -d access_token=xxx -d params=*CP# arduino replies to the ping correctly and the Core understands the answer.

Next step is try to use the software serial for the arduino and see what happens. I will post here updates…
in the meantime thank you all again for your kind support!

EDIT:
Software serial worked great… just changed my code adding the below lines and using ser. instead of Serial.

#include <SoftwareSerial.h>
SoftwareSerial ser(3, 4); // RX, TX
1 Like

Hi @peekay123 Where might I find that ArduinoSerialCommand library?

Thanks!

@peekay123 had this linked in one of his earlier posts

I saw that, but mistakenly took it to mean he had ported it…my bad

@techbutler, arrrgghhh! I forgot to put the (ported) library up on my github! I’ll do that later today. :wink:

@techbutler, I posted the code here. I did not configure it as a web IDE library since you may want to modify Serial port being used. Let me know how it goes! :smiley:

merci bien

1 Like

Hello,
what if i would like to connect a second arduino, and query both with the same method i done for the first sending a string and waiting for the response (obviously at two different times). i think i can use serial2 of the core…

Could this be a good idea or better to use alternatives methods, i2c for example?

Thank you,
dk

@d82k, if you are only running the SerialCommand code on the Arduinos then it can be done using Serial1 and Serial2. Is this what you meant?

Hi @peekay123,
hum… I did not explained myself correclty, sorry.
If I would like to have two arduinos talking with the Core (adapting the simple code I wrote in my previous post) I think I can use Serial2 (probably increasing rates as well). The question was: is this a smart idea to have the core communicating via serial to two arduinos or maybe is best to find another solution such as i2c to connect them all? Considering that arduinos need to talk only with the Core and not each others…
Thank you,
dk

Both solutions will work. The I2C will take 2 less pins.

OK @peekay123 I’m finally crying uncle trying to get this SerialCommand library working for me. I’m attempting to go spark to spark with publish/subscribe and then core to arduino Mega with the SerialCommand. Even though I am using the library on the arduino side, your port adds support for serial port modification which the original does not. My spark code is a modified version of this hackster project and the arduino code is just the hardware only example, but with Serial3 added in. I modified SerialCommand.h to define Serial3.

The publish/subscribe part works fine.

My scope says something is being pushed out of D1 on the spark for each button push, but it must not be the right thing.

Thanks as always.

My Spark code:

#include "Serial2/Serial2.h"

int sendLedPin = D2; //choose the pin for the send (local) LED
int inputPin = D3; //choose the input pin (for a pushbutton)
int receiveLedPin = D4; //choose the pin for the receive (Core1-dependent LED)
int val = 0; //variable for reading the pushbutton pin status
int sendLedVal = 0; //variable for keeping the state of the local pushbutton dependent LED (D2)

void ledTwoToggle(const char *toggle, const char *onOff); //handler function for Spark.subscribe()

void setup() {
    
    Serial.begin(9600);
    Serial2.begin(9600);
    pinMode(receiveLedPin, OUTPUT); //Set the pin controlling the Core1-dependent LED as an OUTPUT
    pinMode(sendLedPin, OUTPUT); //Set the pin controlling the local pushbutton-dependent LED as an OUTPUT
    pinMode(inputPin, INPUT); //Set the pin connected to the pushbutton as an INPUT
    digitalWrite(sendLedPin, LOW); //Ensure the local LED is set to off to begin with
    
    Spark.publish("Core2Toggle", "State", 60, PRIVATE); //Set up Spark.publish() so that the state of the local LED is published to the Spark Cloud PRIVATELY
    Spark.subscribe("Core1Toggle", ledTwoToggle, "xxxxxxxxxxxxxxxxxxxxxxxxx"); //Set up Spark.subscribe() so that the state of Core1's Led is recorded and handled by ledTwoToggle
}

void loop() {
    
    while(Serial2.available())
		Serial.write(Serial2.read());
		
    while(Serial.available())
		Serial2.write(Serial.read());
    
}

void ledTwoToggle(const char *toggle, const char *onOff){ //handler function for Spark.subscribe()
    if (strcmp(onOff, "ON") == 0){ //if sendLed on Core1 is ON according to Spark.publish()
        digitalWrite(receiveLedPin, HIGH); //then turn on receiveLed
        Serial2.print("ON");
        Serial2.print('\r');
        Serial.print("ledON");
    } else if (strcmp(onOff, "OFF") == 0){ //if sendLed on Core1 is OFF according to Spark.publish()
        digitalWrite(receiveLedPin, LOW); //then turn off receiveLed
        Serial2.print("OFF");
        Serial2.print('\r');
        Serial.print("ledOFF");
    }
}

My Arduino Code:

#include <SerialCommand.h>


#define arduinoLED 13   // Arduino LED on board

SerialCommand SCmd;   // The demo SerialCommand object

void setup()
{  
  pinMode(arduinoLED,OUTPUT);      // Configure the onboard LED for output
  digitalWrite(arduinoLED,LOW);    // default to LED off

  Serial.begin(9600);
  Serial3.begin(9600);

  // Setup callbacks for SerialCommand commands 
  SCmd.addCommand("ON",LED_on);       // Turns LED on
  SCmd.addCommand("OFF",LED_off);        // Turns LED off
  //SCmd.addCommand("HELLO",SayHello);     // Echos the string argument back
  //SCmd.addCommand("P",process_command);  // Converts two arguments to integers and echos them back 
  SCmd.addDefaultHandler(unrecognized);  // Handler for command that isn't matched  (says "What?") 
  Serial.println("Ready"); 

}

void loop()
{  
  SCmd.readSerial();     // We don't do much, just process serial commands
}


void LED_on()
{
  Serial.println("LED on"); 
  digitalWrite(arduinoLED,HIGH);  
}

void LED_off()
{
  Serial.println("LED off"); 
  digitalWrite(arduinoLED,LOW);
}




// This gets set as the default handler, and gets called when no other command matches. 
void unrecognized()
{
  Serial.println("What?"); 
}