Что такое UART? Подключение TX/RX, скорость в бодах и Serial на Arduino
Что такое UART и как он работает? Перекрёстное подключение TX/RX, скорость в бодах, стартовые и стоповые биты, связь двух Arduino, SoftwareSerial, уровни 5V/3.3V, Serial2 на ESP32 и UART на Pico.
Краткий ответ на вопрос «Что такое UART?»: UART (Universal Asynchronous Receiver-Transmitter, универсальный асинхронный приёмопередатчик) — аппаратный узел последовательной связи, который позволяет двум устройствам обмениваться данными побайтно всего по двум сигнальным проводам (TX и RX) с общей землёй GND. Каждая строка, которую ты видишь в мониторе порта, когда Arduino подключена к компьютеру, поступает через UART. Десятки модулей, например GPS-приёмники, Bluetooth-модуль HC-05, Wi-Fi-модуль ESP-01, GSM-модуль SIM800L, сканеры отпечатков пальцев и MP3-плееры, тоже общаются с Arduino по UART.
В этой статье мы пошагово разберём, почему UART не нужна тактовая линия, что такое скорость в бодах, как байт оформляется стартовым битом, битами данных и стоповым битом, зачем перекрёстно подключают TX и RX, как наладить сначала одностороннюю, а затем двустороннюю связь двух Arduino, каковы ограничения SoftwareSerial, как безопасно соединять платы на 5 V и 3,3 V, а также три UART у ESP32 и пины UART у Raspberry Pi Pico. В последнем разделе ты узнаешь, как формировать пакеты с начальным и конечным символами, чтобы данные не смешивались, и разберёшь самые частые ошибки.

Что такое UART и как он работает?
Ключевое слово в названии UART — «асинхронный»: в I2C и SPI вместе с данными передаётся тактовый сигнал, а у UART тактовой линии нет. Вместо этого обе стороны заранее договариваются о скорости — скорости в бодах. В состоянии покоя линия находится в HIGH (1). Чтобы отправить байт, передатчик переводит линию в LOW на время одного бита; это стартовый бит, который сообщает приёмнику: «Начинай отсчёт». Затем идут 8 бит данных, начиная с младшего значащего бита (LSB), за ними может следовать необязательный бит чётности, и наконец линия удерживается в HIGH не менее одного битового интервала; это стоповый бит. Настройка Arduino по умолчанию — 8N1: 8 бит данных, без чётности, 1 стоповый бит.
| Бит | Старт | D0 | D1 | D2 | D3 | D4 | D5 | D6 | D7 | Стоп |
|---|---|---|---|---|---|---|---|---|---|---|
| Буква «A» (0x41 = 0100 0001) | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 |
| Уровень линии | LOW | HIGH | LOW | LOW | LOW | LOW | LOW | HIGH | LOW | HIGH |
Каждый бит длится 1 / baud секунды. При 9600 бод на бит приходится 104,2 микросекунды; поскольку кадр 8N1 содержит 10 бит на байт (старт + 8 бит данных + стоп), можно передать максимум 960 байт в секунду. Обнаружив спадающий фронт стартового бита, приёмник считывает уровень линии в середине каждого бита. Даже если частоты двух генераторов немного различаются, данные читаются правильно, пока накопленная за 10 бит ошибка меньше половины бита; поэтому суммарная ошибка скорости должна оставаться примерно ниже 2–3%. Arduino Uno с кварцевым резонатором на 16 MHz не может точно обеспечить 115200 бод, и реальная скорость отличается примерно на 2,1%; связь всё равно работает, поскольку это в допустимых пределах.
| Скорость, бод | Длительность бита | Максимум байт в секунду (8N1) | Где используется |
|---|---|---|---|
| 9600 | 104,2 µs | 960 | NEO-6M GPS, режим передачи данных HC-05, DFPlayer Mini, классическая настройка монитора порта |
| 19200 | 52,1 µs | 1920 | Некоторые датчики и старые модемы |
| 38400 | 26,0 µs | 3840 | Режим AT-команд HC-05 |
| 57600 | 17,4 µs | 5760 | Старые загрузчики Arduino, верхний предел для SoftwareSerial |
| 115200 | 8,68 µs | 11 520 | ESP32 и ESP-01, быстрый отладочный вывод |
| 1000000 и выше | 1 µs или меньше | 100 000+ | Короткие соединения между платами, быстрая регистрация данных |
Сравнение UART, I2C и SPI
Три самых распространённых способа последовательной связи на Arduino — UART, I2C и SPI. UART работает только между двумя устройствами, один к одному, и обе стороны могут передавать данные в любой момент (полный дуплекс). I2C объединяет десятки устройств на двух общих проводах с помощью адресов; SPI гораздо быстрее и использует четыре провода, но требует отдельного пина выбора для каждого устройства. Подробности — в статьях «Что такое I2C» и «Что такое SPI».
| Характеристика | UART | I2C | SPI |
|---|---|---|---|
| Провода | 2 (TX, RX) + GND | 2 (SDA, SCL) + GND | 4 (SCK, MOSI, MISO, CS) + GND |
| Тактовая линия | Нет (асинхронный) | Да | Да |
| Число устройств | 2 («точка-точка») | До 127, по адресам | По числу пинов CS |
| Типичная скорость | 9600–115200 бод | 100–400 kHz | 1–80 MHz |
| Оба направления одновременно | Да (полный дуплекс) | Нет | Да |
| Типичные модули | GPS, Bluetooth, GSM, ESP-01, сканер отпечатков пальцев | OLED, LCD, RTC, BME280 | SD-карта, RFID, TFT, LoRa |
Перекрёстное подключение TX и RX и общая земля GND
Золотое правило подключения UART: пин TX (передача) одного устройства подключается к пину RX (приём) другого, то есть провода перекрещиваются. Представь связь рта и уха: когда один говорит, другой должен слушать. Если соединить TX с TX, два выхода окажутся соединены, и данные не пройдут. Третий провод, GND, задаёт обеим платам общую точку отсчёта напряжения; без него «HIGH» и «LOW» теряют смысл, а входящие данные превращаются в мусорные символы. Даже при питании плат от разных источников их земли нужно соединить.
| Arduino A | Провод | Arduino B | Примечание |
|---|---|---|---|
| TX (D11, SoftwareSerial) | → | RX (D10, SoftwareSerial) | Передаваемые A данные поступают к B |
| RX (D10, SoftwareSerial) | ← | TX (D11, SoftwareSerial) | Ответ B поступает к A |
| GND | — | GND | Общая земля, обязательна |
| 5V | Необязательно | 5V | Только если по USB питается лишь одна плата |
Связь двух Arduino: в одну сторону

В первом примере плата A десять раз в секунду передаёт плате B значение потенциометра на A0, а плата B соответственно регулирует яркость светодиода на D9. Обе платы используют SoftwareSerial на D10 (RX) и D11 (TX), оставляя USB-соединение и монитор порта свободными. Поскольку значения отправляются через println(), каждое число завершается символами «\r\n» (конец строки); по ним приёмник понимает, что число передано полностью. Подключение: D11 платы A к D10 платы B, D10 платы A к D11 платы B и земли вместе.
1#include <SoftwareSerial.h>
2
3SoftwareSerial link(10, 11); // RX = 10, TX = 11 (diğer karta / to the other board)
4
5void setup() {
6 Serial.begin(9600); // USB: bilgisayar / computer
7 link.begin(9600); // iki tarafta aynı baud / same baud on both sides
8}
9
10void loop() {
11 int deger = analogRead(A0); // potansiyometre 0-1023 / potentiometer 0-1023
12 link.println(deger); // ör. "512\r\n" / e.g. "512\r\n"
13 Serial.println(deger);
14 delay(100); // saniyede 10 ölçüm / 10 readings per second
15}
161#include <SoftwareSerial.h>
2
3SoftwareSerial link(10, 11); // RX = 10, TX = 11
4const int LED_PIN = 9; // PWM pini / PWM pin
5
6char tampon[8]; // en fazla 7 karakter + '\0' / up to 7 chars + '\0'
7byte konum = 0;
8
9void setup() {
10 Serial.begin(9600);
11 link.begin(9600);
12 pinMode(LED_PIN, OUTPUT);
13}
14
15void loop() {
16 while (link.available()) { // gelen her baytı oku / read every incoming byte
17 char c = link.read();
18 if (c == '\n') { // satır bitti / line complete
19 tampon[konum] = '\0';
20 int deger = atoi(tampon);
21 analogWrite(LED_PIN, map(deger, 0, 1023, 0, 255));
22 Serial.println(deger);
23 konum = 0;
24 } else if (c != '\r' && konum < sizeof(tampon) - 1) {
25 tampon[konum++] = c; // satıra ekle / append to the line
26 }
27 }
28}
29В коде приёмника обрати внимание на две вещи. Во-первых, данные никогда не приходят «целиком»: «512» поступает как три отдельных байта с промежутками примерно в 1 миллисекунду. Поэтому мы собираем байты в буфере и преобразуем их в число, когда приходит конец строки. Во-вторых, код никогда не ждёт: функции вроде readString() или parseInt() при отсутствии данных по умолчанию ждут 1 секунду и замедляют программу. Читать байты по мере поступления — самый надёжный и быстрый подход. Мы также ограничиваем размер буфера, чтобы повреждённые данные не записывались за пределы массива.
Двусторонняя связь: команда и ответ
В реальных проектах обычно нужен двусторонний обмен: одна плата отправляет команду, другая выполняет её и отвечает. В примере ниже плата A работает как мост: пересылает B каждый символ, введённый в мониторе порта, и выводит каждый символ, поступающий от B. Плата B понимает команды «LED ON», «LED OFF» и «DURUM?» (состояние), отвечает на каждую и также самостоятельно сообщает о нажатии кнопки на D2. Не забудь выбрать конец строки Newline («Новая строка») в мониторе порта; по этому символу B определяет завершение команды.
1#include <SoftwareSerial.h>
2
3SoftwareSerial link(10, 11); // RX = 10, TX = 11
4
5void setup() {
6 Serial.begin(9600);
7 link.begin(9600);
8 Serial.println("Komut yaz / type a command: LED ON, LED OFF, DURUM?");
9}
10
11void loop() {
12 if (Serial.available()) link.write(Serial.read()); // bilgisayar -> B kartı / computer -> board B
13 if (link.available()) Serial.write(link.read()); // B kartı -> bilgisayar / board B -> computer
14}
151#include <SoftwareSerial.h>
2
3SoftwareSerial link(10, 11); // RX = 10, TX = 11
4const int LED_PIN = 13; // kart üstündeki LED / on-board LED
5const int BUTON_PIN = 2; // buton GND'ye / button to GND
6
7String satir = "";
8int oncekiButon = HIGH;
9
10void komutCalistir(String k) {
11 k.trim(); // \r ve boşlukları at / strip \r and spaces
12 if (k == "LED ON") {
13 digitalWrite(LED_PIN, HIGH);
14 link.println("OK LED=1");
15 } else if (k == "LED OFF") {
16 digitalWrite(LED_PIN, LOW);
17 link.println("OK LED=0");
18 } else if (k == "DURUM?") { // durum sorgusu / status query
19 link.print("LED=");
20 link.print(digitalRead(LED_PIN));
21 link.print(" BUTON=");
22 link.println(digitalRead(BUTON_PIN) == LOW ? 1 : 0);
23 } else {
24 link.print("HATA / unknown: ");
25 link.println(k);
26 }
27}
28
29void setup() {
30 link.begin(9600);
31 pinMode(LED_PIN, OUTPUT);
32 pinMode(BUTON_PIN, INPUT_PULLUP);
33 satir.reserve(32);
34}
35
36void loop() {
37 while (link.available()) {
38 char c = link.read();
39 if (c == '\n') {
40 komutCalistir(satir);
41 satir = "";
42 } else if (satir.length() < 31) {
43 satir += c;
44 }
45 }
46
47 int buton = digitalRead(BUTON_PIN); // değişince kendiliğinden bildir / report changes unprompted
48 if (buton != oncekiButon) {
49 oncekiButon = buton;
50 link.println(buton == LOW ? "BUTON BASILDI / pressed" : "BUTON BIRAKILDI / released");
51 delay(20); // basit debounce / simple debounce
52 }
53}
54Вызов trim() на плате B удаляет символ \r, который приходит при настройке монитора порта «Both NL & CR», и лишние пробелы, поэтому команды распознаются при обеих настройках. Вызов reserve(32) для объекта String предотвращает повторное выделение памяти при каждом добавлении символа и уменьшает фрагментацию 2 КБ ОЗУ Uno. Эта структура также лежит в основе обмена с Arduino из программы на Python на компьютере; подробности — в статье «Последовательная связь Arduino с Python».
Ограничения SoftwareSerial
SoftwareSerial имитирует UART программно вместо аппаратной реализации: процессор самостоятельно отсчитывает время каждого бита. Это очень удобно, но имеет свою цену. При передаче прерывания отключаются на всё время каждого байта; при 9600 бод это около 1 миллисекунды на байт, в течение которой millis() может отставать, импульсы сервопривода — дрожать, а данные другого последовательного порта — теряться. Одновременно принимать данные может только один порт SoftwareSerial; если открыть второй, нужно выбрать принимающий порт через listen(). На платах вроде Mega и Leonardo для RX подходят только определённые пины с поддержкой прерываний.
| Характеристика | Аппаратный UART (Serial) | SoftwareSerial | AltSoftSerial |
|---|---|---|---|
| Пины на Uno | D0 (RX), D1 (TX), общие с USB | Почти любой пин (PCINT для RX) | Фиксированные: D8 (RX), D9 (TX) |
| Максимальная надёжная скорость | 1–2 Мбод | 57600 бод (115200 — на пределе) | Стабилен на умеренных скоростях (9600–38400) |
| Нагрузка на процессор | Очень низкая (аппаратный буфер) | Высокая, при передаче прерывания отключены | Средняя, использует Timer1 |
| Одновременная передача и приём | Да | Нет | Да |
| Несколько портов | 4 на Mega | Одновременно принимает только один | Один порт |
| Конфликты | Загрузка и монитор порта | Чувствительные к таймингам библиотеки, например Servo и NeoPixel | ШИМ на D10 и Servo (Timer1) |
Согласование уровней 5V и 3.3V
В UART уровень «HIGH» равен рабочему напряжению платы: 5 V у Arduino Uno, 3,3 V у ESP32, Raspberry Pi Pico, ESP-01 и большинства современных модулей. Если напрямую подключить выход TX на 5 V ко входу RX на 3,3 V, вход получит перенапряжение, которое повредит пин сразу или со временем; ESP32 и Pico на RP2040 не выдерживают 5 V. Обратное направление обычно работает: Uno воспринимает 3,0 V и выше как HIGH, поэтому читает TX с уровнем 3,3 V, но это близко к порогу, и на длинных проводах преобразователь уровней надёжнее.
| Соединение | Что нужно | Пример |
|---|---|---|
| Uno TX (5 V) → ESP32 / Pico RX (3,3 V) | Делитель напряжения или преобразователь уровней | 1 kΩ последовательно + 2 kΩ к GND: 5 × 2/3 ≈ 3,3 V |
| ESP32 / Pico TX (3,3 V) → Uno RX (5 V) | Обычно напрямую | Uno воспринимает напряжение выше 3,0 V как HIGH |
| Uno TX → HC-05 RX | Рекомендуется делитель напряжения | Вход RX у HC-05 рассчитан на уровень 3,3 V |
| Uno TX → SIM800L RX | Делитель напряжения | Уровень сигнала SIM800L — около 2,8 V |
| Обе платы на 5 V или обе на 3,3 V | Напрямую | Uno ↔ Nano, ESP32 ↔ Pico |
UART на ESP32: Serial, Serial1 и Serial2
У ESP32 есть три аппаратных UART, и самое удобное — благодаря матрице GPIO их линии можно переназначить почти на любые пины. UART0 (Serial) подключён к USB-UART-преобразователю и используется монитором порта. UART2 (Serial2) по умолчанию выведен на GPIO 16 (RX) и 17 (TX). Старые пины UART1 по умолчанию (GPIO 9 и 10) подключены к флеш-памяти платы и не подходят для прямого использования, поэтому всегда запускай Serial1 с указанием пинов: begin(baud, SERIAL_8N1, RX, TX). Код ниже создаёт двусторонний мост между монитором порта и устройством на UART2 (GPS, другой Arduino, датчиком); он идеально подходит для просмотра предложений NMEA от GPS-модуля.
| UART | Имя в Arduino | RX / TX по умолчанию | Примечание |
|---|---|---|---|
| UART0 | Serial | GPIO 3 / GPIO 1 | Подключён к USB-UART-преобразователю, используется для загрузки и монитора порта |
| UART1 | Serial1 | GPIO 9 / GPIO 10 (флеш-память, не использовать) | Укажи другие пины в begin(), например 25 / 26 |
| UART2 | Serial2 | GPIO 16 / GPIO 17 | На платах WROVER пины 16/17 заняты PSRAM, выбери другие |
1// ESP32: UART0 = Serial (USB), UART2 = Serial2 (GPIO 16/17)
2const int RXD2 = 16; // karşı cihazın TX'i buraya / the other device's TX goes here
3const int TXD2 = 17; // karşı cihazın RX'ine / to the other device's RX
4
5void setup() {
6 Serial.begin(115200); // USB Seri Monitör / USB Serial Monitor
7 Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2); // baud, çerçeve, RX, TX / baud, frame, RX, TX
8 // UART1'i de istediğin pinlere taşıyabilirsin / UART1 can be moved to any free pins:
9 // Serial1.begin(115200, SERIAL_8N1, 25, 26);
10 Serial.println("UART2 hazir / ready");
11}
12
13void loop() {
14 while (Serial2.available()) Serial.write(Serial2.read()); // UART2 -> USB
15 while (Serial.available()) Serial2.write(Serial.read()); // USB -> UART2
16}
17UART у ESP32 работают на скорости до 5 Мбод, и у каждого есть аппаратный буфер; приёмный буфер по умолчанию составляет 256 байт, его можно увеличить до begin() вызовом вроде Serial2.setRxBufferSize(1024). Это важно для GPS-модулей, передающих десятки предложений в секунду, или GSM-модулей с длинными ответами. Поскольку пины ESP32 работают на 3,3 V, при подключении Arduino на 5 V не забудь делитель из предыдущего раздела. Распиновку ESP32 можно посмотреть в утилите распиновки.
Пины UART Raspberry Pi Pico и MicroPython
У Raspberry Pi Pico два аппаратных UART (uart0 и uart1), каждый можно вывести на несколько разных пар пинов. В MicroPython REPL и вывод print() работают через отдельный виртуальный последовательный порт по USB, поэтому UART0 полностью свободен; отключать провода при загрузке кода, как на Arduino, не нужно. Пины Pico работают на 3,3 V, а у Pico на RP2040 не выдерживают 5 V. Код ниже выполняет на Pico те же задачи, что плата B на Arduino: читает строки из UART0, включает и выключает встроенный светодиод командами «LED ON» и «LED OFF» и отвечает. Если хочешь связать его со скетчем моста на Uno, не забудь делитель напряжения на линии TX Uno.
| UART | Пины TX | Пины RX | Пример MicroPython |
|---|---|---|---|
| uart0 | GP0, GP12, GP16 | GP1, GP13, GP17 | UART(0, 9600, tx=Pin(0), rx=Pin(1)) |
| uart1 | GP4, GP8 | GP5, GP9 | UART(1, 9600, tx=Pin(4), rx=Pin(5)) |
1from machine import UART, Pin
2import time
3
4uart = UART(0, baudrate=9600, tx=Pin(0), rx=Pin(1)) # UART0: GP0 = TX, GP1 = RX
5led = Pin("LED", Pin.OUT) # Pico ve Pico W dahili LED / on-board LED
6
7tampon = b""
8while True:
9 if uart.any():
10 tampon += uart.read() # gelen baytlar / incoming bytes
11 while b"\n" in tampon: # her tam satırı işle / handle each full line
12 satir, tampon = tampon.split(b"\n", 1)
13 try:
14 komut = satir.decode().strip()
15 except UnicodeError:
16 continue # bozuk bayt: atla / corrupt byte: skip
17 if komut == "LED ON":
18 led.on()
19 uart.write("OK LED=1\n")
20 elif komut == "LED OFF":
21 led.off()
22 uart.write("OK LED=0\n")
23 else:
24 uart.write("HATA / unknown: " + komut + "\n")
25 if len(tampon) > 64: # satır sonu hiç gelmezse taşmayı önle / avoid overflow
26 tampon = b""
27 time.sleep_ms(5)
28Формирование пакетов: начальный и конечный символы
UART — поток байтов; он не знает, где что начинается и заканчивается. Когда передатчик отправляет «23.5,48,812», приёмник может начать слушать с середины, байт может потеряться из-за помех, или два измерения могут слиться. Решение — оформить данные в пакет: если каждый пакет начинается с «<» и заканчивается «>», приёмник игнорирует всё до первого «<», обрабатывает пакет при поступлении «>» и отбрасывает неполные пакеты между ними. Передатчику нужно лишь вывести значения между Serial.print('<'), запятыми и Serial.print('>'). Код приёмника ниже можно сразу проверить, введя <23.5,48,812> в монитор порта.
1// Paket biçimi / packet format: <sicaklik,nem,isik> ör. / e.g. <23.5,48,812>
2const byte MAKS = 32;
3char tampon[MAKS];
4byte konum = 0;
5bool paketIcinde = false; // '<' görüldü mü? / have we seen '<'?
6
7void paketiIsle(char* p) {
8 char* parca = strtok(p, ","); // ilk alan / first field
9 if (!parca) return;
10 float sicaklik = atof(parca);
11 parca = strtok(NULL, ",");
12 if (!parca) return; // eksik alan: paketi at / missing field: drop
13 int nem = atoi(parca);
14 parca = strtok(NULL, ",");
15 if (!parca) return;
16 int isik = atoi(parca);
17
18 Serial.print("Sicaklik / temp: ");
19 Serial.print(sicaklik, 1);
20 Serial.print(" Nem / humidity: ");
21 Serial.print(nem);
22 Serial.print(" Isik / light: ");
23 Serial.println(isik);
24}
25
26void setup() {
27 Serial.begin(9600); // Seri Monitör'den <23.5,48,812> yazarak dene / test from the Serial Monitor
28}
29
30void loop() {
31 while (Serial.available()) {
32 char c = Serial.read();
33 if (c == '<') { // yeni paket başladı / a new packet starts
34 paketIcinde = true;
35 konum = 0;
36 } else if (c == '>' && paketIcinde) { // paket bitti / packet complete
37 tampon[konum] = '\0';
38 paketIcinde = false;
39 paketiIsle(tampon);
40 } else if (paketIcinde) {
41 if (konum < MAKS - 1) tampon[konum++] = c;
42 else paketIcinde = false; // çok uzun, bozuk: at / too long, corrupt: drop
43 } // paket dışındaki baytlar yok sayılır / bytes outside packets are ignored
44 }
45}
46| Метод | Пример | Плюсы | Минусы |
|---|---|---|---|
| Текст с концом строки | 512\n | Самый простой, читается в мониторе порта | По неполной строке нельзя определить её начало |
| Начальный и конечный символы | <23.5,48,812> | Самостоятельно восстанавливается после потери синхронизации | Нельзя использовать < и > внутри данных |
| Текст с контрольной суммой (как NMEA) | $GPGGA,...*47 | Повреждённые пакеты обнаруживаются | Чуть больше вычислений и кода |
| Двоичный пакет | 0xAA, длина, данные, CRC | Самый короткий и быстрый | Трудно читать и отлаживать |
При помехах или длинных проводах можно пойти дальше и добавить к пакету контрольную сумму. Хороший пример — формат NMEA, используемый GPS-модулями: все символы между «$» и «*» объединяются операцией XOR, а результат записывается в конце как двузначное шестнадцатеричное число. Приёмник выполняет такой же расчёт и отбрасывает пакет, если результат не совпадает. Это защищает от незаметных ошибок, например когда повреждённое значение «812» обрабатывается как «872».
Идеи проектов с UART
- Управление с телефона: Bluetooth-модуль HC-05 по сути является беспроводным UART; управляй светодиодом, реле или робомашинкой с телефона через HC-05.
- Запись GPS-координат: разбирай предложения NMEA, которые модуль NEO-6M GPS отправляет по UART, и записывай координаты на SD-карту.
- Система из двух плат: соедини по UART Uno, считывающую датчики, с ESP32, которая отправляет данные в интернет через Wi-Fi.
- SMS-сигнализация: отправляй AT-команды модулю SIM800L по UART и получай SMS при открытии двери.
- Панель управления на компьютере: отправляй команды Arduino из настольного приложения на Python и строй графики данных датчиков.
- MP3-плеер: выбирай треки, регулируй громкость и воспроизводи голосовые оповещения по UART с помощью DFPlayer Mini.
Частые ошибки и их решение
| Симптом | Вероятная причина | Решение |
|---|---|---|
| Мусорные символы в мониторе порта | Скорости в бодах не совпадают | Выбери одинаковую скорость в коде и мониторе порта |
| Данные вообще не поступают | TX подключён к TX, RX — к RX | Подключи провода перекрёстно: TX → RX, RX → TX |
| Случайные искажённые символы | GND не подключён | Соедини земли обеих плат |
| Ошибка загрузки (not in sync) | К D0/D1 подключён модуль | Отключи провода на время загрузки или используй SoftwareSerial |
| Команды не распознаются | Конец строки — \r\n или отсутствует | Выбери Newline в мониторе порта и очищай текст через trim() |
| Конец длинных сообщений теряется | Переполнен буфер на 64 байта | Избегай delay(), читай данные по мере поступления, снизь скорость |
| Пин RX ESP32 не работает или повреждён | TX с уровнем 5 V подключён напрямую | Добавь делитель напряжения или преобразователь уровней |
| SoftwareSerial даёт ошибки на 115200 | Программный отсчёт времени не успевает | Используй 57600 или ниже либо перейди на аппаратный UART |
UART — первый способ связи, который стоит освоить в электронике: достаточно двух проводов, общей земли GND и одинаковой скорости в бодах; при правильной настройке он работает годами без проблем. Освоив перекрёстное подключение, согласование уровней и формирование пакетов, ты сможешь легко использовать десятки модулей — от GPS до GSM. В приложении BlueGrays есть пошаговые проекты со схемами и кодом: односторонняя и двусторонняя связь между двумя Arduino, включение светодиода с телефона по Bluetooth и машинка с управлением по Bluetooth.
Частые вопросы
Как расшифровывается UART и для чего он нужен?
UART расшифровывается как Universal Asynchronous Receiver-Transmitter — универсальный асинхронный приёмопередатчик. Он позволяет двум устройствам обмениваться данными побайтно без тактовой линии, используя только провода TX и RX и заранее согласованную скорость в бодах. Монитор порта Arduino, модули GPS, Bluetooth и GSM используют UART.
Как подключить TX и RX?
Пин TX одного устройства подключается к RX другого, а RX — к TX другого, то есть соединение перекрёстное. Пины GND обоих устройств тоже обязательно нужно соединить. Подключение TX к TX полностью блокирует передачу данных.
Что такое скорость в бодах и какую выбрать?
Скорость в бодах — число передаваемых бит в секунду, и она должна совпадать с обеих сторон. Для Arduino и модулей наиболее распространены значения 9600 и 115200; 9600 — скорость по умолчанию у большинства GPS- и Bluetooth-модулей, а 115200 предпочитают для ESP32 и быстрого вывода. Начни со скорости по умолчанию, указанной в документации модуля.
UART и последовательный порт — одно и то же?
В повседневной речи они часто означают одно и то же. UART — аппаратный узел, преобразующий данные в последовательную форму; последовательный порт — соединение COM или /dev/tty на компьютере. RS-232 и RS-485 — стандарты, использующие другие уровни напряжения для передачи сигналов UART на большие расстояния.
Как использовать несколько UART на Arduino?
У Uno один аппаратный UART, общий с USB; для дополнительных портов используют SoftwareSerial, но одновременно принимать данные может только один из них. У Arduino Mega три дополнительных аппаратных UART (Serial1, Serial2 и Serial3), у ESP32 всего три, а у Raspberry Pi Pico — два.
Какой длины может быть кабель UART?
UART с уровнями TTL 3,3 V или 5 V надёжно работает на расстоянии до нескольких метров при низких скоростях в бодах; с ростом скорости расстояние сокращается. Для более длинных линий приёмопередатчики RS-485 (например, MAX485) обеспечивают сотни метров, а RS-232 — около 15 метров.
Что собрать после прочтения
Все проекты
Односторонняя связь между двумя Arduino
Ты заставляешь две Arduino разговаривать по одному проводу: нажми кнопку на одной, и на другой загорится светодиод, нажми снова — погаснет. Плата-передатчик сообщает о нажатии кнопки коротким сообщени

Двусторонняя связь между двумя Arduino
Две Arduino соединены проводами и разговаривают друг с другом: нажми кнопку на одной, и на другой загорится свет, нажми снова — погаснет. На обеих платах одна и та же программа, поэтому каждая и отпра

Управление светодиодом с телефона по Bluetooth
Небольшая репетиция того, как включать и выключать свет в комнате с телефона. Bluetooth-модуль передаёт в Arduino буквы, отправленные с телефона; одна буква включает красный светодиод, другая — зелёны

Машинка на L298N с управлением по Bluetooth
Преврати телефон в пульт и управляй своей машинкой-роботом. Arduino получает команды из приложения-пульта на телефоне через Bluetooth-модуль и вращает колёса через драйвер моторов; машинка едет вперёд

Клавиатура разработчика на Python
Если надоело снова и снова набирать одни и те же шаблоны при программировании, эта маленькая клавиатура создана для тебя. Arduino Leonardo подключается к компьютеру как обычная клавиатура, а каждая кл

Измерение расстояния HC-SR04 (вывод в порт)
Датчик HC-SR04 работает совсем как летучая мышь, которая находит дорогу в темноте: он посылает звук, которого ты не слышишь, слушает эхо и измеряет, насколько далеко предмет перед ним. Arduino каждые

Температура и влажность с DHT11
Насколько тепло в твоей комнате и влажный ли воздух или сухой? Датчик DHT11 измеряет температуру и влажность, а Arduino выводит значения на двухстрочный LCD-экран и обновляет их каждые пару секунд. Ес

Измерение освещённости модулем LDR на ESP32
Наблюдение в мониторе порта в реальном времени за сырым значением ADC модуля LDR и относительным процентом освещённости, вычисленным по опорным значениям темноты и света. Этот процент — не измерение в люксах. Учит логике калибровки модуля. Идеально выполнить его перед проектом 10, потому что он нужен для определения порога.
Другие статьи
Приложение BlueGrays
Собери эту схему шаг за шагом в телефоне
Схема подключения, код и список деталей на одном экране. 200+ проектов на Arduino, ESP32 и Pico готовы к сборке.
Наведи камеру телефона
Наведи камеру на код — откроется магазин приложений на телефоне.
или открыть магазин

