У многих микроконтроллеров есть интерфейс UART, позволяющий передавать и принимать различные данные. У интерфейса есть два вывода на плате – пины TX и RX. На большинстве Arduino-плат к этим пинам подключен USB-UART преобразователь (расположен на плате), при помощи которого плата может определяться компьютером при подключении USB кабеля и обмениваться с ним информацией. На компьютере создаётся виртуальный COM порт (последовательный порт), к которому можно подключиться при помощи программ-терминалов и принимать-отправлять текстовые данные. Таким же образом кстати работают некоторые принтеры и большинство станков с ЧПУ.
В самой Arduino IDE есть встроенная “консоль” – монитор порта, кнопка с иконкой лупы в правом верхнем углу программы. Нажав на эту кнопку мы откроем сам монитор порта, в котором будут настройки:
Конец строки: тут есть несколько вариантов на выбор, чуть позже вы поймёте, на что они влияют. Лучше поставить нет конца строки, так как это позволит избежать непонятных ошибок на первых этапах знакомства с платформой. Нет конца строки – никаких дополнительных символов в конце введённых символов после нажатия на кнопку отправка или клавишу Enter.
NL – символ переноса строки в конце отправленных данных.
CR – символ возврата каретки в конце отправленных данных.
NL+CR – и то и то.
Скорость – тут на выбор нам даётся целый список скоростей, т.к. общение по Serial может осуществляться на разных скоростях, измеряемых в бод (baud), и если скорости приёма и отправки не совпадают – данные будут получены некорректно. По умолчанию скорость стоит 9600, её и оставим.
Объект Serial
Начнём знакомство с одним из самых полезных инструментов Arduino-разработчика – Serial, который идёт в комплекте со стандартными библиотеками. Serial позволяет как просто принимать и отправлять данные через последовательный порт, так и наследует из класса Stream кучу интересных возможностей и фишек, давайте сразу их все рассмотрим, а потом перейдём к конкретным примерам.
Запустить связь по Serial на скорости speed (измеряется в baud, бит в секунду). Скорость можно поставить любую, но есть несколько “стандартных” значений. Список скоростей для монитора порта Arduino IDE:
- 300
- 1200
- 2400
- 4800
- 9600 чаще всего используется, можно назвать стандартной
- 19200
- 38400
- 57600
- 115200 тоже часто встречается
- 230400
- 250000
- 500000
- 1000000
- 2000000 – максимальная скорость, не работает на некоторых китайских платах
Serial.end()
Прекратить связь по Serial. Также освобождает пины RX и TX.
Serial.available()
Возвращает количество байт, находящихся в буфере приёма и доступных для чтения.
Serial.availableForWrite()
Возвращает количество байт, которые можно записать в буфер последовательного порта, не блокируя при этом функцию записи.
Serial.write(val), Serial.write(buf, len)
.Отправляет в порт val численное значение или строку, или отправляет количество len байт из буфера buf. Важно! Отправляет данные как байт (см. таблицу ASCII), то есть отправив 88 вы получите букву X:Serial.write(88);
Serial.print(val), Serial.print(val, format)
Отправляет в порт значение val – число или строку, фактически “печатает”. В отличие от write выводит именно текст, т.е. отправив 88, вы получите 88:
Serial.print(88);
. Отправляет любые стандартные типы данных: численные, символьные, строковые. Также методы print()/println() имеют несколько настроек для разных данных, что делает их очень удобным инструментом отладки:
format позволяет настраивать вывод данных: BIN, OCT, DEC, HEX выведут число в соответствующей системе счисления: двоичная, восьмеричная, десятичная (по умолчанию) и 16-ричная. Цифра после вывода float позволяет настраивать выводимое количество знаков после точки:
Serial.println(), Serial.println(val), Serial.println(val, format)
Полный аналог print(), но автоматически переводит строку после вывода. Позволяет также вызываться без аргументов (с пустыми скобками) просто для перевода курсора на новую строку.
Serial.flush()
Ожидает окончания передачи данных.
Serial.peek()
Возвращает текущий байт с края буфера, не убирая его из буфера. При вызове Serial.read() будет считан тот же байт, но из буфера уже уберётся.
Serial.read()
Читает и возвращает крайний символ из буфера.
Serial.setTimeout(time)
Устанавливает time (миллисекунды) таймаут ожидания приёма данных для следующих ниже функций. По умолчанию равен 1000 мс (1 секунда).
Serial.find(target), Serial.find(target, length)
Читает данные из буфера и ищет набор символов target (тип char), опционально можно указать длину length. Возвращает true, если находит указанные символы. Ожидает передачу по таймауту.
Serial.findUntil(target, terminal)
Читает данные из буфера и ищет набор символов target (тип char) либо терминальную строку terminal. Ожидает окончания передачи по таймауту, либо завершает приём после чтения terminal.
Serial.readBytes(buffer, length)
Читает данные из порта и закидывает их в буфер buffer (массив char[ ] или byte[ ]). Также указывается количество байт, который нужно записать – length (чтобы не переполнить буфер).
Плоттер
Помимо монитора последовательного порта, в Arduino IDE есть плоттер – построитель графиков в реальном времени по данным из последовательного порта. Достаточно отправлять значение при помощи команды Serial.println (значение) и открыть плоттер по последовательному соединению, например построим график значения с аналогового пина A0:
Плоттер поддерживает несколько линий графиков одновременно, для их отображения нужно соблюдать следующий протокол отправки данных: значения выводятся в одну строку, одно за другим по порядку, разделяются пробелом или запятой и в конце обязательно перенос строки.
Давайте выведем значения с аналоговых пинов A0, A1 и A2:
В Arduino IDE с версии 1.8.10 добавили возможность подписать графики, для этого перед выводом нужно отправить названия в виде
название 1, название 2, название n с переносом строки, и дальше просто выводить данные:
Отправка в порт
Рассмотрим самый классический пример для всех языков программирования: Hello World!
Отправка в порт позволяет узнать значение переменной в нужном месте программы, этот процесс называется отладка. Когда код работает не так, как нужно, начинаем смотреть, где какие переменные какие значения принимают. Или выводим текст из разных мест программы, чтобы наблюдать за порядком её работы. Во взрослых средах разработки и более серьёзных микроконтроллерах есть аппаратная отладка, которая позволяет наблюдать за ходом выполнения программы и значениями любых переменных без вывода в порт.