Устройства с COM-портом и Arduino
Встроенные функции Serial* работают со всем, что отображается как COM-порт: Arduino, ESP32 или
Raspberry Pi Pico через USB, адаптер USB — последовательный порт, GPS-приёмник, сканер штрихкодов в
режиме последовательного порта, чековый принтер или принтер этикеток, 3D-принтер или контроллер ЧПУ,
принимающий G-код, лабораторный прибор или самодельный кнопочный пульт, макропанель, поворотная
ручка или контроллер светодиодов. Устройство отправляет и принимает строки текста; ваши скрипты
превращают эти строки во что угодно, что умеет Input.Observer.
Несколько идей:
- Кнопочный пульт или макропанель. Arduino считывает свои кнопки и выводит
B1,B2, ... Монитор COM-порта превращает каждую строку в сочетание клавиш, мультимедийную клавишу или команду окна. - Ручка громкости или прокрутки. Потенциометр или энкодер выводит своё положение; монитор устанавливает громкость или прокручивает.
- Индикаторы состояния. Жест или горячая клавиша отправляет
LED 255 0 0плате, управляющей светодиодной лентой, и свет показывает, что идёт запись или сборка завершилась ошибкой. - Датчики. Таймер запрашивает у платы температуру или освещённость и показывает её, записывает в файл или затемняет экран.
- Сканеры и считыватели. Каждый штрихкод или RFID-метка, которые присылает считыватель, становится набранным текстом, поисковым запросом или поиском в файле.
- Станки. Отправляйте строки G-кода принтеру или плоттеру, по одному
SerialWriteTextLineна команду.
Поиск порта
Windows даёт каждому устройству имя вроде COM3. Диспетчер устройств показывает его в разделе
Порты (COM и LPT); Arduino IDE — в меню выбора платы. Скрипт тоже может их перечислить:
n = SerialEnumeratePorts();
if (n == 0) UtilityPrint("No COM ports. Is the board plugged in?");
for (i = 0; i < n; i = i + 1) {
UtilityPrint(SerialGetEnumeratedPortAt(i));
}
Список отсортирован по номеру, поэтому COM3 идёт перед COM10. Номер может измениться, если
подключить устройство к другому USB-разъёму.
Скорость, формат кадра и окончания строк
- Скорость (
baudRate) должна совпадать со скоростью устройства: числом вSerial.begin(...)скетча Arduino, обычно9600или115200. - Формат кадра почти всегда 8 бит данных, без контроля чётности, один стоповый бит:
8,SerialParity.None,SerialStopBits.One. Пишите константы: простое число1в качестве аргумента стоповых битов означает полтора стоповых бита. - Окончания строк. Принятая строка заканчивается на заданном вами
terminator, который удаляется из строки. Пустой текст означает CR LF — то, что отправляетSerial.printlnв Arduino. Для устройства, завершающего строки одним LF, используйте"\n"; для одного CR —"\r".SerialWriteTextLineзавершает отправляемое тем же завершителем или через CR LF, если порт открывает сам этот вызов. С CR LF скетч Arduino, читающий черезSerial.readStringUntil('\n'), получает строку с завершающим CR, который удаляетtrim(); с"\n"удалять нечего. - Сигналы. При открытии порта включаются его сигналы DTR и RTS, как это делает Arduino IDE. Это перезапускает большинство плат Arduino Uno и Nano, а также другие платы с такой же схемой сброса.
Три способа общаться с устройством
-
Один вопрос — один ответ.
SerialWriteTextLineиSerialGetTextLineдля неоткрытого порта открывают его на скоростиbaudRateиз вызова, 8-N-1, на время одного вызова. Если порт уже открыт, аргументbaudRateне учитывается. Подходит для устройства, которое не перезапускается при открытии порта. См. Задать вопрос устройству на COM-порту. -
Постоянно открытый порт.
SerialOpenPortоткрывает порт с вашими настройками до вызоваSerialClosePortи собирает каждую строку, которую отправляет устройство, для чтения черезSerialGetTextLine. Большинство плат Arduino Uno и Nano перезапускаются при каждом открытии порта, поэтому откройте порт один раз, в глобальном событии Load, а жесты и горячие клавиши пусть пишут в него.SerialOpenPortвозвращаетfalseдля порта, который отсутствует, отключён или открыт в другой программе; для порта, который Input.Observer уже открыл или который занимает монитор, он останавливает действие с ошибкой.// Load global event: open the port once, at the sketch's speed. An Uno or Nano// restarts every time its port opens, so a port opened per command would lose// the command while the board boots.if (!SerialOpenPort("COM4", 115200, SerialParity.None, 8, SerialStopBits.One, "")) {UtilityPrint("COM4 isn't available: unplugged, or open in the Arduino IDE's Serial Monitor?");}// Any gesture or hotkey: send a command line and read the board's reply.// (The sketch reads a line with Serial.readStringUntil('\n') and answers OK.)if (SerialWriteTextLine("COM4", "LED 255 0 0", 115200)) {reply = SerialGetTextLine("COM4", 1, 115200);if (reply != "OK") UtilityPrint(StringFormat("Board said: {0}", reply, ""));} -
Монитор.
SerialMonitorCreateвыполняет скрипт для каждой строки, которую отправляет устройство, в фоне, до вызоваSerialMonitorDelete. Строка — этоContextGetSerialTextLine(). См. Кнопки устройства на COM-порту как мультимедийные клавиши и:// Arduino side: a potentiometer on A0, one reading per line.// void setup() { Serial.begin(115200); }// void loop() { Serial.println(analogRead(A0)); delay(50); }// Empty text as the terminator means CR LF, which Serial.println sends.SerialMonitorCreate("knob", "COM4", 115200, SerialParity.None, 8, SerialStopBits.One, "","line = ContextGetSerialTextLine(); if (StringIsNumber(line, true)) MultimediaSetVolume(AudioEndpoint.Playback, StringToNumber(line, true) / 1023.0);");
Что нужно знать о мониторах.
- Строки обрабатываются по одной, в порядке поступления: скрипт для следующей строки начинается, когда скрипт для предыдущей завершился. Ожидать могут до 256 строк; сверх этого отбрасываются самые старые.
- Остановка всех действий останавливает скрипт, выполняющийся для строки, и отбрасывает ожидающие строки. Сам монитор продолжает работать. Горячая клавиша остановки всех действий идёт дальше: она удаляет все мониторы и закрывает их порты.
- Любой скрипт, включая собственный скрипт монитора, может отправлять данные в отслеживаемый порт
через
SerialWriteTextLine, поэтому монитор может отвечать своему устройству.SerialGetTextLineне может читать отслеживаемый порт: каждая строка достаётся монитору. - Каждое имя монитора принадлежит одному порту.
SerialMonitorCreateс именем монитора этого порта заменяет этот монитор. Он останавливает действие с ошибкой, если это имя уже отслеживает другой порт, если порт открыт черезSerialOpenPortили если порт занимает другой монитор. Порт, который отсутствует, отключён или открыт в другой программе, даётfalse. - Отключение устройства завершает монитор и записывает строку на вкладку Система консоли.
Ничто не перезапускает монитор, когда устройство возвращается. Выполните
SerialMonitorCreateснова (из горячей клавиши или из события Load при следующем запуске).
COM-порт может быть открыт только одной программой. Пока в Arduino IDE открыт Монитор порта
или Плоттер по последовательному соединению, Input.Observer не может открыть порт, а пока порт
открыт в Input.Observer, IDE не может загрузить скетч. Закройте порт (SerialClosePort или
SerialMonitorDelete) перед загрузкой.