Uma breve observação sobre o design do software "UART": existem pelo menos abordagens qualitativamente diferentes que você pode adotar, dependendo dos requisitos:
Um driver de controle de bits "assuma tudo" desabilitará todas as interrupções e usará o código contado no ciclo para registrar cada bit. O recebimento de dados com um driver "assumir tudo" exige que, quando os dados cheguem, o controlador não faça nada além de aguardá-los.
Um driver de controle de bits "assumir o loop principal" se comportará como o descrito acima, exceto pelo uso de um recurso de timer para temporizações de bits, em vez de contagem de ciclos. Interrupções que não demoram muito para serem reparadas podem ficar ativadas. Para transmissão serial, o recurso de timer de taxa fixa pode ser compartilhado com outros fins; para recepção serial, no entanto, o driver bit-bang precisará ser capaz de recarregar o timer quando o bit inicial chegar, de modo a expirar no meio de cada bit de tempo recebido.
Um driver de bit-bang totalmente acionado por interrupção usa um timer de taxa fixa que está sendo executado em alguns múltiplos da taxa de dados de preferência (3x e 5x são melhores que 4x) e faz tudo através desse timer. Esse driver pode ser executado simultaneamente com todo o resto, mas exigirá uma CPU mais rápida do que os tipos de driver anteriores exigiriam.
Para evitar que os dois primeiros estilos de controlador esperem eternamente por dados que talvez nunca venham, é comum que as rotinas de leitura incluam um valor de tempo limite. Observe que se o loop de um controlador, por exemplo, "obtém um byte enquanto aguarda até 100 ms, faça outras coisas se não houver nenhum, e obtenha o próximo byte, etc." e um byte chegar entre o tempo limite da rotina "get" e o controlador começar a esperar novamente, esse byte será perdido; o dispositivo com o qual está se comunicando terá que esperar essa possibilidade.
Somente o terceiro estilo de driver poderá lidar com a possibilidade de um byte de dados começar a chegar enquanto um byte de dados estiver sendo transmitido. Os dois primeiros estilos podem, no entanto, ser usados para alguns protocolos de comunicação full-duplex de velocidade total se o controlador precisar falar apenas quando for falar com ele. O truque é ter uma rotina de "leitura e gravação de dados" que espere por um bit inicial recebido e, quando for detectado, se sobreponham a uma leitura e gravação, de modo que o controlador envie cada bit assim que estiver prestes a examinar os dados recebidos. Uma vez que o controlador detecte o bit inicial de entrada, ele saberá exatamente quando deve procurar os próximos 8 bits de dados e o bit de parada e, assim, saberá que pode usar com segurança o tempo entre eles para gerar seus próprios dados.
Uma observação final: um controlador que usa um dos dois primeiros estilos de bit-bang uart para receber dados deve processar cada byte de dados antes da borda descendente do bit de início do próximo byte para evitar a perda de dados. Se o controlador souber que o processamento levará pelo menos meio tempo, poderá maximizar o tempo disponível para processamento, aceitando cada byte assim que pegar o último bit de dados, em vez de aguardar o bit de parada. Como outro meio de dar mais tempo ao controlador, no entanto, pode ser útil ter o dispositivo que está transmitindo dados com dois bits de parada em vez de um. Se a "paridade de marca" puder ser configurada, isso adicionará outro tempo extra de bit. A transmissão em, por exemplo, 115200-8-M-2 permitirá mais tempo de processamento que 57600-8-N-1, mesmo que os dados sejam alimentados mais de 1,6 vezes mais rápido.