Как работает последовательная связь на Arduino?
Относительно плат Arduino Uno, Mega2560, Leonardo и аналогичных:
- Как работает последовательная связь?
- Насколько быстр последовательный порт?
- Как установить связь между отправителем и получателем?
Обратите внимание: это справочный вопрос.
@Nick Gammon, 👍21
1 ответ
Лучший ответ:
Асинхронная последовательная (обычно называемая последовательной) связь используется для отправки байтов с одного устройства на другое. Устройство может быть одним или несколькими из следующих:
- Ардуино
- ПК
- GPS
- Считыватель RFID-карт
- ЖК-дисплей
- Модем
- Другое
Тактовая частота и выборка данных
В отличие от SPI / USB / I2C последовательные коммуникации не имеют тактового сигнала. Частота дискретизации - это согласованная частота дискретизации (известная как скорость передачи данных). И отправитель, и получатель должны быть настроены на использование одинаковой скорости, иначе получатель получит бессмысленные данные (из-за того, что биты не будут дискретизироваться с той же частотой , с которой они были отправлены).
Передача является асинхронной, что в основном означает, что байты могут быть отправлены в любое время с различными интервалами между ними. На этом рисунке показана отправка одного байта:
На графике выше показана передаваемая буква «F». В ASCII это 0x46 (в шестнадцатеричном формате) или 0b01000110 (в двоичном формате). Наименее значимый (младший) бит передается первым, поэтому на графике выше вы видите биты, поступающие в следующем порядке: 01100010
.
Время «простоя» между байтами передается как непрерывные биты «1» (фактически линия передачи постоянно удерживается на высоком уровне).
Чтобы указать начало байта, стартовый бит всегда указывается путем понижения линии, как показано на графике. Как только приемник видит стартовый бит, он ждет в течение 1,5 времени выборки, а затем делает выборку битов данных. Он ждет 1,5 времени, чтобы:
- Пропускает начальный бит
- Сэмплы на полпути к следующему биту
Если скорость передачи данных составляет, например, 9600 бод, то частота дискретизации составит 1/9600 = 0,00010416
секунд (104,16 мкс).
Таким образом, при скорости 9600 бод после получения стартового бита приемник ждет 156,25 мкс, а затем производит выборку каждые 104,16 мкс.
Цель стопового бита — гарантировать, что между каждым байтом определенно есть 1-бит. Без стопового бита, если байт заканчивается нулем, то оборудование не сможет отличить его от начального бита следующего байта.
Чтобы получить вышеуказанный вывод на Uno, вы можете написать этот код:
void setup()
{
Serial.begin(9600);
Serial.print("F");
}
void loop ()
{
}
Количество бит данных
Чтобы сэкономить время передачи (в старые времена, хех) вам разрешалось указывать разное количество бит данных. Аппаратное обеспечение AtMega поддерживает нумерацию бит данных от 5 до 9. Очевидно, что чем меньше бит данных, тем меньше информации вы можете отправить, но тем быстрее это будет.
Биты четности
Вы можете опционально иметь бит четности. Он вычисляется, если требуется, путем подсчета количества единиц в символе, а затем путем проверки того, что это число нечетное или четное, путем установки бита четности в 0 или 1 по мере необходимости.
Например, для буквы "F" (или 0x46 или 0b01000110) вы можете видеть, что там 3 единицы (в 01000110). Таким образом, у нас уже есть нечетная четность. Итак, бит четности будет следующим:
- Нет четности: пропущено
- Четность: 1 (3 + 1 четно)
- Нечетность: 0 (3 + 0 нечетно)
Бит четности, если он присутствует, появляется после последнего бита данных, но перед стоповым битом.
Если получатель не получает правильный бит четности, это называется «ошибкой четности». Это указывает на наличие какой-то проблемы. Возможно, отправитель и получатель настроены на использование разных скоростей передачи данных (битов), или на линии был шум, который превратил ноль в единицу или наоборот.
Некоторые ранние системы также использовали «марковую» четность (где бит четности всегда был равен 1 независимо от данных) или «пробеловую» четность (где бит четности всегда был равен 0 независимо от данных).
9-битная передача
Некоторое коммуникационное оборудование использует 9-битные данные, поэтому в этих случаях бит четности превращается в 9-й бит. Существуют специальные методы для отправки этого 9-го бита (регистры являются 8-битными регистрами, поэтому 9-й бит должен быть помещен в другое место).
Количество стоповых битов
Раннее оборудование, как правило, было несколько медленнее в электронном плане, поэтому, чтобы дать приемнику время для обработки входящего байта, иногда указывалось, что отправитель должен отправить два стоповых бита. Это в основном добавляет больше времени, когда линия данных удерживается на высоком уровне (еще одно битовое время) до того, как может появиться следующий стартовый бит. Это дополнительное битовое время дает приемнику время для обработки последнего входящего байта.
Если получатель не получает логическую 1, когда должен быть стоповый бит, это называется «ошибкой кадрирования». Это указывает на наличие какой-то проблемы. Вполне возможно, что отправитель и получатель настроены на использование разных скоростей передачи данных.
Обозначение
Обычно последовательная связь обозначается указанием скорости, количества битов данных, типа четности и количества стоповых битов, например:
9600/8-N-1
Это говорит нам:
- 9600 бит в секунду
- 8 бит данных
- Нет четности (вместо этого вы можете увидеть: E=чет, O=нечет)
- 1 стоповый бит
Важно, чтобы отправитель и получатель пришли к согласию по вышеизложенному, в противном случае коммуникация вряд ли будет успешной.
Распиновка
Arduino Uno имеет цифровые контакты 0 и 1, доступные для аппаратного последовательного порта:
Чтобы соединить два Arduino, нужно поменять Tx и Rx следующим образом:
Скорость
Поддерживается широкий диапазон скоростей (см. рисунок ниже). «Стандартные» скорости обычно кратны 300 бод (например, 300/600/1200/2400 и т. д.).
Другие «нестандартные» скорости могут быть обработаны путем установки соответствующих регистров. Класс HardwareSerial делает это за вас. Например.
Serial.begin (115200); // установить скорость 115200 бод
Как правило, если вы используете 8-битные данные, вы можете оценить количество байтов, которые вы можете передать в секунду, разделив скорость передачи данных на 10 (из-за стартового бита и стопового бита).
Таким образом, при скорости 9600 бод вы можете передать 960 байт (9600 / 10 = 960
) в секунду.
Ошибки скорости передачи данных
Скорость передачи данных на Atmega генерируется путем деления системных часов и последующего подсчета до заданного числа. Эта таблица из технического описания показывает значения регистров и процент ошибок для часов 16 МГц (например, на Arduino Uno).
Бит U2Xn влияет на делитель тактовой частоты (0 = деление на 16, 1 = деление на 8). Регистр UBRRn содержит число, до которого досчитывает процессор.
Итак, из таблицы выше мы видим, что получаем 9600 бод при частоте 16 МГц следующим образом :
16000000 / 16 / 104 = 9615
Мы делим на 104, а не на 103, потому что счетчик является нулевым относительно. Таким образом, ошибка здесь составляет 15 / 9600 = 0,0016
, что близко к тому, что указано в таблице выше (0,02%).
Вы заметите, что некоторые скорости передачи данных имеют более высокий уровень ошибок, чем другие.
Согласно техническому описанию максимальный процент ошибок для 8 бит данных находится в диапазоне от 1,5% до 2,0% (более подробную информацию см. в техническом описании).
Ардуино Леонардо
Arduino Leonardo и Micro имеют разный подход к последовательной связи, поскольку они подключаются к хост-компьютеру напрямую через USB, а не через последовательный порт.
Из-за этого вам придется подождать, пока Serial станет «готовым» (пока программное обеспечение установит USB-соединение), с парой дополнительных строк, например:
void setup()
{
Serial.begin(115200);
while (!Serial)
{} // дождитесь готовности последовательной связи
Serial.print("Fab");
}
void loop ()
{
}
Однако, если вы хотите на самом деле общаться через контакты D0 и D1 (а не через USB-кабель), то вам нужно использовать Serial1 вместо Serial. Это можно сделать так:
void setup()
{
Serial1.begin(115200);
Serial1.print("Fab");
}
void loop ()
{
}
Уровни напряжения
Обратите внимание, что Arduino использует уровни TTL для последовательной связи. Это означает, что он ожидает:
- «Нулевой» бит — это 0 В
- Единичный бит — это +5 В
Старое последовательное оборудование, предназначенное для подключения к последовательному порту ПК, вероятно, использует уровни напряжения RS232, а именно:
- «Нулевой» бит — это от +3 до +15 вольт
- Единичный бит — это от −3 до −15 вольт
Мало того, что это «инвертировано» по отношению к уровням TTL («единица» более отрицательна, чем «ноль»), Arduino не может обрабатывать отрицательные напряжения на своих входных контактах (а также положительные, превышающие 5 В).
Таким образом, вам нужна схема интерфейса для связи с такими устройствами. Для входа (в Arduino) достаточно простого транзистора, диода и пары резисторов:
Для двусторонней связи вам необходимо иметь возможность генерировать отрицательные напряжения, поэтому требуется более сложная схема. Например, чип MAX232 сделает это в сочетании с четырьмя конденсаторами по 1 мкФ, которые будут действовать как схемы подкачки заряда.
Серийный номер программного обеспечения
Существует библиотека SoftwareSerial, которая позволяет вам осуществлять последовательную связь (до определенного момента) программно, а не аппаратно. Это имеет то преимущество, что вы можете использовать различные конфигурации выводов для последовательной связи. Недостаток в том, что выполнение последовательной связи программным обеспечением более интенсивно использует процессор и более подвержено ошибкам. Подробнее см. в разделе Software Serial.
Мега2560
Arduino "Mega" имеет 3 дополнительных аппаратных последовательных порта. Они обозначены на плате как Tx1/Rx1, Tx2/Rx2, Tx3/Rx3. Их следует использовать вместо SoftwareSerial, если это возможно. Чтобы открыть эти другие порты, используйте имена Serial1, Serial2, Serial3, например:
Serial1.begin (115200); // запуск аппаратного последовательного порта Tx1/Rx1
Serial2.begin (115200); // запуск аппаратного последовательного порта Tx2/Rx2
Serial3.begin (115200); // запуск аппаратного последовательного порта Tx3/Rx3
Прерывания
Как отправка, так и получение с использованием библиотеки HardwareSerial используют прерывания.
Отправка
Когда вы делаете Serial.print
, данные, которые вы пытаетесь напечатать, помещаются во внутренний буфер «передачи». Если у вас 1024 байта или больше оперативной памяти (например, на Uno), вы получаете 64-байтовый буфер, в противном случае вы получаете 16-байтовый буфер. Если в буфере есть место, то Serial.print
немедленно возвращается, таким образом не задерживая ваш код. Если места нет, то он «блокируется», ожидая, пока буфер не опустеет достаточно, чтобы там было место.
Затем, по мере передачи каждого байта оборудованием, вызывается прерывание (прерывание «USART, Data Register Empty»), и процедура обработки прерывания отправляет следующий байт из буфера через последовательный порт.
Получение
По мере получения входящих данных вызывается процедура обработки прерывания (прерывание «USART Rx Complete»), и входящий байт помещается в буфер «приема» (того же размера, что и буфер передачи, упомянутый выше).
Когда вы вызываете Serial.available
, вы узнаете, сколько байтов доступно в этом "приемном" буфере. Когда вы вызываете Serial.read
, байт удаляется из приемного буфера и возвращается в ваш код.
На Arduino с 1000 байтами или более оперативной памяти нет необходимости спешить с удалением данных из буфера приема, если вы не даете ему заполниться. Если он заполняется, то все последующие входящие данные отбрасываются.
Обратите внимание, что из-за размера этого буфера нет смысла ждать поступления очень большого количества байтов, например:
while (Serial.available () < 200)
{ } // ждем поступления 200 байт
Это никогда не сработает, потому что буфер не может вместить столько данных.
Советы
Перед чтением всегда проверяйте наличие данных. Например, это неверно:
if (Serial.available ()) { char a = Serial.read (); char b = Serial.read (); // может быть недоступен }
Тест
Serial.available
гарантирует, что у вас есть только один доступный байт, однако код пытается прочитать два. Это может сработать, если в буфере два байта, в противном случае вы получите -1, что будет выглядеть как 'ÿ' при печати.Учитывайте, сколько времени занимает отправка данных. Как упоминалось выше, при скорости 9600 бод вы можете передавать только 960 байт в секунду, поэтому попытка отправить 1000 показаний с аналогового порта при скорости 9600 бод не будет успешной.
Ссылки
- Асинхронный (последовательный) периферийный интерфейс - для Arduino
- Как обрабатывать входящие последовательные данные без блокировки
- RS-232 — Википедия
- Справочник по Arduino — серийный номер
- Как Arduino будет общаться по беспроводной сети через XBee?
- Не могу заставить работать software serial
- AT-команда не отвечает на последовательный монитор
- Arduino Преобразование std:string в String
- Как отправить команду AT на sim800l с помощью SoftwareSerial
- Как остановить SoftwareSerial от получения данных и повторно включить его в какой-то другой момент?
- Ардуино для чтения с преобразователя RS232 в последовательный модуль TTL
- Не нашел датчик отпечатков пальцев :( Arduino Mega 2560 Adafruit Fingerprint Sensor