Як працює серійний зв’язок на Arduino?


16

З посиланням на дошки Arduino Uno, Mega2560, Leonardo та подібні дошки:

  • Як працює послідовний зв’язок?
  • Наскільки швидко відбувається серійний?
  • Як з'єднати відправника та одержувача?

Зверніть увагу: це розроблено як опорне запитання.


Це може бути цікавим щодо буферів з обох сторін Nano, підключених до системи Raspian, що працює з реєстратором даних Python, використовуючи лише звичайний USB-кабель програмування між цими двома: arduino.stackexchange.com/questions/11710/…
SDsolar

Відповіді:


16

Асинхронна послідовна (зазвичай її називають послідовною) комунікацією використовується для передачі байтів з одного пристрою на інший. Пристрій може бути одним або декількома з таких:

  • Ардуїно
  • ПК
  • 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. Очевидно, що чим менше бітів даних, тим менше інформації можна надіслати, але тим швидше це буде.


Паритетні біти

Ви можете додатково мати біт парності. Це обчислюється, якщо потрібно, підраховуючи число символів 1, а потім переконайтесь, що це число непарне або навіть встановивши біт парності на 0 або 1, як потрібно.

Наприклад, для літери "F" (або 0x46 або 0b01000110) ви можете побачити, що там є 3 (у 01000110). Таким чином, ми вже маємо непарний паритет. Отже, біт паритету буде таким:

  • Без паритету: пропущено
  • Рівно парність: a 1 (3 + 1 - парний)
  • Парний коефіцієнт: a 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 Uno

Для з'єднання двох Arduinos ви помінятися Tx і Rx , як це:

З’єднання двох Arduinos разом


Швидкість

Підтримується широкий діапазон швидкостей (див. Графіку нижче). "Стандартні" швидкості зазвичай кратні 300 бодів (наприклад, 300/600/1200/2400 тощо).

Іншими "нестандартними" швидкостями можна керувати, встановивши відповідні регістри. Клас HardwareSerial робить це за вас. напр.

Serial.begin (115200);  // set speed to 115200 baud

Як правило, якщо припустити, що ви використовуєте 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)
      {}  // wait for Serial comms to become ready
      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, яка дозволяє здійснювати послідовний зв’язок (до певної точки) в програмному, а не в апаратному забезпеченні. Це має перевагу в тому, що ви можете використовувати різні конфігурації контактів для послідовного зв'язку. Недоліком є ​​те, що виконання послідовних програм у програмі є більш процесорним та більш схильним до помилок. Докладнішу інформацію див. У програмі Serial Software .


Мега2560

У Arduino "Mega" є 3 додаткові апаратні послідовні порти. Вони позначені на дошці як Tx1 / Rx1, Tx2 / Rx2, Tx3 / Rx3. Їх слід використовувати, якщо можливо, SoftwareSerial. Щоб відкрити ці інші порти, ви використовуєте імена Serial1, Serial2, Serial3, як це:

Serial1.begin (115200);  // start hardware serial port Tx1/Rx1
Serial2.begin (115200);  // start hardware serial port Tx2/Rx2
Serial3.begin (115200);  // start hardware serial port Tx3/Rx3

Переривання

Як відправлення, так і отримання, використовуючи бібліотеку HardwareSerial, використовують переривання.

Відправлення

Коли ви робите Serial.print, дані, які ви намагаєтеся надрукувати, розміщуються у внутрішньому буфері передачі. Якщо у вас є 1024 байт або більше оперативної пам’яті (наприклад, в Uno), ви отримуєте 64-байтовий буфер, інакше ви отримуєте 16-байтовий буфер. Якщо в буфері є місце, то Serial.printповертається негайно, тим самим не затримуючи код. Якщо немає місця, він "блокує", чекаючи, поки буфер буде спорожнений достатньо, щоб було місце.

Потім, коли кожен байт передається апаратним забезпеченням, викликається переривання (переривання "USART, реєстр даних порожній") і програма переривання пересилає наступний байт з буфера з послідовного порту.

Отримання

Після отримання даних, що надходять, викликається процедура переривання (переривання "USART Rx Complete") і вхідний байт поміщається в буфер "прийому" (той же розмір, як буфер передачі, згаданий вище).

Коли ви телефонуєте, Serial.availableви дізнаєтесь, скільки байтів доступно в тому буфері "отримання". При дзвінку Serial.readбайт видаляється з буфера прийому і повертається до вашого коду.

У Arduinos, що має 1000 байт оперативної пам’яті, не потрібно поспішати видаляти дані з буфера прийому, за умови, що ви не дозволяєте їх заповнювати. Якщо вона заповнюється, будь-які подальші вхідні дані відкидаються.

Зауважте, що через розмір цього буфера немає сенсу чекати надходження дуже великої кількості байтів, наприклад:

while (Serial.available () < 200)
  { }  // wait for 200 bytes to arrive

Це ніколи не буде працювати, оскільки буфер не може так сильно вмістити.


Поради

  • Перед читанням завжди переконайтеся, що дані доступні. Наприклад, це неправильно:

    if (Serial.available ())
      {
          char a = Serial.read ();
          char b = Serial.read ();  // may not be available
      }

    Serial.availableТест тільки гарантує , що ви є один байт доступні, однак код намагається прочитати два. Це може спрацювати, якщо в буфері є два байти, якщо ні, ви отримаєте -1 повернення, яке буде виглядати як "ÿ", якщо надруковано.

  • Будьте в курсі, скільки часу потрібно для надсилання даних. Як згадувалося вище, при 9600 бодах ви передаєте лише 960 байт в секунду, тому спроба надіслати 1000 показань з аналогового порту, при 9600 бод, не буде дуже успішною.


Список літератури


На 1-й графіці: зі стрілками виглядає, що стоп-біт передається спочатку. Якби ви обмінялися Rx / Tx і напрям стрілок, я думаю, що це менш заплутано.
ott--

Це було призначено для читання зліва направо (як це речення), і, отже, речі зліва трапляються першими. Поставте це так: на осцилоскопі, саме так ви б побачили слід.
Нік Гаммон

Гаразд із поясненням осцилографа, я купую це. :-)
ott--

Однак я думав, що ваша думка має багато сенсу. Що думають інші? Чи буде зрозуміліше, якби стрілки перевернулися, і я обміняв Rx / Tx?
Нік Гаммон

1
@ linhartr22 Я змінив його, щоб прочитати "безглузді дані", які, мабуть, ближче.
Нік Гаммон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.