software uart, on a 12f675.
It is entirely done over the tmr1 interrupt, through a state machine - supports 1 start bit, 8 data bits, 1/2 stop bits
//softuart transmission state machine
switch (_utx_status) {
case -1: //start bit has been sent. now send the data
IO_CLR(UTX_PORT, UTX); //send the start bit
_utx_status = 1; //lsb first
break;
case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: //send all 8 data bits
if (_utx_mask[_utx_status] & *_utx_ptr) IO_SET(UTX_PORT, UTX); //send 1 bit
else IO_CLR(UTX_PORT, UTX); //send 0 bit
_utx_status +=1;
break;
case 9: //send the stop bit
IO_SET(UTX_PORT, UTX); //stop bit sent
_utx_status = 11; //10: send two stop bits. 11: send 1 stop bit
break;
case 10: //send the 2nd stop bit
IO_SET(UTX_PORT, UTX); //not necessary
_utx_status = 11;
break;
case 11: //transmission has ended. check for end of string
IO_SET(UTX_PORT, UTX); //utx return to idle state / high
if (*++_utx_ptr) { //if the next char is not '\0', continue transmission
_utx_status = -1; //send the stop condition next
} else { //all chars have been sent -> stop transmission
_utx_status = 0; //indicating module ready
TMR1ON = 0; //turn off tmr1
}
The main loop checks for uart transmission status while flipping a pin:
while (1) {
IO_FLP(LED_PORT, LED); //flip led
if (utx_ready()) { //if uart is available
strcpy(uRAM, str0); //form the string
utx_puts(uRAM); //send message
}
}
The same main loop ports over pretty much any mcu I work with, from avr, 8051, pic, stm8, to 32-bit ARMs, without any modification.