Как напечатать «µ» в последовательном мониторе?
Я пытался напечатать букву µ
на последовательном мониторе Arduino IDE, но у меня не получилось. Есть ли способ напечатать µ
или любые другие символы не ASCII
, такие как Ó
,ß
,Ô
,Ò
,õ
,Õ
,þ
и т. д. с помощью Serial.print()
?
@Peouse Dutta, 👍1
3 ответа
Лучший ответ:
Большая часть того, что будет дальше, уже была рассмотрена в предыдущих ответах. Я Тем не менее, публикую это, потому что чувствую, что пока нет ответа, который бы делал вся история достаточно ясна. Позвольте мне разбить вопрос на два подвопросы.
1. Как правильно печатать символы, не входящие в набор ASCII, на последовательном мониторе?
Ответ — просто отправить их как UTF-8.
Вот и все. Последовательный монитор ожидает, что вы отправите UTF-8, и он будет печатать символы правильно только если вы используете это кодирование. Но это приводит ко второму вопросу:
2. Как мне получить символы в кодировке UTF-8 в моей программе Arduino?
Здесь у вас есть несколько вариантов:
Вариант 1: закодируйте их самостоятельно
Например, греческая буква «μ» (U+03BC) в UTF-8 — это (0xce 0xbc). Вы можно отправить эти байты явно, например
Serial.write(0xce);
Serial.write(0xbc);
или, что более удобно, как
Serial.print("\xce\xbc");
Второй синтаксис более удобен, поскольку он позволяет символу быть встроенным в более длинную строку.
Вариант 2: позволить Arduino IDE кодировать их
Если вы можете получить символы в окне редактора IDE, либо с помощью соответствующую раскладку клавиатуры или путем копирования и вставки из другой приложение, то вы можете использовать их как есть в строке:
Serial.print("μ");
Редактор сохранит исходный код как UTF-8, и эти байты UTF-8 перейдет без помех от исходного файла до скомпилированной программы, до Память Arduino, последовательный порт и, наконец, последовательный монитор.
Этот вариант самый лучший для удобства чтения. Однако он несколько хрупкий: если исходный код когда-либо будет перекодирован (почтовые клиенты и т. д.) серверы иногда так делают), то полученная программа не будет работать как надо ожидается.
Вариант 3: позволить компилятору закодировать их
Вы можете попросить компилятор выполнить кодировку UTF-8 для вас с помощью синтаксис
Serial.print(u8"\u03bc");
Здесь escape-последовательность \u03bc
— это способ представления Unicode
символ U+03BC (т.е. «μ»), а префикс u8
означает, что вы хотите
строка как массив байтов, закодированный в UTF-8.
Обратите внимание, что на практике префикс u8
не нужен, так как gcc
Компилятор по умолчанию предполагает UTF-8. Я бы в любом случае сохранил префикс
потому что не помешает сделать кодировку явной, и это может помочь избежать
разозлить некоторых юристов по языку...
Обратите внимание, что приведенный выше синтаксис работает только для символов от U+0000 до
U+FFFF, т.е. базовая многоязычная плоскость. Для других символов Unicode,
вам нужно использовать синтаксис \U
+ 8 шестнадцатеричных цифр. Например,
символ «» (U+1F60E: улыбающееся лицо в солнцезащитных очках) может быть напечатан
с:
Serial.print(u8"\U0001f60e");
Уточнение по поводу UTF-16: распространенное заблуждение состоит в том, что с
\u
вы записываете символы как кодовые единицы UTF-16, а с помощью \U
вы
запишите кодовые единицы UTF-32. Но это неверно:
Оба синтаксиса используются для описания
один символ (технически, кодовая точка), независимо от
кодировка. Поскольку кодировка UTF-16 для «» — (0xd83d 0xde0e), один
может возникнуть соблазн написать
// Записать в виде кодовых единиц UTF-16 в исходном коде.
Serial.print("\ud83d\ude0e"); // НЕПРАВИЛЬНО
но тогда компилятор справедливо жалуется
error: \ud83d is not a valid universal character
error: \ude0e is not a valid universal character
Так что забудьте о UTF-16. UTF-16 нигде не задействован, кроме как в внутреннее представление, используемое виджетом Java, используемым для реализации последовательный монитор, который является совершенно несущественной деталью реализации.
Serial Monitor использует Unicode, поэтому отправка символов в этом формате возможна. Код UTF-16 для µ — 03BC, и вы можете отправить его, добавив \u
:
Serial.print("\u03BC");
Фактический поток преобразований заключается в том, что вы предоставляете Unicode (по сути UTF-16) в своей строке. Затем C++ преобразует его в поток 8-битных символов в формате UTF-8, который затем отправляется по последовательному соединению. Затем Java получает их и интерпретирует как UTF-8, рекомбинируя их обратно в исходные символы UTF-16 для отображения в JTextArea, которая включает Serial Monitor в Arduino IDE.
Это сложное преобразование происходит потому, что:
- UTF-8 проще передавать по 8-битному каналу передачи данных, но с ним очень сложно работать в программе (из-за последовательностей байтов переменной длины), и
- UTF-16 трудно транслировать (и нарушает совместимость с ASCII), но с ним гораздо проще работать программно (так как это всего лишь 16-битные символы фиксированного размера).
Таким образом, ваш 0x03BC
преобразуется в 0xCE,0xBC
, что является представлением UTF-8 символа Unicode 0x03BC
.
Это зависит от вашей операционной системы, версии Arduino и, возможно, даже от выбранной платы.
Вы выбрали странный символ, потому что существует две его версии: микро µ и мю µ.
См.: https://en.wikipedia.org/wiki/Mu_(letter) и https://en.wikipedia.org/wiki/Micro-. Они не одинаковы.
В Linux с платой Arduino 1.8.5 и Arduino Uno все поддерживает UTF-8 (Arduino ide, последовательный монитор и файл ino).
Чтобы проверить это, я написал микросимвол с помощью AltGr+m в скетче. Он хранится в ino-файле как C2 B5, что является UTF-8. Он отображается в последовательном мониторе как µ.
С gtkterm он отображается как µ, а в шестнадцатеричном виде он показывает C2 B5. Это подтверждает, что в Linux с Arduino версии 1.8.5 все в кодировке UTF-8.
Unicode "\u03BC" показывает µ в последовательном мониторе. Он хранится в ino-файле как 5C 75 30 33 42 43. Это не UTF-8 и не UTF-16, а ASCII для символов "\u03BC". Это нормально, поскольку именно это набрано в скетче. С gtkterm он показывает µ и CE BC в шестнадцатеричном режиме. CE BC — это UTF-8 для mu.
Это значит, что Unicode переведен в UTF-8. Возможно, компилятор переводит его в UTF-8?
Это единственные тесты, которые я провел. Это лишь очень малая часть всех возможностей.
Вывод:
Попробуйте ввести µ (mu или micro) в редакторе Arduino ide.
Использование AltGr+m будет работать только если вы выбрали определенные настройки клавиатуры. Возможно, вы можете скопировать символ со страницы Википедии.
Использование Unicode "\u03BC" кажется возможным.
[ДОБАВЛЕНО]
Внутренним форматом текста в Java был UTF-16, но только фиксированный двухбайтовый формат, а не четырехбайтовый. Поэтому он был только подмножеством символов Unicode. Новейшая версия Java поддерживает настоящий формат UTF-16 для пользовательских строк и, таким образом, поддерживает все символы Unicode.
Данные, которые хранятся в ino-файле, и данные, которые передаются в последовательный монитор, могут быть ASCII для обычных символов с добавлением UTF-8. Большинство специальных символов, которые я использую, требуют двух байтов в формате UTF-8.
Для Majenko: посмотрите на двоичные данные ino-файла и двоичные последовательные данные. Это не фиксированные два байта на символ, а всего один байт для обычных символов.
Я до сих пор не знаю, кто переводит описание символа Unicode в UTF-8. Было бы действительно странно, если бы это делал компилятор, так что где-то Java могла бы автоматически это перевести.
Это не зависит ни от одной из этих вещей. Это зависит исключительно от того, что получает необработанные байты относительно того, что вы размещаете в своем скетче. Поскольку это Java, а Java использует 16-битный UTF-16 (независимо от операционной системы), вы встраиваете 16-битные коды UTF-16 в свои строки для отображения вещей в вашем последовательном мониторе. Если вы отправляете куда-то еще, то вы встраиваете правильные коды для того, куда отправляете. Но поскольку это последовательный монитор, то это UTF-16 и всегда будет UTF-16., @Majenko
@Majenko, я думаю, вам нужно выспаться и взглянуть на него еще раз. Раньше файл ino хранил символы UTF-8, но последовательный монитор их не принимал. Версия arduino имеет значение. Раньше было несколько различий с UTF-8 в Windows и Linux., @Jot
Никому нет дела до UTF-8. Только UTF-16., @Majenko
И сохранение UTF-8 в ino-файле не имеет ничего общего с отправкой UTF-16 на последовательный монитор., @Majenko
- Как узнать частоту дискретизации?
- Что такое Serial.begin(9600)?
- Использовать все контакты как цифровые входы/выходы
- Float печатается только 2 десятичных знака после запятой
- Arduino как USB HID
- Serial1' was not declared in this scope
- Очень простая операция Arduino Uno Serial.readString()
- AT-команда не отвечает на последовательный монитор
Комментарии не предназначены для расширенного обсуждения; эта беседа была [перенесена в чат](https://chat.stackexchange.com/rooms/81360/discussion-on-answer-by-majenko-how-to-print--in-the-serial-monitor)., @Majenko