UART Arduino: различия между версиями

Материал из MIK32 микроконтроллер
м (Sh-sergey переименовал страницу UART в UART Arduino)
 
(не показаны 4 промежуточные версии 1 участника)
Строка 41: Строка 41:
}
}
</syntaxhighlight>
</syntaxhighlight>
Еще один пример про передачу данных между двумя платами. Для реализации нам потребуется две любых платы Ардуино, между которыми мы будем гонять данные. К каждой из них мы подключим две кнопки и два светодиода по одинаковой схеме, и соединим их RX-TX крест-накрест, как было описано выше.
[[Файл:Imageав.png|мини|370x370пкс|Внешний вид подключения]]
Важное примечание. Если платы подключены к разным источникам питания, необходимо обязательно объединить их контакты GND, иначе для сигналов не будет опоры на соседней плате.
Кнопки, подключенные к одной плате, будут управлять светодиодами, подключенными к другой. И наоборот. Для этого каждая плата должна передавать информацию о том, что происходит на ее кнопках другой плате, одновременно принимая от нее такие же данные и управляя согласно им своими светодиодами. Сборки симметричны, функции тоже, значит и программы на обеих платах будут одинаковые.
<syntaxhighlight lang="c">
#define LED_1  4  // светодиод 1
#define LED_2  5  // светодиод 2
#define BUT_1  2  // кнопка 1
#define BUT_2  3  // кнопка 2
byte but[2];  // переменные для отслеживания кнопок
void setup() {
  // инициализируем пины, запускаем сирал порт
  pinMode(LED_1, OUTPUT);
  pinMode(LED_2, OUTPUT);
  pinMode(BUT_1, INPUT);
  pinMode(BUT_2, INPUT);
  Serial.begin(9600);
}
void loop() {
  if (get_but()) {            // с кнопками что-то было
    Serial.write(but[1]);  // отправляем в порт новое состояние кнопок
  }
  if (Serial.available() > 0) {        // если пришли данные от соседних кнопок
    byte incom = Serial.read();        // считываем эти данные
    digitalWrite(LED_1, !(incom / 2));  // зажигаем или гасим светодиод 1
    digitalWrite(LED_2, !(incom % 2));  // зажигаем или гасим светодиод 2
  }
}
byte get_but() {
  static unsigned long timer;
  if (timer + 50 > millis()) return 0; // опрос каждые 50мс (антидребезг)
  timer = millis();
  but[0] = but[1];
  but[1] = digitalRead(BUT_1) + digitalRead(BUT_2) * 10; // данные с обеих кнопок в одну переменную (единицы и десятки)
  if (but[0] != but[1]) return 1;      // если есть изменение, сигнализируем единицей
  return 0;                            // если нет, возвращаем 0
}
</syntaxhighlight>
== Заключение ==
UART бесспорно и заслуженно самый известный и широко применяемый интерфейс передачи данных. С его помощью к Ардуино подключаются датчики, исполнительные устройства, индикаторы и дисплеи, GPS и GPRS-модули. Через него осуществляется заливка программы в Ардуино и ее отладка. С его помощью можно легко и быстро организовать обмен команд и информацией с другим контроллером. Однако, у него есть и недостатки, например ограничение по скорости, относительно невысокая помехозащищенность, требование к точности тактовой частоты у передающей и принимающей платы, что особенно критично для контроллеров, работающих от внутреннего RC-генератора. Тем не менее он остается очень важным инструментом с огромными возможностями.

Текущая версия от 08:42, 4 мая 2022

Универсальный асинхронный передатчик (Univsersal Asynchronos Reciever-Transmitter) - это физическое устройство приёма и передачи данных по двум проводам. Оно позволяет двум устройствам обмениваться данными на различных скоростях. В спецификацию UART не входят аналоговые уровни на которых ведётся общение между устройствами, UART это протокол передачи единиц и нулей, электрическую спецификацию на себя берут другие стандарты, такие как TTL (transistor-transistor logic — транзисторно-транзисторная логика), RS-232, RS-422, RS-485 и другие. На данный момент в микроконтроллерах используется в основном TTL (или точнее CMOS) UART для соединения не более двух устройств. В наших примерах мы часто называем его последовательным портом.

Подключение

Макет подключения
Соединение контактов

У каждого устройства, поддерживающего UART обычно обозначены два вывода: RX и TX. TX — означает transmit (передаю), RX — receive (принимаю). Отсюда становится понятно что RX одного устройства нужно подключать к TX другого. Если Вы подключите RX одного устройства к RX другого, то оба устройства будут слушать друг друга, вы соединили их входы. Если соединить TX и TX - это уже более опасно, это выходы низкого сопротивления устройств и если на одном будет логическая единица, а на втором ноль — по проводу пойдёт ток короткого замыкания (это зависит от конкретной программной или аппаратной реализации). Хотя в современных чипах от этого есть защита, на всякий случай, не стоит на неё ориентироваться. Так же необходимо объединить референсные уровни двух устройств (GND-GND), если не подразумевается гальваническая развязка.

Принимающее устройство UART проверяет принятый пакет (через вывод RX) на наличие ошибок, вычисляя число единиц и сравнивая его со значением бита четности, содержащегося в пакете.

Если ошибки при передаче отсутствуют, то для получения блока данных он перейдет к обработке стартового бита, стоповых битов и бита четности. Возможно, ему понадобится получить несколько пакетов, прежде чем он сможет пересобрать весь байт данных из фреймов данных. После восстановления байт сохраняется в буфере UART.

Принимающее устройство UART использует бит четности для определения факта потери данных при передаче. Потеря данных при передаче происходит, когда бит во время передачи изменил свое состояние. Бит может меняться, в том числе, из-за расстояния передачи, магнитного излучения, несовпадения скоростей передачи.

Скорость передачи данных

Скорость изменения логических уровней (импульсов) на линии принято измерять в бодах. Единица измерения названа так в честь французского изобретателя Жана Мориса Эмиля Бодо.

Скорость при использовании UART может быть любой, единственное требование — скорости передающего и принимающего должны быть одинаковы. Стандартная скорость UART принята за 9600 бод. Arduino без проблем и лишних настроек может принимать и передавать данные на скоростях до 115200 бод.

Так как при передаче данных присутствуют синхронизирующие биты, именуемые старт-бит и стоп-бит, не совсем корректно говорить, что скорость 9600 бод равна 9600 битам в секунду. Если речь идёт о полезных данных, то реальная скорость на 20% ниже. Например, если выставлены параметры 8-N-1 и 9600 бод, то на передачу одного байта уходит десять бит, и 9600/10 = 960 байт, что равно 7680 битам в секунду.

Методы связи

UART позволяет одновременно передавать и принимать данные, однако не всегда это возможно или нужно. Например, если Вам нужно только получать не критические данные (которые можно проверить следующим пакетом, например расстояние, посылаемое лидаром каждые несколько сотен миллисекунд) от цифрового датчика или любого другого устройства и не нужно ничего передавать, такой метод называется симплексным. Всего различают три метода связи:

  • Полнодуплексная — когда ведущий и ведомый могут одновременно принимать и передавать (одновременная передача в обе стороны)
  • Полудуплексная — когда ведущий и ведомый поочерёдно принимают и передают (Поочерёдная передача в обе стороны)
  • Симплексная — когда ведущий или ведомый только передают (Передача в одну сторону)

Пример кода

Передача информации из контроллера на компьютер с ее отображением в мониторе. Это очень важная возможность, позволяющая наблюдать происходящее в программе, если вставить в нее соответствующие строки. Можно выводить на экран содержимое переменных, метки прохождения каких-то точек и так далее.

void setup() {

  Serial.begin(9600);       // запускаем порт
}

void loop() {
  Serial.print("timer: ");  // пишем слово timer:
  Serial.print(millis());   // выводим кол-во миллисекунд с начала запуска программы
  Serial.println("ms");     // подписываем их ms, переводим строку на новую
  delay(1000);              // задержка 1 сек
}

Еще один пример про передачу данных между двумя платами. Для реализации нам потребуется две любых платы Ардуино, между которыми мы будем гонять данные. К каждой из них мы подключим две кнопки и два светодиода по одинаковой схеме, и соединим их RX-TX крест-накрест, как было описано выше.

Внешний вид подключения

Важное примечание. Если платы подключены к разным источникам питания, необходимо обязательно объединить их контакты GND, иначе для сигналов не будет опоры на соседней плате.

Кнопки, подключенные к одной плате, будут управлять светодиодами, подключенными к другой. И наоборот. Для этого каждая плата должна передавать информацию о том, что происходит на ее кнопках другой плате, одновременно принимая от нее такие же данные и управляя согласно им своими светодиодами. Сборки симметричны, функции тоже, значит и программы на обеих платах будут одинаковые.

#define LED_1   4   // светодиод 1
#define LED_2   5   // светодиод 2
#define BUT_1   2   // кнопка 1
#define BUT_2   3   // кнопка 2

byte but[2];  // переменные для отслеживания кнопок

void setup() {
  // инициализируем пины, запускаем сирал порт
  pinMode(LED_1, OUTPUT);
  pinMode(LED_2, OUTPUT);
  pinMode(BUT_1, INPUT);
  pinMode(BUT_2, INPUT);
  Serial.begin(9600);
}

void loop() {
  if (get_but()) {            // с кнопками что-то было
    Serial.write(but[1]);   // отправляем в порт новое состояние кнопок
  }
  if (Serial.available() > 0) {         // если пришли данные от соседних кнопок
    byte incom = Serial.read();         // считываем эти данные
    digitalWrite(LED_1, !(incom / 2));  // зажигаем или гасим светодиод 1
    digitalWrite(LED_2, !(incom % 2));  // зажигаем или гасим светодиод 2
  }
}

byte get_but() {
  static unsigned long timer;
  if (timer + 50 > millis()) return 0; // опрос каждые 50мс (антидребезг)
  timer = millis();
  but[0] = but[1];
  but[1] = digitalRead(BUT_1) + digitalRead(BUT_2) * 10; // данные с обеих кнопок в одну переменную (единицы и десятки)
  if (but[0] != but[1]) return 1;      // если есть изменение, сигнализируем единицей
  return 0;                            // если нет, возвращаем 0
}

Заключение

UART бесспорно и заслуженно самый известный и широко применяемый интерфейс передачи данных. С его помощью к Ардуино подключаются датчики, исполнительные устройства, индикаторы и дисплеи, GPS и GPRS-модули. Через него осуществляется заливка программы в Ардуино и ее отладка. С его помощью можно легко и быстро организовать обмен команд и информацией с другим контроллером. Однако, у него есть и недостатки, например ограничение по скорости, относительно невысокая помехозащищенность, требование к точности тактовой частоты у передающей и принимающей платы, что особенно критично для контроллеров, работающих от внутреннего RC-генератора. Тем не менее он остается очень важным инструментом с огромными возможностями.