In the first available AT90S1200 is no UART implemented and the other AVR's can't use the UART on low baud rates. So software solutions are needed. On the Atmel applications page only half duplex examples available. A half duplex UART can cause transmit corrupt data while receiving and lost or corrupt receive data while transmitting. So a full duplex UART is more powerful.
To receive and transmit data simultaneously, the bit time is divided in 4 slices by the timer T0 interrupt. Every timer interrupt, the RXD input is scanned. If low level is detect, receive started. In the worst case it is done 1/4 bit time after changing. This need a little more precision in calculation of the baudrate for right receiving. The tolerance should not be greater the 1%. In difference to a hardware UART ,every bit is only 1 time sampled. So the risk of erroneous receiving is greater. This compromise is done to decrease register and CPU usage. The software UART need 7 register and 30% of CPU time on 38.4kBaud at 11.0592MHz. For lower baud rates the reload register value (uarttime) must be changed: baudrate = xtal / 32 / uarttime.
To need a minimal count of registers and CPU time, the code is very tricky.
For counting bit slice and bits in the same register together, the half carry
flag is used. The receive done and receive error flags are combined in the
rx state register too. It's the best, you simulate the example code to understand
the function.
The example code use the same pin for transmit and receive for simulation.
In practical use include UART.H to get the pin function equal to the AT90S2313
or AT89C2051.
To send a byte, you must wait until tx_state is equal to tx_done. Then you write the byte into tx_data. After setting tx_state to tx_start, the next timer interrupt send the start bit. After sending the stop bit, the register tx_state is equal tx_done again and the next byte can be send.
If the flag frx_done in the register rx_state is set, a byte was received. This is done in the middle of receiving the stop bit. Then the received byte is available in the register rx_data. On receiving the next stop bit, this register was overwritten by the new received byte. To detect the next received byte you must clear the flag frx_done after reading rx_data.
The example code starts with sending a byte. After the end of receiving and transmission is detect, this byte was received. Then it was written to the transmit register and incremented. And transmit was starting again .