Перейти к содержанию

Интерфейс UART

UART — асинхронный последовательный интерфейс: данные идут по линиям TX и RX без тактового сигнала, а приёмник подстраивается по старт-биту каждого байта. Здесь — формат кадра, допустимое расхождение скоростей, подключение и согласование уровней 3,3 и 5 В, переходники USB–UART и примеры для AVR, STM32 и Arduino.

Обновлено Редакция GAW

UART (Universal Asynchronous Receiver/Transmitter, универсальный асинхронный приёмопередатчик) — узел микросхемы, который превращает байт в последовательность бит на выводе TX и собирает принятые биты в байт на выводе RX. Тактового сигнала нет: обе стороны заранее настроены на одну скорость, а приёмник синхронизируется заново в начале каждого кадра — по спаду старт-бита. Поэтому для связи двух устройств хватает трёх проводов: TX, RX и общего.

UART есть почти в каждом микроконтроллере. Через него работают отладочная консоль и загрузчики прошивки, к нему подключают GPS-приёмники, модемы, модули Bluetooth и Wi-Fi, а компьютер видит его через переходник USB–UART как COM-порт. Сам UART задаёт только формат кадра и скорость. Электрические уровни определяет то, чем кадр передаётся: логические 0 и 3,3 или 5 В на плате, RS-232 или RS-485 на кабеле.

Коротко

  • Линии: TX — выход передатчика, RX — вход приёмника, плюс общий провод. Соединяют накрест: TX одного устройства — на RX другого.
  • Кадр: старт-бит (0), от 5 до 9 бит данных младшим битом вперёд, необязательный бит чётности, 1 или 2 стоп-бита (1). В покое линия в единице. Самый частый формат — 8N1, 10 бит на байт.
  • Скорость одинакова на обеих сторонах, чаще всего 9600 или 115 200 бит/с. Приёмник делает 16 выборок на бит и решает по трём средним.
  • Допуск: частоты сторон могут расходиться в сумме на 2–3,3 % (Maxim, AN2141). Для AVR Microchip рекомендует не больше ±2 % на каждую сторону при кадре 8N1.
  • Уровни на выводах — логические, 0 и 3,3 или 5 В. COM-порт RS-232 с напряжением до ±15 В к ним напрямую не подключают.
  • USART — тот же UART плюс синхронный режим с тактовым выводом: XCK у AVR, CK у STM32.

UART, USART и RS-232: в чём разница

USART (Universal Synchronous/Asynchronous Receiver/Transmitter) — UART, который умеет работать ещё и синхронно. В синхронном режиме по отдельному выводу идёт тактовый сигнал — XCK у AVR, CK у STM32, — и данные защёлкиваются по его фронтам, как в SPI, поэтому точность скорости там не важна. У ATmega328P режим выбирают биты UMSEL01 и UMSEL00: асинхронный, синхронный или ведущий SPI (MSPIM). В синхронном режиме ведущего скорость равна fOSC/(2 · (UBRR0 + 1)), а бит UCPOL0 выбирает, по какому фронту XCK данные выдаются и по какому считываются (ATmega328P, раздел 20.3). В режиме MSPIM модуль становится вторым ведущим SPI. У STM32F1 вывод CK работает только как выход ведущего: тактов нет на старт- и стоп-битах, полярность и фаза программируются (RM0008).

Асинхронный режим USART обычно и называют просто UART: формат кадра и регистры у них общие. Дальше речь только о нём.

UART и RS-232, RS-485. UART определяет, что передаётся: кадр из старт-бита, данных и стоп-битов на заданной скорости. RS-232 и RS-485 определяют, как это передаётся по кабелю: напряжения, нагрузки, разъёмы. Maxim в AN2141 отмечает, что доступность UART привела к использованию того же кадра вне RS-232: в линиях RS-485, через оптроны и просто с несимметричными логическими уровнями 0…3,3 В вместо ±5 или ±10 В.

UART на выводах МКRS-232RS-485
Что задаётформат кадра и скоростьуровни, нагрузки, разъёмыуровни дифференциальной линии
Уровни0 и 3,3 или 5 В, покой — высокий уровень±5…±15 В, «1» и покой — минусразность напряжений проводов A и B
ЛинииTX, RX, общий проводTxD, RxD, общий провод, квитированиепара A и B, общий провод
Дальностьплата, короткий кабельоколо 15–20 мдо 1200 м
Схематочка — точкаточка — точкашина

Для RS-232 и RS-485 между UART и разъёмом ставят трансивер: MAX3232 или MAX485. Сам UART разницы не замечает: кадр и его временные параметры те же, меняются только напряжения на проводе.

Кадр UART: старт-бит, данные, чётность и стоп-биты

Когда передавать нечего, передатчик держит линию в единице — это состояние покоя (в терминах RS-232 — MARK). Кадр начинается старт-битом: линия на один бит переходит в ноль, и по этому спаду приёмник понимает, что пошли данные. Дальше идут биты данных, начиная с младшего, затем необязательный бит чётности и стоп-биты — снова единица. Следующий кадр может начаться сразу после стоп-бита или после паузы любой длины. USART ATmega328P понимает 30 сочетаний: 5, 6, 7, 8 или 9 бит данных, без чётности, с чётной или нечётной, один или два стоп-бита (ATmega328P, раздел 20.4).

Кадр UART: общий формат и символ U (0x55) в формате 8N1Вверху — формат кадра: в покое линия в единице, кадр начинается старт-битом (всегда 0), за ним от 5 до 9 бит данных начиная с младшего D0, необязательный бит чётности P и один или два стоп-бита (всегда 1). Поля D5–D8, P и второй стоп-бит есть не во всех форматах. Внизу — символ U, код 0x55, в формате 8N1 на выводе TX: старт-бит 0, биты данных 1, 0, 1, 0, 1, 0, 1, 0 и стоп-бит 1, то есть меандр с периодом в два бита. Точки отмечают середины бит, где приёмник считывает уровень. Кадр 8N1 длится 10 бит.Формат кадрапокойпокойСтартD0D1D2D3D4D5D6D7D8PСтопСтоп 2всегда 05–9 бит данных, младший бит первымчётностьстоп-биты, всегда 1поле есть не во всех форматахСимвол «U» (0x55) в формате 8N1Старт0D01D10D21D30D41D50D61D70Стоп1TX101 битпериод — 2 битакадр 8N1 — 10 битсередина бита: здесь приёмник считывает уровеньбит длится 104,2 мкс при 9600 бит/с и 8,68 мкс при 115 200 бит/с
Вверху — формат кадра; пунктиром показаны поля, которые есть не во всех форматах. Внизу — символ «U» (0x55) в формате 8N1: его биты чередуются, и на линии получается меандр с частотой вдвое ниже скорости.

Символ «U» удобен для проверки. Его код 0x55 — это 0101 0101, младший бит идёт первым, и вместе со старт- и стоп-битом на линии чередуются 0 и 1. Получается меандр с периодом два бита: при 9600 бит/с — 4800 Гц, при 115 200 бит/с — 57,6 кГц. Его частоту можно измерить осциллографом или частотомером и сразу узнать скорость. Тот же байт 0x55 шина LIN использует для подстройки скорости (LIN 2.2A).

Длительность бита — величина, обратная скорости: 104,2 мкс при 9600 бит/с, 8,68 мкс при 115 200 бит/с. Кадр 8N1 занимает 10 бит, из них полезных 8, поэтому при 115 200 бит/с через линию проходит не больше 11 520 байт в секунду.

Запись формата: 8N1, 7E1, 8E1

Формат кадра записывают тремя символами: число бит данных, тип чётности и число стоп-битов. N (none) — бита чётности нет, E (even) — чётная, O (odd) — нечётная; реже встречаются M (mark) — бит чётности всегда 1 и S (space) — всегда 0.

ФорматДанныеЧётностьСтоп-битыБит в кадреГде встречается
8N18нет110формат по умолчанию в Arduino: Serial.begin(скорость) — это SERIAL_8N1
8E18чётная111Modbus RTU: по спецификации чётность по умолчанию — even
8N28нет211Modbus RTU без чётности: спецификация требует тогда два стоп-бита
7E17чётная110Modbus ASCII и другие текстовые протоколы на 7-битных символах
9N19нет111многопроцессорный режим: девятый бит отличает адрес от данных

Бит чётности

Бит чётности дополняет число единиц: при чётной (even) чётности общее число единиц в данных и бите чётности чётное, при нечётной (odd) — нечётное. Аппаратно это исключающее ИЛИ всех бит данных, а при нечётной чётности результат ещё инвертируется (ATmega328P, раздел 20.4.1). В «U» = 0x55 четыре единицы, поэтому бит чётности в формате 8E1 равен 0, в 8O1 — 1. Режимы mark и space, они же stick parity, в UART 16550 включает отдельный бит: бит чётности передаётся и проверяется как постоянная 1 или 0 (TI, TL16C550C).

Чётность ловит любое нечётное число искажённых бит в кадре, но пропускает два: если перевернулись два бита, сумма по модулю 2 не меняется. Поэтому протоколы добавляют контрольную сумму на уровне пакета: Modbus RTU — CRC, Modbus ASCII — LRC.

Стоп-биты и девятый бит

Стоп-бит гарантирует, что перед следующим старт-битом линия побудет в единице и спад будет заметен. Приёмник проверяет только первый стоп-бит: так устроены и USART AVR, и UART 16550, и USART STM32, а второй стоп-бит лишь удлиняет паузу между кадрами (ATmega328P, раздел 20.4; TL16C550C; RM0008). Поэтому передатчик с двумя стоп-битами понятен приёмнику, настроенному на один: лишний стоп-бит для него — просто пауза. У AVR бит USBS0, задающий число стоп-битов, вообще влияет только на передатчик. Полтора стоп-бита — экзотика: у 16550 они бывают только при 5-битных символах (TL16C550C), у STM32 — в режиме смарт-карт (RM0008).

В 9-битном формате старший бит часто служит признаком адреса. В многопроцессорном режиме AVR (бит MPCM0) ведомые принимают только кадры с девятым битом, равным 1, — адресные. Узнав свой адрес, ведомое сбрасывает MPCM0 и принимает следующие кадры данных, а остальные их не видят (ATmega328P, раздел 20.9). У STM32 тот же приём называется выходом из режима mute по адресной метке (RM0008).

Скорость UART: стандартный ряд и 115 200 бит/с

Скорость UART измеряют в битах в секунду. Её часто называют скоростью в бодах — для UART это одно и то же: каждый символ на линии несёт один бит.

Скорость, бит/сДлительность битаБайт в секунду (8N1)Делитель 16550 при 1,8432 МГц
1200833,3 мкс12096
2400416,7 мкс24048
4800208,3 мкс48024
9600104,2 мкс96012
19 20052,08 мкс19206
38 40026,04 мкс38403
57 60017,36 мкс57602
115 2008,68 мкс11 5201
230 4004,34 мкс23 040—
460 8002,17 мкс46 080—
921 6001,09 мкс92 160—
1 000 0001,00 мкс100 000—

Почему ряд именно такой, видно по UART 16550 — микросхеме последовательного порта ПК. Её генератор скорости делит частоту кварца на программируемый делитель от 1 до 65 535 и выдаёт сигнал в 16 раз выше скорости: делитель = fXIN/(16 · скорость) (TI, TL16C550C). Кварц 1,8432 МГц — это ровно 16 × 115 200 Гц, поэтому все скорости из таблицы до 115 200 бит/с получаются при целых делителях, а делитель 1 даёт 115 200 бит/с — наибольшую скорость, которую 16550 получает от такого кварца.

Выше 115 200 бит/с идут кратные значения 230 400, 460 800 и 921 600 бит/с и «круглые» 250 000, 500 000 и 1 000 000 бит/с — они удобны для кварцев 8 и 16 МГц: ATmega328P на 16 МГц получает их без ошибки (таблица 20-7). Предел самого UART — у AVR в режиме U2X0 = 1 частота fOSC/8, то есть 2 Мбит/с на 16 МГц, у STM32F1 — 4,5 Мбит/с (RM0008), у мостов USB–UART — от 2 до 12 Мбит/с (таблица мостов ниже).

Почему кварцы 11,0592 и 14,7456 МГц

Если тактовая частота кратна 1,8432 МГц, делитель для стандартных скоростей получается целым. Отсюда «странные» кварцы в схемах с UART: 3,6864; 7,3728; 11,0592; 14,7456 и 18,432 МГц — это 2, 4, 6, 8 и 10 раз по 1,8432 МГц. На ATmega328P с любым из них все скорости до 230 400 бит/с получаются с нулевой ошибкой (ATmega328P, таблицы 20-5–20-7). У классического 8051 с 12 тактами на машинный цикл кварц 11,0592 МГц и TH1 = 0xFD дают ровно 9600 бит/с. Этот и другие варианты считает калькулятор скорости UART.

Как приёмник находит середину бита

Передатчику просто: он выдаёт биты по своему таймеру. Приёмник не знает, когда начнётся кадр, и должен сам найти середину каждого бита. Для этого его тактируют частотой, кратной скорости, и линия RX опрашивается много раз за бит — это передискретизация (oversampling). Типовой коэффициент — 16: так работают UART 16550 (TI, TL16C550C), USART AVR в обычном режиме и USART STM32F1. В режиме удвоенной скорости AVR (U2X0 = 1) выборок на бит 8.

Приёмник UART: передискретизация и выборка в середине битаЛиния RXD: покой в единице, спад в начале старт-бита, старт-бит, бит D0 со значением 1 и начало бита D1. При U2X = 0 приёмник делает 16 выборок на бит. Выборка 1 — первая, на которой линия уже в нуле; от фронта до неё проходит меньше 1/16 бита. Значение бита решают выборки 8, 9 и 10 по большинству из трёх; для старт-бита они же отсекают короткие помехи. При U2X = 1 выборок 8 на бит, а решают выборки 4, 5 и 6.покойстарт-битбит D0D1…RXDU2X = 016 выборок123456789101112131415161234567891011121314151612345678U2X = 18 выборок12345678123456781234выборки, по большинству которых решается уровень бита1 — первая выборка с нулём после спада: от фронта до неё меньше 1/16 бита (1/8 при U2X = 1)
Приёмник USART AVR: 16 выборок на бит, при U2X0 = 1 — 8. Отсчёт начинается с первой выборки, на которой линия уже в нуле; уровень бита решают три средние выборки по большинству. По рисункам 20-5 и 20-6 даташита ATmega328P.

Так это устроено у ATmega328P (раздел 20.8):

  1. Поиск старт-бита. Приёмник ждёт перехода линии из 1 в 0. Первую выборку с нулём он считает выборкой 1.
  2. Проверка старт-бита. Выборки 8, 9 и 10 (4, 5 и 6 при U2X0 = 1) должны дать ноль хотя бы в двух случаях из трёх. Если большинство — единицы, спад был помехой, и приёмник снова ждёт спада. Так короткий выброс на линии не превращается в ложный байт.
  3. Приём бит. Дальше каждые 16 выборок приёмник берёт три средние и решает по большинству: две или три единицы — бит равен 1. Такое голосование работает как фильтр нижних частот.
  4. Стоп-бит. Его читают так же, и ноль на месте стоп-бита означает ошибку кадра. Следующий старт-бит приёмник распознаёт уже сразу после выборок голосования стоп-бита, не дожидаясь его конца.

У STM32F1 проверка старт-бита строже: спад должен подтвердиться двумя тройками выборок — 3, 5, 7 и 8, 9, 10. Если в какой-то тройке нулей меньше двух, приёмник возвращается в ожидание; если в тройке ноль только в двух выборках из трёх, старт-бит принимается, но взводится флаг шума NE (RM0008, раздел 27.3.3). Данные читаются по выборкам 8, 9 и 10, и любое расхождение между ними отмечается тем же флагом NE.

Из этой схемы следуют три важных свойства:

  • Ошибка не накапливается. Приёмник подстраивается по спаду каждого старт-бита, поэтому расхождение частот действует только в пределах одного кадра (Maxim, AN2141).
  • Момент старта известен с точностью до выборки. Спад приходит в любой момент между выборками, и синхронизация неточна на 1/16 бита, а при U2X0 = 1 — на 1/8. Отчасти поэтому режиму удвоенной скорости нужна более точная частота (ATmega328P, раздел 20.3.2).
  • Помехоустойчивость. Короткую помеху в середине бита перевешивают две другие выборки, а выброс на линии в покое не запускает приём.

Допустимое расхождение скоростей

Абсолютная точность частоты UART не важна — важна разница частот передатчика и приёмника. Синхронизация происходит по спаду старт-бита, дальше приёмник отсчитывает биты по своим часам, и ошибка растёт к концу кадра. Хуже всего приходится стоп-биту — последнему биту, который проверяется.

Расхождение скоростей: выборки приёмника смещаются к концу кадраВверху — символ U (0x55) в формате 8N1 на выходе передатчика. Ниже — моменты выборок приёмника, который синхронизировался по спаду старт-бита и дальше отсчитывает биты по своим часам. При той же скорости каждая выборка приходится на середину бита. Если приёмник быстрее на 3 %, к стоп-биту выборка сдвигается на 0,28 бита, но ещё остаётся в зоне уверенного чтения. Если быстрее на 6 %, выборка стоп-бита сдвигается на 0,54 бита и попадает в бит D7, равный нулю: приёмник фиксирует ошибку кадра. Затенены средние 75 % каждого бита — зона, где по Maxim AN2141 уровень уже установился.СтартD0D1D2D3D4D5D6D7СтопTXприёмник:та же скоростьв серединена 3 % быстреесдвиг 0,28 битана 6 % быстреесдвиг 0,54 битаошибка кадрасредние 75 % бита: уровень уже установился (Maxim AN2141)
Модель: приёмник читает каждый бит в середине по своим часам. Если он быстрее передатчика на 3 %, выборка стоп-бита смещается на 0,28 бита, но остаётся в зоне уверенного чтения; на 6 % — на 0,54 бита, попадает в бит D7 и даёт ошибку кадра.

Оценка Maxim: от 2 до 3,3 %

Расчёт из AN2141 сделан для кадра 8N1 и приёмника с 16 выборками на бит. Середина стоп-бита отстоит от спада старт-бита на 9,5 бита, то есть на 16 × 9,5 = 152 такта приёмника. Насколько выборка может уйти от середины бита, зависит от линии:

  • на короткой линии с буферированными логическими уровнями или на паре RS-485 внутри прибора уровень надёжно читается в средних 75 % бита: допустимо отклонение ±37,5 % бита, или ±6 тактов;
  • на длинном ёмком кабеле RS-232 фронты затянуты, надёжны только средние 50 % бита: ±25 %, или ±4 такта.

Ещё один такт съедает неопределённость момента старта. Остаётся ±5 или ±3 такта на 152, то есть ±3,3 % на нормальной линии и ±2 % на тяжёлой. Это общий бюджет на обе стороны, и делить его можно в любой пропорции: если у одной стороны кварц, почти весь запас достаётся другой (AN2141).

Там же даны ориентиры по источникам частоты: кварцевый генератор с точностью 100 ppm (0,01 %) расходует ничтожную часть бюджета, а дешёвый керамический резонатор с точностью ±0,5 % и ещё ±0,5 % ухода от температуры и старения укладывается в жёсткие 2 % даже на обеих сторонах линии.

Допуски приёмника AVR и STM32

Для USART AVR Microchip приводит точные границы (ATmega328P, раздел 20.8.3). D — сумма числа бит данных и бита чётности; Rslow и Rfast — самая низкая и самая высокая скорость входящего потока, которую приёмник ещё примет, относительно его собственной скорости:

Rslow=(D+1) SS−1+D S+SF,Rfast=(D+2) S(D+1) S+SM,R_\text{slow} = \frac{(D + 1)\,S}{S - 1 + D\,S + S_F}, \qquad R_\text{fast} = \frac{(D + 2)\,S}{(D + 1)\,S + S_M},

где SS — число выборок на бит (16 или 8), SFS_F и SMS_M — номера первой и средней голосующих выборок: 8 и 9 при U2X0 = 0, 4 и 5 при U2X0 = 1.

DФорматыДиапазон при U2X0 = 0РекомендацияДиапазон при U2X0 = 1Рекомендация
55N193,20…106,67 %±3,0 %94,12…105,66 %±2,5 %
66N1, 5E194,12…105,79 %±2,5 %94,92…104,92 %±2,0 %
77N1, 6E194,81…105,11 %±2,0 %95,52…104,35 %±1,5 %
88N1, 7E195,36…104,58 %±2,0 %96,00…103,90 %±1,5 %
98E1, 9N195,81…104,14 %±1,5 %96,39…103,53 %±1,5 %
109E196,17…103,78 %±1,5 %96,70…103,23 %±1,0 %

Рекомендованная ошибка — примерно половина полного допуска с округлением вниз: Microchip считает, что передатчик и приёмник делят его поровну. Для 8N1 при U2X0 = 0 полный допуск — от −4,64 до +4,58 %. В таблице 20-2 даташита вместо −4,64 напечатано −4,54 %, но из Rslow = 95,36 % следует именно −4,64 %.

RM0008 задаёт для USART STM32F1 один общий допуск. В него должна уложиться сумма четырёх составляющих: ошибки передатчика вместе с его генератором, ошибки квантования делителя приёмника, ухода генератора приёмника и искажений линии — например, разной задержки фронта и спада в трансиверах (раздел 27.3.5):

КадрДробная часть делителя равна 0Дробная часть не равна 0
10 бит (M = 0): 8N1, 7E13,75 %3,33 %
11 бит (M = 1): 8E1, 9N13,41 %3,03 %

Числа приведены для случая, когда флаг шума NE считается ошибкой; если его игнорировать, допуск немного больше — от 3,53 до 4,375 %.

Что из этого следует на практике:

  • держите ошибку каждой стороны в пределах ±2 %, а для кадров с чётностью и режима U2X0 = 1 — ±1,5 %, как рекомендует Microchip;
  • суммарное расхождение до 2 % выдерживает даже длинный кабель, до 3 % — короткая линия (AN2141); предел самих приёмников — от 3,03 до 3,75 % у STM32F1 и около 4,6 % у AVR для 8N1;
  • длинный кадр, режим ×8 и длинный кабель уменьшают запас.

Производители мостов USB–UART говорят о том же. Silicon Labs в даташите CP2102N приводит общее правило: ошибка и передатчика, и приёмника — не больше ±2 %, а WCH указывает, что приёмник CH340 допускает расхождение около 2 %.

Расчёт делителя скорости для AVR и STM32

Скорость получается делением тактовой частоты на целое число (у STM32 — на число с дробной частью), поэтому точно получить нужную скорость удаётся не на любой частоте. Ошибку считают как (BAUDфакт/BAUD − 1) · 100 %.

AVR. Генератор скорости делит fOSC на UBRR0 + 1, а затем на 16 или, при U2X0 = 1, на 8 (ATmega328P, таблица 20-1):

UBRR=fOSC16⋅BAUD−1    (U2X0=0),UBRR=fOSC8⋅BAUD−1    (U2X0=1).UBRR = \frac{f_\text{OSC}}{16 \cdot BAUD} - 1 \;\; (U2X0 = 0), \qquad UBRR = \frac{f_\text{OSC}}{8 \cdot BAUD} - 1 \;\; (U2X0 = 1).

UBRR0 — 12-битное целое от 0 до 4095, результат округляют до ближайшего целого. Пример — 115 200 бит/с при кварце 16 МГц, как на Arduino Uno:

РежимUBRR0Фактическая скоростьОшибка
U2X0 = 016 000 000 / (16 · 115 200) − 1 = 7,68 → 8111 111 бит/с−3,5 %
U2X0 = 116 000 000 / (8 · 115 200) − 1 = 16,36 → 16117 647 бит/с+2,1 %
U2X0 = 0, кварц 14,7456 МГц14 745 600 / (16 · 115 200) − 1 = 7115 200 бит/с0 %

Без удвоения ошибка −3,5 % больше рекомендованных ±2 %, и с точным партнёром — компьютером через мост USB–UART — связь будет сбоить. С U2X0 = 1 ошибка +2,1 % укладывается в полный допуск этого режима (96,00…103,90 %), но превышает рекомендованные для него ±1,5 %. Такая связь работает, если вторая сторона точна, — например, мост CH340G с кварцем ошибается меньше чем на 0,3 % (WCH). Два AVR на 16 МГц с одинаковой настройкой договорятся при любой из этих ошибок: их скорости ошибаются одинаково.

STM32. USART делит частоту своей шины на USARTDIV — число с 12-битной целой и 4-битной дробной частью, которое записывают в регистр USART_BRR (RM0008, раздел 27.3.4):

BAUD=fCK16⋅USARTDIV.BAUD = \frac{f_\text{CK}}{16 \cdot USARTDIV}.

Здесь fCK — частота PCLK2 для USART1 и PCLK1 для USART2–USART5, а не системная частота. Для 115 200 бит/с на шине 72 МГц USARTDIV = 72 000 000 / (16 · 115 200) = 39,0625: целая часть 39, дробная 0,0625 · 16 = 1, USART_BRR = 0x271, ошибки нет. На шине 36 МГц USARTDIV = 19,53125, в регистр попадает 19,5 (0x138), и скорость выходит 115 385 бит/с — ошибка +0,16 %. Функция HAL_UART_Init() сама берёт частоту нужной шины и считает регистр (STM32 HAL).

Для других частот, для режимов U2X и OVER8 и для 8051 значение регистра и ошибку на всех стандартных скоростях сразу считает калькулятор скорости UART. В программах на C для AVR удобен заголовок <util/setbaud.h> из avr-libc: по F_CPU и BAUD он вычисляет UBRR_VALUE, сам решает, нужен ли режим U2X (USE_2X), и предупреждает при компиляции, если ошибка больше BAUD_TOL — по умолчанию 2 %.

Внутренний RC-генератор: почему UART «не работает»

Если микроконтроллер тактируется от встроенного RC-генератора, его неточность может съесть весь допуск UART. Типичная картина: прошивка работает на одном экземпляре платы и выдаёт мусор на другом или теряет связь при нагреве.

Источник частотыТочностьДанные
Кварцевый генератор±100 ppm = ±0,01 %Maxim, AN2141
Керамический резонатор±0,5 % плюс ±0,5 % от температуры и старенияMaxim, AN2141
RC-генератор ATmega328P, заводская калибровка±10 % при 3 В и 25 °CATmega328P, таблица 29-9
RC-генератор ATmega328P после калибровки OSCCAL±1 %там же
HSI STM32F103, заводская калибровкаот −1,1 до +1,8 % при 25 °C, от −2 до +2,5 % при −40…+105 °CSTM32F103x8, таблица 24
Встроенный генератор CH340C, N, K, E, X, B±1,2 % при −5…+55 °C, ±1,8 % при −25…+75 °CWCH, CH340
Генератор 48 МГц моста CP2102N±0,25 %Silicon Labs, CP2102N

Что из этого следует:

  • ATmega328P без кварца. Заводская калибровка гарантирует лишь ±10 %, и в допуск UART это не укладывается. После подстройки регистра OSCCAL точность ±1 % (ATmega328P, раздел 9.6), но она держится, пока не изменились температура и напряжение питания.
  • STM32 на HSI. При комнатной температуре генератор может уйти на +1,8 %, и если на другой стороне CH340C со своими ±1,2 %, в сумме выходит 3 %: больше 2 %, которые допускает приёмник CH340, и у самого края допуска USART STM32F1. HSI можно подстроить битами регистра RCC_CR до 1 % (STM32F103x8, таблица 24), но для надёжной связи лучше кварц.
  • Фьюз CKDIV8. Новый ATmega328P поставляется с RC-генератором 8 МГц и запрограммированным фьюзом CKDIV8, то есть работает на 1 МГц (ATmega328P, раздел 9.2.1). Если программа собрана с F_CPU = 8 МГц, все скорости UART получаются в 8 раз ниже: вместо 9600 бит/с — 1200. Снимите фьюз CKDIV8 или выставьте делитель регистром CLKPR в начале программы — даташит разрешает это при любом состоянии фьюза.
  • Автоподстройка. Если кварц поставить нельзя, скорость можно измерить по известному символу. Так устроен LIN: ведомые узлы работают без кварца и подстраиваются по байту синхронизации 0x55 в начале каждого кадра (LIN 2.2A).

Ошибки приёма: кадр, чётность, переполнение и break

UART сообщает об ошибках флагами состояния. Названия у разных производителей свои, смысл один:

ОшибкаЧто произошлоAVR, UCSR0ASTM32F1, USART_SR16550, LSR
Ошибка кадра (framing error)на месте первого стоп-бита прочитан 0FE0FEFE
Ошибка чётности (parity error)бит чётности не совпал с даннымиUPE0PEPE
Переполнение (overrun)пришёл новый символ, а прежние ещё не прочитаныDOR0OREOE
Шум (noise)выборки внутри бита не совпали—NE—
Breakлиния в нуле дольше целого кадраFE0 и байт 0x00FE, в режиме LIN — LBDBI

Ошибка кадра — главный признак неверной скорости или формата: приёмник ждёт стоп-бит, а линия в нуле. Её же дают помехи и плавающий вход RX без подтяжки. У AVR флаги ошибок хранятся в буфере приёма вместе с символом, поэтому UCSR0A читают до UDR0: чтение UDR0 сдвигает буфер, и флаги меняются (ATmega328P, раздел 20.7.4). UART 16550 после ошибки кадра пытается пересинхронизироваться, считая, что ошибку вызвал следующий старт-бит (TL16C550C).

Ошибка чётности бывает, только если чётность включена. Arduino молча выбрасывает такие байты: обработчик прерывания HardwareSerial читает UDR0, но не кладёт символ в буфер (ArduinoCore-avr).

Переполнение означает, что программа не успевает забирать данные. У ATmega328P буфер приёма — два символа, и ещё один может ждать в сдвиговом регистре: флаг DOR0 взводится, когда буфер полон, символ в сдвиговом регистре ждёт, а на линии уже начался следующий старт-бит (раздел 20.7.4). У STM32F1 регистр данных один; при переполнении символ в RDR сохраняется, а всё, что принято в сдвиговый регистр после него, теряется (RM0008). При 115 200 бит/с символ 8N1 приходит каждые 86,8 мкс — столько времени есть у программы, чтобы забрать байт, если нет FIFO или DMA. Лечится приёмом по прерыванию в кольцевой буфер, DMA и управлением потоком.

Break — линия в нуле дольше полного кадра: старт-бита, данных, чётности и стоп-битов (TL16C550C). Приёмник видит его как символ 0x00 с ошибкой кадра. UART 16550 кладёт в FIFO один нулевой символ, ставит флаг BI и принимает следующий символ только после того, как линия вернётся в единицу; STM32 обрабатывает break как ошибку кадра (RM0008). Передать break умеют и 16550 — битом 6 регистра LCR, — и STM32: бит SBK выдаёт 10 или 11 нулевых бит, а в режиме LIN — 13 (RM0008). Мосту CP2102N для этого нужен внешний резистор 10 кОм от TXD на землю: на время break мост отпускает вывод TXD, и линию прижимает резистор (Silicon Labs). Break открывает, например, каждый кадр LIN.

Пауза на линии (idle) — не ошибка, а полезное событие. STM32 ставит флаг IDLE, когда после принятого символа линия пробыла в единице целый кадр. По нему удобно определять конец пакета переменной длины — на этом построена функция HAL_UARTEx_ReceiveToIdle_DMA() (STM32 HAL).

Управление потоком: RTS/CTS и XON/XOFF

Управление потоком останавливает передатчик, когда приёмнику некуда класть данные. Без него единственная защита от переполнения — заведомо быстрая обработка на приёмной стороне.

Аппаратное, RTS/CTS. Каждая сторона выдаёт сигнал RTS (Request To Send) — «готова принимать» — и слушает вход CTS (Clear To Send) — «можно передавать». Соединяют их накрест, как данные: RTS одного устройства — на CTS другого (RM0008, рисунок 299; Silicon Labs, CP2102N). На логических выводах оба сигнала активны низким уровнем. У STM32 RTS прижат к нулю, пока приёмник готов, а передача идёт, пока на CTS ноль (RM0008). У мостов CP2102N, CH340 и FT232R RTS и CTS тоже активны нулём, у CH340 и FT232R это видно и по названиям выводов — RTS# и CTS#.

Сигнал «стоп» действует не мгновенно: символ, который уже передаётся, будет дослан.

  • STM32 при снятии CTS завершает текущий кадр (RM0008).
  • UART 16550 в режиме auto-CTS остановится перед следующим символом, если CTS снят до середины последнего стоп-бита текущего (TL16C550C).
  • CP2102N после снятия CTS передаёт ещё не больше двух байт (Silicon Labs).

Поэтому приёмник снимает RTS заранее, пока в буфере есть место. CP2102N, например, запрещает передачу, когда в его буфере приёма набирается 448 байт из 512, и разрешает снова, когда занято не больше 384 байт (Silicon Labs).

На высоких скоростях без аппаратного управления потоком не обойтись. Silicon Labs требует его для CP2102N на скоростях выше 1 Мбод, а WCH для потоков от 1 Мбит/с в одну сторону или от 500 кбит/с в обе советует вместо CH340 мост CH343 с аппаратным управлением потоком.

Программное, XON/XOFF. Приёмник посылает по своей линии TX символ XOFF — «стоп», а освободившись, XON — «продолжай». Это управляющие символы DC3 (0x13) и DC1 (0x11) (ECMA-48). Лишние провода не нужны, но для двоичных данных способ не годится: байты 0x11 и 0x13 встречаются в самих данных. Есть и ловушка взаимной блокировки: если обе стороны одновременно отправят XOFF, каждая будет ждать XON от другой. У CP2102N на этот случай есть настройка XOFF_CONTINUE: мост продолжает передавать свои XON и XOFF, даже получив XOFF (Silicon Labs).

Сигналы квитирования на разъёме DE-9 и нуль-модемный кабель разобраны в статье про RS-232.

Подключение UART: TX к RX и общий провод

Подключение UART: TX к RX накрест и общий проводДва устройства с UART. Выход TX первого соединён со входом RX второго, выход TX второго — со входом RX первого, общие провода GND соединены. Пунктиром показано необязательное аппаратное управление потоком: выход RTS каждого устройства идёт на вход CTS другого.Устройство 1микроконтроллерУстройство 2модуль или USB–UARTTXTXRXRXRTSRTSCTSCTSGNDGNDданные: TX → RXуправление потоком — если нужнообщий провод обязателен
TX одного устройства — на RX другого, общий провод обязателен. Пунктиром — необязательное аппаратное управление потоком: RTS каждой стороны идёт на CTS другой.

Три правила — те же, что в справочнике Arduino:

  1. Накрест. Выход TX одного устройства — на вход RX другого, и наоборот. TX — выход данных, RX — вход.
  2. Общий провод. Уровни TX и RX отсчитываются от земли, поэтому GND устройств соединяют обязательно. Если устройства питаются от одного источника, земля уже общая через провода питания.
  3. Одинаковые уровни. На выводах UART — логика, а не RS-232: подключать их к COM-порту с напряжениями до ±12 В нельзя, нужен преобразователь вроде MAX3232 (Arduino, Language Reference).

Если на модуле непонятно, какой вывод выход, помогает простая проверка. Передатчик в покое держит на TX высокий уровень и не боится нагрузки, а вход RX обычно лишь слабо подтянут внутри микросхемы: у FT232R — резисторами 200 кОм, у CH340 и CP2102N — токами в десятки и сотни микроампер. Подключите к выводу резистор 10 кОм на землю: выход TX останется в единице, а напряжение на входе RX заметно упадёт.

Согласование уровней 5 и 3,3 В

Согласование UART 5 В и 3,3 В: делитель на входе RX 3,3-вольтового устройстваСлева Arduino Uno на ATmega328P с питанием 5 В, справа модуль с питанием 3,3 В. Выход D1 (TX) Arduino подключён к входу RX модуля через делитель: R1 10 кОм последовательно и R2 20 кОм на общий провод, на входе получается 3,33 В. Выход TX модуля подключён к входу D0 (RX) Arduino напрямую: 3,3 В выше порога высокого уровня ATmega328P, который при питании 5 В равен 3,0 В. Общие провода соединены.Arduino UnoATmega328P, 5 ВD1 (TX)D0 (RX)GNDМодуль 3,3 Ввходы без допуска 5 ВRXTXGNDR110 кОмR220 кОм5 В3,33 В3,3 В напрямую: порог ATmega328P при 5 В — 0,6·VCC = 3,0 ВДелитель: 5 В · 20 / (10 + 20) = 3,33 В. Линия TX в покое в единице, поэтому через делитель всё время течёт 0,17 мА.
Arduino Uno на 5 В и модуль на 3,3 В. Выход 5 В идёт на вход 3,3 В через делитель, выход 3,3 В подключён к входу ATmega328P напрямую: его порог высокого уровня при питании 5 В — 3,0 В.

5 В на вход 3,3 В. Выход 5-вольтового устройства выдаёт почти 5 В, а вход 3,3-вольтовой микросхемы обычно рассчитан на напряжение не выше питания плюс несколько десятых вольта. У STM32F103 выводы двух типов: на обычных допустимо не больше 4,0 В, на помеченных FT (five-volt tolerant) — до VDD + 4,0 В (STM32F103x8, таблица 6). USART1 на PA9 и PA10 и USART3 на PB10 и PB11 выведены на выводы FT, а USART2 на PA2 и PA3 — на обычные (таблица 5). Если вход не допускает 5 В, ставят делитель напряжения:

URX=5 В⋅R2R1+R2=5 В⋅20 кОм10 кОм+20 кОм≈3,33 В.U_\text{RX} = 5\ \text{В} \cdot \frac{R_2}{R_1 + R_2} = 5\ \text{В} \cdot \frac{20\ \text{кОм}}{10\ \text{кОм} + 20\ \text{кОм}} \approx 3{,}33\ \text{В}.

Делитель вместе с ёмкостью входа затягивает фронты. Его эквивалентное сопротивление 10 ‖ 20 кОм = 6,67 кОм; с ёмкостью вывода STM32F103 5 пФ (таблица 36) постоянная времени около 33 нс, с ёмкостью монтажа — порядка 0,1 мкс. Это малая доля бита даже при 115 200 бит/с, где бит длится 8,68 мкс. Для скоростей от 1 Мбит/с резисторы берут в 10 раз меньше — 1 и 2 кОм — или ставят буфер с 5-вольтовыми входами, как в разделе о согласовании уровней статьи про SPI. Номиналы для другого напряжения подберёт калькулятор делителя. Линия TX в покое находится в единице, поэтому через делитель 10 и 20 кОм всё время течёт 0,17 мА.

3,3 В на вход 5 В. Здесь всё решает порог высокого уровня приёмника:

Приёмник с питанием 5 ВВысокий уровень гарантирован отВыход 3,3 В
ATmega328P, Arduino Uno0,6 · VCC = 3,0 Вгодится, запас 0,3 В
CH3402,3 Вгодится
FT232R при VCCIO = 5 Впорог переключения 1,0–1,5 Вгодится

Выход STM32F103 гарантирует в единице не меньше VDD − 0,4 В при токе 8 мА, то есть 2,9 В при питании 3,3 В (таблица 37). Вход AVR почти не потребляет тока, и на практике уровень близок к 3,3 В — работать будет. Но при питании AVR выше 5 В или просевшем питании 3,3-вольтовой стороны запас исчезает; для надёжности ставят буфер с ТТЛ-совместимыми входами.

Модуль USB–UART. У CH340 уровни выходов равны его напряжению питания: при 5 В выход TXD выдаёт 5 В. Чтобы получить 3,3 В, CH340 питают от 3,3 В, соединив выводы V3 и VCC, и тогда напряжение на подключённых к нему цепях не должно превышать 3,3 В: 5 В на входах допускают только CH340X и CH340C, CH340N из партий с номером, начинающимся на 4 (WCH). У FT232R уровни задаёт отдельный вывод VCCIO от 1,8 до 5,25 В, у CP2102N в корпусе QFN24 — вывод VIO от 1,71 В до VDD, у PL2303GC — VDD_IO от 1,8 до 5 В. Если на модуле есть переключатель 3,3/5 В, проверьте результат вольтметром: в покое на TX модуля должно быть не больше напряжения питания вашей платы.

Длина линии

UART с логическими уровнями рассчитан на связь внутри прибора. В качестве нормальной линии Maxim в AN2141 приводит шину длиной около метра с буферированными КМОП-уровнями. Сигнал отсчитывается от земли, а потенциалы земли у разнесённых устройств различаются: падение напряжения от токов питания на общем проводе прямо складывается с сигналом, туда же добавляются наводки. К тому же выводы микроконтроллера не рассчитаны на перенапряжения и разряды, которые приходят по кабелю.

Если линия длиннее или выходит из корпуса, тот же кадр UART передают через трансивер: RS-232 — на расстояние около 15–20 м, RS-485 — на сотни метров по витой паре. Для гальванической развязки ставят оптроны или цифровые изоляторы — AN2141 упоминает оптоизолированные линии среди типичных применений UART.

Если вход RX может остаться неподключённым, например на съёмном кабеле, подтяните его к питанию. Плавающий вход ловит наводки, и приёмник видит ложные старт-биты. WCH для схем, где CH340 и микроконтроллер питаются раздельно, рекомендует подтягивать вход RX микроконтроллера к его питанию резистором 2–22 кОм.

Переходники USB–UART: CH340, CP2102N, FT232R и PL2303

Компьютер видит мост USB–UART как виртуальный COM-порт: программа выбирает скорость и формат кадра, драйвер передаёт их мосту, а мост формирует кадры на выводах TXD и RXD. Уровни на этих выводах логические, как у микроконтроллера. Чтобы получить настоящий RS-232 или RS-485, после моста ставят преобразователь (WCH, CH340).

МостСкоростьУровни выводовСигналы модемаБуферыVID:PID
CH340 (WCH)50 бит/с – 2 Мбит/сравны питанию, 5 или 3,3 ВRTS, DTR, CTS, DSR, RI, DCD у CH340G, C, B, T; у CH340N — только RTSвстроенные1A86:7523
CP2102N (Silicon Labs)300 бод – 3 МбодVDD 3,0–3,6 В или VIO от 1,71 В; на входах до 5,8 В по абсолютному максимумуполный наборпо 512 байт на приём и передачу10C4:EA60
FT232R (FTDI)300 бод – 3 МбодVCCIO 1,8–5,25 В, порог входов 1,0–1,5 Вполный набор, любую линию можно инвертировать128 байт к UART, 256 байт от UART0403:6001
PL2303GC (Prolific)5 бит/с – 12 Мбит/сVDD_IO 1,8–5 В, входы допускают 5 Вполный набор768 и 256 байт067B:23A3

Что ещё важно при выборе:

  • CH340. CH340G, T и R нужен внешний кварц 12 МГц, и тогда ошибка скорости передачи меньше 0,3 %. CH340C, N, K, E, X и B обходятся без кварца, но их встроенный генератор даёт ошибку до 1,8 % (WCH). Драйвер совместим с CH341; в Linux мост обслуживает модуль ch341.
  • CP2102N. Встроенный генератор 48 МГц с точностью ±0,25 %, бесплатные драйверы виртуального COM-порта для Windows, macOS и Linux (Silicon Labs). Старый CP2102 работает до 1 Мбит/с, и для новых разработок производитель рекомендует CP2102N.
  • FT232R. Уровни выводов задаёт VCCIO, а настройкой во встроенной EEPROM можно инвертировать любую линию UART. FTDI выпускает драйверы VCP и D2XX (FTDI).
  • PL2303. Драйвер Prolific для Windows 8, 8.1 и 10 не поддерживает снятые с производства PL-2303HXA и PL-2303X, а для Windows 11 — ещё и PL-2303TA, TB, HXD, RA, SA, EA; производитель рекомендует PL2303GC. Prolific отдельно предупреждает о поддельных PL-2303HX ревизии A: в диспетчере устройств они дают ошибку с кодом 10.

Какой мост стоит в переходнике, видно по идентификатору VID:PID: в Windows — в свойствах устройства («ИД оборудования»), в Linux — в выводе lsusb. Значения по умолчанию указаны в таблице; драйверы Linux для этих мостов — ch341, cp210x, ftdi_sio и pl2303 (ядро Linux).

Автосброс Arduino через DTR

Arduino Uno R3: связь ATmega16U2 с ATmega328P и автосброс через DTRМост USB–UART ATmega16U2 соединён с ATmega328P через резисторы 1 кОм: выход TXD1 через RN4B идёт на вход RXD (вывод D0 разъёма), выход TXD ATmega328P через RN4A — на вход RXD1 моста. Вывод D1 разъёма подключён к TXD ATmega328P. Сигнал DTR моста через конденсатор C5 100 нФ подаётся на RESET; RESET подтянут к +5 В резистором RN1D 10 кОм, диод D2 не даёт ему подняться выше питания. Внизу — временная диаграмма: когда программа открывает порт, DTR переходит в ноль, напряжение на RESET падает до нуля и восстанавливается с постоянной времени 10 кОм × 100 нФ = 1 мс; этого хватает для сброса.ATmega16U2мост USB–UARTPD3 (TXD1)PD2 (RXD1)PD7 (DTR)ATmega328Pосновной МКPD0 (RXD)PD1 (TXD)RESETRN4B1 кОмD0 разъёмаRN4A1 кОмD1 разъёмаC5100 нФRN1D10 кОмD2+5 ВПрограмма открыла портDTRRESET+5 В0,2·VCCτ = RC = 10 кОм · 100 нФ = 1 мсниже 0,2·VCC напряжение держится около 0,22 мс, а для сброса достаточно 2,5 мкс
Последовательная часть Arduino Uno R3: мост ATmega16U2 связан с ATmega328P через резисторы 1 кОм, сигнал DTR через конденсатор 100 нФ сбрасывает ATmega328P при открытии порта. По схеме A000066.

У Arduino Uno мост USB–UART — отдельный микроконтроллер ATmega16U2. Его линия DTR подключена к выводу RESET ATmega328P через конденсатор 100 нФ (C5 на схеме Uno R3), а RESET подтянут к +5 В резистором 10 кОм (RN1D). Когда сигнал DTR включается — на выводе это переход в ноль, — напряжение на RESET вслед за ним падает почти до нуля: напряжение на конденсаторе мгновенно измениться не может. Потом конденсатор заряжается через резистор с постоянной времени τ = 10 кОм · 100 нФ = 1 мс.

Ниже 0,2 · VCC — уровня, при котором ATmega328P гарантированно видит сброс, — напряжение остаётся τ · ln 1,25 ≈ 0,22 мс, а для сброса достаточно импульса длиной 2,5 мкс (ATmega328P, таблица 29-11). Диод D2 не даёт RESET подняться заметно выше питания, когда DTR возвращается в единицу.

Arduino IDE пользуется этим перед загрузкой скетча, а в macOS и Linux плата сбрасывается при каждом открытии порта программой. Следующие полсекунды работает загрузчик: он перехватывает первые байты, поэтому программе на компьютере стоит подождать около секунды после открытия порта, прежде чем что-то отправлять (Arduino). Если автосброс мешает, на Uno можно разрезать перемычку RESET-EN.

Загрузчик слушает порт на своей скорости, и она зависит от платы: у Uno и Nano с новым загрузчиком — 115 200 бит/с, у Nano со старым загрузчиком и Pro Mini на 16 МГц — 57 600 бит/с (ArduinoCore-avr, boards.txt). Если в IDE выбран не тот вариант платы, загрузка не начнётся.

Самодельной плате с ATmega328P и внешним переходником нужна та же цепь: конденсатор 100 нФ последовательно между выводом DTR переходника и RESET и подтяжка RESET к питанию. WCH в даташите CH340 приводит похожую схему для STM32F103: сигналы DTR и RTS моста управляют выводами BOOT0 и NRST, и встроенный загрузчик запускается без нажатия кнопок.

Полудуплекс по одному проводу, LIN и RS-485

UART полнодуплексный: TX и RX работают одновременно. Но его кадр годится и для линий, где все говорят по одному проводу по очереди.

Однопроводный режим. У STM32 его включает бит HDSEL: TX и RX соединяются внутри, а вывод TX отпускается, когда передавать нечего, поэтому его настраивают как открытый сток или вход. Конфликты на линии разрешает программа: аппаратура передачу не блокирует (RM0008, раздел 27.3.10). У AVR серии DA для этого есть режим One-Wire: бит LBME подключает приёмник к выводу TXD, бит ODME делает выход открытым стоком, а единицу на линии держит подтягивающий резистор. Передатчик при этом принимает собственные байты, и, сравнив их с отправленными, легко заметить столкновение (AVR128DA, раздел 25.3.3.2.6). На полудуплексном UART построен и однопроводный интерфейс программирования UPDI этих микроконтроллеров. У классических AVR такого режима нет, и линию собирают снаружи по тому же принципу: выход TX через диод, катодом к выводу, и общая подтяжка — получается монтажное И, как в I²C.

LIN — однопроводная автомобильная шина поверх UART: один ведущий и несколько ведомых, скорость от 1 до 20 кбит/с, рабочее напряжение бортовой сети 8–18 В. Каждый кадр начинается полем break — не меньше 13 бит нуля — и байтом синхронизации 0x55, по которому ведомые без кварца подстраивают скорость (LIN 2.2A). USART STM32 в режиме LIN сам выдаёт такой break и распознаёт его на приёме (RM0008).

RS-485 — электрический уровень для шины на сотни метров. UART при этом не меняется: к нему добавляются трансивер и сигнал переключения направления. У AVR передатчик трансивера удобно выключать по флагу TXC0: он взводится, когда последний стоп-бит полностью ушёл в линию и новых данных нет (ATmega328P, раздел 20.6.3). Подробно — в статье про RS-485.

UART в AVR: регистры и приём по прерыванию

USART0 ATmega328P выведен на PD0 (RXD) и PD1 (TXD) — выводы 0 и 1 Arduino Uno. Модулем управляют пять регистров (ATmega328P, раздел 20.11):

РегистрБитыНазначение
UDR07–0запись — байт в буфер передатчика, чтение — принятый байт из двухуровневого буфера
UCSR0ARXC0, TXC0, UDRE0, FE0, DOR0, UPE0, U2X0, MPCM0флаги приёма и передачи, ошибки, удвоение скорости, многопроцессорный режим
UCSR0BRXCIE0, TXCIE0, UDRIE0, RXEN0, TXEN0, UCSZ02, RXB80, TXB80прерывания, включение приёмника и передатчика, старший бит размера символа, девятые биты
UCSR0CUMSEL01, UMSEL00, UPM01, UPM00, USBS0, UCSZ01, UCSZ00, UCPOL0режим, чётность, число стоп-битов, размер символа, полярность такта
UBRR0H, UBRR0L11–0делитель скорости, 12 бит

Формат задают биты UCSZ02…UCSZ00 (011 — 8 бит данных, 111 — 9), UPM01 и UPM00 (00 — без чётности, 10 — чётная, 11 — нечётная) и USBS0 (0 — один стоп-бит, 1 — два). После сброса UCSR0C = 0x06, то есть 8N1.

Источников прерывания три: RXC0 — принят байт, UDRE0 — буфер передатчика свободен, TXC0 — передача полностью завершена. Прерывание по RXC0 повторяется, пока байт не прочитан из UDR0, а по UDRE0 — пока в UDR0 не записан новый байт или прерывание не запрещено (разделы 20.6.3 и 20.7.3).

Пример для ATmega328P на 16 МГц: приём по прерыванию в кольцевой буфер, передача опросом флага, эхо принятых байтов. Скорость 57 600 бит/с выбрана намеренно: <util/setbaud.h> включит U2X0 и получит UBRR0 = 34 с ошибкой −0,8 %, а на 115 200 бит/с ошибка была бы +2,1 %, и заголовок выдал бы при компиляции предупреждение о превышении допуска.

#ifndef F_CPU
#define F_CPU 16000000UL
#endif
#define BAUD 57600
#include <util/setbaud.h>      /* UBRR_VALUE and USE_2X for F_CPU and BAUD, checked at compile time */
#include <avr/interrupt.h>
#include <avr/io.h>
#include <stdint.h>

#define RX_SIZE 64u            /* power of two, so the index wraps with a mask */
static volatile uint8_t rx_buf[RX_SIZE];
static volatile uint8_t rx_head;   /* written only by the ISR */
static volatile uint8_t rx_tail;   /* written only by the main loop */
static volatile uint8_t rx_lost;   /* bytes lost to overrun or a full buffer */
static volatile uint8_t rx_bad;    /* frames dropped for framing or parity errors */

void uart_init(void)
{
    UBRR0H = UBRRH_VALUE;
    UBRR0L = UBRRL_VALUE;
#if USE_2X
    UCSR0A = _BV(U2X0);                               /* 8 samples per bit */
#else
    UCSR0A = 0;
#endif
    UCSR0C = _BV(UCSZ01) | _BV(UCSZ00);               /* 8N1 */
    UCSR0B = _BV(RXCIE0) | _BV(RXEN0) | _BV(TXEN0);   /* RX interrupt, receiver, transmitter */
}

ISR(USART_RX_vect)
{
    uint8_t status = UCSR0A;    /* the flags belong to the byte in UDR0: read them first */
    uint8_t data = UDR0;
    if (status & _BV(DOR0)) rx_lost++;                /* earlier bytes were lost in hardware */
    if (status & (_BV(FE0) | _BV(UPE0))) {            /* wrong baud rate, noise or a break */
        rx_bad++;
        return;
    }
    uint8_t next = (uint8_t)((rx_head + 1u) & (RX_SIZE - 1u));
    if (next == rx_tail) {                            /* ring buffer full: drop the byte */
        rx_lost++;
        return;
    }
    rx_buf[rx_head] = data;
    rx_head = next;
}

/* Returns the next received byte or -1 if the buffer is empty. */
int16_t uart_getc(void)
{
    if (rx_head == rx_tail) return -1;
    uint8_t c = rx_buf[rx_tail];
    rx_tail = (uint8_t)((rx_tail + 1u) & (RX_SIZE - 1u));
    return c;
}

void uart_putc(uint8_t c)
{
    while (!(UCSR0A & _BV(UDRE0))) {}                 /* wait for an empty transmit buffer */
    UDR0 = c;
}

int main(void)
{
    uart_init();
    sei();
    for (;;) {
        int16_t c = uart_getc();
        if (c >= 0) uart_putc((uint8_t)c);            /* echo */
    }
}

Кольцевой буфер не требует запрета прерываний: индекс rx_head меняет только обработчик прерывания, rx_tail — только основная программа, и оба однобайтовые, поэтому их чтение и запись у AVR неделимы. Одна ячейка буфера всегда остаётся пустой, чтобы полный буфер отличался от пустого, — в нём помещается 63 байта. Чтобы передача не останавливала программу, её делают так же: второй кольцевой буфер и прерывание по UDRE0, которое разрешают при записи в буфер и запрещают, когда он опустел. Так устроен Serial в Arduino. Подробнее о семействе — в разделе AVR.

UART в STM32 и Arduino

STM32: HAL, прерывания и DMA

В HAL для STM32 параметры UART собраны в структуре UART_InitTypeDef: скорость, длина слова, стоп-биты, чётность, режим и аппаратное управление потоком. Ловушка в длине слова: бит чётности у STM32 входит в слово и занимает его старший бит (RM0008, таблица 195). Поэтому 8E1 — это UART_WORDLENGTH_9B плюс UART_PARITY_EVEN, а 7E1 — UART_WORDLENGTH_8B с чётностью.

UART_HandleTypeDef huart1;   /* GPIO, clocks and the DMA channel are configured elsewhere (CubeMX) */
static uint8_t rx_buf[64];

void uart1_start(void)
{
  huart1.Instance = USART1;                    /* PA9 = TX, PA10 = RX, clocked from PCLK2 */
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;       /* 8E1 = UART_WORDLENGTH_9B + UART_PARITY_EVEN */
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  HAL_UART_Init(&huart1);                      /* computes USART_BRR from the actual PCLK2 */

  static const uint8_t hello[] = "ready\r\n";
  HAL_UART_Transmit(&huart1, hello, sizeof hello - 1, 100);   /* blocking, 100 ms timeout */
  HAL_UARTEx_ReceiveToIdle_DMA(&huart1, rx_buf, sizeof rx_buf);
}

/* Called when the buffer is half full, full, or the line stays idle for one frame. */
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t size)
{
  if (huart->Instance != USART1) return;
  if (HAL_UARTEx_GetRxEventType(huart) == HAL_UART_RXEVENT_HT) return;  /* wait for the rest */
  handle_packet(rx_buf, size);                 /* your code: size bytes have arrived */
  HAL_UARTEx_ReceiveToIdle_DMA(huart, rx_buf, sizeof rx_buf);
}

HAL_UART_Transmit() блокирует программу, пока все байты не уйдут или не истечёт таймаут. HAL_UART_Receive_IT() и HAL_UART_Receive_DMA() принимают заранее известное число байт в фоне, а HAL_UARTEx_ReceiveToIdle_DMA() удобна для пакетов неизвестной длины: DMA складывает байты в буфер, а обработчик вызывается, когда линия замолчала на время кадра. В режиме DMA обработчик срабатывает и на половине буфера — отсюда проверка типа события (STM32 HAL). Ошибки приёма — FE, NE, ORE, PE — приходят в HAL_UART_ErrorCallback().

Arduino: Serial

Serial.begin(скорость) настраивает USART на формат 8N1, другой формат передают вторым аргументом: Serial.begin(9600, SERIAL_8E1). Что происходит внутри ядра Arduino для AVR (ArduinoCore-avr):

  • U2X. begin() сначала пробует режим удвоенной скорости и отказывается от него, только если делитель не помещается в 12 бит или если это 57 600 бит/с на 16 МГц — исключение оставлено ради совместимости с загрузчиком старых плат и прошивкой моста ATmega8U2 на Uno и Mega 2560. Поэтому на Uno 115 200 бит/с идёт с U2X0 = 1 и ошибкой +2,1 %, а 57 600 бит/с — без U2X и с той же ошибкой +2,1 %, хотя с U2X было бы −0,8 %.
  • Буферы. На приём и на передачу — по 64 байта, если у микроконтроллера не меньше 1 КБ ОЗУ, иначе по 16. Когда приёмный буфер полон, новые байты молча выбрасываются, флага ошибки нет. При 115 200 бит/с 63 свободных байта заполняются за 63 × 86,8 мкс ≈ 5,5 мс, так что delay() в цикле на такое время уже теряет данные.
  • Чётность. Байты с ошибкой чётности выбрасываются в обработчике прерывания.
  • Передача. Serial.write() и Serial.print() возвращаются сразу, пока в буфере передачи есть место, и ждут, когда он полон. Serial.flush() ждёт, пока последний байт полностью уйдёт в линию.
  • Чтение. Serial.read() при пустом буфере возвращает −1 (Arduino, Language Reference). Если записать результат в char и напечатать, получится символ с кодом 0xFF — частая причина «мусора» в выводе.
const size_t LINE_MAX = 32;
char line[LINE_MAX];
size_t len = 0;

void setup() {
  Serial.begin(115200);              // 8N1; Serial.begin(9600, SERIAL_8E1) for 8E1
}

void loop() {
  while (Serial.available() > 0) {   // read everything that has arrived, never wait
    char c = Serial.read();
    if (c == '\n') {
      line[len] = '\0';
      Serial.print("got: ");
      Serial.println(line);
      len = 0;
    } else if (c != '\r' && len < LINE_MAX - 1) {
      line[len++] = c;
    }
  }
  // no long delay() here: at 115200 bit/s the 64-byte receive buffer fills in about 5.5 ms
}

Выводы 0 и 1. На Uno, Nano, Mini и Mega они же связаны с мостом USB–UART, и всё, что к ним подключено, может мешать связи с компьютером, вплоть до неудачной загрузки скетча (Arduino, Language Reference). На Uno R3 мост ATmega16U2 подключён к ATmega328P через резисторы 1 кОм (схема A000066): внешнее устройство, подключённое к выводу 0, пересиливает выход моста, и загрузчик не слышит компьютер. Отключайте такое устройство на время загрузки или используйте другой UART: у Mega есть Serial1–Serial3 на отдельных выводах, а у Leonardo и Micro порт на выводах 0 и 1 — это Serial1, отдельный от USB-порта платы. Светодиоды RX и TX на Uno мигают только при обмене через USB, а не на выводах 0 и 1 (Arduino).

Отладка UART

Начинайте с самого простого и двигайтесь к сложному:

  1. Петля. Замкните TX и RX одного устройства — например, переходника USB–UART — и откройте терминал: каждый набранный символ должен вернуться. Вернулся — порт, драйвер и настройки терминала в порядке, ищите проблему в проводах или на другой стороне. У UART 16550 есть и внутренняя петля для такой проверки (TL16C550C).
  2. Мультиметр. В покое на TX — напряжение питания логики, то есть единица. Постоянный ноль на TX означает, что передатчик выключен или линия в состоянии break.
  3. Осциллограф. Самый короткий импульс — это длительность бита, а скорость равна единице, делённой на неё: 104 мкс — 9600 бит/с, 8,7 мкс — 115 200 бит/с. Удобно попросить устройство передавать «U»: меандр с частотой вдвое ниже скорости. Заодно видны уровни (3,3 или 5 В), затянутые фронты и помехи.
  4. Логический анализатор с декодером UART. Декодеру сообщают скорость, число бит данных, чётность, число стоп-битов, порядок бит (младший первым) и полярность: для логических уровней — обычную. Частоту выборки берите с запасом: при 1 МГц на бит 115 200 бит/с приходится около 8,7 отсчёта — для декодера хватает, но фронты видны с точностью ±1 мкс, то есть ±12 % бита. Кадры с ошибкой декодер обычно отмечает — это первый признак неверной скорости или формата. Линию RS-232 удобнее смотреть на стороне логики, до преобразователя: там 0 и 3,3 или 5 В и сигнал без инверсии.
  5. Терминал. Проверьте скорость, формат, отключённое управление потоком и то, что порт не занят другой программой. Учтите, что открытие порта может сбросить Arduino через линию DTR, — об этом в разделе об автосбросе.

«Кракозябры»: как распознать причину

Что видноВероятная причинаЧто сделать
случайные символы, много ошибок кадра, байтов приходит больше или меньше, чем отправленоразные скоростиизмерить длительность бита осциллографом
поток нулевых байтов с ошибками кадраприёмник намного быстрее передатчика: длинные нулевые биты читаются как целые нулевые символывыставить скорость передатчика
латинские буквы частично заменены другими символами: «ABCabc» в Windows-1251 выглядит как «ABГбвc»передатчик в формате 7E1, приёмник в 8N1: бит чётности принят как восьмой бит данныхвыставить одинаковый формат
часть символов пропадает без явных ошибокприёмник ждёт чётность, которой нет, и выбрасывает байты с ошибкой чётности, или переполняется буферпроверить формат и как часто программа читает буфер
латиница в порядке, испорчена только кириллицакодировка: передаётся UTF-8, а терминал показывает Windows-1251, или наоборотнастроить кодировку терминала, UART тут ни при чём
символы «ÿ» или «�» с кодом 0xFFпрограмма печатает результат Serial.read() без проверки Serial.available()читать, только когда есть данные
ничего не приходитперепутаны TX и RX, нет общего провода, включено управление потоком без CTS, порт занятпетля, мультиметр, настройки порта

Как выглядит рассогласование скоростей, можно предсказать. Если приёмник быстрее передатчика, каждый длинный бит он читает как несколько своих, и байтов становится больше. Например, «A» (0x41), переданная на 9600 бит/с, на приёмнике с 19 200 бит/с, устроенном как USART AVR, превращается в два байта: 0x06 с ошибкой кадра и 0xFE. Если приёмник медленнее, несколько символов сливаются в один, и байтов становится меньше. Поэтому первым делом сравните число отправленных и принятых байтов.

Типичные ошибки

ОшибкаСимптомЧто сделать
TX соединён с TX, RX — с RXничего не принимается, выходы двух передатчиков работают друг против другасоединить накрест: TX → RX
нет общего проводасвязи нет или она зависит от того, как лежат проводасоединить GND устройств
5 В на входе 3,3-вольтовой микросхемыпревышен абсолютный максимум, ток течёт через защитный диод входа; поначалу всё может работатьделитель или буфер, у STM32 — вывод FT
неверная тактовая частота: CKDIV8, RC-генератор, F_CPU не совпадает с реальноймусор и ошибки кадра; при CKDIV8 скорость ровно в 8 раз нижефьюзы, кварц, осциллограф
RS-232 подключён к выводам UART напрямуюинверсия: покой RS-232 — минус, а UART ждёт единицу; ±12 В могут вывести вход из строяпреобразователь MAX3232
выводы 0 и 1 Arduino заняты внешним устройствомскетч не загружается, монитор порта молчитотключать устройство на время загрузки, другой UART
мост USB–UART подключён к компьютеру, а плата без питанияплата «полуживая»: ток с TXD моста течёт в неё через защитный диод входа RXDобщее питание; WCH предлагает диоды и транзистор в линиях
включено аппаратное управление потоком, а CTS не подключёнпередача не начинаетсявыключить управление потоком или подключить RTS и CTS
форматы кадра не совпадают: 8N1 и 7E1 или 8E1часть символов искажена или пропадаетодинаковые настройки на обеих сторонах
в Arduino IDE выбран не тот вариант платызагрузка не начинается: загрузчик ждёт другую скоростьUno и Nano с новым загрузчиком — 115 200 бит/с, Nano со старым и Pro Mini 16 МГц — 57 600

Для связи между приборами и на длинных линиях тот же кадр UART передают через RS-232 и RS-485, для микросхем на одной плате есть синхронные SPI и I²C. Другие интерфейсы — в разделе «Интерфейсы».

Частые вопросы

Чем UART отличается от USART?

USART — это UART, который умеет работать ещё и синхронно: тактовый сигнал идёт по отдельному выводу (XCK у AVR, CK у STM32), и данные защёлкиваются по его фронтам, как в SPI. В асинхронном режиме USART ничем не отличается от UART — тот же кадр из старт-бита, данных и стоп-битов, — поэтому асинхронный режим USART обычно и называют UART. USART в AVR умеет работать и ведущим SPI.

Как подключать UART: TX к TX или TX к RX?

Накрест: TX одного устройства — к RX другого, RX — к TX, и обязательно общий провод GND. TX — выход данных, RX — вход; если соединить TX с TX, два выхода окажутся друг против друга, а входы останутся без сигнала. Уровни должны совпадать: вход 3,3 В без допуска 5 В подключают к 5-вольтовому выходу через делитель, а к COM-порту RS-232 — только через преобразователь вроде MAX3232.

Какая ошибка скорости UART допустима?

Суммарное расхождение частот передатчика и приёмника — около 2–3 %: Maxim в AN2141 получает ±3,3 % для короткой линии и ±2 % для длинного кабеля. Для AVR Microchip рекомендует держать ошибку каждой стороны в пределах ±2 % при кадре 8N1 и ±1,5 % — с битом чётности или в режиме удвоенной скорости U2X. Ошибку для конкретной частоты и скорости считает калькулятор скорости UART на gaw.ru.

Какая максимальная скорость UART?

Её задают тактовая частота и делитель. USART ATmega328P в режиме U2X выдаёт до f/8 — 2 Мбит/с при кварце 16 МГц, USART STM32F1 — до 4,5 Мбит/с. Мосты USB–UART: CH340 — до 2 Мбит/с, CP2102N и FT232R — до 3 Мбод, PL2303GC — до 12 Мбит/с. На скоростях выше 1 Мбит/с производители мостов советуют включать аппаратное управление потоком, иначе приёмник не успевает забирать данные.

Почему в мониторе порта «кракозябры»?

Чаще всего не совпадает скорость. Проверьте, что в терминале выбрана та же скорость, что в программе, и что микроконтроллер работает на той частоте, под которую программа собрана: новый ATmega328P с завода идёт на 1 МГц из-за фьюза CKDIV8, а его RC-генератор без калибровки ошибается до 10 %. Если искажена только часть символов, не совпадает формат кадра, например 7E1 и 8N1. Если испорчена только кириллица, дело в кодировке терминала, а не в UART.

Какой длины может быть провод UART?

UART с логическими уровнями рассчитан на связь внутри прибора: в качестве хорошей линии Maxim в AN2141 приводит шину длиной около метра с буферированными КМОП-уровнями. Чем длиннее провод, тем сильнее затягиваются фронты, собираются помехи и расходятся потенциалы земли устройств. Для метров и десятков метров тот же кадр UART передают через RS-232, для сотен метров — через RS-485.

Источники

  1. Microchip. ATmega48A/PA/88A/PA/168A/PA/328/P Data Sheet (DS40002061B), 2020 — гл. 20 — USART0: формат кадра, приём и выборки, флаги ошибок, табл. 20-1–20-7 — скорость и допуск приёмника; п. 9.2 и табл. 29-9 — RC-генератор и фьюз CKDIV8; табл. 29-11 — сброс; табл. 30-1 — пороги входов
  2. STMicroelectronics. RM0008 Reference manual STM32F101xx–STM32F107xx, Rev 21, 2021 — гл. 27 — USART: обнаружение старт-бита и шум (п. 27.3.3), дробный делитель (п. 27.3.4), допуск приёмника (п. 27.3.5, табл. 193 и 194), чётность, LIN, однопроводный режим, RTS/CTS
  3. STMicroelectronics. STM32F103x8, STM32F103xB Datasheet (DS5319), Rev 20 — табл. 5 — выводы FT, табл. 6 — допустимые напряжения, табл. 24 — точность HSI, табл. 36 и 37 — ёмкость и уровни выводов
  4. Maxim Integrated (Analog Devices). Tutorial 2141: Determining Clock Accuracy Requirements for UART Communications, 2003 — выборка в середине бита при 16 тактах на бит, допустимое расхождение ±3,3 и ±2 %, кварц и керамический резонатор
  5. Texas Instruments. TL16C550C Asynchronous Communications Element with Autoflow Control (SLLS177I), 2021 — делитель скорости и кварц 1,8432 МГц, стоп-биты и stick parity, флаги OE, PE, FE и BI, auto-RTS и auto-CTS
  6. WCH (Nanjing Qinheng Microelectronics). CH340 手册(一): USB 转串口芯片 CH340, версия 3D — китайская версия даташита: скорости, точность встроенного генератора и допуск приёмника, пороги входов, назначение выводов, защита от обратного питания, загрузка STM32 через DTR и RTS
  7. Silicon Labs. CP2102N Data Sheet, Rev. 1.5 — форматы и скорости, генератор ±0,25 %, правило ±2 %, RTS/CTS и XON/XOFF, передача break, VIO и допустимые напряжения
  8. Silicon Labs. CP2102/9 Single-Chip USB to UART Bridge, Rev. 1.7 — скорость до 1 Мбит/с; для новых разработок производитель рекомендует CP2102N
  9. FTDI. FT232R USB UART IC Datasheet, Version 2.16 (FT_000053) — скорости и делитель, VCCIO и пороги входов, буферы, инверсия сигналов, VID и PID по умолчанию
  10. Prolific. PL2303GC USB to Full UART IC with GPIO, Data Sheet V1.0.7, 2025 — скорости 5 бит/с – 12 Мбит/с, VDD_IO 1,8–5 В, управление потоком, VID и PID
  11. Prolific. PL2303 Windows Driver Download (страница поддержки, архив 19.01.2023) — версии микросхем без поддержки Windows 8–11, предупреждение о поддельных PL-2303HX
  12. Arduino. ArduinoCore-avr: HardwareSerial и boards.txt — HardwareSerial.h, HardwareSerial.cpp, HardwareSerial_private.h — буферы по 64 байта, выбор U2X и исключение для 57 600 бит/с, байты с ошибкой чётности; boards.txt — скорости загрузчиков
  13. Arduino. Language Reference: Serial, Serial.read() — выводы 0 и 1, уровни TTL, подключение TX к RX и общий провод
  14. Arduino. Arduino/Genuino Uno: описание платы (arduino.cc, архив 2017) — автосброс через DTR и конденсатор 100 нФ, перемычка RESET-EN, работа загрузчика после сброса
  15. Arduino. UNO R3 schematic (A000066) — резисторы 1 кОм RN4A и RN4B между ATmega16U2 и ATmega328P, цепь C5, RN1D и D2 на RESET
  16. AVR-LibC. <util/setbaud.h>: Helper macros for baud rate calculations — UBRR_VALUE, USE_2X и допуск BAUD_TOL = 2 %
  17. STMicroelectronics. STM32F1 HAL: драйвер stm32f1xx_hal_uart — UART_InitTypeDef, расчёт BRR от PCLK1 и PCLK2, бит чётности на месте старшего бита, HAL_UARTEx_ReceiveToIdle_DMA
  18. Microchip. AVR128DA28/32/48/64 Data Sheet (DS40002183E), 2024 — п. 25.3.3.2.6 — однопроводный режим USART (LBME, ODME), гл. 35 — UPDI
  19. LIN Consortium. LIN Specification Package, Revision 2.2A, 2010 — кадр LIN на основе UART, поле break не короче 13 бит, байт синхронизации 0x55, скорость 1–20 кбит/с
  20. Modbus Organization. MODBUS over Serial Line Specification and Implementation Guide V1.02 — спецификация, 2006: чётность по умолчанию, два стоп-бита без чётности, 7 бит данных в режиме ASCII
  21. Ecma International. ECMA-48: Control Functions for Coded Character Sets, 5th edition, 1991 — управляющие символы DC1 и DC3
  22. The Linux Kernel. drivers/usb/serial: ch341.c, cp210x.c, ftdi_sio_ids.h, pl2303.h — драйверы мостов USB–UART и их идентификаторы VID:PID