Serial communication with Arduino

My ultimate goal here is to establish a serial link between an Arduino and a raspberry pi 4, using Linux code created from XoJo. As a first step, I attempted to get serial comms working between my mac m1 running xojo and an arduino. Unfortunately I have not had luck getting it working. Xojo is able to connect to the Arduino serial port and recieves the first transmission “0,0,0” from arduino and then nothing is heard or sent either way…

Arduino code is a modified serial comms example:

int firstSensor = 0; // first analog sensor
int secondSensor = 0; // second analog sensor
int thirdSensor = 0; // digital sensor
int inByte = 0; // incoming serial byte

void setup() {
// start serial port at 9600 bps and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}

pinMode(2, INPUT); // digital sensor is on digital pin 2
establishContact(); // send a byte to establish contact until receiver responds
}

void loop() {
// if we get a valid byte, read analog ins:
Serial.println(“getting ready to read”);
if (Serial.available() > 0) {
Serial.read();
Serial.println(“This is a response”);

}
delay (1500);
}

void establishContact() {
while (Serial.available() <= 0) {
Serial.println(“0,0,0”); // send an initial string
delay(300);
}
}

not sure how to show xojo code here. The serialConnection “data received” event does this:

Var data As String
data = Me.LookAhead(Encodings.ASCII)
If data.IndexOf(EndOfLine.Windows) > -1 Then
TextArea1.AddText (Me.ReadAll(Encodings.ASCII)+chr(10)+chr(13))
End If

Sending serial data is done like this:

SerialConnection1.Write (TextField1.Text)
SerialConnection1.Flush

Any help is appreciated!

Matt

  1. Paste your code.
  2. Select it.
  3. Click the “code brackets” icon in the forum post editor: image
Var data As String
data = Me.LookAhead(Encodings.ASCII)
If data.IndexOf(EndOfLine.Windows) > -1 Then
TextArea1.AddText (Me.ReadAll(Encodings.ASCII)+chr(10)+chr(13))
End If

Sending serial data is done like this:

SerialConnection1.Write (TextField1.Text)
SerialConnection1.Flush

I don’t know if this is your issue, but generally speaking, spending a lot of time in the DataReceived event is not a good idea - it can cause the port to miss incoming bytes in my experience. I usually do a ReadAll of the buffer to a string variable and start a TImer.CallLater with, say, 2ms to the code that actually parses the data. This moves the parsing code into Xojo’s main thread.

3 Likes

I read somewhere it is better to spend minimum time in dataAvailable, and rather grab the serial data in a timer. in the timer, the code looking something like this:

Dim s as String
Do Until SerialConnection1.BytesAvailable = 0
  s=SerialConnection1.ReadAll()
  TextArea1.addtext(s+chr(10)+chr(13))
Loop

I a mot sure how to use this timer method though. Does the timer fire once, activated within DataAvailable?

Matt

I have a thread which processs the data. When there is no data, the thread suspends itself. Then, in the DataAvailable event, I resume the thread. The thread then does the ReadAll, ad processes the data until there is no more. Repeat.

1 Like

i would replace this from setup to the loop

if (firstContact==0) {
Serial.println('0,0,0'); // send an initial string
delay(500);
}

in the loop you read the incomming commands from xojo.

https://docs.arduino.cc/built-in-examples/communication/SerialEvent/
https://docs.arduino.cc/built-in-examples/control-structures/SwitchCase2/
https://docs.arduino.cc/built-in-examples/strings/StringAdditionOperator/
https://docs.arduino.cc/built-in-examples/strings/StringConstructors/

at (android) phone i found a nice terminal app in google play store.
serial usb terminal from Kai Morich

i link my uno r4 and phone with usb-c to usb-c cable.

I think the arduino side is behaving well, as it does what it is supposed to in the serial monitor, and when connected to a serial terminal on the mac. Trouble is on the xojo side…

Yes, you read it in my post just above yours!

In DataAvailable (or DataReceived or whatever it’s called in your version of Xojo):

RXBuffer = me.ReadAll
Timer.CallLater(2, AddressOf ParseData)

Where RXBuffer is a property of your SerialConnection subclass, or of your window, or a module, although those wouldn’t be very OOPish.

In your ParseData method you do all the buffer parsing stuff, and set RXBuffer to “” (null string) when you find what you’re looking for so it’s cleared for the next message.

Yes, every time new data is received.

I am having a frustrating time getting this to work. It seems if I put some breakpoints in the code, it will acually read the first line of test from the arduino, but no more. If I eliminate the breakpoints, I get nothing.

DataReceived looks like:

RXBuffer = me.readall(Encodings.windowsansi)
Timer.CallLater(10, AddressOf ParseData)

ParseData looks like:

Dim s as String
TextArea1.addtext("got: "+RXbuffer)
Do Until SerialConnection1.BytesAvailable <= 0
  s=SerialConnection1.ReadAll()
  TextArea1.addtext(s)
Loop

I get an error when I try to send data as well:

SerialConnection1.Write (TextField1.Text)
SerialConnection1.XmitWait
SerialConnection1.Flush

What the heck is going on??? (obviously not a great programmer…)

I wouldn’t do this. You’ve already cleared the buffer in DataReceived. Let DataReceived do its job, there’s no need for you to loop.

Also, I’d use a shorter time on the Timer.CallLater, like 1 or 2 ms.

What error do you get?

There’s been some discussion here lately that in recent versions of Xojo, calling Flush clears the receive buffer, so try it without that.

OK, I don’t get an error when writing to serial port now. and the first time through, xojo receives the first line from Arduino, but then nothing after that.

I can force it to get another line by 1) resetting the Arduino, and 2) disconnecting and reconnecting to the serial port in Xojo. One or the other is not sufficient. I have to do both. Is Xojo jamming up the Arduino somehow?

If I understand your Arduino code correctly, the establishContact() method is the only place where something is being sent, and that method is only called in the setup() method. The setup method is only executed once, at startup. So, only receiving “0,0,0” once and then nothing would be the behavior I’d expect.
If you want to continuously send data, you have to do that in the loop() method.

1 Like

Hi, Not sure of what you are doing, but Here is some arduino and xojo code that works well for me.

Basically if you have a serial connection the dataAvailable event will fire on the XOJO device.

This is from a windows machine to arduino. I hope this helps and gives you some ideas.

This code is in the DataAvailable event of a XOJO Serial control. It is triggered whenever there is code available at the serial port. I have a button to stop and start the communication process. I change the label to Stop after I press Start. The serial data received is output to a text area.

if btnStartStop.Caption = "Stop" then
  dim RxData as String
  
  while me.BytesAvailable > 0 
    RxData = RxData + me.readall
    me.poll
  wend
  OutputArea.AppendText(RxData)
End if

This is code in the arduino sketch. I send a string that contains setup information for this particular device.

static void serialReader()
{
	String serialInputString = "";

	while (Serial.available())
	{
		// get the new byte:
		char inChar = (char)Serial.read();
		// add it to the serialInputString:
		serialInputString += inChar;

		if (inChar == ']')
		{
			stringComplete = true;
			parseSerialInputString(serialInputString);
		}
	}
}

I call serialReader() from the setup loop. I first check to see if there is a byte in the EEPROM that indicates if this device has been set up. If not the setup process proceeds.

	while (!Serial)
		{
			// wait for serial port to connect. Needed for native USB port only
		}

		AppPrtLn(F("Begin setup..."));
		setupProcess();

		while (!uploadSuccessful) //check eeprom if device not setup do it
		{
			if (suLoop > 0)
			{
				serialReader();
			}
			else
			{
				AppPrtLn(F("Setup not Complete"));
				delay(20000);
			}
		}

i advise to collect all data (global) and then process this block and truncate it.
because the data comes in nibbles.
be aware that serial data can arrive corrupt, usually at higher transfer rate.

Well then if you have a serial connection between the equipment when the arduino sends the data, the dataAvailable event on the xojo device should fire. You can then collect it and parse it accordingly.

When the DataAvailable event fires, you may have a complete message, a partial message, or the end of one message and the beginning of another. You cannot assume that DataAvailable contains a single, discrete message.

1 Like

My structure for this sort of data (arriving in this bitty fashion) involves an intermediate buffer. The app and its data are line based, and the app needs to have a complete line (terminated by some sort of end-of-line) to process. So it asks for one. My get-a-line method then looks in the intermediate buffer for bytes, one by one, until it has a complete line it can return to the app. If it runs out of bytes while doing this, it (being in a thread), pauses itself until resumed by the DataAvailable event. It then does a single ReadAll to get any data that’s waiting and continues trying to assemble a complete line to return to the app. When it has that, it returns it.

Thus the parts of the app that need a line to process are insulated from how and in what fragments the data actually arrives.

One needs to:

  1. understand how trhe data actually arrives
  2. understand what the app’s needs are for data
  3. create a structure that marries these up.
  4. only then write some code to implement it.

Aren’t you controlling how the data is sent from the arduino device?

Yes, but you aren’t controlling how the data arrives in Xojo.

Sorry, I guess I don’t understand. It seems like you should be able to send the data formatted with a start character and an end character, send it in xml or json format, or alternately send a request for the data from the xojo device.

Whether you’re controlling how the data is sent is not the issue. As @Tim_Hare said, the data may arrive in bits as he described. That is outside your control. What you have to do is to work out how to deal with it. My data comes/goes via sockets rather than serial connections, but as soon as I understood how it may arrive, was when I sat down and worked out how to deal with it, as I described. Sending it in XML or JSON is not the issue.