Why does the string output from Arduino look like alien text? - string

I'm trying to set up a serial communication between Arduino and MATLAB over USB. I have this basic code where I'm sending "hello" from MATLAB to Arduino, and I read it back and print it in MATLAB. However, the "hello" sent from Arduino looks like a strange text.
Arduino:
void setup() {
Serial.begin(57600);
Serial.println("ready");
}
void loop() {
String input;
if (Serial.available()) {
char c = Serial.read();
while (c != '\n') {
input += c;
c = Serial.read();
}
Serial.println("I received: " + String(input));
input = "";
}
}
MATLAB:
s = serial('COM3');
set(s, 'BaudRate', 57600);
fopen(s);
pause(1);
first = strtrim(convertCharsToStrings(fgetl(s)));
if first == "ready"
fprintf(s, '%s', 'hello\n');
for i = 1:10
tline = strtrim(convertCharsToStrings(fgetl(s)));
disp(tline);
if size(tline, 2) > 0
fprintf(s, '%s', 'hello\n');
end
end
end
fclose(s);
The output in MATLAB looks like this:
I received: hÿÿÿÿÿÿeÿÿÿÿÿÿÿlÿÿÿÿÿÿÿÿlÿÿÿÿÿÿoÿÿÿÿÿÿÿ
Also, I would appreciate any constructive criticism on improving my code for serial communication. This is my first time, and I'm trying to get a simple setup in which Arduino and MATLAB take turns writing and reading. Thank you.

Your microcontroller code reads faster than you're physically sending characters, so you're reading from an empty buffer. Serial.available() has one char for you, you read it, then you read more chars even though the receive buffer is already empty. Serial.read() will return -1 when there's nothing to read. -1 cast to char is 0xFF, or in Ascii 'ÿ'.
You could change loop() to something like
void loop() {
String input;
while (Serial.available()) {
char c = Serial.read();
if (c != '\n') {
input += c;
} else {
Serial.println("I received: " + String(input));
input = "";
}
}
}
Or you could go with Arduino's Serial.readString():
void setup() {
Serial.begin(57600);
Serial.setTimeout(20);
Serial.println("ready");
}
void loop() {
String input = Serial.readString();
Serial.println("I received: " + input);
}
Both untested, but you get the idea.

Related

Arduino - unable to connect to wifi

I have this (partial) code, that is used to read the ssid and password from a text file on a SD card.
This data should then be used to connect to the local wifi. But it is unable to connect, and keeps saying "Establishing connection to WiFi..."
I also dont seem to be able to print what I have read from the SD card. Previously my readline function returned a string. That I was able to print properly and verified that the file is read as expected. Then, since wifi requires a Char* I changed the code to Char* and since then it didnt work anymore:
#include <SD.h>
#include <AccelStepper.h>
#include <MultiStepper.h>
#include <WiFi.h>
File myFile;
char* ssid;
char* password;
void setup() {
// put your setup code here, to run once:
pinMode(thetaPos, INPUT);
pinMode(rhoPos, INPUT);
Serial.begin(115200);
Serial.print("Initializing SD card...");
if (!SD.begin()) {
Serial.println("initialization failed!");
while (1);
}
Serial.println("initialization done.");
myFile = SD.open("/config.txt");
if (myFile) {
// read from the file until there's nothing else in it:
ssid = readLine();
password = readLine();
Serial.println(ssid);
Serial.println(password);
connectToNetwork();
// close the file:
myFile.close();
} else {
// file didn't open
}
}
void loop() {
}
char* readLine() {
char* received = "";
char ch;
while (myFile.available()) {
ch = myFile.read();
if (ch == '\n') {
return received;
} else {
received += ch;
}
}
return received;
}
void connectToNetwork() {
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Establishing connection to WiFi..");
}
Serial.println("Connected to network");
}
what am I doing wrong?
this is the serial output:
Initializing SD card...initialization done.
ore calibration nvs commit failed(0x%x)
wdt_config->intr_handle)
Establishing connection to WiFi..
Establishing connection to WiFi..
Establishing connection to WiFi..
Establishing connection to WiFi..
Well, where is the error? This won't work as you hope:
char* readLine() {
char* received = ""; // poiner to \0 somewhere...
char ch;
while (myFile.available()) {
ch = myFile.read();
if (ch == '\n') {
return received;
} else {
received += ch; // move pointer to location ch bytes after...
}
}
return received;
}
You are utilizing pointer arithmetic - you are moving pointer around the memory and you are not storing anything anywhere. It's not String class that overloads += char and allows you to concatenate character to the end of it.
Basically you can use:
String readLine() {
String received;
while (myFile.available()) {
ch = myFile.read();
if (ch == '\n') {
return received;
} else {
received += ch;
}
}
return received;
}
and it'll work (althrough it's not a good idea to append character by character to the String - heap memory gets fragmented really fast by this approach)
To avoid other mistakes, usage is something like:
String ssid = readLine();
String pass = readLine();
Wifi.begin(ssid.c_str(), pass.c_str());
//// definitely do not do something like:
// Wifi.begin(readLine().c_str(), readLine().c_str()); // !!! WRONG !!!
//// as the order of executing parameters isn't specified (and in the GCC it's from the last to the first)

Arduino bitRead() outputing binary number using LED

I am now trying to have my Arduino Uno to output a binary number sent from my mobile phone through bluetooth. The mobile phone would be sending an integer to the Arduino. Hopefully the Arduino converts the integer into binary and turning on corresponding LED. 4 LEDs are used to represent the binary number. However, the LED just flashes once or all the LED turn on when I input a number. Here is my code:
int li1;
const byte numPins = 4;
int pins[] = {10,11,12,13};
void setup () {
Serial.begin(19200);
pinMode(10,OUTPUT);
pinMode(11,OUTPUT);
pinMode(12,OUTPUT);
pinMode(13,OUTPUT);
}
void loop() {
while(!Serial.available());
li1 = Serial.read();
for (byte i=0; i<numPins; i++) {
byte temp = bitRead(li1, i);
digitalWrite(pins[i],temp);
}
}
li1 is the variable I get from the mobile phone.
Thank you for helping.
Probably not the answer, but do not have enough reputation to leave a comment.
Try setting a sleep after you write the bytes in case its going away to quick.
int li1;
const byte numPins = 4;
int pins[] = {10,11,12,13};
void setup () {
Serial.begin(19200);
pinMode(10,OUTPUT);
pinMode(11,OUTPUT);
pinMode(12,OUTPUT);
pinMode(13,OUTPUT);
}
void loop() {
while(!Serial.available());
li1 = Serial.read();
for (byte i=0; i<numPins; i++) {
byte temp = bitRead(li1, i);
digitalWrite(pins[i],temp);
delay(4000);
}
}

String converted when I send it in a structure with RF24 library

I'm sending a data struct with the RF24 library from one node to another. This structure contains two string and one float.
When I send the structure with the transmitter and I print it to the serial output I get this:
El sensor PIR situat en Menjador te el valor 1.00
I see this in the receiver when I print it to the serial output:
El sensor œ>U situat en Üߧŋ>r te el valor 1.00
Why are the two String changed ("PIR" and "Menjador")?
The structure is this:
struct sensorData {
String sensorType;
String sensorLocation;
float sensorValue;
} PIR1, sensor;
This is how I write it to the radio:
radio.write( &PIR1, sizeof(PIR1) ));
This is how I read it from the radio:
radio.read( &sensor, sizeof(sensor));
And this is how I print it to the serial output in the receiver:
void printOutData(sensorData* data) {
Serial.print("El sensor ");
Serial.print(data->sensorType);
Serial.print(" situat en ");
Serial.print(data->sensorLocation);
Serial.print(" te el valor ");
Serial.println(data->sensorValue);
}
Thank you!!
The String type does not actually contain the bytes of the sensor type and location; it points to the bytes. You are bascially sending the memory address of those bytes, not the bytes themselves.
You need to change your data structure so that it can contain the bytes inside the structure, with "C strings" aka "char arrays":
static const uint8_t SENSOR_TYPE_SIZE = 4;
static const uint8_t SENSOR_LOC_SIZE = 12;
struct sensorData {
char sensorType[ SENSOR_TYPE_SIZE ];
char sensorLocation[ SENSOR_LOC_SIZE ];
float sensorValue;
} PIR1, sensor;
Of course, you will have to change how you set those member values. Without your complete sketch, I can only offer a few possibilities:
void setup()
{
Serial.begin( 9600 );
// Set to a constant value (i.e., a double-quoted string literal)
strncpy( PIR1.sensorType, "TMP", sizeof(PIR.sensorType)-1 );
PIR1.sensorType[ sizeof(PIR.sensorType)-1 ] = '\0'; // NUL-terminate
// Set to characters received over Serial, up to size-1 chars *or* a newline
// (This blocks until the line is entered! Nothing else will happen
// until the line has been completely received.)
size_t count = Serial.readBytesUntil( '\n', PIR1.sensorType, sizeof(PIR.sensorType)-1 );
PIR.sensorType[ count ] = '\0'; // NUL-terminate
}
void loop()
{
// Non-blocking receive of a line. Other things can be performed
// while we're waiting for the newline to arrive.
if (Serial.available()) {
// A char finally came in!
char c = Serial.read();
// end-of-line?
if (c == '\n') {
// Pressed ENTER, send what we have now
PIR.sensorLocation[ count ] = '\0'; // NUL-terminate the C string
radio.write( &PIR1, sizeof(PIR1) ));
// Reset for next time
count = 0;
} else { // not end-of-line, save another char (if there's room)
if (count < sizeof(PIR.sensorLocation)-1) {
PIR.sensorLocation[ count++ ] = c;
}
}
}
// Do some other things here... maybe check some buttons?
}
There are many reasons to avoid String, so switching to char arrays will actually pay off in the long run.

Echo Serial Strings with Arduino

EDIT 2: I got the solution. Anytime someone wants the code I'd be happy to provide. Peace.
Topic:
I'm trying an experiment of echoing strings that I receive in my arduino.
So this is the code so far:
byte byteRead = 0;
bool readable = LOW;
char fullString[50];
int index = 0;
void setup() {
Serial.begin(9600);
}
void loop() {
// State 1
if (Serial.available()) {
readable = HIGH; // flag to enter in the next state when there's nothing else to read
byteRead = Serial.read();
fullString[index] = (char)byteRead;
index++;
}
// State 2
if (readable == HIGH && !Serial.available()){
fullString[index] = '\0'; // '\0' to terminate the string
Serial.println(fullString);
// resets variables
index = 0;
readable = LOW;
}
/**
* Somehow a delay prevents characters of the string from having
* a line printed between them.
* Anyways, when the string is too long, a line is printed between
* the first and second characters
*/
delay(5);
}
Somehow this delay in the end prevents the characters of the string from having a line printed between them, like this:
H
e
l
l
o
Nonetheless, when the string is too long, a line is printed between the first and second characters.
Do you know a better way of doing this?
EDIT: Next time I'd appreciate answers from someone who actually KNOWS programming. Not just condescending idiots.
that's my String Echo
#define MAX_BUFFER_SIZE 0xFF
char buffer[MAX_BUFFER_SIZE];
void setup() {
Serial.begin(115200);
buffer[0] = '\0';
}
void loop() {
while (Serial.available() > 0) {
char incomingByte;
size_t i = 0;
do {
incomingByte = Serial.read();
buffer[i++] = incomingByte;
} while (incomingByte != '\0' && i < MAX_BUFFER_SIZE);
if(i > 0){
delay(1000); /// delay for the echo
Serial.write(buffer, i);
}
}
}
You want to echo the string read, so just echo the input.
void setup() {
Serial.begin(9600);
}
void loop() {
int c = Serial.read();
if (c >= 0) Serial.write(c);
}

How to read a string value with a delimiter on Arduino?

I have to manage servos from a computer.
So I have to send manage messages from computer to Arduino. I need manage the number of servo and the corner. I'm thinking of sendin something like this : "1;130" (first servo and corner 130, delimeter ";").
Are there any better methods to accomplish this?
Here is my this code :
String foo = "";
void setup(){
Serial.begin(9600);
}
void loop(){
readSignalFromComp();
}
void readSignalFromComp() {
if (Serial.available() > 0)
foo = '';
while (Serial.available() > 0){
foo += Serial.read();
}
if (!foo.equals(""))
Serial.print(foo);
}
This doesn't work. What's the problem?
You can use Serial.readString() and Serial.readStringUntil() to parse
strings from Serial on arduino
You can also use Serial.parseInt() to read integer values from serial
Code Example
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
Note: Serial.available() inherits from the Stream utility class.
https://www.arduino.cc/reference/en/language/functions/communication/serial/available/
This is a Great sub I found. This was super helpful and I hope it will be to you as well.
This is the method that calls the sub.
String xval = getValue(myString, ':', 0);
This is The sub!
String getValue(String data, char separator, int index)
{
int found = 0;
int strIndex[] = {
0, -1 };
int maxIndex = data.length()-1;
for(int i=0; i<=maxIndex && found<=index; i++){
if(data.charAt(i)==separator || i==maxIndex){
found++;
strIndex[0] = strIndex[1]+1;
strIndex[1] = (i == maxIndex) ? i+1 : i;
}
}
return found>index ? data.substring(strIndex[0], strIndex[1]) : "";
}
Most of the other answers are either very verbose or very general, so I thought I'd give an example of how it can be done with your specific example using the Arduino libraries:
You can use the method Serial.readStringUntil to read until your delimiter from the Serial port.
And then use toInt to convert the string to an integer.
So for a full example:
void loop()
{
if (Serial.available() > 0)
{
// First read the string until the ';' in your example
// "1;130" this would read the "1" as a String
String servo_str = Serial.readStringUntil(';');
// But since we want it as an integer we parse it.
int servo = servo_str.toInt();
// We now have "130\n" left in the Serial buffer, so we read that.
// The end of line character '\n' or '\r\n' is sent over the serial
// terminal to signify the end of line, so we can read the
// remaining buffer until we find that.
String corner_str = Serial.readStringUntil('\n');
// And again parse that as an int.
int corner = corner_str.toInt();
// Do something awesome!
}
}
Of course we can simplify this a bit:
void loop()
{
if (Serial.available() > 0)
{
int servo = Serial.readStringUntil(';').toInt();
int corner = Serial.readStringUntil('\n').toInt();
// Do something awesome!
}
}
You need to build a read buffer, and calculate where your 2 fields (servo #, and corner) start and end. Then you can read them in, and convert the characters into Integers to use in the rest of your code. Something like this should work (not tested on Arduino, but standard C):
void loop()
{
int pos = 0; // position in read buffer
int servoNumber = 0; // your first field of message
int corner = 0; // second field of message
int cornerStartPos = 0; // starting offset of corner in string
char buffer[32];
// send data only when you receive data:
while (Serial.available() > 0)
{
// read the incoming byte:
char inByte = Serial.read();
// add to our read buffer
buffer[pos++] = inByte;
// check for delimiter
if (itoa(inByte) == ';')
{
cornerStartPos = pos;
buffer[pos-1] = 0;
servoNumber = atoi(buffer);
printf("Servo num: %d", servoNumber);
}
}
else
{
buffer[pos++] = 0; // delimit
corner = atoi((char*)(buffer+cornerStartPos));
printf("Corner: %d", corner);
}
}
It looks like you just need to correct
foo = ''; >>to>> foo = "";
foo += Serial.read(); >>to>> foo += char(Serial.read());
I made also shomething similar..:
void loop(){
while (myExp == "") {
myExp = myReadSerialStr();
delay(100);
}
}
String myReadSerialStr() {
String str = "";
while (Serial.available () > 0) {
str += char(Serial.read ());
}
return str;
}
This code reads string until it sees '>' character
void loop() {
// put your main code here, to run repeatedly:
String msg = getMessage();
}
String getMessage() {
String msg = "";
while (Serial.available()>0) {
msg = Serial.readStringUntil('>');
}
return msg;
}
It's universal parser
struct servo
{
int iServoID;
int iAngle;
};
std::vector<std::string> split(const std::string& str, const std::string& delim)
{
std::vector<std::string> tokens;
size_t prev = 0, pos = 0;
do
{
pos = str.find(delim, prev);
if (pos == std::string::npos) pos = str.length();
std::string token = str.substr(prev, pos-prev);
if (!token.empty()) tokens.push_back(token);
prev = pos + delim.length();
}
while (pos < str.length() && prev < str.length());
return tokens;
}
std::vector<servo> getServoValues(const std::string& message)
{
std::vector<servo> servoList;
servo servoValue;
std::vector<std::string> servoString;
std::vector<std::string> values = split(message, ",");
for (const auto& v : values)
{
servoString.clear();
servoString = split(v, ";");
servoValue.iServoID = atoi(servoString[0].c_str()); //servoString[0].toInt();
servoValue.iAngle = atoi(servoString[1].c_str());// servoString[1].toInt();
servoList.emplace_back(servoValue);
}
return servoList;
}
to call:
std::string str = "1;233,2;123";
std::vector<servo> servos = getServoValues(str);
for (const auto & a : servos)
std::cout<<a.iServoID << " " << a.iAngle << std::endl;
Result
1 233
2 123

Resources