19 de setembro de 2021

Do bit Ao Byte

Embarcados, Linux e programação

Desafio maker 04: Solução – PORTB e PORTC

solução | TaskHandle | PORTB | bitwise | bit field | função lambda | função recursiva em C++

A ideia do Desafio maker 03 surgiu de uma necessidade real que tive, onde estava programando um PIC de 240 bytes e faltava espaço para criar mais duas variáveis. Daí tive a ideia de utilizar pinos que estavam sobrando para guardar os estados. No final era algo mais simples do que propus, mas depois que implementei a solução percebi que com 3 pinos poderia guardar 8 valores sem precisar declarar uma única variável – no Arduino, utilizando o registrador PORTB.

Para a resposta do desafio escrevi um código imperfeito, mas ilustra bem o recurso. Invés de criar uma variável, utilizamos a definição dos próprios pinos para armazenar os valores. Claro que esses pinos devem estar disponíveis, senão teríamos problemas.

Como a proposta era também validar se o valor enviado é zero e não podemos ler o valor duas vezes, a única maneira de manter uma memória seria utilizar uma segunda porta com os estados dos primeiros 3 bits da PORTB. Somando zero o valor permanece imutado, de modo que podemos então zerar ambas as portas, PORTB e PORTC. Mas o que são a PORTB e PORTC?

Solução: Registradores PORTB e PORTC

Quando criei essa solução para meu problema, utilizei PIC, cuja configuração é um pouco diferente do Arduino. Por isso, tive que me referenciar à documentação para saber como reproduzir de forma similar no Arduino. E daí me repito: Decorar não é aprender. Se você tem o conceito, sabe o que precisa ser pesquisado e a solução sai rapidamente.

Pela documentação a PORTB são os bits referentes aos pinos de 8 à 13. O PORTC contém os bits dos pinos 0 à 7 analógicos. Ambas definem o estado do pino, mas ainda resta configurar a direção (INPUT / OUTPUT). A direção é configurada através do registrador DDR; DDRB e DDRC, no caso.

Ao lermos a serial, subtraímos 48 do char para termos o valor numérico, então atribuímos o valor ao registrador da PORTB e começamos a validação dos requisitos do desafio.

Para descobrir se o valor digitado foi o 0, bastou atribuir o valor ao registrador PORTB e compará-lo com o PORTC. Se forem diferentes, iguala o PORTC, se forem iguais, zera ambos os registradores.

O código (mais uma vez, com falhas, mas funcional para provar o conceito) ficou assim:

void setup() {
    Serial.begin(9600);

    //valor inicial da soma: 0 - tudo em LOW (PORTB)
    DDRB  = 0b000000;
    PORTB = 0b000000;

    //verificador - PORTC
    DDRC  = 0b11111111; //OUTPUT
    PORTC = 0b00000000; //LOW

}

void loop() {
    if (Serial.available() > 0){
        PORTB = PORTB+(uint8_t) Serial.read()-48<<0;
        if (PORTB<8){
            Serial.println(PORTB);
        }
        else{
            Serial.println("Resultado maior que o limite");
            PORTB = 0b000000;
        }
        
        
        if (PORTB&PORTC){
            PORTB = 0b000000;
            PORTC = 0b00000000;
        }
        else{
            PORTC = PORTB;
        }
    }
}

Último detalhe: A serial não deve ter terminador de linha, apenas 1 byte deve ser enviado.

Um artigo que recomendo periodicamente é o “Dominando PCF8574 com Arduino“, que serve para qualquer plataforma. Nele disponho diversas manipulações de bits, que facilitarão o entendimento, se não mexeu ainda com isso.

Até o próximo desafio!