Работа с последовательным портом UART (serial) на Arduino
Последовательный интерфейс (serial) предназначен передачи данных через универсальный асинхронный порт UART. Порт UART очень часто используется для передачи данных с Ардуино на компьютер, и обратно, а также для связи нескольких плат ардуин между собой.
Для многопортовых DUE/MEGA см. здесь.
Основные функций для работы с последовательным портом (Serial)
Serial.begin(rate) — Открывает последовательный порт и задаёт скорость для последовательной передачи данных. Типичная скорость обмена для компьютерной коммуникации — 9600.
Очевидно, когда задействован последовательный порт, выводы 0 (RX) и 1 (TX) не могут использоваться для других целей.
Serial.println(data) — Передаёт данные в последовательный порт, сопровождая автоматическим возвратом каретки и переходом на новую строку.
Serial.print(data) — тоже самое без возврата каретки и перехода на новую строку.
Serial.begin(скорость_передачи); — Инициализация порта. Задает скорость передачи в битах в секунду. Нормированные скорости: 300, 1200, 2400, 4800, 9600, 14400, 19200, 38400, 57600, или 115200.
count = Serial.available(); — Принимаемые по последовательному порту байты попадают в буфер микроконтроллера, откуда Ваша программа может их считать. Функция возвращает количество накопленных в буфере байт. Последовательный буфер может хранить до 128 байт.
char = Serial.read(); — Считывает следующий байт из буфера последовательного порта. возвращает -1 если нет входящих данных
Serial.flush(); — Ожидает окончания передачи исходящих данных (до версии Arduino 1.0 функция очищала буфер последовательного соединения)..
Разные варианты функции print:
Serial.print(b, DEC); — выводит ASCII-строку — десятичное представление числа b.
Serial.print(b, BYTE) — выводит младший байт числа b.
(аналогично HEX, OCT, BIN).
Serial.print(str) // если str — строка или массив символов, побайтно передает str на COM-порт.
Serial.println(); — отличие заключается в том, что после данных дополнительно выводятся два символа – символ возврата каретки (ASCII 13, или ‘\r’) и символ новой линии (ASCII 10, или ‘\n’).
Функция write:
Serial.write(uint8_t c); — Записывает данные в последовательный порт. Данные посылаются как байт или последовательность байт.
Serial.write(val); // где val — переменная для передачи, как единственный байт
Serial.write(str); // где str — строка для передачи, как последовательность байт
Serial.write(buf, len); // где buf — массив для передачи, как последовательность байт; len — длина массива.
Пример 1. Передача данных по Serial-порту с Arduino на компьютер
Инициализация порта со скоростью 9600 бот и передача данных (от Arduino на внешние устройства, например на компьютер):
Пример 2. Передача данных по Serial-порту с компьютера на Arduino
serialEvent() — функция вызывается автоматически, когда поступают данные.
Serial.setTimeout() — задает максимальное время (в мс) для работы Serial.readBytesUntil();
Возможные проблемы
1) auto-reboot DTR : возможна автоперезагрузка МК при передаче на него данных по serial-пору. Чтобы отключить это, надо поставить конденсатор 10мкФ между RES и GND. Я ставил электролитический кондер (естественно, + на RES).
Как соединить две ардуины по UART (serial) порту
Схема соединения двух ардуин:
Длина провода и скорость: RS-232 (англ. Recommended Standard 232) — стандарт физического уровня для асинхронного интерфейса (UART).
Расстояние связи по RS232 максимум 15 метров.
Но всё зависит от скорости.
Работа Arduino MEGA/DUE с несколькими последовательными serial портами
Многопортовые ардуино.
Как вы уже заметили, на ардуиновских платах Mega и Due имеется по 4 последовательных порта, а именно:
Serial — выводы 0 (RX) and 1 (TX);
Serial1 — выводы 19 (RX) and 18 (TX);
Serial2 — выводы 17 (RX) and 16 (TX);
Serial3 — выводы 15 (RX) and 14 (TX).
Естественно, что на Due используется напряжение 3.3 В (на MEGA как обычно 5 В).
Как с ними работать?
Здесь синим цветом выделены собственно имена объектов ( Serial , Serial1 , Serial2 , Serial3 ), которые используются в коде программы для работы с их методами. Всё просто! Например,
Пример вывода на дисплей LCD1602 через последовательный порт UART Arduino из-под Linux средствами языка Python
Короче говоря, есть комп с линуксом, к которому подключена Arduino через USB, а к арудине подключен дисплей LCD1602, и мы хотим на него выводить инфу.
Сначала привожу полный код программы для Arduino UNO, к которой подключен дисплей LCD1602:
Я сделал здесь решетку ‘#’ в качестве символа завершения передачи пакета данных. Как только в потоке данных встречается символ #, данные выводятся на дисплей, и буфер обнуляется, при этом сам символ ‘#’ не выводится. Конечно, можно было бы использовать ‘\n’ или др.
Далее мы напишем скрипт на Python, который будет выводить инфу на дисплей. Я выбрал Python, потому что это прикладной язык и он лучше всего подходит для подобных задач. С такими языками как C++/C# и т.п. больше возни с библиотеками, а здесь всё просто, особенно если это дело происходит под линуксом.
Первым делом устанавливаем необходимые библиотеки (для 2-ой или 3-ей версии python)
$sudo apt-get install python-serial
$sudo apt-get install python3-serial
Далее в интерпретаторе python пишем:
Здесь ардуина у меня подключена к порту /dev/ttyUSB0 — это я узнавал из Arduino IDE. Обычно она всегда на этом порту сидит, если других устройств на последовательный порт не подключено.
Как вы уже догадались, и в первой, и во второй программы должна быть указано одинаковая скорость в бодах. В моем случае это 9600 — стандартная, хотя и маленькая скрость. Может быть и больше (читай выше).
Serial Monitor. Общаемся с компьютером
Для общения между платой Arduino и компьютером или другим устройством в контроллере используется интерфейс UART или USART, который в сочетании со встроенным в UNO USB-to-UART конвертером, позволит установить двунаправленую связь с компьютером через виртуальный последовательный порт. У некоторых моделей Arduino может быть несколько портов. Порт соединяется через цифровой пин 0 (RX) и 1 (TX) при подключении к компьютеру через USB, поэтому не используйте пины 0 и 1 для ввода/вывода.
Раньше на старых компьютерах были COM-порты, сейчас они создаются виртуально при помощи микросхемы FTDI, когда мы подключаем плату к компьютеру через USB.
Вам часто придётся использовать общение между устройствами для обмена информацией. Можно как посылать сигнал с компьютера, например, с клавиатуры, так и принимать сигналы с платы. Это полезно, чтобы узнать, что вообще происходит с сигналом из нужного вывода платы.
В Arduino IDE есть специальный значок с изображением лупы, который запускает Serial Monitor (монитор порта).
Для корректной работы с портом требуется выполнение двух условий: выбрать правильный COM-порт, выбрать скорость работы в скетче, которая должна совпадать со скоростью, выбранной в мониторе порта.
Для общения используется класс Serial. В методе setup() мы открываем порт для общения функцией Serial.begin() с указанием скорости в бодах (baud). Бод — это количество изменений сигнала в секунду. В нашем случае сигналы могут быть только двоичными, так что скорость в бодах соответствует скорости в битах в секунду. Можно использовать любую скорость, главное чтобы на приёмной и передающей сторонах они были одинаковыми. Доступные скорости можно посмотреть в настройках порта. Значение 9600 является стандартным и его можно не менять (9600 бод — 960 символов — один стартовый бит, восемь бит на сам символ и конечный бит). Если установить неправильную скорость, то вместо данных получим «мусор» — данные, которые нельзя обработать. Для обмена данными между другими компонентами скорость может быть и выше, например между платой и Bluetooth-модулем.
На платах Arduino Mega и Arduino Due доступны также Serial1, Serial2, Serial3.
Чтобы отправить сообщение в порт, используются методы print() (символы идут подряд) или println() (с переводом на новую строку).
Давайте выведем какое-нибудь сообщение. Это можно сделать в методе setup(), так как нам не нужно повторять одну и ту же фразу бесконечно. Метод loop() оставляем пустым.
Если посылаем строку, то обрамляем её кавычками. Если число, то кавычки не используем. Изменим функцию setup().
Можно заменить строки и числа на переменные. Перепишем пример.
Немного о числах. При работе с дробными числами, можно указать число знаков после запятой.
Работа с массивами и строками
Разберём пример отправки строк в случайном порядке. Любая строка уже является массивом символов. Поэтому вместо типа String, можно использовать массив char[]. Для примера создадим массив из четырёх имён и будем выводить их в случайном порядке через разные промежутки времени, используя функцию random().
Приём данных
Выводить данные в порт просто. А вот принимать данные с компьютера и других источников сложнее. При отправлении данных, они складываются в буфер, ожидая, когда плата их прочитает. Объём буфера составляет 64 байта. Чтобы постоянно не читать пустой буфер, есть специальная функция проверки буфера Serial.available(). Она возвращает число байт, которые лежат в буфере. Обычно в коде создают условие проверки — если в буфере больше 0 байт, то выполняем какие-то команды.
Для демонстрации создадим странный пример — создадим переменную, присвоим ей данные через Serial.read() и попросим её прислать полученные данные через Serial.print(). Получится круговорот данных или эхо.
Проверяем на числах. Отправляем число 9, а получаем 57. Если вы получаете две строки с числами 57 и 10, то в нижней части окна выберите настройку No line ending вместо Newline.
Попробуем также отправить букву. Опять вместо t возвращается 116. Ерунда какая-то. Всё просто, функция read() работает с символьными значениями и мы видим код символа из стандартной таблицы символов ASCII.
Чтобы решить проблему, нужно изменить тип данных на char.
Вроде проблема решена. Мы можем принимать отдельные цифры и буквы. Но буквы только английские, а числа только однозначные.
Если мы планируем работать только с однозначными числами, то можно написать такой код.
Решение какое-то половинчатое. А как быть с большими числами или словами?
Если отправить двузначное число 23, то ответ разбивается на части — 2 и 3. Получается, что переменная получит последнее число 3 (промежуточные значения перезаписываются). Чтобы обработать всё число, нужно использовать метод parseInt().
Теперь вы можете вводить любые числа. Но, наверное, вы заметите теперь небольшую задержку в ответах. Метод внутри себя перемалывает данные. Кстати, вы можете использовать и обычные символы. Если набор символов состоит только из букв, то вернётся 0. Если будут попадаться и цифры, то будут возвращаться цифры. Попробуйте комбинировать различные сочетания цифр и букв, чтобы понять, как будут обрабатываться данные.
Управление светодиодом с клавиатуры
Напишем пример управления встроенным светодиодом с клавиатуры. Если нажата клавиша 1, то светодиод должен загореться, при нажатии клавиши 0 выключим светодиод.
Часть кода нам уже знакома — мы используем встроенный светодиод под номером 13.
Сигнал от компьютера поступает в виде байта. Создаём новую переменную incomingByte для этих целей.
Последовательный порт включается командой begin() с указанием скорости.
Если с компьютера поступает сигнал, то функция available() вернёт количество байт, доступное для чтения. Таким образом, мы просто убеждаемся, что какой-то сигнал пришёл (больше нуля).
После первой проверки мы проверяем введённый символ, который может быть представлен и как байт. Если символ равен единице, то включаем светодиод, как мы делали раньше. Если символ равен 0, то выключаем.
Как это выглядит на практике. Заливаем скетч и запускаем Serial Monitor (Ctrl+Shift+M). В окне Serial Monitor наверху есть текстовое поле. Вводим в него числа 1 или 0 и нажимаем кнопку Send. Можно также нажать клавишу Enter для быстрого ввода.
Для общего развития в скетч добавлены также две строчки кода, определяющие код нажатой клавиши. Таким образом вы можете узнать код для клавиш 0 и 1. Вы также можете нажимать и на другие клавиши, они не повлияют на светодиод, но вы увидите коды клавиш.
Чуть более сложный пример, когда строка задана в виде массива и символы выводятся по очереди.
Функция Serial.end() закрывает последовательное соединение, порты RX и TX освобождаются и могут быть использованы для ввода/вывода.
В различных уроках вы будете принимать сигналы от платы Arduino. Это полезно, например, для отладки приложения, когда вы выводите сообщения и по ним ориентируетесь, какая часть программа работает, а какая — нет. Способность общения между Arduino и компьютером очень важна. Вы можете принимать сигналы не только в Arduino IDE, но и в других приложениях на компьютере. Например, в связке с Arduino часто используют приложение Processing, в котором рисуют графики поступаемых сигналов.
Если вы больше не нуждаетесь в получении данных, то закрывайте окно Serial Monitor.
Также существует библиотека SoftwareSerial. Она позволяет осуществить последовательную передачу данных через другие цифровые контакты Arduino.
Другие варианты
Чтение данных из последовательного порта возможно другими способами. Ищите расширения, например, Arduino Chrome Serial Monitor. На видео можно посмотреть, как создать расширение самостоятельно.
На C# также можно написать приложение, которое будет уметь считывать данные.
Processing также умеет работать с последовательным портом.
Дополнительное чтение
ASCIITable — распечатываем таблицу символов ASCII в разных форматах
Arduino.ru
Serial
Набор функций Serial служит для связи устройства Ардуино с компьютером или другими устройствами, поддерживающими последовательный интерфейс обмена данными. Все платы Arduino имеют хотя бы один последовательный порт (UART, иногда называют USART). Для обмена данными Serial используют цифровые порты ввод/вывода 0 (RX) и 1 (TX), а также USB порт. Важно учитывать, что если вы используете функции Serial, то нельзя одновременно с этим использовать порты 0 и 1 для других целей.
Среда разработки Arduino имеет встроенный монитор последовательного интерфейса (Serial monitor). Для начала обмена данными необходимо запустить монитор нажатием кнопки Serial monitor и выставить ту же скорость связи (baud rate), с которой вызвана функция begin().
Плата Arduino Mega имеет три дополнительных последовательных порта: Serial1 на портах 19 (RX) и 18 (TX), Serial2 на портах на портах 17 (RX) и 16 (TX), Serial3 на портах на портах 15 (RX) и 14 (TX). Чтобы использовать эти порты для связи с компьютером понадобится дополнительные адаптеры USB-to-serial, т.к. они не подключены к встроенному адаптеру платы Mega. Для связи с внешним устройством через последовательный интерфейс соедините TX порт вашего устройства с RX портом внешнего устройства и RX порт вашего устройства с портом TX внешнего и соедините «землю» на устройствах. (Важно! Не подключайте эти порты напрямую к RS232 порту, это может повредить плату).