Manual

do

Maker

.

com

Manipulação da matriz de LEDS do UNO R4

Manipulação da matriz de LEDS do UNO R4

No artigo anterior vimos como manipular cada bit para cada LED da matriz, escrevendo um array de 96 valores. É sem dúvidas a maneira mais simples de manipular os LEDs, considerando a visualização, mas não é a forma mais eficiente, nem a mais econômica.

Para fazer o frame, usamos um array de 96 valores, mas cada posição ocupa 1 byte, já que utilizamos uint8_t (acá, unsigned char). Imagine o desperdício, já que 1 byte comporta 256 valores possíveis e, deles, usamos apenas 1 valor para representar 1 bit. Claro, enquanto o projeto for simples, não fará diferença, mas a partir do momento em que for necessário prezar pelos recursos, esse seria nosso primeiro vilão.

Vamos ver agora em "UNO R4 LED Matrix" como controlar a matriz de LEDs de uma forma mais eficiente.

Array de 96 posições para a matriz de LEDs

Apenas para rememorar, no artigo Como controlar a matriz de LEDs do UNO R4 nós vimos a manipulação dos LEDs através de uma matriz bi-dimensional de 96 valores, que ficou assim:

uint8_t frame[8][12] = {
  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};

Sem dúvidas é visualmente simples interagir, porque vemos o resultado desejado no código. É rápido e efetivo, mas dispendioso.

Então, qual a maneira mais eficiente para manipular a matriz de LEDs do UNO R4? - Simples; usando um array de 32 bits inteiros, conforme especificado na documentação da matriz de LEDs do UNO R4.

Controle de um array de inteiros

Aqui nós deixaremos de usar um array bi-dimensional de uint8_t para usar um array comum de 3 unsigned long int. Quando referenciamos um long automaticamente ele é um inteiro, portanto a declaração incluindo int é opcional.

Por que precisamos de 3 valores no array?

A razão de o array ser composto por 3 longs é porque temos um array de 96 LEDs. Como cada long equivale a 32 bits, temos 96/3, que resulta em 3. O coração padrão no array bi-dimensional é assim:

uint8_t heart_byte[8][12] = {
{0,0,1,1,0,0,0,1,1,0,0,0},
{0,1,0,0,1,0,1,0,0,1,0,0},
{0,1,0,0,0,1,0,0,0,1,0,0},
{0,0,1,0,0,0,0,0,1,0,0,0},
{0,0,0,1,0,0,0,1,0,0,0,0},
{0,0,0,0,1,0,1,0,0,0,0,0},
{0,0,0,0,0,1,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0}
};

Já utilizando unsigned long, o resultado é esse:

unsigned long frame[] = {
  0x3184a444,
  0x42081100,
  0xa0040000
};

Como saber onde está cada bit nessa bagunça?

É eficiente, mas e agora pra desenhar? - Bem, uma das opções é utilizar a ferramenta online fornecida pelo Arduino.cc. É uma ferramenta visual para desenhar seus quadros e animações, mas vai te afastar da essência (a biblioteca já faz um tanto desse afastamento).

Se seu negócio é Ctrl+C e Ctrl+V, ou se é curioso, o editor da matriz de LEDs do UNO R4 é esse.

Se seu interesse é aprendizado, sigamos juntos.

Converter um array de 3 longs para um array bi-dimensional

A primeira coisa que podemos desejar é converter um frame que já esteja em "formato humanamente ilegível", para fazermos um retrabalho. Por exemplo, converter um sorriso para uma tristeza. Nesse caso, o código de exemplo da documentação (supracitada) exemplifica com clareza, mas exige um trabalho manual para separar os bits em 12 colunas de 8 bits. É muito trabalho com mouse, então preferi escrever um código que já devolva o array pronto para usar no sketch:

unsigned long heart_int[] = {
  0x3184a444,
  0x42081100,
  0xa0040000
};

void long2byte(){
  String line = "";

  for (uint8_t i=0;i<3;i++){
    //32 bits por volta; separado em 4 bytes
    unsigned long value[4] = {(heart_int[i]&~0x00ffffff)>>24,
                        (heart_int[i]&~0xff00ffff)>>16,
                        (heart_int[i]&~0xffff00ff)>>8,
                        (heart_int[i]&~0xffffff00)>>0}; 

    for (uint8_t y=0;y<4;y++){
      for (char pos=7;pos>-1;pos--){
        if ((value[y]&(1<<pos)) > 0){
          line = line + "1";
        }
        else{
          line = line + "0";
        }
      }
    }
  }
  //Agora imprime a matriz
  Serial.println("uint8_t heart_byte[8][12] = {");
    uint8_t start = 0;
    uint8_t end   = 12;

    for (uint8_t j=0;j<8;j++){
      Serial.print("{");
      for (uint8_t i=start;i<end;i++){
        Serial.print(line[i]);
        if (i+1 != end){
          Serial.print(",");
        }
      }
      start = end;
      end   = end + 12;
      if (j+1 != 8){
        Serial.println("},");
      }
      else{
        Serial.println("}");
      }
    }
    Serial.println("};");
}

void setup() {
  Serial.begin(9600);
  Serial.println("Starting...");
  delay(3000);
  long2byte();
}

void loop() {
  
}

O resultado será o mesmo do exemplo mais acima, do heart_byte.

Por fim, não é exatamente assim que costumo escrever minha lógica, mas de cara me deparei com um bug que não sei se é da toolchain, do framework ou da própria placa, mas em uma interação de loops encadeados para manipulação da matriz, me deparei com um erro "Fault on interrupt or bare metal(no OS) environment". Sem debugger, vasculhei cada uma das poucas variáveis em busca do problema. Não tenho nenhuma certeza, como pode ser visto ao início desse parágrafo, mas a única certeza que tenho é que o problema não foi no meu código em si, porque não fiz nada atípico. Por fim, dei uma "ajeitada" para contornar o problema, mas não curti muito me deparar com tal bug.

No próximo artigo relacionado, faremos o caminho oposto; converteremos um array bi-dimensional em um array de longs.

Você pode acompanhar as novidades pelo nosso perfil no Instragram, ou então pelo nosso canal Manual do Maker no Youtube.

Nome do Autor

Djames Suhanko

Autor do blog "Do bit Ao Byte / Manual do Maker".

Viciado em embarcados desde 2006.
LinuxUser 158.760, desde 1997.