Arduino LM35 Sensor über Serial an GUI Software Qt

Hallo Forum,

ich versuche gerade die gesendete Daten vom Arduino in meiner Software (mit Qt geschrieben) zu verarbeiten und diese in eine Datenbank zu schreiben (MySQL).
Nun zu meinem kleinen Testprogramm:

int LM35 = A0;
float SensorValue = 0;
float temperatur = 0;

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

void loop() {
SensorValue = analogRead(LM35);
temperatur = (5.0 * analogRead(LM35) * 100.0) / 1024;
Serial.print(temperatur,1);
delay(1000);
}

ich schicke mir ständig (alle 1000ms) den Wert als float (4 Byte).
Nur das Programm gibt mir Folgendes im qDebug aus:

MyThread: “24.9”
MyThread: “24”
MyThread: “.9”
MyThread: “24.9”
MyThread: “24.”
MyThread: “9”
MyThread: “2”
MyThread: “4.9”
MyThread: “24.9”
MyThread: “24”
MyThread: “.9”
MyThread: “24.9”

Gelöst habe ich es (nicht schön zumindest und auch nicht ganz richtig):

    while(1)
        {
            if(serial.bytesAvailable() > 0 ||serial.waitForReadyRead(10))
            {
                QByteArray reading;
                reading = serial.readAll();
                serial.write(reading);
     
                qDebug() << reading.size();
     
                QMutex mutex;
                mutex.lock();
                if(this->Stop)
                {
                    break;
                }
                mutex.unlock();
     
                if(reading.size() == 4) //das ist nur solange richtig wenn es über 10 Grad ist
                    emit serialReading(reading);
     
                //this->msleep(1000);
     
     
            }
        }

Wie kann ich in der Software sagen ließ mir nur die ersten 4 Byte´s ein? Oder schickt mir Arduino nicht 4 Byte sondern was anderes?
Hoffe mir kann vielleicht einer helfen?

Gruß

Alex

Wenn du das so machst, schickst du einen C String. Also ASCII

Um einen Float Wert Binär zu schicken musst du glaube ich das machen:

Serial.write((byte*)&temperatur, 4);

Also die Adresse des Floats nehmen und auf einen Zeiger auf Byte casten. Damit werden die 4 Bytes praktisch als Array angesprochen- Dann write() statt print() nehmen und die Länge in Bytes als 2. Parameter angeben.

Serenifly:
Wenn du das so machst, schickst du einen C String. Also ASCII

Um einen Float Wert Binär zu schicken musst du glaube ich das machen:

Serial.write((byte*)&temperatur, 4);

Also die Adresse des Floats nehmen und auf einen Zeiger auf Byte casten. Damit werden die 4 Bytes praktisch als Array angesprochen- Dann write() statt print() nehmen und die Länge in Bytes als 2. Parameter angeben.

Ich werde das mal ausprobieren. Die "4" nach "&temperatur" gibt mir die Byte größe an? Sehe ich das richtig?

Gruß

Ja. Siehe hier:

Serial.write(buf, len)

Arrays sind in C keine komplexen Datentypen, sondern nur Zeiger. Deshalb muss man an Funktionen die Arrays verarbeiten auch die Länge übergeben.

Byte Array nach Float geht übrigens so, falls du das in Qt brauchst:

unsigned char data[4];
...
float f = *(float*)data;

Und dazwischen natürlich mal irgendwas in das Array schreiben

Nimm openHAB und diesen Sketch:
http://www.mikrocontroller.net/articles/Evaluations-Platine_für_Heimautomatisierung

Ganz unten sind die Dateien.

Mein Testprojekt hab ich jetzt folgendermaßen abgeändert:

int LM35 = A0;
float SensorValue = 0;
float temperatur = 0;

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

void loop() {
SensorValue = analogRead(LM35);
temperatur = (5.0 * analogRead(LM35) * 100.0) / 1024;
Serial.write((byte*)&temperatur, 4);
delay(1000);
}

Nun bekomme ich über TeraTerm hieroglyphen :smiley: also den richtigen wert.
Bei Qt macht es mir etwas mehr Probleme.
Hab es mal so probiert:

QByteArray reading = serial.readAll();
            serial.write(reading);
            float f = reading.toFloat();
            qDebug() << f;
Nimm openHAB und diesen Sketch:
http://www.mikrocontroller.net/articles/Evaluations-Platine_f%C3%BCr_Heimautomatisierung

Ganz unten sind die Dateien.

Soll nicht böse gemeint sein aber bleibe lieber bei Qt da ich mich soweit schon zurecht finde. Nur mit Serial Verbindungen habe ich noch nichts gemacht. Ist schon neu für mich.

openHAB hat alle möglichen Verbindungen.
Schau kurz in die Wiki rein, Bindings · openhab/openhab1-addons Wiki · GitHub
Binding=Addon
Läuft auch auf der Fritzbox.

Hast du mal getestet ob in deinem Array die richtige Wert stehen? Also mal Debugger oder über das Array iterieren und alle 4 Bytes ausgeben. Du kannst auch einfach mal einen festen Float Wert nehmen, diesen als Byte Array ansprechen und ausgeben. Dann kannst du vergleichen.

Dein Problem kann das hier sein:

serial.bytesAvailable() > 0

Die serielle Schnittstelle ist sehr langsam. Bei 9600 Bytes dauert ein Zeichen ca. 1ms!! Wenn du also abfragst ob ein Byte da ist, sind die restlichen noch unterwegs.

Wenn du 4 Bytes erwartest, solltest du auch warten bis 4 Bytes da sind und noch schon nach dem ersten Byte alles einlesen.

Lass mir jetzt mal probehalber immer 32.2 schicken als festen Wert um zu schauen was dabei heraus kommt.
Welche Baudrate kann ich noch nehmen?
Werde mal die if Abfrage nochmal überarbeiten.

Danke schonmal für die Hilfe.

Gruss

Mit der Baudrate sollte eigentlich alles übliche gehen. Auf dem PC gehen meistens sogar Baudraten über 115200 wie 250000. Wobei das bei dir nicht nötig ist.

Das Problem geht dabei aber so oder so nicht weg. Selbst wenn ein Zeichen nur ein paar Dutzend µs braucht, ist das für einen Prozessor eine lange Zeit.

Mein Code in der Software sieht wie folgt aus:

if(serial.bytesAvailable() == 4 ||serial.waitForReadyRead(10))
        {
            QByteArray reading = serial.readAll();
            serial.write(reading);
            qDebug() << reading.size();
            qDebug() << reading;
            qDebug() << reading.toFloat();
            bool ok;
            float f = reading.toFloat(&ok);
            qDebug()<<f;

Und im Arduino Nano:

float temperatur = 27.8;

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

void loop() {
Serial.write((byte*)&temperatur, 4);
delay(1000);

}

Arduino gibt folgendes aus:

ffÞA

Und Debug vom Programm:

4 
"ff?A" 
0 
0 
0 
4 
"ff?A" 
0 
0 
0 
3 
"ff?" 
0 
0 
0 
1 
"A" 
0 
0 
0 
4 
"ff?A" 
0 
0 
0 
2 
"ff" 
0 
0

Irgendwo mag er das nicht :relaxed:

Okay jetzt hab ich es das er die Zahl richtig umwandelt:

if(serial.bytesAvailable() == 4 ||serial.waitForReadyRead(10))
        {
            QByteArray reading = serial.readAll();
            serial.write(reading);
            char *data = reading.data();
            float f = *(float*)data;
            qDebug() << data << " " << f;

Aber beim einlesen mit den Byte´s ist es noch nicht ganz richtig wie ich möchte:

ff?A   27.8 
0 
ff?A   27.8 
0 
ff?A   27.8 
0 
ff?   2.04242e-38 
0 
A   9.10844e-44 
0 
ff?A   27.8

Mit Qt im speziellen kenne ich mich nicht aus. Daher kann ich nicht sagen was die Qt Funktionen im Detail machen.

char *data = reading.data();

Das sollte unsigned char sein. Char lässt negative Zahlen zu. Wobei das hier nicht unbedingt einen Fehler verursacht.

Wenn man die 4 Bytes von 27.8 für sich ausgibt sollte folgendes rauskommen:
102
102
222
65

Um den Inhalt von Arrays bequem byte-weise auszugeben kannst du das machen:

void printArray(void* data, unsigned int size)
{
	unsigned char* ptr = (unsigned char*)data;
	for(unsigned int i = 0; i < size; i++)
		  qDebug() << (int)ptr[i] << " ";
}

Sowas sollte zum Einlesen auch gehen:

unsigned char data[4];
data[0] = serial.readByte();  ///weiß nicht ob es das so gibt, aber ein Byte lesen sollte irgendwie möglich sein
data[1] = serial.readByte();
data[2] = serial.readByte();
data[3] = serial.readByte();

float f = *(float*)data;

Das sollte unsigned char sein. Char lässt negative Zahlen zu. Wobei das hier nicht unbedingt einen Fehler verursacht.

Negative Zahlen brauche ich falls es im Winter unter 0 Grad fallen sollte. Also wäre es in dem Fall richtig?
Ein read.Byte gibt es leider nicht :frowning:

Negative Zahlen für float natürlich. Aber nicht für die eingelesenen Bytes. Aber wie gesagt, macht das hier glaube ich keinen Unterschied. Funktionen wie read() verwenden da auch char* statt unsigned char*

Wenn das die verwendete Serial Klasse ist:
http://qt-project.org/doc/qt-5/qserialport.html

Kann man readData() verwenden um eine eine bestimmte Anzahl an Bytes zu lesen:
http://qt-project.org/doc/qt-5/qiodevice.html#readData

Sicherer ist es dann auch wenn du bei serial.bytesAvailable() auf >= 4 abfragst, statt auf == 4

Das ist aber auch nur die maximale Anzahl. Wenn weniger da ist, liest er auch weniger. Und ein paar Posts weiter oben hat reading.size() anscheinend nicht immer 4 geliefert obwohl du gewartet hast bis 4 Bytes da waren. Das ist etwas seltsam

Wenn das die verwendete Serial Klasse ist:
http://qt-project.org/doc/qt-5/qserialport.html

Kann man readData() verwenden um eine eine bestimmte Anzahl an Bytes zu lesen:
http://qt-project.org/doc/qt-5/qiodevice.html#readData

ja das ist die klasse, aber was gebe ich als "qint64 maxSize" an? Das versteh ich jetzt leider nicht ganz :frowning:

  1. Du willst ja 4 Bytes in das Array schreiben und dass dann in einen Float wandeln.

Sorry aber jetzt blicke ich gar nicht mehr durch...entweder liegt es an der Uhrzeit oder ich kapier es wirklich gerade nicht :frowning:
sorry

if(serial.bytesAvailable() >= 4)
{
    unsigned char data[4];
    serial.readData(data, 4);
}

Vier Bytes in ein Array einlesen....

Ich weiß aber gar nicht ob es daran liegt. Es könnte das gleiche rauskommen. Theoretisch sollte das auch mit der Qt Abstraktion über QByteArray gehen.

Du kannst auch den Rückgabewert abfragen. Der sagt dir wie viele Bytes tatsächlich gelesen wurden.