Почему нужно использовать latin-1 вместо utf-8 при использовании python с arduino?

При чтении и записи с подключением последовательного порта python к arduino, если я не использую latin-1 ('ISO-8859-1'), результаты не такие, как ожидалось. Например, если у меня есть

int outP = 5;
//...
int outV = Serial.read();
analogWrite(outP, outV);

В то время как с python у меня есть

serial_port.write(chr(255).encode())

Я считываю 3,78 В с контакта, тогда как если я использую

serial_port.write(chr(255).encode(encoding = 'latin-1'))

Я получаю 5.04 В. Я читал, что latin-1 и utf-8 не всегда совпадают, но есть ли что-то в arduino, что требует использования latin-1? Конечно, они возвращают разные значения при тестировании каждой кодировки, используя 255 дает b'\xc3\xbf' (от 'Ä¿') с utf-8 или b'\xff' от ('ÿ') с latin-1, но почему arduino работает с latin-1?

К вашему сведению другие варианты, которые работают

v = 255

serial_port.write(v.to_bytes(1, byteorder = 'big'))

serial_port.write(bytes[v])

, 👍1


1 ответ


Лучший ответ:

2

но есть ли что-то в arduino, что требует использования latin-1?

Нет, не совсем.

Все сводится к тому, что Serial.read() считывает байты независимо от того, с какой кодировкой они могут использоваться. ISO-8859 кодирует только кодовые точки символов в диапазоне 0-255, поэтому, когда вы выбираете кодовую точку 0-255 и отправляете ее как ISO-8859, она отправляется как 1 байт, то есть так, как ваш код был записан для ее получения.

Кодовая точка 255, такая как utf-8, потребует кодирования нескольких байтов и поэтому приведет к нескольким вызовам Serial.read() для данного значения.

Если вы откроете python3 REPL и поставите chr(255).encode() или более явно chr(255).encode('utf-8'), то увидите, что это приведет к b'\xc3\xbf'. Таким образом, на стороне Arduino вы увидите это как два отдельных результата Serial.read (), 0xC3 и 0xBF.

Когда вы просто берете строки и UTF-8 и выплескиваете их через Serial.println(), Arduino блаженно не знает, что это UTF-8, а не ISO-8859. На самом деле вы можете использовать любую кодировку, какую захотите, но с оговоркой, что если вы используете c-строки для их хранения, то кодировка должна быть такой, чтобы ни один нулевой байт не находился в середине строки.


Возможно, вы захотите рассмотреть возможность использования struct.pack вместо того, чтобы связывать байтовые строки python с последовательностями chr() и .encode(что угодно). struct.pack также приведет к байтовой строке, но она больше предназначена для этого.

Вы можете импортировать struct, а затем struct.pack('B', 255) приведет к b'\xff так же, как chr(255).encode('iso8859-1'), но, по крайней мере, выражает намерение. "B" здесь означает диапазон unsigned char, спецификаторы формата вы найдете в документации. Вы получите большую выгоду, когда начнете использовать несколько полей, где struct.pack будет намного менее громоздким, чем chr, encode и конкатенация строк.

,

Да, `len(chr(255).encode(encoding = 'latin-1')) возвращает 1, а `len(chr(255).encode ()) возвращает 2, @user14094230

хорошо, спасибо, какой формат следует использовать с struct.pack?, @user14094230

Я перенес свой предыдущий комментарий в ответ и обратился к вашему вопросу там., @timemage