+ в общем-то прерывание нужно использовать только на приём, чтобы вовремя забирать то, что туда прилетело. При передаче, как правило, это не нужно. Достаточно отслеживать то, что передача ещё не закончена, и затем пихать туда новый байт. У меня примерно так и сделано, есть типовая подпрограммка отсылки байта через UART, с ожиданием опустошения буфера.
Я обычно активно использую прерывания (как правило, - структура программы - главный цикл, с контролем системных флагов, и системный таймер, который заправляет отсчётами всяких таймаутов, и установкой флагов для периодичности выполнения задач), для всей периферии, которая мне нужна, я безбоязненно включаю прерывания, и в общем и целом программа глубоко нелинейна. Как правило, при такой структуре, "зависон" в цикле отправки одного байта (помним, что прерывания разрешены, и задачи по прерываниям выполняются) никого не напрягает.
Итог: по прерыванию UART у меня только "распарсивание" пакетов в софтовом приёмном буфере (в соответствии с моим протоколом), а передача небуферизирована - просто цикл с ожиданием окончания передачи предыдущего байта. Там, где нужна буферизированная передача - организую частный специальный буфер именно для этой операции, а саму операцию, выделяю в отдельную задачу, которая выполняется, когда до неё дойдёт очередь, и освободятся ресурсы (у меня сделана эдакая "мультизадачная" среда на 16 задач с пиоритетом и очередью" очень удобная штука, как шаблон для проектов :))
Надеюсь, что как-то паонятно (хотя чувствую - о"объяснил" очень туманно :((
Ну во п/п передачи выглядит примерно так:
;П/П передачи байта через USART C0
;TMP - передаваемые данные, никакие регистры (в т.ч. и TMP) не портятся
;10/VII.13
TxD_USART_C0:
push TMP ;Сохраним данные, пока проверяем статус USART
wait_if_USART_C0_busy: ;Ждём, если USART занят
sei ;Разрешим все прерывания на время ожидания освобождения регистра данных UART
lds TMP,USARTC0_STATUS ;Проверяем, не занят ли USART передачей?
sbrs TMP,USART_DREIF_bp ;Если USART занят,
rjmp wait_if_USART_C0_busy ; то ждём, иначе
; начинаем передачу.
;-- Передача байта
pop TMP ;вспомним, что хотели передавать :)
sts USARTC0_DATA,TMP ;передаём
ret
А кусок кода, с передачей данных по UART, примерно вот так:
;-- стандартный канал обмена для приложения
.macro SendBYTE_byUSART_C0 ;макрос передачи байта через USART_C0
ldi TMP,@0
call TxD_USART_C0 ;Используемая п/п "TxD_USART_C0" умеет
; ждать, когда буфер ещё занят отправляемыми данными.
.endmacro
#define TxD_USART_exchange TxD_USART_C0 ;определение П/П порта обмена данными
#define SendBYTE_byUART_exchange SendBYTE_byUSART_C0 ;Имя макроса передачи байта по каналу обмена
.
.
.
mov TMP,STAT
call TxD_USART_exchange
;
mov TMP,STAT_plus
call TxD_USART_exchange
lds TMP,S_Parameter_Waveforms
call TxD_USART_exchange
lds TMP,S_Parameter_MTime0
call TxD_USART_exchange
lds TMP,S_Parameter_MTime1
call TxD_USART_exchange
lds TMP,S_Parameter_Frequency0
call TxD_USART_exchange
.
.
.
Ну или с использованием макроса, примерно вот так:
.
.
.
Set_STAT_DATAtype DT_About ;Установим в регистре STAT подходящий тип передаваемых данных
mov TMP,STAT
call TxD_USART_stuff
;
SendBYTE_byUART_exchange Hardware_VERSION
SendBYTE_byUART_exchange Hardware_REVISION
SendBYTE_byUART_exchange Software_VERSION
SendBYTE_byUART_exchange Software_REVISION
SendBYTE_byUART_exchange dateDay
SendBYTE_byUART_exchange dateMonth
SendBYTE_byUART_exchange dateYear
.
.
.
Чёт-то посмотрел сейчас и ужаснулся, сколько я вложенных макросов использую :( надо с этим что-то делать :))