Controlando "qualquer" quantia de LEDs com 3 pinos

As vezes você tem uma ideia legal, algum circuito com PIC que vá utilizar LEDs ou displays de 7 segmentos pra exibir alguma informação, mas se depara com a pequena quantidade de pinos do microcontrolador. Surgem opções:
  • Migrar para um com mais portas é uma opção, mas convenhamos que as vezes isso sai meio caro;
  • Utilizar varredura (aplicável em bargraphs, LEDs RG, RGB, RGBW, displays de sete segmentos ou matrizes de LED), mas o esforço na programação fica bem maior;
  • Utilizar um expansor de portas, mas não é tão fácil achar tais CIs por aqui no Brasil, e o preço dos módulos ainda assim não é a opção mais barata quando se quer apenas mais saídas;
  • Utilizar Shift-Registers. Baratos, simples de usar, podem ser usados tanto para ampliar o número de saídas quanto o de entradas e são fáceis de serem encontrados.
Obviamente, usaremos esta opção. Neste post, em especial, falaremos apenas sobre o uso de Shift-Registers para aumentar o número de saídas, pois ainda não os usei para entradas. Quem nunca ouviu falar sobre estes CIs, deem uma olhada neste outro post antes de continuar a ler este post.

3 pinos para controlar 8 LEDs. Isto parece bom!

O estrangeiro e sua língua

Usaremos aqui, dentre os vários modelos existentes, o 74HC595. É um modelo bem popular e simples de usar.

Imagem retirada do datasheet da Texas Instrument


O modo de utilizar ele é bem simples: o bit a ser registrado é inserido na entrada SER. Quando um pulso ocorrer na entrada SRCLK, este bit será registrado no latch da saída QA. Ao inserir um novo bit, o que estava em QA é movido para QB e assim por diante (mais detalhes no post já citado). Um pulso de clock na entrada RCLK faz com que os dados que estão nos latches internos apareçam na saída. SRCLR limpa os latches internos e OE habilita ou desabilita todas as saídas. Este pino é útil para controlar todas as saídas juntas por PWM (aqui não há como controlar por PWM cada saída individualmente).
Quando todos os latches estiverem completos e um novo bit for inserido, o que estava em QH será movido para QH', o que será utilizado para cascatear vários CIs desse. A animação abaixo mostra um pouco de como funciona esse deslocamento dos bits dentro do CI (daí o nome Shift-Register, ou registrador de deslocamento):

Veja como os dados entram pela entrada SER e, quando o registrador fica cheio, eles saem na mesma sequência pela saída QH'.
Muito embora você possa escrever um programa para enviar bit por bit (ou fazer isso na mão mesmo, montando o circuito no protoboard e com chaves gerar os bits e clocks), nós não faremos isto. Ao invés, usaremos o protocolo SPI de comunicação, que faz exatamente este trabalho de enviar bit por bit de um byte e gera o sinal de clock automaticamente. Isso economiza código e deixa o programa em sí mais fluido, uma vez que a tarefa é executada pelo hardware e não pelo firmaware.

Serial Peripheral Interface, ou para os íntimos, SPI

Protocolo bastante usado por memórias, sensores e outros dispositivos, o SPI é um protocolo bem útil no mundo dos microcontroladores por ser simples e fácil de usar, ao mesmo tempo que é capaz de enviar uma quantia maior de dados por segundo do que o I²C, por exemplo.
No PIC, este protocolo é gerenciado pelo módulo Master Synchronous Serial Port (MSSP), responsável também pela operação do I²C. Existem dois registradores associados a ele, que são os seguintes:



  • WCOL: não falarei sobre ele agora para simplificar as coisas;
  • SSPOV: como trabalharemos com o PIC como Mestre na comunicação, este bit é ignorável;
  • SSPEN: habilita ou desabilita as portas seriais e configura os respectivos pinos;
  • CKP: dita o estado lógico do clock quando o sistema estiver ocioso;
  • SSPM3:0: Seleciona o modo de operação do módulo. As opções para habilitá-lo como I²C estão ocultas. Veja que é possível usar o TMR2 como fonte de clock, quando for necessários frequências menores que a menor possível de Fosc/64.
Embora o datasheet do 74HC595 garanta 91MHz de operação em 5 V, eu tive problemas com a maior frequência que o PIC gerou (48 MHz / 4 = 12 MHz). Isto pode ser culpa da protoboard (altas frequências e protoboard não combinam). Acabei usando 3 MHz (Fosc/16).

 

  • SMP: determina em qual parte do clock os bits serão amostrados;
  • CKE: dita se os dados serão transmitidos na rampa de subida ou de descida do clock;
  • BF: melhor amiga indica quando o buffer receber um byte completo.
Os demais bits não explicitados são irrelevantes para o SPI, sendo utilizados apenas no I²C.
A imagem abaixo mostra o funcionamento melhor dos sinais envolvidos no protocolo e como os bits SMP e CKE influenciam no seu funcionamento. Para o 74HC595 ambos serão deixados em 0.

Esta, assim como as imagens dos registradores, foram tirados do datasheet fornecido pela Microchip.


Hora do código!

Juntando tudo isso, temos o seguinte código de exemplo:

Como sempre, começamos com os #pragma configurando o PIC (run - > Set Configuration Bits no MPLAB para gerar os pragmas de configuração) e os #define para informar o clock do processador, inserir o cabeçalho padrão (xc.h) e criar um rótulo para o pino RC6, aqui chamado de RCLK. Isto facilita sabermos a função de cada pino sem precisar recorrer sempre ao esquema.
Em seguida criamos um vetor (conjunto de variáveis) constante, ou seja, ele fica salvo na memória do programa, liberando espaço para variáveis, porém, por ser uma constante do programa, não pode ser alterado (e nem precisa!). Neste vetor está o conjunto de dados que quero passar via SPI, que aqui no caso é a "máscara" para controlar um display de 7 segmentos, contendo os bytes para exibir os números de 0 a 9. Caso ligue LEDs ou um bargraph, neste vetor poderia estar uma sequência de animações, por exemplo.

A função SPI_Write é a responsável por enviar os bytes via SPI. Dentro desta função começamos carregando o buffer com o valor que queremos transmitir. Quando isso ocorrer, o módulo MSSP automaticamente fará a transmissão, colocando bit por bit no pino RC7 (SDO) do PIC enquanto gera o clock no pino RB1 (SCK) e preenche o buffer a partir do LSB com o valor lido no pino RB0 (SDI). Esperamos o bit SSPIF mudar para 1, indicando que a transmissão foi concluída. Por fim, geramos um clock para a entrada RCLK do Shift-Register, para que o dado recebido seja colocado nas saídas.

Na main, configuramos os PORTs, utilizados como saída (nenhuma entrada, já que estamos interessados em apenas transmitir dados aqui), e em seguida o MSSP, que se encarregará de configurar suas portas corretamente. Limpamos o bit SSPIF que pode eventualmente ter sido colocado em 1 quando o MSSP foi ativado. Por fim, criamos um loop que chamará a função SPI_Write passando a ela como dado cada um dos bytes do vetor mask, fazendo uma contagem crescente de 0 a 9 no display. 

O circuito é o da figura a seguir:



Ao infinito e além!

E se precisar controlar 4 displays? Ou 100 LEDs? Dá? Dá! Veja o esquema abaixo:


Veja que a única coisa que muda é que os demais Shift-Registers recebem os dados agora do pino QH' do CI anterior e compartilham as mesmas linhas de clock. Já na parte do programa, cuide para enviar sempre o byte do último CI (neste circuito acima, por exemplo, envie primeiro o byte do CI3 e depois o do CI2). Lembre-se que os dados entrarão no CI2 e serão "empurrados" para o CI3 pela saída QH' do CI2, por isso devemos mandar sempre "de trás pra frente" (se estiver confuso ainda, olhe novamente a animação que está lá em cima). Cascateando os CIs nesta lógica, você pode criar, em teoria, infinitas saídas.

Existem CIs melhores para isso, como o MAX7219, mas lembrem-se: as vezes é possível achar soluções simples, mais baratas e que nos atendam da mesma forma. Se você quiser o recurso de varredura que o MAX7219 possui, para economizar bateria, por exemplo, você pode usar as entradas G (OE) do 74HC595 para isso, precisando apenas de um leve esforço no programa (usar o Timer para criar interrupções que realizarão a varredura. Nada difícil).
Esses dois vídeos mostram dois exemplos de uso do que foi dito aqui:


 
Espero que este post tenha sido útil a vocês! Se gostaram, compartilhem pra que mais pessoas sejam ajudadas! Se inscreva e acompanhe porque o próximo post será provavelmente sobre overclock no PIC (isso mesmo!).

Comentários