Jeg opretter applikationer til en computer, der skal bruges til at styre robotarmen. Jeg ville gøre det første forsøg på at køre applikationen ikke på motoren, men på dioden og kontrollere, om den vil ændre dens lysstyrke afhængigt af skyderen. Jeg skrev en ansøgning i Qt, der sender remme til Arduino, og Arduino læser jeg og konverterer til int. Problemet er, at selvom skyderen er indstillet til 0, viser Arduino det ikke, ofte er tallene ikke enige for ofte (ofte for små), også når jeg pludselig flytter talskyderen hele tiden tæller fremad i stedet for tilbage.
Arduino-kode:
String br; void setup() { Serial.begin(9600); pinMode(9, OUTPUT); } void loop() { while (Serial.available()>0) { br = Serial.readString(); analogWrite(9, br.toInt()); Serial.println(br.toInt()); } }
Qt-kode:
void MainWindow::on_horizontalSliderGrip_sliderMoved(int position) { this->sendMessageToDevice(QString::number(position) + "n"); qDebug() << "Grip: " << QString::number(position); } void MainWindow::sendMessageToDevice(QString message) { if(this->device->isOpen() && this->device->isWritable()) { //this->addToLogs("Sending information to the device " + message); this->device->write(message.toStdString().c_str()); } else { this->addToLogs("I can not send a message. The port is not open!"); } }
Kommentarer
- Serial.readString () er meget mangelfuld og bør undgås. Læs dette: majenko.co.uk/blog/reading-serial-arduino
- Og jeg er sikker du mente at føje
\n
til dine udgående meddelelser, ikken
… - når du fejler et problem som f.eks. din sæt
Serial.println(br);
forananalogWrite()
for at se, hvad der modtages
Svar
Som Majenko skrev i sin kommentar, ligger dit problem med Serial.readString()
. Det er generelt ikke en god måde at håndtere serielle data på. Den læser data fra den serielle grænseflade, indtil timeout (standard 1s) opstår. Så det vil prøve at læse indtil 1 sekund efter din sidste ændring af skyderen og returnere hele dataene som en streng. String.toInt()
begynder derefter at læse strengen fra det første tegn og konvertere dem til et heltal, indtil den læser et ikke-cifret tegn (hvilket betyder n
, som du sender). Det stopper der og returnerer den allerede konverterede værdi.
Dette betyder, at ud af alle de data, der blev sendt til Arduino, vil kun den første værdi blive brugt. Resten smides væk.
Bedre, du skal bruge en ikke-blokerende kode, der håndterer meddelelserne (numre i dit tilfælde) korrekt. Dette gøres ved at læse de indgående serielle data byte for byte, tilføje dem i en buffer, indtil et specielt skilletegn modtages. Derefter bliver beskeden behandlet som en helhed. Derefter kan den næste besked læses og behandles. På denne måde går du ikke glip af nogen af sendværdierne.
Det specielle skilletegn er vilkårligt; du kan bruge ethvert tegn, der ikke forekommer i de gyldige data. Så det er ok at bruge tegnet n
. Men for det meste bruges den nye linjetegn \n
, så du også kan sende meddelelser med alfanumeriske tegn. Mest sandsynligt mente du allerede at bruge \n
.
Som et eksempel på denne serielle kode kan du tage readline()
funktion fra Majenkos blogindlæg :
char buf[80]; int readline(int readch, char *buffer, int len) { static int pos = 0; int rpos; if (readch > 0) { switch (readch) { case "\r": // Ignore CR break; case "\n": // Return on new-line rpos = pos; pos = 0; // Reset position index ready for next time return rpos; default: if (pos < len-1) { buffer[pos++] = readch; buffer[pos] = 0; } } } return 0; } void setup() { Serial.begin(115200); } void loop() { if (readline(Serial.read(), buf, 80) > 0) { Serial.print("You entered: >"); Serial.print(buf); Serial.println("<"); } }
Du kan konvertere tegnbufferen til en int med atoi()
i if-sætningen i void loop()
og brug den til ´analogWrite () `.