Добавлю свои "пять копеек" к обсуждению.
Поскольку UART - устройство асинхронное, что прием и передача друг на друга не "завязаны" и реализуются независимо.
Мой опыт применения UART'ов следующий. Приемная часть состоит из двух частей - одна в прерывании приемника, вторая - в отдельном процессе. В прерывании приемника осуществляется прием символа и его анализ: если это первый символ в пакете, то в нем закодирована длина пакета - эта величина фиксируется, и ожидающему процессу сигналится флаг событий, по которому процесс переход в ожидание [пакета] с таймаутом (таймаут рассчитывается, исходя из длины пакета, скорости передачи и т.д.). В прерывании теперь в при приеме очередного символа ведется подсчет входящих символов, и когда их количество достигает нужной величины (закодированной в первом символе пакета), код прерывания сигналит флаг события еще раз. Таким образом, получаем две активизации процесса приемника - на старте пакета и в конце. Т.е. процесс приемника не дергается на приеме каждого символа. В конце же и производится собственно обработка пакета (контрольные суммы, требуемые действия).
Для приемника используется обычный буфер - не кольцевой, т.к. этого вполне достаточно - источник данных по определению один - приемник UART, а длина буфера должна быть достаточна для приема пакета максимальной длины. Время обработки пакета также меньше времени прихода символа, поэтому одного буфера оказывается достаточно. Если время обработки пакета велико, то тут уже можно думать о двух буферах или кольцевом буфере, но это уже другая история - ведь тут вся логика приемного процесса должна быть иной - он должен быть способен одновременно обрабатывать принятый пакет и принимать следующий. Я старался избегать этой ситуации, тем более, что действия по обработке пакета реально тривиальны - проверили контрольную сумму и передали данные дальше в программу по назначению, после чего уже снова можем принимать очередной пакет.
Передатчик собственно на ОС никак не "завязан". У передатчика есть функция send, которая формирует пакет на отправку и инициирует оную (в MSP430 для этого достаточно просто разрешить прерывание UART Tx Data Register Empty). И есть обработчик прерываний, который выпихивает данные из буфера передатчика в UART. Т.к. источников передачи может быть несколько и все они могут работать асинхронно и одновременно, то буфер передатчика реализован в виде кольцевого буфера. Код для MSP430:
Код
#pragma vector = USART1TX_VECTOR
__interrupt void TUART::TxBUF_Empty_ISR()
{
U1TXBUF = TxBuf.pop();
if(TxBuf.get_count() == 0) DisableTxInt();
}
//---------------------------------------------------------------------------
Из кода видно, что действия очень простые: извлекли очередной байт из буфера, сунули его в регистр данных передатчика, проверили, есть ли еще данные в буфере. Если их нет, то запретили прерывание от передатчика, чтобы оно не возникало, когда регистр данных TxD опустеет.
«Отыщи всему начало, и ты многое поймёшь» К. Прутков