30 de julho de 2021

Do bit Ao Byte

Embarcados, Linux e programação

Output com CD74HC4067 e Arduino Pro Micro

Arduino Pro Micro

Escrevi 2 artigos sobre esse multiplexador; o primeiro, fazendo leitura analógica; o segundo, leitura digital. Acontece que estava convicto de que o Arduino Pro Micro teria a mesma disposição do Arduino Leonardo, mas ledo engano, já que com isso tenho a oportunidade de mostrar a migração do código feito no Arduino Leonardo. Como faltou o GPIO 11 no Arduino Pro Micro, tive que reavaliar a situação.

Datasheet do Atmega32u4

Arduino é o nome da placa de prototipagem, infelizmente confundido até os dias de hoje com a MCU, que é Atmel. Sabendo o nome da MCU (está escrito sobre ela, seja qual for), basta procurar no Google pelo datasheet. O link do datasheet, para os interessados.

De PORTB para PORTF

O grande susto foi quando, ao perceber a diferença, ter olhado para o pinout do Arduino Pro Micro, e perceber que o número de GPIO é menor, além de distribuídos em poucos bits. Por sorte, os pinos analógicos estão na sequência, do 0 ao 3 – digo, no registrador PORTF. Desse modo foi possível manter o código “econômico” dos artigos anteriores, mudando apenas o registrador. Mas primeiro tive que me certificar de que seria possível utilizar o ADC como pino de saída digital. No datasheet:

Arduino Pro Micro - Analog as digital pin

A importância dos bits em sequência se dá ao fato de estarmos utilizando bitwise para configurar os pinos, e também para selecionar o canal do CD74HC4067. De outro modo, seria mais viável utilizar as funções da API do Arduino, mas o código cresceria um bocado.

Quando procurei pela sequência de pinos no mesmo registrador, me deparei também com a ausência de dois bits: PF2 e PF3.

É a primeira vez que preciso ler o datasheet de um Atmega, no caso, para me certificar do fato de não ter os bits PF2 e PF3. No datasheet está claro que não está no pinout, mas o bit obviamente existe, senão o registrador não iria até PF7.

Arduino Pro Micro - PORTF

Tendo resolvido essas questões, e coincidentemente a sequência sendo a mesma do PORTB (os 4 bits mais significativos), só tive que mudar a nomenclatura. Daqui em diante, os artigos relacionados serão feitos no Arduino Pro Micro, com base no código que segue:

#define READ_MUX_PIN 9

uint16_t pb_values = 0;

void handler(uint8_t value){
    //agora não tem propósito, mas essa função fará sentido em outro artigo
    Serial.print(value,BIN);
    Serial.print(" - ");
    Serial.println(pb_values);
}

uint8_t getValues(){
    for (uint8_t i=0;i<16;i++){
        PORTF |= (i<<4);
        delay(1);

        pb_values = digitalRead(READ_MUX_PIN);

        Serial.print("C");
        Serial.print(i);
        Serial.print(":");
        handler(pb_values);
        
        PORTF &= ~(i<<4);
        delay(1);
    }
}

void setup() {
    DDRF  = 0xF<<4;
    PORTF &= ~(0xF<<4);

    pinMode(READ_MUX_PIN,INPUT_PULLUP);

    Serial.begin(9600);
}

void loop() {
  getValues();
  delay(2000);
}

Como usar o CD74HC4067 no Arduino UNO?

Pode usar o PORTB tranquilamente, o registrador é o mesmo para o atmega328p:

Arduino Pro Micro e Arduino UNO

Onde comprar o CD74HC4067?

Esse multiplexador extremamente barato você encontra na Eletrônica Mangili, que tem outros itens interessantes em sua lista, mas o link direto para o multiplexador é esse.

CD74HC4067 como OUTPUT

Para fazer o teste de OUTPUT, coloquei um LED em VCC e GND ao pino 0 do multiplexador. Criei um código simples incrementado ao disposto mais acima, com a função handler fazendo a interação. Ao abrir o monitor serial, coloque “nenhum final de linha” na caixa de seleção do rodapé. Se digitar 0, o LED deve se acender. Se digitar outro número (até 9), devolverá o estado do pino. Se não tiver colocado GND em nenhum pino, qualquer número maior que 0 deve retornar 1. Se estiver com algum pino menor que 9 deve retornar 0.

Arduino Pro Micro - INPUT e OUTPUT

Como coloquei apenas o pino 0 com um LED, fiz uma lógica na função loop() para acender o LED se digitar 0. Quando o número for maior que 0, o LED se apagará.

#define ENABLE_MUX_PIN 8
#define READ_MUX_PIN   9

uint16_t pb_values = 0;

void handler(bool do_read,uint8_t channel, bool turn_on){
    if (do_read){
        Serial.println("reading...");
        pinMode(READ_MUX_PIN,INPUT_PULLUP);

        //pinMode(ENABLE_MUX_PIN,INPUT);
        //digitalWrite(ENABLE_MUX_PIN,LOW);

        PORTF |= (channel<<4);
        
        delay(1);
        pb_values = digitalRead(READ_MUX_PIN);
        Serial.println(pb_values);
        
        PORTF &= ~(channel<<4);
        return;
    }

    if (!turn_on){
        PORTF |= (channel);    
    }
    else{
        PORTF &= ~(channel);
    }

    pinMode(READ_MUX_PIN,OUTPUT);
    digitalWrite(READ_MUX_PIN,LOW);

    pinMode(ENABLE_MUX_PIN,OUTPUT);
    digitalWrite(ENABLE_MUX_PIN,LOW);

}

uint8_t getValues(){
    for (uint8_t i=0;i<16;i++){
        PORTF |= (i<<4);
        delay(1);

        pb_values = digitalRead(READ_MUX_PIN);

        Serial.print("C");
        Serial.print(i);
        Serial.print(":");
        Serial.println(pb_values);
        
        PORTF &= ~(i<<4);
        delay(1);
    }
}

void setup() {
    DDRF  = 0xF<<4;
    PORTF &= ~(0xF<<4);

    pinMode(READ_MUX_PIN,INPUT_PULLUP);
    pinMode(ENABLE_MUX_PIN,OUTPUT);

    Serial.begin(9600);
    delay(1000);
}

void loop() {
  //getValues();
  if (Serial.available()){
    uint8_t value = Serial.read()-48;
    if (value == 0){
      handler(false, 0, true);
    }
    else{
      handler(true, value, false);
    }
  }
  delay(2000);
}

Acender vários LEDs de uma vez

Primeiro, não é possível acionar mais de um pino de uma vez. Lembre-se que essa placa é um multiplexador. Se houver a necessidade de manter continuamente o estado de mais de um pino, use um PCF8574, por exemplo.

Já se a intenção é só ligar diversos LEDs de uma vez, basta fazer um loop nos canais desejados com delay bem baixo. É como fazemos no display de 7 segmentos. A impressão de que estarão ligados todos ao mesmo tempo se chama POV (Persistence Of Vision).

Pin map Atmega32u4

Como deixei o mapa de pinos do Leonardo, fica como referência também o do Arduino Pro Micro:

Arduino Pro Micro - pin mapAté a próxima!

 

Revisão: Ricardo Amaral de Andrade