LAB #2. Библиотека COM-port
Объект Serial.
Чтение данных через Com-port

Основы работы
COM-порт в Arduino реализуется через интерфейс UART (Universal Asynchronous Receiver/Transmitter), который позволяет обмениваться данными с компьютером или другими устройствами.

Подключение и настройка
  • Пины подключения: RX (прием) - пин 0, TX (передача) - пин 1
  • При работе с COM-портом эти пины нельзя использовать для других целей
  • Связь осуществляется через USB-UART преобразователь
void setup() {
    Serial.begin(9600);  // Инициализация на скорости 9600 бод
}
Методы чтения данных через COM-порт "от ПК к Ардуино"

Основные функции чтения

Serial.available() - возвращает количество байт, доступных для чтения

Serial.read() - читает один байт из буфера

Serial.parseInt() - считывает число целиком

Serial.parseFloat() - считывает число с плавающей точкой


Чтение :


В порт также можно отправлять данные извне и читать их из программы.

Отправителем в Serial может быть окно монитора порта или другой МК/микросхема, например GPS или GSM модем.

  • Для проверки наличия входящих данных используется метод
 available() - он вернёт количество входящих байт. В таком условии можно проверить, что есть хотя бы один байт для чтения:
void loop() {
    if (Serial.available() > 0 ) {
        // есть входящие данные
    }
}
Serial.read для символов

  • Отправим в порт обратно принятые данные, для этого их сначала нужно прочитать - метод read().
  • Он возвращает тип int, но сами данные подразумевают байт, а если данные отправлены из монитора порта - то это всегда символ - char.
  • принимать и выполнять с символами математические операции нельзя, результат будет непредсказуемый.
  • Для конвертации принятого значения в символ нужно просто привести его к символьному типу - (char)Serial.read(), например для отправки обратно в порт.
void setup() {
    Serial.begin(9600);
}

void loop() {
    if (Serial.available()) {
        Serial.print((char)Serial.read());

        // или
        // char c = Serial.read();
        // Serial.print(c);
    }
}
  • Если сделать вывод без конвертации к char, то в порт будут печататься коды символов из таблицы ASCII:
void setup() {
    Serial.begin(115200);
}

void loop() {
    if (Serial.available()) {
        Serial.println(Serial.read());
    }
}

Отправьте текст abc в поле ввода монитора порта, он вернётся как коды символов 97, 98, 99 - соответствуют кодам символов из таблицы.
Serial.read для целых число от 0 до 9

  • при сохранении переменной в в символьном типе с ней дальше не удобно работать (нельзя сложить, сравнить с числом и т.д.)
  • если просто сохранить полученное значение из буфера в тип данных int мы получим в переменной код из таблицы ASCII
void setup() {
    Serial.begin(9600);
}

void loop() {
    if (Serial.available()) {
        int c = Serial.read();
        Serial.print(c); 
    }
}

такой код при отправке 1 в порт выдаст 49
  • для преобразования символа в число можно вычесть (-'0')
  • но это работает только с одиночными цифрами от 0 до 9 и символами
void setup() {
    Serial.begin(9600);
}

void loop() {
    if (Serial.available()) {
        int c = Serial.read() - '0';
        Serial.print(c); 
    }
}

такой код при отправке 1 в порт выдаст 1
целые числа больше 9

Для предыдущего примера если в порти отправить (12345) -Число, состоящее больше чем из одной цифры, разобьется на кусочки, и получается что наша переменная принимает значение только последней цифры отправленного числа.

  • для работы с двухзначными и более числами используется метод ParseInt

ParseInt подождёт, пока придут все отправленные вами цифры, и сложит из них число. Никакой нолик вычитать больше не нужно.

Теперь наша переменная примет большое число полностью, и можно работать с ним дальше. Но так как эта функция ждёт новые цифры, вы можете заметить небольшую задержку выполнения.

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

void loop() {
    if (Serial.available()) {
        int c = Serial.ParseInt();
        Serial.print(c); 
    }
}

такой код при отправке 105 в порт выдаст 105 но с небольшой задержкой
вещественные числа

  • для работы с числами с точкой используется метод ParseFloat

ParseFloat подождёт, пока придут все отправленные вами цифры, и сложит из них число.


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

void loop() {
    if (Serial.available()) {
    
        // float числа
        float f = Serial.parseFloat();
        Serial.println(f);
    }
}
строки

Текст в монитор порта отправляется и принимается посимвольно - в примерах выше мы его посимвольно принимаем и выводим.

Можно прочитать весь отправленный текст как String-строку:
void setup() {
    Serial.begin(9600);
}

void loop() {
    if (Serial.available()) {
        String s = Serial.readString();
        Serial.println(s);
    }
}
Отправьте текст в поле ввода - он придёт обратно, но с ощутимой задержкой.

Метод readString() является блокирующим - он собирает строку посимвольно, ожидая поступления новых символов.

Если после получения символа проходит тайм-аут - передача считается завершённой и возвращается строка. Тайм-аут можно настроить - Serial.setTimeout(миллисекунды), по умолчанию установлен 1000 мс.

Поставьте например 50:
void setup() {
    Serial.begin(9600);
    Serial.setTimeout(50);
}

void loop() {
    if (Serial.available()) {
        String s = Serial.readString();
        Serial.println(s);
    }
}

между отправкой в монитор и получением текста обратно не будет такой заметной паузы.
терминирующий символ. (STREAM - инструменты)
Он отправляется в конце текста и будет сигналом конца строки, чтобы МК не ждал тайм-аут.
Чтение строки такого формата выполняется методом readStringUntil(символ), пусть таким символом будет точка с запятой - ';':
void setup() {
    Serial.begin(9600);
    // стандартный тайм-аут
}

void loop() {
    if (Serial.available()) {
        String s = Serial.readStringUntil(';');
        Serial.println(s);
    }
}

Отправьте на МК какой-нибудь текст, например test - он вернётся с задержкой. А если отправить test; - без задержки.
  • Также в мониторе порта можно настроить "конец строки" - поставьте NL, а в качестве терминирующего символа в программе - '\n' (Serial.readStringUntil('\n');).
  • Теперь любой отправленный текст будет приниматься без задержки.
в нижнем правом углу терминала
void setup() {
    Serial.begin(9600);
    // стандартный тайм-аут
}

void loop() {
    if (Serial.available()) {
        String s = Serial.readStringUntil('\n');
        Serial.println(s);
    }
}
Парсинг пакетов*

  • При помощи Stream-инструментов можно очень просто разбирать несложные текстовые протоколы связи, например пакеты вида "ключ:значение<перенос строки>": сначала читаем до двоеточия, затем до символа переноса строки:
void setup() {
    Serial.begin(9600);
}

void loop() {
  if (Serial.available()) {
    String key = Serial.readStringUntil(':');
    String val = Serial.readStringUntil('\n');

    Serial.println(key);
    Serial.println(val);
    Serial.println();
  }
}

Нужно включить отправку NL в настройках монитора порта

ЗАДАНИЕ

Научиться выполнять арифметические вычисления с различными типами данных в Arduino и формировать информативный вывод результатов.
Задача
Написать программу для Arduino, которая выполняет следующие действия:

Реализовать вычисление двух арифметических выражений:
  • Первое выражение содержит только целые числа (тип int)
  • Второе выражение содержит целые и вещественные числа (типы int и float)
Сформировать подробный вывод в Serial порт, включающий:
  • Само выражение в текстовом виде
  • Значения используемых переменных
  • Результат вычислений
Вариант Пример 1 (целые числа) Пример 2 (целые и вещественные)
1 Переменные:
a = 12, b = 5, c = 3
Выражение:
a * b - c / 2
Переменные:
x = 4.5, y = 6, z = 2.75
Выражение:
x + y * z - x / 2
2 Переменные:
m = 20, n = 8, k = 4
Выражение:
m / n + k * 3
Переменные:
p = 7.2, q = 5, r = 1.5
Выражение:
p * q - r / 2 + p
3 Переменные:
x1 = 15, y1 = 9, z1 = 6
Выражение:
x1 - y1 / z1
Переменные:
a1 = 3.14, b1 = 4, c1 = 2.5
Выражение:
a1 * b1 + c1 / 2
4 Переменные:
s = 30, t = 10, u = 5
Выражение:
s / t * u
Переменные:
v = 6.25, w = 8, x = 1.2
Выражение:
v + w * x - v / 2
5 Переменные:
p1 = 25, q1 = 5, r1 = 2
Выражение:
p1 / q1 + r1 * 3
Переменные:
s1 = 5.5, t1 = 7, u1 = 3.25
Выражение:
s1 * t1 - u1 / 2
6 Переменные:
a2 = 18, b2 = 6, c2 = 4
Выражение:
a2 / b2 * c2
Переменные:
d = 4.8, e = 9, f = 2.1
Выражение:
d + e * f - d / 2
7 Переменные:
x3 = 24, y3 = 8, z3 = 3
Выражение:
x3 / y3 + z3 * 2
Переменные:
a3 = 6.7, b3 = 5, c3 = 1.5
Выражение:
a3 * b3 - c3 / 2
8 Переменные:
w1 = 16, x1 = 4, y1 = 7
Выражение:
w1 / x1 + y1
Переменные:
z1 = 8.4, a1 = 3, b1 = 2.2
Выражение:
z1 * a1 - b1 / 2
9 Переменные:
a4 = 14, b4 = 7, c4 = 2
Выражение:
a4 * b4 / c4
Переменные:
x4 = 5.6, y4 = 4, z4 = 1.8
Выражение:
x4 + y4 * z4
10 Переменные:
m2 = 22, n2 = 11, k2 = 3
Выражение:
m2 / n2 * k2
Переменные:
p2 = 9.1, q2 = 6, r2 = 2.4
Выражение:
p2 - q2 * r2 / 2
Вывод результата кода
Made on
Tilda