Комментировать исходную программу, полагаю, большого смысла нет. Вам для начала нужно отделить друг от друга два уровня в программе:
нижний - работа с регистрами UART, приём и передача отдельных байт
и верхний - работа с символьной строкой.
Ниже минимальный интерфейс в традициях языка С, аналогично функциям getchar/putchar, про них в любом учебнике написано. Это реализация самая простая, без использования прерываний (при инициализации бит RXCIE устанавливать не надо).
При желании можете реализовать работу с UART-ом по прерываниям, но начать лучше с этого и потом двигаться от простого к сложному.
CODE
#ifndef EOF
#define EOF (-1)
#endif
int Uputchar( int data )
{
while ( !( UCSRA & (1<<UDRE)) )
; // ждём готовности передатчика
return UDR = data; // записали data в регистр передатчика
// и, для бОльшей похожести на putchar(),
// возвращаем это-же значение как результат функции
}
int Ugetchar( void )
{
if ( UCSRA & (1<<RXC) )
return UDR; // возвращаем байт, принятый приёмником
else
return EOF; // если приёмник ничего пока не принял, то возвращаем EOF
}
Теперь, пользуясь только Ugetchar(), принимаете символы один за другим и собираете из них строку.
Что с этой строкой дальше делать - это уже Ваша забота.
Для вывода тоже используете только Uputchar(), и нет необходимости на этом уровне задумываться как работает UART.
Russia est omnis divisa in partes octo.