Как отправить переменные, не являющиеся символами через Serial

Я пытаюсь создать графический интерфейс, который отправляет данные из обработки в arduino через последовательный интерфейс. С помощью пары ребят я придумал базовую структуру, которая отправляет идентификатор переменной, значение переменной и символ завершения (\n). Пока все так хорошо!

Однако [arduino reference][1] советует использовать char только для хранения символов. Как бы я отправил байт или int по последовательному каналу, все еще имея возможность использовать символ завершения, чтобы убедиться, что все работает так, как ожидалось?

правка: Используя код arduino из ответа Эдгара ниже и следующий код обработки, я получаю ошибку "не удалось разобрать значение".

import processing.serial.*;

SerialConnection serialConnection;

boolean data_processed = false;
char[] var_array = new char[31];
char var_id;
char var_val;
char space = ' ';
char termchar = '\n';

void setup() {
  serialConnection = new SerialConnection(this, 9600);
}

void draw() {
  serialConnection.startSerialCommunication();

  if (serialConnection.isReady) {
    var_id = 'a';
    var_val = 127;
    serialConnection.serialPort.write(var_id);
    serialConnection.serialPort.write(space);
    serialConnection.serialPort.write(var_val);
    serialConnection.serialPort.write(termchar);

    delay(50);
    while (serialConnection.serialPort.available() > 0) {
      for (int i = 0; i < 30; i++) {
        char inchar = serialConnection.serialPort.readChar();
        var_array[i] = inchar;
        print(var_array[i]);
      }
    }
  }
}

, 👍1

Обсуждение

https://www.arduino.cc/reference/en/language/variables/data-types/char/, @jsotola


1 ответ


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

2

Если вы хотите отправить числовые значения на ардуино, самый простой вариант -отправить их в формате ASCII-текста. Таким образом, вы просто отправляете символы.

Предположим, например, простой текстовый протокол вида

foo 42
bar 5678
baz -12

Каждое сообщение состоит из имени переменной, за которым следует ее числовое значение. Имя и значение a разделены пробелом. Каждое сообщение завершается строчной передачей ('\n').

Чтобы разобрать сообщение, сначала нужно разбить его на пробел. Для этого очень удобна функция strsep(). Затем вы должны разобрать вторую часть сообщения (значение) как целое число. Я бы использовал strtol() для этой работы. Складывая все вместе:

void process(char *message) {
    char *name = strsep(&message, " ");  // разбить на пробел
    if (!message) {
        Serial.println("Error: no value given");
        return;
    }
    char *endp;  // конец числового значения
    long value = strtol(message, &endp, 0);
    if (endp == message) {
        Serial.println("Error: could not parse value");
        return;
    }
    /* Successfully parsed. */
    Serial.print(name);
    Serial.print(" received value ");
    Serial.println(value);
}

Обратите внимание, что существуют некоторые проверки на вменяемость, чтобы убедиться, что сообщение действительно соответствует ожидаемому формату. Очевидно, что вы должны заменить последние три строки чем-то более значимым для вашего приложения.

Пример скетча с использованием этого:

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

void loop() {
    static char buffer[40];
    static size_t buffer_pos = 0;
    while (Serial.available()) {
        char c = Serial.read();
        if (c == '\n') {  // конец сообщения
            buffer[buffer_pos] = '\0';  // завершение строки
            process(buffer);
            buffer_pos = 0;  // сброс для следующего сообщения
        } else if (buffer_pos < sizeof buffer - 1) {
            buffer[buffer_pos++] = c;  // буфер символа
        }
    }
}
,

Спасибо за ответ, Эдгар! Извините за задержку с ответом, хотелось пройти через все. Я очень ценю пример кода. Кроме того, я даже не знал, что эти функции существуют. Если я правильно понимаю, что происходит, вы передаете адрес буферного массива функции процесса, которая разыменовывает его, а затем передается в функции str? Что меня смущает, так это то, что похоже, что функция process принимает один символ в качестве аргумента, но на самом деле она обрабатывает весь буферный массив. Это нормальное поведение C при использовании указателей на массивы или специфично для функций str..?, @Zhelyazko Grudov

Кроме того, эти функции имеют двойные указатели. Это безумие., @Zhelyazko Grudov

Наконец, мне нравится, насколько элегантен этот код, здесь есть чему поучиться!, @Zhelyazko Grudov

@ZhelyazkoGrudov: Re “Если я правильно понимаю, что происходит, вы проходите по адресу буферного массива”: Точно. Всякий раз, когда вы передаете массив функции в C или C++, он “распадается” на указатель на его первый элемент. Это поведение “распада на указатель” является общим: оно влияет на все массивы всякий раз, когда вы делаете с ними что-то в основном. Все функции str*() ожидают указателя на первый элемент массива charс нулевым окончанием. Специфика их заключается в том, что они интерпретируют первый найденный нулевой символ как конец строки., @Edgar Bonet

Здорово это знать! Спасибо за объяснение., @Zhelyazko Grudov

Извините, что снова беспокою вас, Эдгар, я столкнулся с ошибкой "не удалось разобрать значение", хотя, насколько я понимаю, я отправляю данные в правильном формате. Я отредактировал вопрос, чтобы включить код обработки, который я использую., @Zhelyazko Grudov

@ZhelyazkoGrudov: Ваш код обработки отправляет escape-символ (ASCII-код 127) вместо "127". Arduino ожидает строку ASCII: попробуйте отправить 1", затем 2", затем "7". Я не знаю обработки, но более чем вероятно, что у него есть метод, аналогичный Arduino print (), который будет форматировать число в ASCII для вас. Затем вы можете написать что-то вроде " serialConnection.SerialPort.print(127);`. Я не знаю точного названия этого метода. Если вам нужно спросить, поищите какой-нибудь форум, имеющий отношение к обработке (не здесь)., @Edgar Bonet

Большое вам спасибо, что нашли время ответить еще раз, Эдгар. Я очень, очень ценю это., @Zhelyazko Grudov