Из string в int, проблема

Я создаю приложения для компьютера, которые будут использоваться для управления манипулятором робота. Я хотел сделать первую попытку запустить приложение не на моторе, а на диоде и проверить, будет ли он менять свою яркость в зависимости от положения ползунка. Я написал приложение на Qt, которое отправляет стринги в Arduino, а Arduino я читаю и преобразовываю в int. Проблема в том, что хотя ползунок установлен на 0, Arduino не показывает это, часто цифры не совпадают слишком часто (часто слишком малы), также когда я внезапно перемещаю ползунок числа, все время считаю вперед, а не назад.

Код Arduino:

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:

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!");
   }
}

, 👍0

Обсуждение

Serial.readString() глубоко ошибочен, и его следует избегать. Прочтите это: https://majenko.co.uk/blog/reading-serial-arduino, @Majenko

И я *уверен*, что вы хотели добавить \n к своим исходящим сообщениям, а не n..., @Majenko

при отладке такой проблемы, как ваша, поставьте Serial.println(br); перед analogWrite(), чтобы увидеть, что было получено, @jsotola


1 ответ


Лучший ответ:

1

Как написал Маженко в своем комментарии, ваша проблема связана с Serial.readString(). Как правило, это не лучший способ обработки последовательных данных. Он считывает данные из последовательного интерфейса до тех пор, пока не истечет время ожидания (по умолчанию 1 с). Таким образом, он попытается прочитать до 1 секунды после вашего последнего изменения ползунка и вернет все данные в виде одной строки. Затем String.toInt() начнет считывать строку с первого символа и преобразовывать их в целое число, пока не будет прочитан нецифровой символ (имеется в виду n, которые вы отправляете). На этом он останавливается и возвращает уже преобразованное значение.

Это означает, что из всех данных, отправленных на Arduino, будет использоваться только первое значение. Остальные выбрасываются.

Лучше использовать неблокирующий код, который правильно обрабатывает сообщения (цифры в вашем случае). Это делается путем чтения входящих последовательных данных байт за байтом, добавления их в буфер, пока не будет получен специальный символ-разделитель. Затем сообщение обрабатывается как единое целое. После этого следующее сообщение может быть прочитано и обработано. Таким образом, вы не пропустите ни одно из отправленных значений.

Специальный символ-разделитель является произвольным; вы можете использовать любой символ, который не встречается в допустимых данных. Поэтому использование символа n здесь допустимо. Но в основном используется символ новой строки \n, так что вы также можете отправлять сообщения с буквенно-цифровыми символами. Скорее всего, вы уже хотели использовать \n.

В качестве примера этого последовательного кода вы можете взять функцию readline() из Сообщение в блоге Маженко:

char buf[80];

int readline(int readch, char *buffer, int len) {
    static int pos = 0;
    int rpos;

    if (readch > 0) {
        switch (readch) {
            case '\r': // Игнорировать CR
                break;
            case '\n': // Возврат на новую строку
                rpos = pos;
                pos = 0;  // Сбросить индекс позиции, готовый к следующему разу
                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("<");
    }
}

Вы можете преобразовать символьный буфер в тип int с помощью atoi() в операторе if в void loop() и использовать его для ´analogWrite()`.

,