Arduino:Основы/Интерпретация последовательно передаваемых данных
Содержание | Знакомство с Arduino | Продукты | Основы | Справочник языка Arduino | Примеры | Библиотеки | Хакинг | Изменения | Сравнение языков Arduino и Processing |
Интерпретация последовательно передаваемых данных [1]
Последовательно передаваемые данные – это данные, которые передаются байт за байтом от одного устройства к другому. И то, как оба устройства (компьютер или микроконтроллер) будут интерпретировать эти данные, когда будет начало сообщения, когда будет его конец, и что делать с этими данными в процессе передачи из точки А в точку Б – решать именно вам.
Но перед тем, как вы сможете передавать сообщения, оба устройства должны договориться о том, с какой скоростью они будут обмениваться данными, о количестве битов в байте и т.д. Как правило, неплохим считается стандарт с 8 битами, без бита четности и с одним стоповым битом. Для небольшого количества данных подойдет скорость в диапазоне от 2400 до 9600 бод.
Для отображения буквенно-цифровых символов (букв, чисел и знаков препинания) компьютеры используют числа, содержащиеся в байтах. Существует стандартная кодировка под названием ASCII (расшифровывается как American Standard Code for Information Interchange, т.е. «американский стандартный код для обмена информацией»), которая присваивает каждой букве и цифре значение от 0 до 255. Например, заглавной «А» соответствует значение «65». Эту таблицу можно найти во многих мануалах к компьютерам, а также онлайн – например, здесь.
ASCII – это очень распространенная кодировка (хотя и не единственная), поэтому очень многие девайсы используют ее в своем последовательном протоколе. Кроме того, как можно судить из названия, ASCII во многом основана на английском коммуникационном процессе. Она удобна, т.к. любой ASCII-символ можно представить одним байтом, но в то же время имеет и ограничения. Другие буквенно-цифровые системы, которые имеют больше символов, чем в латинице, в ASCII представить нельзя. ASCII можно заменить Unicode, но, к счастью, самая распространенная форма Unicode (т.е. UTF-8) совместима с ASCII. Если хотите почитать о Unicode более подробно, предлагаю взглянуть на этот информативный пост от Умера Мэнсора (Umer Mansoor).
Если вы передаете одно число, значение которого меньше 255, то его можно уместить в байт. Этот вид сообщений довольно прост. Вы можете отсылать один и тот же байт снова и снова, и у компьютера не возникнет никаких проблем, чтобы его получить. Но если отсылать больше (как это обычно и бывает), все становится чуть сложнее – компьютер должен знать, где у получаемого сообщения начало и конец. Разные устройства, выполняя те или иные действия, используют разные коды. К примеру, если устройство вроде кассетного магнитофона, проигрывателя CD-дисков и т.д. управляется при помощи последовательной передачи данных, в руководстве к ним всегда будет раздел, в котором описываются сообщения, которые он ожидает получить, а также скорость получения этих сообщений.
При работе с платой Arduino преобразование исходного значения байта в итоговый ASCII-символ осуществляется при помощи модификатора DEC. Например, так:
Serial.print(myVar, DEC);
То есть, если значением myVar будет 134, функция вернет три байта, содержащие символы «1», «3» и «4».
Допустим, вы должным образом запрограммировали микроконтроллер, подключили его к компьютеру и хотите приступить к передаче каких-нибудь данных. Но для начала нужно протестировать, что именно отсылает микроконтроллер, и для этого подойдет самая простейшая программа. На Mac с этой задачей хорошо справляется ZTerm, а на PC – HyperTerminal. Задайте те же скорость передачи данных и другие настройки, что и на микроконтроллере, и подключайтесь. Если в настройках будет вариант Flow Control (т.е. «управление потоком передачи данных»), поставьте None. В итоге вы должны увидеть все отправленные вами ASCII-символы. Самая большая трудность в последовательной передаче данных – сделать так, чтобы в итоге у вас были все необходимые байты, и чтобы все они были расположены в правильном порядке. Если компьютер (или микроконтроллер) во время приема данных от последовательного порта занят чем-то еще или его буфер переполнен (т.е. если получаете больше данных, чем компьютер способен обработать), то некоторые данные вы рискуете потерять. Нет какого-то одного способа проверить, правильные ли данные вы получаете, но есть несколько фундаментальных вещей, которые стоит иметь в виду:
Сколько байтов я отправляю? А получаю столько же?
Например, если микроконтроллер отсылает три переменные от трех датчиков, компьютер должен получить все три.
Я получаю байты в правильном порядке?
Если отправитель раз за разом отсылает «ABC» (так, что в итоге получается «ABCABCABCABC»), может случиться так, что получатель начнет получать эти сообщения не с самого начала (и получит в итоге что-то вроде «BCABCABCABCA»). Это может стать проблемой, если, к примеру, «A» отвечает за правый переключатель, «B» – за центральный, а «С» – за левый. Чтобы избежать этого, имеет смысл в начале или конце вашей строки данных вписать константу, которая будет отличаться от других значений. Например, если за символ «A» отвечает число от 0 до 100, и за «В» отвечает число от 0 до 100, и также за «С» отвечает число от 0 до 100, то вначале каждой строки полезно будет вписать значение 101. В программе на BASIC это может выглядеть следующим образом:
PICBasic Pro:
A var byte
B var Byte
C var Byte
headerByte var byte
headerbyte = 101
main:
' Здесь генерируем значения для A, B и C
serout2 portc.6, 16468, [headerByte, A, B, C]
goto main
BX-24:
Dim A as byte
Dim B as Byte
Dim C as Byte
dim headerByte as byte
headerbyte = 101
' Здесь пишем код, чтобы задать последовательный порт
do
' Здесь генерируем значения для A, B и C
call putQueue(OutputBuffer, headerByte, 1)
call putQueue(OutputBuffer, A, 1)
call putQueue(OutputBuffer, B, 1)
call putQueue(OutputBuffer, C, 1)
loop
Wiring/Arduino:
char A;
char B;
char C;
char headerByte = 101;
void setup() {
Serial.begin(9600);
}
void loop() {
// Здесь генерируем значения для A, B и C
Serial.print(A, BYTE);
Serial.print(B, BYTE);
Serial.print(C, BYTE);
Serial.print(headerByte, BYTE);
}
Но эту задачу можно выполнить и по-другому – методом «вызова и ответа». То есть девайс-отправитель ждет запроса на отправку данных, затем дожидается и отправляет, а затем ждет нового запроса. Таким образом, девайс-получатель будет знать, что в его буфере одновременно будет находиться лишь одна строка данных. То есть вам нужно сделать так, чтобы последовательный порт девайса-получателя мог уместить то количество данных, которые девайс-отправитель отсылает в своей строке, а так же так, чтобы девайс-отправитель умел ждать и отправлял данные только после того, как получит байт-запрос. Если в качестве отправителя выступает микроконтроллер, его можно запрограммировать следующим образом (см. ниже). В этом примере получатель, будучи готовым к получению новых данных, шлет отправителю запрос – букву «А», за которую в кодировке ASCII отвечает число «65».
PicBasic Pro:
main:
' Ждем входящих данных:
serin2 portc.7, 16468, [inputVar]
' Если мы получили от PC байт со значением «65» (ASCII-значение для «А»),
' отсылаем данные:
if inputVar = 65 then
serout2 portc.6, 16468, [A, B, C]
endif
goto main
BX-24:
' Выясняем, есть ли что-нибудь в очереди:
gotaByte = statusQueue(inputBuffer)
' Если в буфере есть данные, берем первый байт:
if (gotaByte = true) then
call getQueue(inputBuffer, inByte, 1)
if inByte = 65 then
' Высылаем байты:
call putQueue(OutputBuffer, A, 1)
call putQueue(OutputBuffer, B, 1)
call putQueue(OutputBuffer, C, 1)
end if
else
inByte = 0
end If
Arduino:
// Выясняем, есть ли что-нибудь в очереди:
if (Serial.available() > 0) {
// Если в буфере есть данные, берем первый байт:
char inByte = Serial.read();
if (inByte == 'A') {
// Высылаем байты:
Serial.print(A, BYTE);
Serial.print(B, BYTE);
Serial.print(C, BYTE);
}
}
Мои данные являются частью какой-то более крупной переменной?
Допустим, вы отсылаете от BX-24 целочисленную переменную. Длина этой переменной – два байта, поэтому компьютер при получении этой переменной как раз получит два этих байта. Чтобы снова преобразовать эти два байта в одно число, воспользуйтесь этой формулой:
integerVar = (byte1Var * 256) + byte2Var
Если непонятно, представьте, что конвертируете шестнадцатеричное значение в десятичное. В данном же случае каждый байт – это число с целочисленным основанием 256. Чтобы убедиться в том, что формула верна, попробуйте отослать константу с числом больше 256.
Мои данные искажаются при передаче?
Последовательная передача данных – штука непростая в том смысле, что оба девайса нужно правильно заземлить, а провода для отправки и передачи данных должны быть правильно изолированы и подключены. Разного рода электрический шум может проникнуть в вашу систему и помешать передаче данных. Чтобы минимизировать время на устранение неполадок, лучше начать с отправки сообщения с константой. К примеру, если вы планируете отослать три байта с данными от датчиков, не стоит начинать с отправки значений, действительно полученных от датчиков. Начните с констант.
PicBasic Pro:
outByte var byte
outByte = 65
serout2 portc.6, 16468, [outByte]
outByte = 66
serout2 portc.6, 16468, [outByte]
outByte = 67
serout2 portc.6, 16468, [outByte]
BX-24:
dim outByte as byte
outByte = 65
call putQueue(OutputBuffer, outByte, 1)
outByte = 66
call putQueue(OutputBuffer, outByte, 1)
outByte = 67
call putQueue(OutputBuffer, outByte, 1)
Arduino:
Serial.print(65, BYTE);
Serial.print(66, BYTE);
Serial.print(67, BYTE);
Если вы видите, что девайсу-получателю приходят именно те данные, которые вы отсылаете, то код можно поменять, чтобы вы могли отсылать уже не константы, а данные, действительно полученные от датчиков. Кроме того, перед тем, как заниматься отладкой «железной» части, которая, как правило, богата на всевозможные неисправности и неполадки, займитесь софтверной. Код – гораздо более контролируемая область, чем «железо».
См.также
Внешние ссылки
Arduino продукты | |
---|---|
Начальный уровень | Arduino Uno • Arduino Leonardo • Arduino 101 • Arduino Robot • Arduino Esplora • Arduino Micro • Arduino Nano • Arduino Mini • Arduino Starter Kit • Arduino Basic Kit • MKR2UNO • TFT-дисплей Arduino |
Продвинутые функции | Arduino Mega 2560 • Arduino Zero • Arduino Due • Arduino Mega ADK • Arduino Pro • Arduino Motor Shield • Arduino USB Host Shield • Arduino Proto Shield • MKR Proto Shield • MKR Proto Large Shield • Arduino ISP • Arduino USB 2 Serial Micro • Arduino Mini USB Serial Adapter |
Интернет вещей | Arduino Yun • Arduino Ethernet • Arduino MKR1000 • Arduino WiFi 101 Shield • Arduino GSM Shield V2 • Arduino WiFi Shield • Arduino Wireless SD Shield • Arduino Wireless Proto Shield • Arduino Ethernet Shield V2 • Arduino Yun Shield • Arduino MKR1000 Bundle |
Носимые устройства | Arduino Gemma • Lilypad Arduino Simple • Lilypad Arduino Main Board • Lilypad Arduino USB • LilyPad Arduino SimpleSnap |
3D-печать | Arduino Materia 101 |
Устаревшие устройства | - |
Примеры Arduino | |
---|---|
Стандартные функции | |
Основы |
|
Цифровой сигнал |
|
Аналоговый сигнал |
|
Связь |
|
Управляющие структуры |
|
Датчики |
|
Дисплей |
Примеры, объясняющие основы управления дисплеем:
|
Строки |
|
USB (для Leonardo, Micro и Due плат) |
В этой секции имеют место примеры, которые демонстрируют использование библиотек, уникальных для плат Leonardo, Micro и Due.
|
Клавиатура |
|
Мышь |
|
Разное |