O documento descreve como acender displays de 7 segmentos ligados a microcontroladores. Explica como calcular resistores limitadores de corrente para cada segmento, dimensionar a saída do microcontrolador e multiplexar vários displays. Apresenta um programa em BASIC que faz um contador e mostra os números de 0 a 9 em um display conectado ao PortB de um ATmega328P.
O documento descreve como acender displays de 7 segmentos ligados a microcontroladores. Explica como calcular resistores limitadores de corrente para cada segmento, dimensionar a saída do microcontrolador e multiplexar vários displays. Apresenta um programa em BASIC que faz um contador e mostra os números de 0 a 9 em um display conectado ao PortB de um ATmega328P.
O documento descreve como acender displays de 7 segmentos ligados a microcontroladores. Explica como calcular resistores limitadores de corrente para cada segmento, dimensionar a saída do microcontrolador e multiplexar vários displays. Apresenta um programa em BASIC que faz um contador e mostra os números de 0 a 9 em um display conectado ao PortB de um ATmega328P.
O documento descreve como acender displays de 7 segmentos ligados a microcontroladores. Explica como calcular resistores limitadores de corrente para cada segmento, dimensionar a saída do microcontrolador e multiplexar vários displays. Apresenta um programa em BASIC que faz um contador e mostra os números de 0 a 9 em um display conectado ao PortB de um ATmega328P.
Baixe no formato PDF, TXT ou leia online no Scribd
Fazer download em pdf ou txt
Você está na página 1de 71
MULTIPLEXAO DE DISPLAYS LEDS
PARTE 1 - DISPLAYS DE LEDS DE 7 SEGMENTOS
Uma coisa que todo mundo quer fazer, assim que toma contato com alguma linguagem de programao, ligar um display de 7 segmentos ( ou mais de um ) em um microcontrolador.
Um display de 7 segmentos nada mais do que 7 ( na verdade 8 por causa do ponto decimal ! ) Leds que podem ter os anodos ( ANODO COMUM ) ou os catodos ( CATODO COMUM ) ligados juntos, e as outras pontas desses Leds esto disponveis independentemente umas das outras.
Assim, podemos ligar qualquer um desses Leds, bastando circular uma corrente neles, que geralmente vai de 5 mA a 20 mA . Neste caso, essa corrente vai circular durante todo o tempo em que o Led correspondente no display estiver acionado.
Primeiro, vamos ver como que definimos a corrente que vai atravessar o Led.
RESISTOR LIMITADOR COMO DIMENSIONAR
A maneira mais fcil utilizar um resistor limitador, ento vamos comear usando um display do tipo catodo comum, na cor vermelha.
Note que eu deixei claro uma coisa: cor vermelha! Por que isso importante?
Existe no mercado displays nas cores vermelha verde, azul e branca!
Cada uma dessas cores implica que a tenso de conduo do Led assume um determinado valor, e muito importante para o clculo da corrente que vai circular no Led, a qual ser limitada por um resistor!
O valor exato da tenso encontrado no datasheet do Led, mas para uso do dia a dia usaremos uma tabela com valores mais comumentes adotados. Estes valores so aproximados para uma corrente de 20 mA, pois a tenso varia conforme a corrente.
Desta maneira, para calcular o valor do resistor a ser posto em srie com o Led, basta fazer a seguinte conta:
R = V/I = (Vout Vled) / 0,02
Voc deve estar pensando que a tenso de sada de um microcontrolador alimentado com 5 V tambm 5 V, como aprendeu nos cursos, no ? No no !!!! Depende da corrente que passa por ela !
Se voc usar um Led com baixa tenso, como 1,7 Volts, no muda muito o resultado. Mas se voc utilizar um Led azul, com 3,5 V de tenso de conduo, vai perceber que seu resultado pode estar errado em at mais de 30% ! Por isso que importante saber EXATAMENTE qual a tenso que teremos na sada!
Para determinar exatamente o valor de Vout, voc tem de consultar o datasheet de seu microcontrolador..... Vou aqui utilizar o ATMEGA328P como exemplo, pois hoje o microcontrolador mais utilizado pelos iniciantes devido ao seu farto uso nos Ardunos.
Consultando o grfico na pgina 363, voc verifica que quando alimentado com 5 V, para uma corrente de 20 mA a tenso de sada chega a 4,45 Volts, portanto vamos usar este valor.
J se a corrente fosse de 10 mA, a tenso de sada ser de 4,75 Volts.
Como exemplo prtico, vamos supor que vamos usar um Led Vermelho, portanto usaremos um resistor de ( 4,45 1,7) / 0,02 = 137 Ohms; neste caso usaremos o valor comercial de 150 Ohms.
Agora, temos aqui outro problema:
Imagine que voc ligou os sete segmentos em seu microprocessador. Quando voc quiser acender o nmero 8, a corrente que ser fornecida pelo microcontrolador ao display ser de 8 X 20mA = 160 mA, que uma corrente considerada alta para um microcontrolador.
Voc ter de consultar novamente o datasheet e verificar se o seu modelo utilizado suporta essa corrente.
Veja o que temos na pgina 313 do datasheet:
Aqui, vemos que o microcontrolador suporta tanto a corrente em cada pino (40 mA) como a corrente total ( 200 mA ). Podemos prosseguir sem nenhum problema.
Antes de montar nosso circuito, vou explicar uma outra maneira de se utilizar os Leds, que se chama Modo Pulsado.
Repare que at agora estamos falando de manter uma corrente constante, todo o tempo em que o Led estiver aceso. Isso no obrigatrio, podemos sim variar a corrente nele! E desta maneira podemos fazer uma corrente maior passar por ele, desde que seja por pouco tempo.
Vamos ver um datasheet de um display Led para vermos quais informaes o fabricante fornece:
Vamos considerar o caso do display vermelho ( RED ) . Olhe que interessante:
Corrente mxima em modo contnuo: 30 mA Pico de corrente: 70 mA ( mais abaixo explicarei ) Corrente mdia modo pulsado: 30 mA Condio de trabalho modo pulsado: duty de 1/10 e tempo do pulso de 0,1 milisegundos Caso voc queira que seu display dure bastante, nunca passe a corrente de 30 mA....
No modo Pulsado, nosso display suporta um pico de corrente de 70 mA , DESDE QUE a durao dele seja de apenas 0,1 milissegundo, e que depois disso fique desligado por no mnimo 1 milissegundo ANTES DE SER LIGADO NOVAMENTE ( repare o duty de 1/10 , isto , 1 perodo ligado e 10 perodos desligado ).
Agora, vamos identificar os segmentos:
A figura acima ilustra eletricamente as conexes internas para os casos de catodo comum e de anodo comum. O que importante ver as letras que identificam os segmentos: A , B , C, D, E, F, G .
Agora, lembre-se de que o que vir abaixo vale para o display utilizado no exemplo, que de CATODO COMUM, e, portanto, ele vai acender quando a sada for colocada no estado alto ( nvel 1 ) .
Para mostrar o nmero 1 , acendemos os segmentos B e C . Para o nmero 7, acendemos A, B e C. Para o nmero 8, acendemos todos os segmentos.
Simples, no ?
Em nosso programa, temos apenas de criar uma tabela que nos mostra quais segmentos temos de acender para formarmos o nmero que quisermos.
Para facilitar, repare que ligamos os segmentos em uma mesma porta do microcontrolador, e da seguinte maneira:
Bit 0 A Bit 1 B e assim por diante at o Bit 6 G.
Ou seja, utilizando binrio, temos do MSB ao LSB: 0GFEDCBA
Portanto, basta utilizar uma nica operao de escrita nos 8 bits do port utilizado, e podemos fazer acender qualquer nmero que desejarmos. Assim, criaremos uma tabela na memria, informando quais os bits que precisam ser ligados para acender o nmero que quisermos! Onde o bit tiver o valor binrio 1 significa que o segmento correspondente vai estar aceso ! uma idia bem simples.
DIGITO Seg A Seg B Seg C Seg D Seg E Seg F Seg G Binrio
Portanto, para acendermos o numero 3 no display, basta colocarmos na sada do Port o numero 01001111b , que o hexadecimal 4Fh . Agora, s montarmos a nossa tabela.
Apenas como curiosidade, se utilizssemos um display do tipo ANODO COMUM, como que ficaria a nossa tabela?
Um display do tipo anodo comum teria o terminal comum ligado ao + 5V, portanto o segmento iria acender apenas quando o nvel da porta fosse colocado em nvel baixo (0).
Na prtica, pode utilizar a tabela acima, apenas INVERTENDO O NVEL DOS BITS! Ou seja, para acender o numero 3, na sada colocaremos o numero 10110000b , que B0h em hexadecimal.
APRESENTANDO O CIRCUITO
Vamos considerar o esquema abaixo com um display tipo Catodo Comum:
No utilizaremos o ponto decimal para facilitar. Desta maneira, estamos utilizando 7 sadas para acionar os 7 segmentos, e ligamos o catodo comum direto ao terra ( GND ).
O componente marcado como RN1 um tipo de CI , que contm apenas 8 resistores dentro. No mercado chama-se Resistor Array. Mas voc pode utilizar resistores independentes se quiser!
Para fazer a programao, utilizarei a linguagem Basic, utilizando a verso gratuita do compilador BASCOM, muito utilizado por engenheiros e hobbystas em milhares de projetos.
Com ela voc compilar qualquer programa, a nica limitao da verso free que voc no pode ultrapassar 4K de objeto a ser gravado. Mas apenas projetos grandes vo ultrapassar este tamanho, e no o caso de nenhum projeto apresentado aqui.
Seque abaixo o programa, com os comentrios na cor verde:
' Programa DISPLAY1 ' Faz um contador e mostra a sada em um ' display de 7 segmentos tipo catodo comum '
$regfile = "m328pdef.dat" 'usa um ATMEGA328P
$crystal = 8000000 'usando clock interno
$hwstack = 40 $swstack = 16 $framesize = 32
Config Portb = Output ' vamos usar o PortB como sada digital
Dim I As Byte 'criamos uma varivel I do tipo BYTE
Dim Saida As Byte 'criamos uma varivel SAIDA do tipo Byte
Saida = 0 ' inicialmente vamos garantir o display apagado
Portb = Saida 'apaga o display
Do ' vamos fazer um loop todo o tempo For I = 0 To 9
Saida = Lookup(i , Tabela) ' procura o valor correspondente ao display na tabela ' e armazena na varivel SAIDA
Portb = Saida ' coloca os segmentos correspondentes ao nmero em I na sada
Wait 1 ' espera 1 segundo antes de trocar
Next I
Loop 'volta ao incio do programa
End
Tabela: ' aqui est a tabela com a correspondencia dos segmentos a acender
Data &H3F , &H06 , &H5B , &H4F , &H66 Data &H6D , &H7D , &H07 , &H7F , &H67
Este programa, depois de compilado, tem o tamanho enorme de 370 bytes apenas.
Basta compilar, gerar o .hex e gravar no seu microcontrolador Atmega328P.
Quando energizar, o programa vai comear a mostrar os dgitos de 0 a 9, trocando a cada 1 segundo.
O que o programa faz criar um contador, que vai de 0 at 9, e consulta uma tabela de equivalncia, que vai retornar o valor necessrio para acender o display e formar o nmero que desejamos mostrar.
Devido a isto ser muito simples, vamos passar para o prximo tpico, que a Multiplexao.
MULTIPLEXAO EM DISPLAYS DE 7 SEGMENTOS
J vimos que tivemos de utilizar 7 pinos de sada do nosso microcontrolador para acender um nico dgito.
Mas, e se o display tiver, por exemplo, 4 dgitos ? Se fizermos o mesmo processo, e ainda tivermos de utilizar o ponto decimal em todos eles, iremos precisar de 32 pinos de sada! E imagine a corrente que vai passar, seria da ordem de 4 x 160 ma = 640 mA, totalmente impossvel para qualquer microcontrolador.
Para contornarmos este problema, usamos uma tcnica em que apenas um display est aceso em qualquer tempo! Acendemos primeiro o display numero 1, apagamos ele, e em seguida acendemos o display numero dois, apagamos ele ... e assim sucessivamente at acender o quarto display, quando ento apagamos ele e voltamos a acender o primeiro novamente.
Se fizermos isto bem rpido, os nossos olhos tero a impresso de que todos esto acesos ao mesmo tempo! o mesmo efeito que existia na TV com tubo, e no cinema tambm, que nada mais de mostrar apenas uma parte da imagem de cada vez, e se repetimos isso pelo menos 30 vezes por segundo, nossos olhos no vo perceber que estamos fazendo a troca, e vo ser enganados, tendo a iluso de que todos esto sempre acesos. Simples, no ?
Para conseguirmos isto, vamos usar apenas 8 pinos do microcontrolador, que iro ser ligados em todos os 4 displays no mesmo segmento ( incluindo o ponto decimal ), e mais 4 pinos, onde controlaremos qual o display que ir acender. Totalizamos assim 12 pinos, que bem fcil de ter em muitos microcontroladores de hoje em dia.
A primeira idia fazer algo como o esquema abaixo:
Repare que aqui utilizamos um port inteiro para os 8 segmentos, e mais 4 pinos de outro port para selecionar qual dgito ir acender. Usamos novamente uma rede de resistores, que parece um Circuito integrado de 16 pinos, mas que contm dentro 8 resistores apenas. Facilita muito o desenho do circuito!
Agora, repare bem, quando um determinado dgito estiver selecionado, suponha que vamos acender o numero 8 mais o ponto decimal. So 9 pinos do Port B fornecendo a corrente, e do jeito que est o esquema, existe um pino do outro Port C que recebe toda essa corrente somada ! Mas.... Lembra das limitaes de corrente? Nenhum pino suporta mais do que 40 mA ! Portanto, teremos de limitar a corrente em cada segmento para um mximo de 40/9 = 4,5 mA, ou correremos o risco de queimar o nosso microcontrolador.
Podemos fazer o que j fizemos acima no esquema anterior, que usar um resistor maior para fazer essa limitao. Para isso, consultamos outra vez o datasheet que mostra os nveis de tenso versus a corrente de sada, mas agora vamos precisar de outra informao, pois o pino que vai receber toda a corrente vai ser levado para o nvel lgico 0, e deveria estar com 0 Volts, mas devido ao excesso de corrente ele vai ter uma tenso um pouco maior.
Vamos ver agora o comportamento da tenso de sada em nvel baixo:
E agora ???? No existe a informao que queremos para 40 mA. Qual o motivo? O fabricante no quer que usemos essa corrente, pois isso vai diminuir muito a vida til do componente!
Vamos fazer um exemplo terico apenas. Extrapolando o grfico, veremos que para 40 mA teremos uma tenso em torno de 0,9 Volts.
Agora, para calcular o resistor, temos de levar em considerao a queda de tenso do pino que fornece a corrente e do pino que recebe a corrente!
Vamos pesquisar a queda para um pino que em nvel alto fornece 4,5 mA . Este grfico j foi apresentado antes, e fazendo a consulta nele, teremos uma tenso de 4,9 Volts.
A tenso sobre o resistor seria de 4,9 0,9 1,7 = 2,3 / 0,0045 = 511 ohms. Usaremos o valor comercial mais prximo acima, que de 560 ohms.
Na teoria, nosso circuito vai funcionar, dentro dos limites, mas temos um problema: como abaixamos muito a corrente de cada segmento, ele vai ficar com um brilho bem fraco.
Existem modelos especiais de displays de alto brilho, que mesmo com baixa corrente permite um brilho bem razovel, mas estes modelos so caros.
Ainda nem levamos em conta um dos efeitos da Multiplexao: o brilho aparente, para quatro displays, ser dividido por 4, o que tornar ainda mais fraco o brilho de cada dgito.
Qual a soluo para aumentarmos essa corrente atravs dos Leds do Display?
Em vez de ligarmos direto o terminal comum do display em um microcontrolador, vamos utilizar um transistor para receber essa corrente, pois ele suporta muito mais corrente!
Desta maneira, poderemos ainda fornecer o limite de corrente em cada um dos 8 pinos, o que vai permitir um brilho bem maior !
Agora, nossa nica limitao ser o total da corrente que o microcontrolador consegue fornecer no total. Se quisermos fornecer ainda mais corrente para o display, ser necessrio utilizar um CI tipo Source de corrente, como o UDN2981A, entre o microcontrolador e o Display. E nesse caso, lembre-se de levar em conta a tenso VceSat em vez da tenso de sada no pino do microcontrolador quando voc for calcular o resistor limitador.
No nosso programa, a diferena ser a de que antes, para se acender o display, teramos de levar esse pino por onde passa toda a corrente ao nvel 0 , e agora, teremos de levar ao nvel 1, para que o transistor possa conduzir.
Veja o exemplo abaixo:
Repare que usamos um transistor comum BC337, ligado ao nosso microcontrolador atravs de um resistor de 1K8 para limitar a corrente de base. Os resistores dos segmentos tiveram seus valores alterados para 120 Ohms.
Como que fizemos esses clculos?
Se cada pino vai fornecer a corrente de 20 mA, a tenso sobre o resistor dada pela tenso no pino de sada do microcontrolador, menos a tenso Vce saturao do transistor. Vamos ao datasheet do BC337-25 :
- Ganho entre 160 e 400 - Corrente mxima de coletor 800 mA - Tenso de saturao Vce Sat a 100 mA = 0,2 V com corrente de base = 1 mA
Agora, aqui comeamos a ter de pensar.... melhor sempre olhar os valores a partir dos grficos , pois representam muitas variaes interessantes !
Podemos sempre escolher melhor os nossos parmetros, pois basta localizarmos nos grficos qual a situao que mais se assemelha ao uso que estamos querendo fazer, e pegar valores bem mais corretos.
Primeiro, a folha do datasheet que nos interessa muito:
Normalmente, quando queremos ligar um rel, ou acender um Led, queremos levar o transistor saturao. Assim, basta fornecer na base uma corrente maior do que 1 mA e garantimos que a tenso entre o coletor e o emissor ser bem baixa, em torno de 0,2 Volts.
Mas o que acontece com um transistor quando est muito saturado? Ele vai demorar muito mais tempo para cortar a corrente de coletor quando a corrente de base levada a zero!
Traduzindo, quando quisermos cortar o transistor, ele vai continuar conduzindo por um tempo, e esse tempo a mais depende de quanto maior a relao entre a corrente de coletor e a corrente de base!
Na prtica, acontece o seguinte:
Se quisermos fazer o Multiplex em alta velocidade, tipo cada display acender pelo menos 30 vezes por segundo ( o que vai dar uma freqncia de Multiplex de 120 Hertz para os quatro dgitos ), o tempo em que cada display deveria ficar aceso acaba aumentando, e muitas vezes o digito anterior ainda vai ter um pouco de brilho quando o prximo digito acender! E isso faz com que todos os segmentos paream acesos ao mesmo tempo, ou com que aqueles que deveriam estar sempre apagados aparecem com um brilho pequeno, mas suficiente para atrapalhar a leitura de nosso display!
Como evitar este efeito? Simples, com duas implementaes:
- Evitar saturar muito o transistor - Esperar um pequeno tempo entre apagar um display e acender o outro.
Vamos cuidar do transistor. Olhando novamente o grfico da figura 4, vemos que se fornecemos uma corrente de base de 0,7 mA , j iremos saturar o transistor, e que vai apresentar um VCE de 0,3 Volts. J da figura 5 tiramos a informao de que VBE ser de 0,8 V nessa situao com 100 mA de corrente do coletor.
Lembramos aqui que a corrente que vai atravessar esse transistor vai variar de 20 mA at 160 mA , portanto temos de considerar que a VBE pode ser um pouco maior, VCE pode ser um pouco maior, e a corrente de base teria de ser um pouco maior tambm !
Vamos assim definir que a corrente de base mnima tem de ser pelo menos 2 mA, e que a VBE mxima pode ser de 0,8 V, e que VCE mxima ser de 0,3 V.
R = (5 0,8)/0,002 = 2,1 Kohm
Usaremos o valor imediatamente abaixo para garantir, que ser de 1,8 Kohm.
E o resistor usado nos segmentos do Led?
R = ( 4,45 0,3 1,7 )/0,02 = 122 ohms . Vamos adotar o valor comercial de 120 ohms.
Esta foi a maneira que cheguei aos valores do esquema mostrado acima.
Uma anlise mais profunda vai nos mostrar que quando apenas um segmento de um display estiver aceso, a corrente que vai passar pelo coletor ser de apenas 20 mA, e como a corrente de base no muda, o transistor vai estar muito saturado, e vai demorar mais tempo para desligar esse segmento, o que vai atrapalhar bastante a visualizao, pois vai existir uma situao com dois transistores acionados , um conduzindo muita corrente ( normal ) e um outro que vai conduzir bem pouco porque ainda no conseguiu cortar totalmente, e assim dois displays vo estar com segmentos acesos, um mais forte que o outro, tornando impossvel entender os resultados mostrados.
Assim, teremos de fazer de qualquer maneira a soluo pelo programa, que demorar um pouco entre desligar um dgito e acender o outro.
Essa demora pode ser relativamente pequena. Uma experincia que fiz mostrou que nas condies de circuito acima, se eu esperar 30 microsegundos aps desligar o segmento antes de acender o outro, j faz o display ficar perfeito.
Vamos aos exemplos, chega de teoria!
Usaremos um display de quatro dgitos. Poderemos mostrar qualquer numero entre 0000 e 9,999 .
LGICA DO PROGRAMA DE MULTIPLEXAO
Vamos criar uma matriz tipo Byte para armazenar quatro bytes. Cada byte armazenar o nmero que queremos que seja mostrado no respectivo display. Assim, os valores desses bytes vo estar entre 0 e 9.
O nosso programa principal ser o responsvel por colocar os quatro nmeros a serem mostrados dentro dessa matriz, bem como indicar qual o display que temos de acender o ponto decimal.
Fazendo desta maneira, o processo de fazer o Multiplex vai demorar apenas 33 microsegundos, isso j com o delay, usando o clock interno de 8 MHz no Atmega328P.
Como esse processo ocorre 120 vezes em 1segundo, o tempo total perdido ser de aproximadamente 4 milisegundos, ou seja, perdemos apenas 4% do tempo do processador para fazer todo o processo !
Criaremos uma rotina que vai ser acionada por uma interrupo a cada 8,33 milisegundos, que ser responsvel por tratar todo o processo do Multiplex. Para isso, vamos usar um dos Timers que temos no microcontrolador. Pode-se usar qualquer um deles! Eu usei o Timer0 de 8 bits no primeiro exemplo, e nos outros dois eu usei o Timer1 de 16 bits.
Lembra que logo acima eu expliquei sobre a freqncia do Multiplex? Para uma boa visualizao, cada segmento tem de acender pelo menos 30 vezes a cada segundo. Ento, como usamos 4 displays, teremos de multiplicar isso por 4, obtendo 120 Hz.
Na prtica, quanto maior essa freqncia, mais perfeito fica o efeito, mas o brilho diminui conforme aumentamos a freqncia.... Por que isso acontece?
Vamos usar aqui 120 Hz como exemplo. Se cada display tem de acender 30 vezes por segundo, a grosso modo seu brilho ser reduzido a 1/30 do brilho que teria se ficasse aceso o tempo todo ! Se aumentarmos o Multiplex para 200 Hz, cada display acender por apenas 1/50 do normal....
O nosso olho ajuda a no percebermos tanta variao, devido ao efeito da persistncia da retina. Mas voc percebe bastante a diminuio quando muda de 120 para 200 Hertz, pois os brilhos j esto bem fracos.
Ento, vamos voltar ao nosso programa.
A cada interrupo, apagaremos imediatamente o display que estava aceso, e incrementamos um contador, que nos indica o prximo display a ser aceso. Sabendo qual o dgito, pegamos o valor numrico que tem de ser mostrado nele, consultamos uma tabela que vai nos dizer quais os segmentos que teremos de acender, verificamos tambm se temos de acender o ponto decimal desse display, e aguardamos um pequeno tempo de 15 microsegundos, antes de ligar o display selecionado. Assim, eliminamos o problema que eu comentei bem l em cima, sobre o transistor sair da saturao.
Quando chegarmos ao ultimo dos 4 dgitos, fazemos tudo de novo a partir do primeiro.
Segue a sequncia abaixo, onde cada display aceso sequencialmente (programa foi compilado com freqncia de Multiplex de 4 hertz para as capturas), e por fim o uma captura feita em velocidade real. Repare que as cores vermelhas nos terminais dos componentes significam que existe nvel 1, e as azuis que a tenso nvel 0. Assim fica fcil verificar todos os nveis em cada passo do programa. Apenas um aviso sobre os resistores R1 at R4 : Eles no so necessrios no circuito real ! Mas so necessrios para o correto funcionamento do simulador Isis do Proteus.
Simples, no ?
Esse processo possui um pequeno inconveniente. Imagine que o seu programa principal calculou o numero a ser mostrado no display. Agora, imagine que j atualizou 3 dos 4 dgitos, e nesse momento acontece uma interrupo do timer, e vai justamente mostrar um dos novos dgitos j atualizados. Na prtica, voc perceberia que de vez em quando acontece algo esquisito, alguns erros piscam muito rpido no numero mostrado.
Para evitar isto, eu sugiro sempre o seguinte procedimento:
Deixe para armazenar os nmeros na matriz apenas quando todos estiverem prontos. Antes de atualizar a matriz, pare o Timer !!!! Com isso voc garante que no acontecer a interrupo. Quando terminar de armazenar o ltimo dgito, libere novamente o Timer!
Creio que agora voc j sabe tudo para fazer o seu prprio projeto com displays multiplexados.
Embora este pequeno tutorial foi baseado no Atmega328P, pode ser aplicado em qualquer microprocessador. O uso da Linguagem Basic do Bascom torna bem simples a compreenso e a migrao para outras linguagens.
Um ultimo comentrio sobre o delay necessrio no programa. O delay pode ser maio ou menos, conforme a velocidade de processamento de seu programa. Nos exemplos aqui da apostila, usamos um AVR com 8 MHz. Se usarmos a velocidade interna de 1 MHz, temos de eliminar o comando de delay, pois j vai demorar bastante para executar a rotina de interrupo, em torno de 150 microsegundos. E se o clock for de 16 MHz, temos de aumentar o comando de delay para 24 microsegundos.
E se utilizar um Pic tipo 16f ou 18F ? s lembrar que o processamento dele 4 vezes menor que o de um AVR no mesmo clock.
PROGRAMAS EM BASCOM
Todos os programas apresentados aqui compilam com sobras na verso Demo do Bascom. Disponibilizarei tambm os arquivos para a simulao no ISIS para cada um deles.
Apresentarei trs programas, sendo o primeiro um mostrador que mostra uma contagem que vai de 0000 at 9999 e volta para 0000.
O segundo uma verso mais elaborada do primeiro, pois ele oculta os zeros esquerda (no significativos) da contagem.
O terceiro e ltimo mostra como obter um voltmetro de 0 a 5 volts Dc.
PROGRAMA 1 MOSTRADOR CONTADOR DE 0000 AT 9999
Segue o primeiro programa, que depois de compilado tem o tamanho de 826 bytes.
'---------------------------------------------------------------------- ' PROGRAMA MULTIPLEX1 - Implementa o Multiplex com 4 dgitos, e ' um contador para ficar alterando os numeros a serem mostrados. ' Mostra semelhante a um multmetro, mostrando sempre 4 digitos acesos ' por exemplo, quando 0 mostrar 0000 . ' Este programa utiliza o Timer0 de 8 bits para a base de tempo ' e implementa um refresh de 120 Hertz aproximado. '----------------------------------------------------------------------
Dim Digitos(4) As Byte Dim Disp_index As Byte Dim Disp_aux As Byte Dim Disp_flag As Bit Dim Dp_position As Byte
Config Portb = Output ' PortB vai acender os segmentos, usaremos todos como sada.
Config Portc.0 = Output Config Portc.1 = Output Config Portc.2 = Output Config Portc.3 = Output ' portc comanda qual display ser aceso. usamos os bits PortC.0 at PortC.3 ' assim configuramos apenas os 4 bits como sada.
Config Timer0 = Timer , Prescale = 1024 Timer0 = 191 ' vamos gerar uma interrupo a cada 8,32 milissegundo ' que corresponde a uma frequencia de Multiplex de 120,2 Hertz ' ou seja, cada display vai acender 30 vezes por segundo !
On Timer0 Timer0_sub Enable Timer0 Enable Interrupts
Wait 1 ' todos os segmentos vao ficar acesos por 1 segundo ' util para ver se algum foi danificado! Digitos(1) = 0 Digitos(2) = 0 Digitos(3) = 0 Digitos(4) = 0 ' comearemos do numero 0000
Do Waitms 100 Incr Digitos(4) If Digitos(4) > 9 Then Digitos(4) = 0 Incr Digitos(3) End If If Digitos(3) > 9 Then Digitos(3) = 0 Incr Digitos(2) End If If Digitos(2) > 9 Then Digitos(2) = 0 Incr Digitos(1) End If If Digitos(1) > 9 Then Digitos(1) = 0 End If Dp_position = 4 Loop
End
'------------- ROTINAS DE INTERRUPO ------------------------------------ Timer0_sub: ' Rotina chamada pelo Timer0 a cada Timer0 = 191 'recarrega o timer novamente para
Portc.0 = 0 Portc.1 = 0 Portc.2 = 0 Portc.3 = 0 ' apaga todos os dgitos
If Disp_index > 3 Then Disp_index = 0 ' vamos ver se j fizemos o ultimo digito, pois ento teremos de ' comear pelo primeiro novamente
Incr Disp_index ' aqui j apontamos para o prximo digito
Disp_aux = Digitos(disp_index) ' pegamos o numero que queremos mostrar Portb = Lookup(disp_aux , Table_0f)
' verifica se temos de acender o ponto decimal tambm If Disp_index = Dp_position Then Disp_aux = Lookup(12 , Table_0f) ' procura na tabela a posio do segmento Portb = Portb Or Disp_aux ' acende apenas o ponto decimal End If
' agora vamos acender os segmentos correspondentes ao numero Disp_aux = Lookup(disp_index , Table_mux) Waitus 15 Portc = Portc Or Disp_aux ' faz acender o dgito correto Return
' TABELA DE SEGMENTOS A ACENDER
Table_0f: Data &B00111111 , &B00000110 , &B01011011 , &B01001111 '0,1,2,3 Data &B01100110 , &B01101101 , &B01111101 , &B00000111 '4,5,6,7 Data &B01111111 , &B01100111 , &B00000000 , &B11111111 '8,9,NADA,TUDO Data &B10000000 'PONTO
Segue o programa aperfeioado, que agora compilado tem 1248 bytes.
'---------------------------------------------------------------------- ' PROGRAMA MULTIPLEX2 - Mostra uma maneira de apagar os dgitos ' que ficam esquerda do numero mostrado, assim no veremos um ' monte de 0 sem nenhum significado ! ' Agora usaremos o Timer1 de 16 bits s para variar ..... ' experimente alterar o valor da constante Taxa e veja que legal ! '----------------------------------------------------------------------
$crystal = 8000000 'vamos usar o clock interno que de 8 Mhz. $regfile = "m328Pdef.dat" ' vamos compilar para o ATMEGA328P $hwstack = 40 $swstack = 16 $framesize = 32
Dim Digitos(4) As Byte ' nosso display ter 4 dgitos Dim Disp_index As Byte Dim Disp_aux As Byte Dim Disp_flag As Bit Dim Dp_position As Byte Dim Numero As Word Dim Str_valor As String * 5 Dim I As Byte Dim Ndigit As Byte Dim Digit_temp(6) As Byte
'----- valores para ajustar a velocidade do Mux ------ Const Taxa = 65471 ' se quiser ver o fliquer, mude para 65341, e se quiser ver ' a mudana uma a uma, use 62932 ' valor normal do programa = 65471
Config Portb = Output ' PortB vai acender os segmentos, usaremos todos como sada.
' portc comanda qual display ser aceso. usamos os bits PortC.0 at PortC.3 ' assim configuramos apenas os 4 bits como sada.
Digitos(1) = 11 Digitos(2) = 11 Digitos(3) = 11 Digitos(4) = 11 ' com o valor 11, vamos acender todos os segmentos Disp_index = 0 Dp_position = 0
Config Timer1 = Timer , Prescale = 1024 Timer1 = Taxa ' vamos gerar uma interrupo a cada 8,32 milissegundo ' que corresponde a uma frequencia de Multiplex de 120,2 Hertz ' ou seja, cada display vai acender 30 vezes por segundo !
On Timer1 Timer1_sub Enable Timer1 Enable Interrupts
Wait 1 ' todos os segmentos vao ficar acesos por 1 segundo ' util para ver se algum foi danificado! Digitos(1) = 0 Digitos(2) = 0 Digitos(3) = 0 Digitos(4) = 0
Numero = 0 ' comearemos do numero 0000
Do Waitms 100 Incr Numero If Numero = 10000 Then Numero = 0 Gosub Acerta
Loop
'---- sub-rotina acerta ------------------------------------------------ ' esta rotina faz com que os zeros esquerda do nmero sejam apagados ' a apresentao do nmero fica muito melhor. ' Acerta: Str_valor = Str(numero) ' vamos converter o numero desejado em uma string de caracteres
Str2digits Str_valor , Digit_temp(1) 'esta funo transforma os dgitos dentro da string em nmeros, onde cada um 'dos dgitos ser armazenado em uma posio de uma matriz numrica. ' muito poderosa e facilita bastante nosso trabalho
Ndigit = Digit_temp(1) 'agora Sabemos Quantos Dgitos Possui O Nmero 'e s precisamos recolocar na ordem que o nosso programa vai apresentar 'pois na converso a matriz foi criada com os os numeros de maior grandeza 'no inicio da matriz e da em diante conforme abaixa a grandeza 'sugiro examinar o help do Bascom para entender o funcionamento.
Stop Timer1 ' Vamos parar a contagem do timer1, para evitar que hava alguma interrupo ' enquanto preparamos todos os novos digitospois poderia haver alguma ' mudana doida n odisplay, entao paramos a contagem ' e no teremos a interrupo do timer1 !
For I = 1 To 4 Digitos(i) = 10 Next I ' j colocamos o caractere que vai apagar todos os 4 dgitos ' agora s reordenar conforme a quantidade de dgitos presente ' no nosso nmero a ser mostrado.
If Ndigit = 4 Then Digitos(1) = Digit_temp(5) Digitos(2) = Digit_temp(4) Digitos(3) = Digit_temp(3) Digitos(4) = Digit_temp(2) Elseif Ndigit = 3 Then Digitos(2) = Digit_temp(4) Digitos(3) = Digit_temp(3) Digitos(4) = Digit_temp(2) Elseif Ndigit = 2 Then Digitos(3) = Digit_temp(3) Digitos(4) = Digit_temp(2) Else Digitos(4) = Digit_temp(2) End If
Start Timer1 ' pronto, vamos liberar o timer1 novamente pois tudo j est pronto ! ' este trecho todo acaba atrasando apenas 18 microsegundos, que no chega 'a ser 3% do tempo normal de cada interrupo, portanto imperceptivel. Return
End
'------------- ROTINAS DE INTERRUPO ------------------------------------ Timer1_sub: ' Rotina chamada pelo Timer1 a cada 8,3 milisegundos Timer1 = Taxa ' recarrega o timer novamente
Portc.0 = 0 Portc.1 = 0 Portc.2 = 0 Portc.3 = 0 ' apaga todos os dgitos
If Disp_index > 3 Then Disp_index = 0 ' vamos ver se j fizemos o ultimo digito, pois ento teremos de ' comear pelo primeiro novamente
Incr Disp_index ' aqui j apontamos para o prximo digito
Disp_aux = Digitos(disp_index) ' pegamos o numero que queremos mostrar
Portb = Lookup(disp_aux , Table_0f) ' pegamos a equivalencia dos segmentos na tabela
' Agora verificamos se temos de acender o ponto decimal tambm If Disp_index = Dp_position Then Disp_aux = Lookup(12 , Table_0f) ' procura na tabela a posio do segmento Portb = Portb Or Disp_aux ' acende apenas o ponto decimal End If
' agora vamos acender os segmentos correspondentes ao numero Disp_aux = Lookup(disp_index , Table_mux) Waitus 15 Portc = Portc Or Disp_aux ' faz acender o dgito correto
Return
'---------------------------------------------- ' TABELA DE SEGMENTOS A ACENDER
Table_0f: Data &B00111111 , &B00000110 , &B01011011 , &B01001111 '0,1,2,3 Data &B01100110 , &B01101101 , &B01111101 , &B00000111 '4,5,6,7 Data &B01111111 , &B01100111 , &B00000000 , &B11111111 '8,9,NADA,TUDO Data &B10000000 'PONTO
'---------------------------------------------- ' TABELA INDICADORA DO DISPLAY A ACENDER
Segue o programa do voltmetro digital, compilado com 2332 bytes.
'---------------------------------------------------------------------- ' PROGRAMA MULTIPLEX3 - Implementa um voltmetro que pode medir ' tenso entre 0 e 5 volts, e mostra com at 3 casa depois da vrgula ' ' ' '----------------------------------------------------------------------
$crystal = 8000000 'vamos usar o clock interno que de 8 Mhz. $regfile = "m328Pdef.dat" ' vamos compilar para o ATMEGA328P $hwstack = 40 $swstack = 16 $framesize = 32
Dim Disp_index As Byte Dim Disp_aux As Byte Dim Disp_flag As Bit Dim Digitos(4) As Byte ' nosso display ter 4 dgitos Dim Dp_position As Byte Dim Numero As Word Dim Str_valor As String * 5 Dim I As Byte Dim Digit_temp(6) As Byte Dim Resultado As Single ' RESULTADO tem de apresentar numeros no inteiros
'----- valores para ajustar a velocidade do Mux ------ Const Taxa = 65471 ' se quiser ver o fliquer, mude para 65341, e se quiser ver ' a mudana uma a uma, use 62932 ' valor normal do programa = 65471
Config Portb = Output ' PortB vai acender os segmentos, usaremos todos como sada.
' portc comanda qual display ser aceso. usamos os bits PortC.0 at PortC.3 ' assim configuramos apenas os 4 bits como sada.
Digitos(1) = 11 Digitos(2) = 11 Digitos(3) = 11 Digitos(4) = 11 ' com o valor 11, vamos acender todos os segmentos Disp_index = 0 Dp_position = 0
Config Timer1 = Timer , Prescale = 1024 Timer1 = Taxa ' vamos gerar uma interrupo a cada 8,32 milissegundo ' que corresponde a uma frequencia de Multiplex de 120,2 Hertz ' ou seja, cada display vai acender 30 vezes por segundo !
On Timer1 Timer1_sub Enable Timer1 ' aqui definimos a subrotina que ir ser chamada a cada ' interrupo, e j deixamos o timer1 correr
Config Adc = Single , Prescaler = Auto , Reference = Avcc Start Adc ' aqui configuramos o conversor a/d para fazer uma leitura ' apenas quando pedirmos, vai usar como referencia 5V
Enable Interrupts ' aqui habilitamos as interrupes definidas no programa
Wait 1 ' todos os segmentos vao ficar acesos por 1 segundo ' util para ver se algum foi danificado! Digitos(1) = 0 Digitos(2) = 0 Digitos(3) = 0 Digitos(4) = 0
Dp_position = 1 ' ponto decimal sempre no primeiro dgito
Do Waitms 100 Numero = 0 For I = 1 To 32 Numero = Numero + Getadc(5) Next I Shift Numero , Right , 5 'fizemos a soma de 32 leituras consecutivas, e calculamos 'a mdia para ter uma melhor estabilidade
Numero = Numero * 5 Resultado = Numero / 1023 ' aqui fizemos o chamado fator de escala, pois o fundo de escala ' 5 volts e nesse caso obteremos leitura de 1023, ento ' basta multiplicar por 5 e dividir por 1023, e j teremos o ' valor em volts.
Str_valor = Fusing(resultado , "#.###") ' convertemos o resultado em uma string j formatada como queremos ' e com arredondamento na ltima casa decimal ! Mais uma ' poderosa instruo do Bascom
Str_valor = Trim(str_valor) ' eliminamos qualquer espao em branco
Str2digits Str_valor , Digit_temp(1) ' fazemos o mesmo truque em tirar todos os digitos da string e ' armazenar em uma matriz como nmero, assim fica muito simples ' pegar cada dgito e apresentar.
Stop Timer1 ' paramos a contagem do timer1 para evitar mostrar resultados ' sem nexo
If Digit_temp(1) = 3 Then ' o valor a mostrar zero Digitos(1) = 0 Digitos(2) = 0 Digitos(3) = 0 Digitos(4) = 0 Else ' temos de ordenar os digitos, agora com uma novidade, pois ' digit_temp(5) tem o ponto decimal, ento pularemos Digitos(1) = Digit_temp(6) Digitos(2) = Digit_temp(4) Digitos(3) = Digit_temp(3) Digitos(4) = Digit_temp(2) End If Start Timer1 ' continua a contagem do Timer1 Loop
End
'------------- ROTINAS DE INTERRUPO ------------------------------------ Timer1_sub: ' Rotina chamada pelo Timer1 a cada 8,3 milisegundos Timer1 = Taxa ' recarrega o timer novamente
Portc.0 = 0 Portc.1 = 0 Portc.2 = 0 Portc.3 = 0 ' apaga todos os dgitos
If Disp_index > 3 Then Disp_index = 0 ' vamos ver se j fizemos o ultimo digito, pois ento teremos de ' comear pelo primeiro novamente
Incr Disp_index ' aqui j apontamos para o prximo digito
Disp_aux = Digitos(disp_index) ' pegamos o numero que queremos mostrar
Portb = Lookup(disp_aux , Table_0f) ' pegamos a equivalencia dos segmentos na tabela
' Agora verificamos se temos de acender o ponto decimal tambm
If Disp_index = Dp_position Then Disp_aux = Lookup(12 , Table_0f) ' procura na tabela a posio do segmento
Portb = Portb Or Disp_aux ' acende apenas o ponto decimal End If
' agora vamos acender os segmentos correspondentes ao numero
Disp_aux = Lookup(disp_index , Table_mux) Waitus 15 Portc = Portc Or Disp_aux ' faz acender o dgito correto Return
'---------------------------------------------- ' TABELA DE SEGMENTOS A ACENDER
Table_0f: Data &B00111111 , &B00000110 , &B01011011 , &B01001111 '0,1,2,3 Data &B01100110 , &B01101101 , &B01111101 , &B00000111 '4,5,6,7 Data &B01111111 , &B01100111 , &B00000000 , &B11111111 '8,9,NADA,TUDO Data &B10000000 'PONTO
'---------------------------------------------- ' TABELA INDICADORA DO DISPLAY A ACENDER
Em anexo, voc encontra os arquivos fontes dos programas, e os arquivos da simulao no sis do Proteus.
A idia voc alterar a taxa do Multiplex, recompilar o programa, e ver na tela do simulador o funcionamento em velocidade reduzida. Voc pode alterar a freqncia do Timer para verificar o funcionamento em baixa velocidade, para ver o programa fazer acender os displays um a um.
Agora, voc deve estar pensando: se eu precisar de um display com bastante brilho, como posso fazer?
Vamos agora conhecer um CI fantstico, com baixo custo e excelente desempenho e que pode entregar muita corrente (at queimar...) aos nossos displays de 7 segmentos ! Ele o famoso MAX7219.
DISPLAYS DE 7 SEGMENTOS COM O MAX7219
Voc j percebeu que se quisermos ter um bom brilho, temos de entregar mais corrente aos segmentos. E para isto teremos de acrescentar um CI do tipo Current Drive ou vulgarmente Source Drive. Ele ficaria ligado entre as 8 sadas do microcontrolador e os 8 segmentos.
At aqui, tudo bem. Mas, vamos complicar um pouco mais. Imagine que agora voc quer fazer um controle automtico de brilho, isto , voc quer poder mudar o brilho do display, talvez para uso com bateria, ou em locais escuros. Como fazer isto?
Podemos mudar os tempos envolvidos na Multiplexao, como por exemplo, aumentando bastante a freqncia. Mas agora o efeito da saturao o nosso novo limitador, pois logo vai parecer que todos os segmentos comeam a acender.... e complica demais.
Para evitar isto, surgiu o MAX7219. Ele um CI controlador de at 8 displays Leds do tipo catodo comum, e pode fornecer at 40 mA por segmento. Pode mudar o brilho com 16 nveis atravs de PWM feito no prprio CI. Pode utilizar de 1 at 8 displays, e pode ser reconfigurado por software. Voc no precisa de tabelas, pode enviar para o CI o valor de cada dgito com 4 bits ( Code B ) e o CI se encarrega dos segmentos. Podemos tambm cascatear vrios CIs, podendo mostrar 16 ou mais dgitos. E o melhor de tudo, voc precisa de apenas 3 pinos do microcontrolador para fazer tudo isto, pois a interface serial, e de altssima velocidade !
Este CI tambm muito utilizado para se fazer matriz de Leds, pois ele pode controlar 64 Leds individuais, dispostos em uma matriz de 8 linhas por 8 colunas. Mas isto um uso um pouco mais avanado e ficar para uma prxima oportunidade.
Como funciona a conversa com o MAX7219? Bem simples, sempre enviaremos 16 bits para ele de uma vez (ou seja, dois bytes consecutivos). Apenas 12 bits tm validade, sendo que 8 bits so referentes a dados, e 4 bits referentes a endereo de um registro.
Dentro do CI, podemos acessar at 16 registros individuais, sendo que 8 deles guardam os nmeros a serem mostrados no display, e os outros 8 restantes so para diversas configuraes.
Assim, para podermos usar o CI, precisamos primeiro configurar o modo de trabalho que queremos, a quantidade de displays que esto conectados nele, e o brilho inicial, que depois pode ser mudado como quisermos.
Chega de conversa e vamos logo aos diagramas. Vamos apresentar os diagramas de conexo, as tabelas que nos interessam, e depois vamos explicar como utilizar este til CI.
Exemplo de uso tpico :
Como juntar dois CIs para termos at 16 dgitos :
FORMATO DE COMUNICAO:
DIAGRAMA DE TEMPOS:
DIAGRAMA DE CORRENTE VERSUS RESISTOR DE SET
Pronto, tudo o que precisamos saber est colocado nas pginas anteriores.
Quando enviarmos os dados seriais, enviaremos primeiro o bit D15, depois o D14, e assim at o ultimo bit, que o D0. Ou seja, sempre ser no formato do MSB at o LSB.
Usamos trs sinais para transmitirmos os dados. Temos dois sinais usados em comunicao serial, que so o CLOCK e o DATA . E o ltimo o CS, ou Chip Select, que tem de ser colocado em nvel 0 quando desejamos que o chip aceite conversar conosco.
Assim, temos de fazer a seguinte sequncia: Primeiro, colocamos CS em nvel 1, a seguir CLOCK em nvel 0, e colocamos DATA no nvel que queremos. Agora podemos comear a conversa: CS=0 CLOCK = 1 (pronto, o que est em DATA j foi para o MAX7219) CLOCK=0 DATA=X ( X pode ser 0ou 1 ) CLOCK=1 (o que estava em DATA foi enviado ao MAX7219) CLOCK=0
Faremos esse processo 16 vezes no total, para enviarmos os 16 bits ao CI, e quando terminarmos, logo aps colocar CLOCK=0, faremos CS=1 e pronto, acabamos!
Veja esse processo na figura onde est escrito DIAGRAMA DE TEMPOS.
Uma coisa que temos de escolher antes de montar o valor do resistor RSET que iremos utilizar. Quanto mais baixo, maior a corrente disponvel em cada segmento. Para isto, vamos direto para a TABELA 11. Suponha que vamos usar um display Vermelho, e que ele permite 30 mA em cada segmento. Consultando o datasheet, voc verifica que a tenso no Led para corrente de 30 mA de 2 Volts. Assim, procure a coluna para 2 Volts, onde ela cruza com a corrente de 30 Ma, nele obtemos o valor de 17.1 kOhms . Usaremos o valor logo acima, que de 18K.
Agora, j temos o hardware definido. Vamos usar 4 displays de 7 segmentos na cor vermelha, tipo catodo comum, com resistor Rset de 18K.
Nosso programa vai enviar os nmeros no formato binrio de 4 bits, representando de 0 a 9, e inicialmente queremos brilho mximo.
Para usarmos o MAX7219, temos primeiro de configurar 4 registros. Veja na TABELA 2, e acompanhe os nomes deles.
Vou utilizar um cdigo de cores: Vermelho indica os bits no-significativos (podem ter qualquer valor), verde indica os bits que selecionam o registro desejado, e em azul os bits de dados que so importantes em cada registro.
Registro DECODE MODE : Veja na tabela 4, vamos configurar para que possamos usar o B-CODE para todos os dgitos. Assim, se quisermos acender o numero 9 no display, o valor binrio a enviar ser 1001b . Portanto, temos de enviar no formato binrio os 16 bits abaixo, indo do MSB ao LSB: 1111100111111111b
Registro SCAN LIMIT : Veja na TABELA 8, como vamos utilizar 4 displays, temos de enviar a seguinte informao binria: 1111101111111011b
Registro INTENSITY : Veja na TABELA 7, como queremos inicialmente o brilho mximo , vamos enviar a seguinte informao binria: 1111101011111111b
Registro SHUTDOWN : Veja na TABELA 3, como queremos que o display entre em operao, vamos enviar a seguinte informao binria: 1111110011111111b
Pronto, com o envio desses 4 conjuntos de dados, o display j ir acender, e estar prontinho para operar normalmente.
Agora, precisamos enviar os dados. Para isto, como temos 4 displays ligados no CI, teremos de enviar 4 conjuntos de dados, cada conjunto ir fazer acender um display em uma determinada posio. Vamos chamar os nossos 4 displays de disp3 .... disp2 ... disp1 ... disp0, ou seja , Disp3 o mais significativo ( esquerda) e Disp0 o menos significativo ( direita).
Temos de acessar os registros com os nomes DIGIT 3, DIGIT 2, DIGIT 1 e DIGIT 0.
Vamos supor que temos de mostrar o numero 1234 . Veja agora a TABELA 2 para achar o registro, e a seguir a tabela 5.
Sequncia binria para DISP 3 : 1111010001110001b Sequncia binria para DISP 2 : 1111001101110010b Sequncia binria para DISP 1 : 1111010101110011b Sequncia binria para DISP 0 : 1111010001110100b
O ponto decimal fica numa posio esquisita, mas vamos mostrar um exemplo: queremos acender o numero 5.678 . Veja a nova sequncia:
Sequncia binria para DISP 3 : 1111010011110101b (veja o ponto aceso, bit d7=1) Sequncia binria para DISP 2 : 1111001101110110b Sequncia binria para DISP 1 : 1111010101110111b Sequncia binria para DISP 0 : 1111010001111000b
At que agora no parece to complicado, no ?
Sugiro que voc estude mais o MAX7219, pois ele faz um excelente controlador de matriz de Leds, e pode-se utilizar em muitas aplicaes diferentes.
Eu mesmo fiz um Analisador de Espectro de udio, onde o mostrador eram duas matrizes de 8x8 Leds, colocadas uma ao lado da outra, utilizando dois CIs MAX7219.
Vamos a seguir mostrar o esquema de ligaes utilizado no programa, repare que em vez de colocar 4 displays de 7 segmentos , usei um modelo diferente, fcilmente encontrado no mercado, tendo os quatro dgitos em uma s pea.
E isto tambm necessrio para uma melhor simulao no Isis, pois este modelo de display suporta uma grande variao nas temporizaes.
Agora, vamos ao programa em Bascom. Iremos modificar o programa do Voltmetro, que fizemos l encima, para usar o MAX7219.
'---------------------------------------------------------------------- ' PROGRAMA MULTIPLEX4 - Implementa um voltmetro que pode medir ' tenso entre 0 e 5 volts, e mostra com at 3 casas depois da vrgula ' Usaremos agora o MAX7219 ' os displays estao numerados assim D4-D3-D2-D1 ' Este programa utiliza aritmtica de ponto flutuante. '----------------------------------------------------------------------
$crystal = 8000000 'vamos usar o clock interno que de 8 Mhz. $regfile = "m328Pdef.dat" ' vamos compilar para o ATMEGA328P $hwstack = 40 $swstack = 32 $framesize = 52
Dim Digitos(4) As Byte Dim Digit_temp(6) As Byte ' nosso display ter 4 dgitos Dim Dp_position As Byte Dim Numero As Word Dim Str_valor As String * 5 Dim I As Byte
Config Adc = Single , Prescaler = Auto , Reference = Avcc Start Adc ' aqui configuramos o conversor a/d para fazer uma leitura ' apenas quando pedirmos, vai usar como referencia 5V
Enable Interrupts ' aqui habilitamos as interrupes definidas no programa
Dp_position = 4 ' ponto decimal sempre no primeiro dgito
'vamos agora inicializar o MAX7219
Numero = Reg_shutdown Gosub Sai_max Numero = Reg_decode_mode Gosub Sai_max Numero = Reg_intensity Gosub Sai_max Numero = Reg_scan_limit Gosub Sai_max
'j configurado !
Do Waitms 100 Numero = 0 For I = 1 To 32 Numero = Numero + Getadc(5) Next I Shift Numero , Right , 5 'fizemos a soma de 32 leituras consecutivas, e calculamos 'a mdia para ter uma melhor estabilidade
Numero = Numero * 5 Resultado = Numero / 1023 ' aqui fizemos o chamado fator de escala, pois o fundo de escala ' 5 volts e nesse caso obteremos leitura de 1023, ento ' basta multiplicar por 5 e dividir por 1023, e j teremos o ' valor em volts.
Str_valor = Fusing(resultado , "#.###") ' convertemos o resultado em uma string j formatada como queremos ' e com arredondamento na ltima casa decimal ! Mais uma ' poderosa instruo do Bascom
Str_valor = Trim(str_valor) ' eliminamos qualquer espao em branco
Str2digits Str_valor , Digit_temp(1) ' fazemos o mesmo truque em tirar todos os digitos da string e ' armazenar em uma matriz como nmero, assim fica muito simples ' pegar cada dgito e apresentar.
If Digit_temp(1) = 3 Then ' o valor a mostrar zero Digitos(1) = 0 Digitos(2) = 0 Digitos(3) = 0 Digitos(4) = 0 Else ' temos de ordenar os digitos, agora com uma novidade, pois ' digit_temp(5) tem o ponto decimal, ento pularemos Digitos(4) = Digit_temp(6) Digitos(3) = Digit_temp(4) Digitos(2) = Digit_temp(3) Digitos(1) = Digit_temp(2) End If For I = 4 To 1 Step -1 Numero = Digitos(i) If Dp_position = I Then Numero = Numero Or &B1111000010000000 End If Select Case I Case 1 Numero = Numero Or &B1111010000000000 Case 2 Numero = Numero Or &B1111001100000000 Case 3 Numero = Numero Or &B1111001000000000 Case 4 Numero = Numero Or &B1111000100000000 End Select Gosub Sai_max Next I
Finalmente, para encerrar, um pouco de matemtica em programao.
Muitas vezes, no temos a enorme facilidade de contarmos com matemtica de ponto flutuante em nossos projetos. Simplesmente porque isso faz o programa ficar muito maior, pois nossos microprocessadores so feitos para trabalhar com dados internos de 8 bits apenas. Ponto flutuante exige um monte de bytes para armazenamento, e um monte de operaes de clculos. E tambm demora muito mais tempo de processamento para serem executadas.
Podemos fazer o voltmetro usando apenas matemtica com 16 bits, que a que temos nos AVRs e nos Pics comuns? (Embora sejam de 8 bits, no d trabalho fazer em partes de 8 bits, e podemos trabalhar fcilmente com nmeros de 16 bits).
Sim, podemos!!!! Sempre temos de usar um pouco de engenhosidade! Afinal, estudamos para isso, para pensar!
Vamos pensar em nosso display. Vamos apresentar 4 dgitos nele. Veja a tenso de 3.574 Volts. Se no tivesse o ponto decimal, seria mostrado o numero inteiro 3574 !
O maior valor que nosso voltmetro pode mostrar 5.000 Volts, ou o numero inteiro 5000.
Afinal, qual o maior numero que podemos trabalhar com 16 bits? Resposta: 65535 !
Se fizermos o fundo de escala de nosso multmetro ser 5000, ento resolvemos o problema! Basta acendermos a vrgula!
Podemos fazer as contas todas usando nmeros de 16 bits ( chama-se WORD a esse tipo de varivel ) , sem nmeros decimais, e no final apresentar o numero do jeito que est !
Sabemos que o conversor A/D dos AVRs e dos Pics sempre apresenta os resultados da converso em 10 bits. Isso significa um nmero entre 0 e 1023.
Se voc se lembrar, nosso ultimo programa faz 32 medidas de tenso em seguida, somando todas elas, e em seguida divide por 32 para achar uma mdia, e temos o resultado novamente entre 0 e 1023.
A minha idia fazer mais medies e ir somando elas, para chegar bem pertinho da soma dar 50000. Ento, vou fazer a soma de 49 medidas, que vai passar um pouquinho, resultando 50127. Temos ento um pequeno erro, de cerca de ((50127/50000) 1) x 100 = 0,254 %
Temos de subtrair isso da contagem, para obtermos o valor que queremos, que 50000. Para isso, vamos lembrar ma matemtica bsica do PERCENTUAL.
0,254% = 0,254/100 = 0,2% + 0,05% + 0,004% !
Agora, matemtica bsica do ginsio: se 2% de 100 igual a 2, equivale a dividir 100 por 50, correto ? E se quisermos 0,2% de 100, equivale a dividir por 500 . Assim, se quisermos saber quanto 0,2% de um nmero, basta dividir ele por 500!
A mesma coisa se aplica aos outros percentuais: 0,05% equivale a dividir o numero por 2000 0,004% equivale a dividir o nmero por 25000
Ento, temos de fazer a seguinte conta:
Se a nossa soma deu 50.127, calculamos os percentuais e subtramos do total!
Olha s:
50127 50127/500 50127/2000 50127/25000 fica assim :
Lembre-se que a diviso comum sempre resulta apenas a parte inteira do numero:
50127 100 25 2 = 50000 !!!!!
Pronto, conseguimos ajustar a nossa medida!
Esse resultado tem 5 dgitos, vamos dividir por 10 para voltarmos aos 4 dgitos , o que resulta em 5000 !
E quanto erro teremos nesse procedimento maluco? Oras, o conversor A/D sempre conta at 1023, portanto ele tem uma resoluo de 5/1023 = 4,89 mV .
Na prtica, muito difcil filtrar os rudos abaixo de 20 mV, portanto estamos trabalhando com uma resoluo terica de 5 mV, mas na prtica considere 20 mV, ou teremos de projetar um belo layout, com muitos filtros.
Segue abaixo o programa, implementando exatamente a tcnica descrita acima. Tente entender, pois muito usada quando trabalhamos em Assembler, ou quando temos pouca memria para o programa.
'---------------------------------------------------------------------- ' PROGRAMA MULTIPLEX 5 - Implementa um voltmetro que pode medir ' tenso entre 0 e 5 volts, e mostra com at 3 casas depois da vrgula ' Usaremos agora o MAX7219 ' os displays estao numerados assim D4-D3-D2-D1 ' Este programa utiliza aritmtica de 16 bits apenas ! '----------------------------------------------------------------------
$crystal = 8000000 'vamos usar o clock interno que de 8 Mhz. $regfile = "m328Pdef.dat" ' vamos compilar para o ATMEGA328P $hwstack = 40 $swstack = 32 $framesize = 52
Dim Digitos(4) As Byte ' nosso display ter 4 dgitos Dim Dp_position As Byte Dim Numero As Word Dim I As Byte
Config Adc = Single , Prescaler = Auto , Reference = Avcc Start Adc ' aqui configuramos o conversor a/d para fazer uma leitura ' apenas quando pedirmos, vai usar como referencia 5V
Enable Interrupts ' aqui habilitamos as interrupes definidas no programa
Dp_position = 4 ' ponto decimal sempre no primeiro dgito
'vamos agora inicializar o MAX7219
Numero = Reg_shutdown Gosub Sai_max Numero = Reg_decode_mode Gosub Sai_max Numero = Reg_intensity Gosub Sai_max Numero = Reg_scan_limit Gosub Sai_max
'j configurado !
Do Waitms 100 Numero = 0 For I = 1 To 49 Numero = Numero + Getadc(5) Next I
' vamos calcular a media, somando 49 ezes a leitura. Porque 49 ? ' se multiplicarmos 49 x 1023, teremos 50.127, que ultrapassa em pouco 50.000 ' SE DIVIDIRMOS 50127/50.000 = 1,00254, que 2,54% maior do que queremos, ' agora, temos um valor que ultrapassa 50.000 em 0,254% . Vamos portanto subtrair ' esses 0,254% !
Resultado1 = Numero Resultado1 = Resultado1 / 500 ' 0,2% Numero = Numero - Resultado1 Resultado1 = Numero Resultado1 = Numero / 2000 '0,05 % Numero = Numero - Resultado1 Resultado1 = Numero Resultado1 = Resultado1 / 25000 ' 0,004 % Numero = Numero - Resultado1
' FINALMENTE SUBTRAIMOS 2,54% ' VAMOS AGORA DIVIDIR POR 10 PARA CHEGARMOS NA ESCALA QUE QUEREMOS. Numero = Numero / 10
Resultado1 = Numero / 1000 Digitos(4) = Low(resultado1) Resultado = Digitos(4) * 1000 Numero = Numero - Resultado
Resultado1 = Numero / 100 Digitos(3) = Low(resultado1) Resultado = Digitos(3) * 100 Numero = Numero - Resultado
Resultado1 = Numero / 10 Digitos(2) = Low(resultado1) Resultado = Digitos(2) * 10 Numero = Numero - Resultado
Digitos(1) = Low(numero)
' prontinho... no precisamos utilizar matemtica de ponto flutuante, que ' sempre faz o programa ficar bem maior. Veremos no final a reduo do programa.
For I = 4 To 1 Step -1 Numero = Digitos(i) If Dp_position = I Then Numero = Numero Or &B1111000010000000 End If Select Case I Case 1 Numero = Numero Or &B1111010000000000 Case 2 Numero = Numero Or &B1111001100000000 Case 3 Numero = Numero Or &B1111001000000000 Case 4 Numero = Numero Or &B1111000100000000 End Select Gosub Sai_max Next I
Este programa compilado tem 1.474 bytes. Se comparar com o anterior, que utiliza ponto flutuante, vemos que a reduo no tamanho enorme, cerca de 35% menor !!!
Repare que fizemos a separao dos 4 dgitos da maneira mais simples possvel, sem utilizar nenhum funo de alto nvel do Bascom. Fiz isto apenas para que voc aprenda esta maneira simples de se separar os dgitos individuais de um nmero.
PARTE 2 MATRIZES DE LEDs
As matrizes de Leds so componentes que geralmente contm 64 Leds no total, organizados em 8 linhas de 8 colunas, conforme a figura abaixo, que mostra uma matriz do tipo CATODO COMUM :
Repare que os catodos dos Leds so interligados 8 a 8. No exemplo acima, para acender o primeiro Led da esquerda, parte superior, temos de colocar uma tenso positiva na primeira coluna pino 13, e colocar nvel 0 na primeira linha, que o pino 1.
Repare a dificuldade que acender vrios Leds.... s possvel acender ao mesmo tempo os Leds pertencentes a uma mesma linha !
Se quisermos acender vrios, temos de recorrer Multiplexao, onde iremos acionar os Leds da primeira linha, em seguida os da segunda linha, e assim at a ltima linha. Se fizermos isto com uma boa velocidade, nosso olho vai fazer a famosa integrao, e veremos como se todos estivessem acesos ao mesmo instante.
Como fazemos isto?
A primeira maneira a mais simples, usamos uma porta inteira de um microcontrolador para fazer as linhas, e outra porta inteira para fazer as colunas. Perderemos 16 pinos do nosso microcontrolador para fazer isto.
Veja o esquema abaixo:
Aqui, usamos o Port B para comutar as colunas, e o Port D para comutar as linhas.
Repare que temos os mesmos problemas de corrente que tivemos acima, usando os displays de 7 segmentos diretamente. A corrente em cada coluna limitada corrente mxima da de um pino, portanto a corrente de cada Led das linhas tem de ser no mximo a da coluna / 8. Isto limita bastante o brilho, quando usamos o princpio do Multiplex.
Vamos ilustrar aqui, como seria um programa para acender um enorme X na matriz.
Imagine que iremos utilizar 8 bytes de memria, totalizando 8 x 8 = 64 bits, portanto uma representao perfeita da matriz.
Vamos apresentar os 8 bytes da seguinte maneira : o primeiro byte representa os Leds da primeira linha; o prximo byte representa a segunda linha, e assim por diante.
Dentro de cada byte, o MSB representa o Led mais esquerda, e o LSB representa o Led mais direita.
Agora, vamos supor que o bit em 1 representa o Led aceso, e 0 representa o Led apagado.
Veja como ficam os nossos 8 bytes para acender o X:
Reparou que tem uma coisa esquisita.. no usamos todas as 8 linhas e as 8 colunas, mas sim 7 linhas e 7 colunas ?
Se voc pretende escrever um texto na matriz, recomendado sempre que o tamanho da matriz seja de nmeros IMPARES, ou seja, 7x7 , 7x5 . Seno, se fosse usado um nmero par, nunca teria uma posio central, aquela bem no meio da matriz, que no nosso caso exatamente o meio do X, que est na Col4 e Byte4.
Nesta representao que adotei, no importa a letra a ser mostrada, sempre teremos o Byte8 igual a 0 e a Col8 igual a 0.
Nosso programa far o Multiplex como se fossem 8 dgitos , fazendo acender uma coluna a cada vez, como se fosse um display do tipo CATODO COMUM, igual ao nosso exemplo l no comeinho ....
Assim, selecionamos a coluna 1 fazendo sair no PortB o valor 01111111b. A seguir, colocamos no PortD o valor 10000010b , e isto far acender os dois Leds.
Na prxima vez, faremos PortB = 10111111b e PortD = 01000100b
E assim por diante. Repararam que exatamente o mesmo princpio que usamos l em cima para fazer o Multiplex do display com 4 dgitos ? S que aqui so 8 dgitos !
A situao muito parecida com a que j vimos antes, porm tratamos agora as 8 colunas da mesma maneira com que tratamos os 4 dgitos. Tivemos de aumentar a freqncia do Multiplex para 240 Hz, para manter a mesma taxa de acender cada coluna pelo menos 30 vezes por segundo.
Veja dois instantes seguidos da Multiplexao, e o efeito total captado pelo nosso olho:
Vamos ao programa em Bascom.
PROGRAMA 5 MATRIX DE 8X8 BSICA
'---------------------------------------------------------------------- ' PROGRAMA MULTIPLEX MATRIX1 - Implementa o Multiplex Basico para ' fazer acender um X na nossa matrix. ' Usaremos uma tabela de 8 bytes para cada letra ou numero a ser ' mostrado, mas por simplicidade colocaremos apenas o valor ' correspondente letra X ' Este programa utiliza o Timer0 de 8 bits para a base de tempo ' e implementa um refresh de 240 Hertz aproximado. '----------------------------------------------------------------------
Config Portb = Output ' PortB vai acender as COLUNAS
Config Portd = Output 'PortD vai acender as LINHAS
Config Timer0 = Timer , Prescale = 256 Timer0 = 126 ' vamos gerar uma interrupo a cada 4,16 milissegundo ' que corresponde a uma frequencia de Multiplex de 240,4 Hertz ' ou seja, cada coluna vai acender 30 vezes por segundo !
On Timer0 Timer0_sub Enable Timer0 Enable Interrupts
Do Waitms 100
Loop
End
'------------- ROTINAS DE INTERRUPO ------------------------------------ Timer0_sub: ' Rotina chamada pelo Timer0 a cada Timer0 = 126 'recarrega o timer novamente para
Portb = 255 ' apaga todos os dgitos
If Disp_index > 8 Then Disp_index = 0 ' vamos ver se j fizemos o ultimo digito, pois ento teremos de ' comear pelo primeiro novamente
Incr Disp_index ' aqui j apontamos para o prximo digito
Disp_aux = Disp_index - 1 ' pegamos os Leds que queremos mostrar ( linha ) nesta coluna Portd = Lookup(disp_aux , Table_x)
Agora, vamos ao prximo passo: Da maneira que desenhamos o circuito, nunca vamos conseguir uma boa corrente para os Leds. Uma das solues utilizar o mesmo princpio dos transistores que utilizamos acima, para poder aumentar a corrente. J seria um excelente passo. Mas existe outra maneira, que a utilizao de um CI Driver de corrente, que vai fazer exatamente a mesma funo dos transistores, e a de um CI Source de corrente, que vai poder fornecer muito mais corrente do que os pinos do microcontrolador. A vantagem que no precisamos mudar nada em nosso programa!
Imagine que voc est usando uma matriz de Leds que suporte a corrente de 40 mA em cada Led. Se vamos acender todos os 8 Leds de uma linha, teremos um total de corrente de 320 mA , que ser fornecida pelo CI Source, e consumida pelo CI Driver.
Desta maneira vamos ter um excelente brilho!
Mas, temos de mais uma vez calcular o valor do resistor limitador de corrente do Led, s que agora temos de calcular em funo das tenses nas sadas dos dois Drivers. Olhando o datasheet, temos que para o ULN2803A a menor tenso VceSat de 0,9 volts, e para o UDN2981A de 1,6 Volts. Assim, se nosso Leds vermelho tiver tenso de conduo para 30 mA de 1,8 Volts, temos uma tenso total de 0,9 + 1,6 + 1,8 = 4,3 volts, e nosso resistor limitador ser de ( 5-4,3)/ 0,03 = 23,3 ohms, e usaremos o valor comercial de 27 ohms.
Apenas um detalhe: em um caso como este, o certo seria alimentar o UDN2981A com mais tenso, para garantir que no haja uma grande variao de brilho por causa da variao das tenses de VceSat dos dois CIs, que podem variar em torno de 0,2 Volts para cada um. Imagine que no pior caso vamos ter as seguintes tenses: 1,1 e 1,8 , mais 1,8 do Led, teremos um total de 4,7 Volts, que com R=27 Ohms vai dar uma corrente de 0,3/27 = 9 mA !!! Percebeu o problema? Menos de um tero da corrente !
Agora, imagine se alimentarmos o UDN2981A com 12 Volts, refazendo os clculos todos, ter um resistor de 12-4,3= 7,7/0,03 = 256 Ohms, e usaremos o valor imediatamente acima que de 270 Ohms.
Se tivermos a mesma variao de tenso VceSat, vamos ter uma corrente de (12- 4,7)/270 = 27 mA, que vai manter o brilho quase que inalterado.
Segue como ficaria o nosso circuito (mantendo 5V de alimentao) :
Agora, evoluindo novamente nosso circuito, imagine que vamos usar DUAS MATRIZES em vez de uma. Como fazer a ligao, se no temos mais uma porta com 8 bits livres ?
Aqui entra um velho amigo, o 74HCT595. Ele um Ci que integra um Shift-Register e um Latch de sada, permitindo que enviemos os dados para ele usando apenas 3 pinos de I/O, usando o formato serial ! E, o melhor de tudo, pode ligar vrios em cascata, um atrs do outro!
Usaremos novamente um nico CI UDN2981A, o qual vai fornecer corrente de sobra para todas as matrizes (afinal, apenas uma vai acender de cada vez), e iremos adicionar um ULN1803A em conjunto com um 74HCT595 para cada matriz adicional.
USANDO 74HCT595 PARA INTERLIGAR VRIAS MATRIZES
A seguir, veremos como utilizar este maravilhoso CI de baixo custo.
Reparem acima as tabelas de funcionamento. Inicialmente, no vamos utilizar o sinal /MR (Master Reset), ligando ele ao positivo. Temos agora apenas quatro sinais, que so o DS (Dado Serial), o STCP (Storage Clock Pulse), o SHCP (Shift Clock Pulse), e o /OE (Output Enable)
Qual a mecnica de funcionamento?
DS Dado serial a ser colocado dentro do shift register
/OE Levamos ao nvel 1 , que coloca a sada em tri-state, fazendo apagar o display.
SHCP Normalmente 0, quando ocorre uma transio para 1 ( subida ), faz com que o nvel presente em DS seja transferido sada 0 (interna) do shift register; o nvel que estava presente na sada 0 (interna) transferido para a sada 1 (interna) e assim sucessivamente at sair na sada 7 (interna) . Na verdade fizemos um deslocamento das 8 sadas do shift register, sendo que entramos com uma nova informao, que o nvel que estava em DS. Agora, fazemos a transio de 1 para 0 , o que prepara para um novo dado.
Basta colocar um novo nvel desejado em DS, e repetir o pulso de SHCP de 0 para 1 e voltar novamente para 0, e mais um dado ser armazenado.
Se repetirmos esse procedimento 8 vezes no total, teremos colocado todos os 8 dados desejados dentro do shift register.
Mas at o momento estas mudanas todas no aparecem nas sadas Q0-Q7 do CI, porque isso s acontece quando mandarmos armazenar os dados!
STCP Normalmente 0, quando vai para 1 permite que os nveis armazenados no shift register sejam transferidos para as sadas Q0-Q7. A seguir, voltamos o nvel para 0 e os dados que esto nas sadas vo se manter, independente do que fizermos nos sinais DS ou SHCP . A sada foi armazenada!
/OE Colocamos novamente em 0, o que habilita as sadas, fazendo acender a coluna.
Assim, nossa rotina far o seguinte: pega os 8 bits que sevem ser transferidos para a Matriz de Leds, e coloca serialmente , um a um, at todos os 8 estiverem transferidos, a selecionamos a linha ou coluna a ser acionada, e fazemos o armazenamento, fazendo com que a linha ou a coluna tenha os seus 8 Leds acesos conforme o nvel do sinal.
Simples, basta apenas fazermos isto tudo rapidamente.
A nossa nova rotina de Multiplex vai fazer o seguinte:
- Pega todos os 8 Leds a serem apresentados na primeira coluna, e coloca na sada de 8 bits do Microcontrolador. Esta sada est ligada diretamente a um UDN2981A que ir entregar uma corrente bem maior a cada Led.
- Habilita a passagem de corrente dessa primeira coluna (sada dos 74HCT595) que esto ligadas a um ULN2803A, que suporta a corrente de todos os Leds acesos.
- Quando houver outra interrupo, vai pegar os 8 Leds a serem apresentados na segunda coluna, e ir habilitar a segunda coluna para acender os 8 Leds. E assim sucessivamente, at terminar todas as colunas existentes (por exemplo, se forem 3 matrizes, teremos 24 colunas).
Qual vai ser a freqncia do Multiplex? Como temos de mostrar cada coluna pelo menos 30 vezes por segundo, nossa freqncia ser 30 vezes o nmero de colunas!
Se quisermos acender 3 matrizes, num total de 24 colunas, teremos de selecionar a freqncia de 720 Hertz.
Para encadearmos vrios 74HCT595, basta ligar a sada /Q7 do primeiro entrada DS do segundo. Os outros sinais so ligados em paralelo. Nesse caso, em vez de enviarmos apenas 8 bits seriais, enviamos tantos bits conformem forem as colunas. No caso de 3 matrizes , sempre enviaremos 24 bits antes de armazenar para ser mostrado.
Um truque legal que em vez de enviarmos sempre os 24 bits seriais, se utilizarmos os 74HCT595 para habilitar as colunas, basta sempre apenas fazer um pulso de clock do shift, e isto j far com que uma sada previamente habilitada se propague, e j poderemos armazenar novamente. Ganhamos bastante tempo com esse procedimento.
Voc vai entender isto melhor quando verificar o circuito.
No caso de um circuito com muitas matrizes, temos de lembrar de duas caractersticas do CI ULN2803A, que so o tempo mnimo para entrar em conduo (20 nano segundos), e o tempo mximo para sair de conduo (130 nano segundos) . Lembra-se da discusso sobre corte e saturao dos transistores, que est l em cima, quase no comeo? o mesmo efeito aqui, porm como este CI prprio para isto, os tempos envolvidos so bem menores. Mas dependendo da freqncia do Multiplex, estes tempos podem ter de ser levados em conta!
Bom, chega de teoria, vamos a um exemplo de um circuito que utiliza duas matrizes de Leds.
Um uso corriqueiro para este tipo de circuito so os painis eletrnicos de Leds, onde os textos ficam passando pelos displays, indo da direita para a esquerda. um efeito muito bonito, e que voc pode implementar tanto no programa principal como na rotina de Multiplex.
Mais para frente, veremos uma soluo bem melhor para isto, que o uso do MAX7219 para o controle de uma matriz completa. Assim, basta encadearmos vrios MAX7219 para fazermos displays enormes, com a facilidade de controle de brilho e uma programao muito mais simples, pois esses CIs j fazem o Multiplex interno para ns!
Para simplificar a simulao, este circuito no apresenta nem o UDN2981A que teria de estar ligado na sada do Port D do microcontrolador, nem os resistores que teriam de estar entre as sadas do UDN2981A e as matrizes, e nem os dois ULN2803A que deveriam estar presentes em cada um dos 74HCT595. Devido ao fato de a presena do ULN2803A faz a inverso da sada, teremos de modificar o programa quando ele for utilizado. Esta modificao ser tambm apresentada.
Da maneira mostrada no esquema, nossas duas matrizes equivalem a uma nica matriz, como o formato de 8 linhas por 16 colunas. Para representar esta coluna, usaremos 16 bytes, sendo que o primeiro byte contem os 8 Leds mais esquerda, respectivamente o LSB em cima e o MSB em baixo; da sucessivamente at o ltimo byte, que representa os 8 Leds mais direita.
Vamos dimensionar uma matriz de 16 bytes para isso, onde os bytes sero acessados desde coluna(1) at coluna(16).
A nossa rotina de Multiplex ser bem simples, ela ir a cada vez inibir a sada fazendo /OE = 1 , e ento pega os Leds que tem de acender na prxima coluna, coloca na sada do Port D, faz DS=0, gera um clock no shift para avanar para a prxima coluna a mostrar, armazena fazendo STCP=1, e ento faz novamente /OE=0 , o que ir acender a coluna desejada.
A cada vez ela seleciona a prxima coluna, tendo o cuidado de voltar ao incio quando estivermos na ltima posio.
Simples e efetivo, no ?
A seguir, o programa que ilustra essa tcnica, e que ir apresentar o mesmo X do programa anterior na primeira matriz, e o inverso do X na segunda matriz.
'---------------------------------------------------------------------- ' PROGRAMA MULTIPLEX MATRIX2 - Implementa o Multiplex Basico para ' fazer acender um X normal na primeira matriz e o inverso desse X na ' segunda matriz. Usamos agora o 74HCT595 para controlar as matrizes ' Usaremos uma Matriz de 16 bytes para armazenar os Leds das duas matrizes. ' ' Este programa utiliza o Timer0 de 8 bits para a base de tempo ' e implementa um refresh de 480 Hertz aproximado. '----------------------------------------------------------------------
Dim Disp_index As Byte Dim Disp_aux As Byte Dim Coluna(16) As Byte Dim Nada As Word Dim Flag As Bit
Config Portb = Output ' PortB vai acender as COLUNAS
Config Portd = Output 'PortD vai controlar os 74HCT595
Ds Alias Portb.0 Shcp Alias Portb.1 Stcp Alias Portb.2 Oe Alias Portb.3
' Vamos agora carregar nossos 16 bytes com o desenho ' do X e do inverso do X que esto na tabela TABLE_X For Disp_index = 0 To 15 Disp_aux = Lookup(disp_index , Table_x) Incr Disp_index Coluna(disp_index) = Disp_aux Decr Disp_index Next Disp_index
Config Timer0 = Timer , Prescale = 256 Timer0 = 191 ' vamos gerar uma interrupo a cada 2,08 milissegundo ' que corresponde a uma frequencia de Multiplex de 480 Hertz ' ou seja, cada coluna vai acender 30 vezes por segundo !
On Timer0 Timer0_sub Enable Timer0 Enable Interrupts
Nada = 65535 ' apenas um padro de 16 bits 1 , que vamos usar para no ' selecionar nenhuma coluna para iniciar o processo !
Oe = 1 'Faz as matrizes apagarem
Shiftout Ds , Shcp , Nada , 1 ' Envia os 16 bits 1 aos shift registers
Stcp = 1 NOP Stcp = 0 ' armazenou e colocou todos os 16bits 1 na saida dos latchs
Shcp = 0 Ds = 0 Disp_index = 0
Do Waitms 100
Loop
End
'------------- ROTINAS DE INTERRUPO ------------------------------------ Timer0_sub: ' Rotina chamada pelo Timer0 Timer0 = 191 'recarrega o timer novamente para
' apaga todos os dgitos Oe = 1
' vamos ver se j fizemos o ultimo digito, pois ento teremos de ' comear pelo primeiro novamente, carregandos 16 bits 1 ! If Disp_index > 16 Then Flag = 1 Shiftout Ds , Shcp , Nada , 1 Stcp = 1 NOP Stcp = 0 Disp_index = 0 Ds = 0 End If
' agora vamos carregar um nivel 1 para a prxima coluna a mostrar ' uso um truque aqui. Se eu acabei de inicializar tudo com os 16 bits 1, ' eu deixo DS=0 para que um nivel zero seja introduzido no shift ' register, assim vai fazer acender uma coluna. A seguir, fao DS=1 ' e todos os outros shifts vo apenas propagar uma s coluna com ' nivel 0. Shcp = 1 NOP Shcp = 0 Stcp = 1 NOP Stcp = 0 Ds = 1
Incr Disp_index ' aqui j apontamos para a coluna
' Se no zeramos os shifts, temos de ter um delay If Flag = 0 Then Waitus 30 Else Flag = 0 End If
' pegamos os Leds que queremos mostrar nesta coluna ' dentro da nossa matriz coluna() Portd = Coluna(disp_index)
' agora vamos acender uma s coluna! Oe = 0 ' Acendemos a coluna Return
' TABELA DE Leds A ACENDER
Table_x: ' primeiro o X normal Data &B10000010 , &B01000100 , &B00101000 , &B00010000 Data &B00101000 , &B01000100 , &B10000010 , &B00000000 ' agora segue o X invertido Data &B01111101 , &B10111011 , &B11010111 , &B11101111 Data &B11010111 , &B10111011 , &B01111101 , &B11111111
Tamanho do programa compilado de 810 bytes.
Seguem algumas telas ilustrando os sinais a cada instante para ver a montagem dos Leds.
As telas mostram respectivamente a primeira coluna, a segunda coluna, a dcima-quinta coluna, e por fim, o efeito que fica devido ao Multiplex, onde vemos todas as colunas acesas ao mesmo tempo.
Como prometi antes, segue o mesmo programa modificado para o caso de usar os drivers UDN e ULN para aumentar bastante o brilho de nossas matrizes.
'---------------------------------------------------------------------- ' PROGRAMA MULTIPLEX MATRIX3 - Implementa o Multiplex Basico para ' fazer acender um X normal na primeira matriz e o inverso desse X na ' segunda matriz. Usamos agora o 74HCT595 para controlar as matrizes ' Usaremos uma Matriz de 16 bytes para armazenar os Leds das duas matrizes. ' ' Este programa utiliza o Timer0 de 8 bits para a base de tempo ' e implementa um refresh de 480 Hertz aproximado. ' Verso modificada para o uso de drivers UDN e ULN '----------------------------------------------------------------------
Dim Disp_index As Byte Dim Disp_aux As Byte Dim Coluna(16) As Byte Dim Nada As Word Dim Flag As Bit
Config Portb = Output ' PortB vai acender as COLUNAS
Config Portd = Output 'PortD vai controlar os 74HCT595
Ds Alias Portb.0 Shcp Alias Portb.1 Stcp Alias Portb.2 Oe Alias Portb.3
' Vamos agora carregar nossos 16 bytes com o desenho ' do X e do inverso do X que esto na tabela TABLE_X For Disp_index = 0 To 15 Disp_aux = Lookup(disp_index , Table_x) Incr Disp_index Coluna(disp_index) = Disp_aux Decr Disp_index Next Disp_index
Config Timer0 = Timer , Prescale = 256 Timer0 = 191 ' vamos gerar uma interrupo a cada 2,08 milissegundo ' que corresponde a uma frequencia de Multiplex de 480 Hertz ' ou seja, cada coluna vai acender 30 vezes por segundo !
On Timer0 Timer0_sub Enable Timer0 Enable Interrupts
Nada = 0 ' apenas um padro de 16 bits 0 , que vamos usar para no ' selecionar nenhuma coluna para iniciar o processo !
Oe = 0
Shiftout Ds , Shcp , Nada , 1 ' Envia os 16 bits 0 aos shift registers
Stcp = 1 NOP Stcp = 0 ' armazenou e colocou todos os 16bits 1 na saida dos latchs
Shcp = 0 Ds = 1 Disp_index = 0
Do Waitms 100
Loop
End
'------------- ROTINAS DE INTERRUPO ------------------------------------ Timer0_sub: ' Rotina chamada pelo Timer0 Timer0 = 191 'recarrega o timer novamente
' apaga todos os dgitos Portd = 0
' vamos ver se j fizemos o ultimo digito, pois ento teremos de ' comear pelo primeiro novamente, carregandos 16 bits 1 ! If Disp_index > 16 Then Flag = 1 Shiftout Ds , Shcp , Nada , 1 Stcp = 1 NOP Stcp = 0 Disp_index = 0 Ds = 1 End If
' agora vamos carregar um nivel 1 para a prxima coluna a mostrar ' uso um truque aqui. Se eu acabei de inicializar tudo com os 16 bits 1, ' eu deixo DS=0 para que um nivel zero seja introduzido no shift ' register, assim vai fazer acender uma coluna. A seguir, fao DS=1 ' e todos os outros shifts vo apenas propagar uma s coluna com ' nivel 0. Shcp = 1 NOP Shcp = 0 Stcp = 1 NOP Stcp = 0 Ds = 0
Incr Disp_index ' aqui j apontamos para a coluna
' Se no zeramos os shifts, temos de ter um delay If Flag = 0 Then Waitus 30 Else Flag = 0 End If ' Acendemos a coluna
' pegamos os Leds que queremos mostrar nesta coluna ' dentro da nossa matriz coluna() Portd = Coluna(disp_index) Return
' TABELA DE Leds A ACENDER
Table_x: ' primeiro o X normal Data &B10000010 , &B01000100 , &B00101000 , &B00010000 Data &B00101000 , &B01000100 , &B10000010 , &B00000000 ' agora segue o X invertido Data &B01111101 , &B10111011 , &B11010111 , &B11101111 Data &B11010111 , &B10111011 , &B01111101 , &B11111111
Por ultimo, apresento uma restrio ao uso desta tcnica para uma grande quantidade de matrizes.
Neste ultimo programa feito para o uso de drivers ULN e UDN, dentro da rotina de interrupo, toda vez que vamos iniciar para fazer a primeira coluna, fazemos 16 shifts com o valor 0 para poder apresentar zero em todas as sadas dos 74hct595 .
Isto demora cerca de 40 micro segundos, e portanto bem rpido. Imagine se voc resolve usar 10 matrizes, ao invs de 2, mesmo adequando o programa, perderemos mais de 300 micro segundos s para zerar os 10 shifts. Isto j pode se tornar bastante demorado, pois se vamos utilizar 10 matrizes, nossa freqncia de Multiplex ser de 2400 hertz, com um tempo entre as interrupes de 416 micro segundos.
Repare que quase no temos folga de tempo para algum processamento adicional. Imagine se voc quiser utilizar 12 ou mais matrizes, este programa no vai funcionar mais.
Para se evitar isto, ao invs de controlarmos o pino do /OE, podemos ligar esse sinal diretamente ao terra, e controlar o pino /MR , onde com um simples pulso j fazemos o Reset de todos os 74hct595, que j vo apresentar nvel 0 em todas as sadas. Assim, melhoramos bastante o programa, e teremos sempre um tempo muito curto na rotina de interrupo.
Modificado desta forma, nossa rotina de interrupo sempre vai ser menor do que 40 micro segundos, e assim podemos utilizar at 40 matrizes ( na teoria ! ) . Relembro aqui que na prtica necessrio um pequeno delay para permitir que a matriz apague totalmente, e em meus testes precisei manter em cerca de 30 micro segundos. Este o motivo de utilizar este pequeno delay na rotina de interrupo. Se no fosse necessrio, nossa rotina no iria demorar nem 10 micro segundos !
Finalmente, vamos ver agora outra maneira de se trabalhar com muitas matrizes, que utilizando novamente o nosso velho MAX7219.
O uso deste CI simplesmente elimina todos os nossos problemas de tempos com a Multiplexao, elimina os drivers de corrente para aumentar o brilho, elimina o uso dos 74HCT595, e ainda permite controlar o brilho em at 16 nveis.
CONTROLANDO VRIAS MATRIZES COM O MAX7219
Voc j viu, acima, como que podemos usar at 8 displays de 7 segmentos com um nico MAX7219. Porm, nada impede que usemos esse mesmo CI para controlar uma matriz de Leds no formato 8X8, pois esse CI possui um modo chamado no-decode, e nesse modo ele faz correspondncia direta nas suas sadas conforme o valor binrio apresentado a ele. Por exemplo, se mandarmos apresentar o numero binrio 10101010, teremos na sada correspondente ao dgito os Leds acesos, de baixo para cima, exatamente correspondendo um Led aceso para um bit 1 .
Ento, podemos usar esse CI, e encadeando vrios deles, sendo que a entrada do segundo vai ligado sada do primeiro, e assim por diante. Qual o limite disto?
Teoricamente, o nico limite o tempo que demora para podermos entregar os dados para todos as 8 colunas de cada um dos displays.
Para voc ter uma idia, se usarmos 10 matrizes, temos de enviar serialmente 16 bits para cada coluna x 8 ( numero de dgitos por matriz ) x 10 ( numero de matrizes ) = 1280 bits . Se enviarmos um bit a cada 5 microsegundos, vamos demorar mais de 6 milisegundos para atualizar as matrizes.
Isto acaba causando um problema quando o nmero de matrizes grande. Se compararmos com o processo utilizando 74hct595, usaramos apenas 8 bits para cada coluna, totalizando 640 bits, e o tempo seria reduzido metade, pouco mais do que 3 milisegundos.
Vamos a seguir apresentar um esquema de ligao para o uso de duas matrizes, e irei apresentar um programa que permite o uso de 2 at 31 matrizes, sem nenhuma modificao, alm de indicar o nmero de matrizes que vamos usar !
Segue o esquema :
Repare que no esquema, usamos dois MAX7219, sendo que cada um controla uma matriz.
Os dados so enviados a partir do pino Portc.0 do microprocessador, e chega entrada Din do Max7219 mais direita. Dele, sai um sinal, atravs do pino Dout, que vai ligado entrada Din do Max7219 mais esquerda.
Primeiro, para armazenas os valores que queremos mostrar, criamos em nosso programa uma matriz chamada Dgitos(), cujo tamanho equivalente ao numero de colunas que queremos mostrar no total.
Com 2 matrizes, temos 2x8 = 16 colunas.
Assim, a nossa primeira coluna, que a que est mais esquerda, vai mostrar o valor armazenado na posio Dgitos(1) de nossa matriz. E a ultima coluna, que a que est mais direita, vai mostrar o numero armazenado na ultima posio, que a Dgitos(16).
curioso que para mostrar os valores corretamente, temos de entrar com os dados a partir do ltimo MAX7219, e no a partir do primeiro! Por qu ?
Os dados so enviados serialmente. Assim, enviamos 16 bits de dados, que fazem o endereamento da coluna correspondente e tambm j informam o valor a ser mostrado, e a seguir enviamos mais 16 bits serialmente, para o segundo display. Desta maneira, os 16 bits enviados primeiro vo acabar ficando dentro do MAX7219 esquerda, e os ltimos 16 bits ficam dentro do MAX7219 direita! A seguir, damos o comando de Armazenar.
Fazemos isso para todas as 8 colunas dos dois Max7219.
O programa para isso muito simples, escrito tambm com o Bascom. E o melhor que voc pode adequar o mesmo programa para mostrar at 31 matrizes! Segue o mesmo :
'---------------------------------------------------------------------- ' PROGRAMA Matrix4 - Usando matrizes com os MAX7219 ' ' Permite o uso de 2 at 31 matrizes de 8x8 , criando uma unica no formato ' de 248 x 8. ' Os valores a serem mostrados esto armazenados em uma matrix de tamanho ' 8 vezes o numero de matrizes, no nosso caso de tamanho 16. ' um programa que serve de ponto de partida para um display mostrador ' de mensagens de texto. '----------------------------------------------------------------------
$crystal = 8000000 'vamos usar o clock interno que de 8 Mhz. $regfile = "m328Pdef.dat" ' vamos compilar para o ATMEGA328P $hwstack = 40 $swstack = 32 $framesize = 350
' a seguir, onde especificamos a quantidade de matrizes, basta mudar ' para quantas voce quiser ! Const N = 2 ' N= numero de matrizes ( limitado entre 2 e 31 )
Const N1 =(n) * 8 Const N2 =(n) - 1
Dim X As Byte Dim Y As Byte Dim Z As Byte Dim Base As Byte Dim Numero As Word Dim I As Byte Dim Digitos(n1) As Byte
' Esta matriz Digitos() vai conter todos os valores a serem mostrados ' desde a primeira coluna ( digitos(1) ) at a ultima coluna ' ( digitos(8Xnumero de matrizes) )
Max_data Alias Portc.0 Max_load Alias Portc.1 Max_clock Alias Portc.2
' vamos colocar alguns valores na matriz For I = 1 To N1 Digitos(i) = I Next I
Enable Interrupts
'vamos agora inicializar os MAX7219
Numero = Reg_shutdown_off Gosub Init_max
Numero = Reg_decode_mode Gosub Init_max
Numero = Reg_intensity Gosub Init_max
Numero = Reg_scan_limit Gosub Init_max 'j tudo configurado !
'a seguir, loop do programa principal ' dentro do trecho do DO...LOOP pode ser colocado todo o programa ' que poderia tratar as mensagens e apresentar no display ' para fazer um display de mensagens rolantes. ' o programa deveria pegar as letras, e procurar os bytes correspondentes ' em uma tabela, e guardar na matriz toda a mensagem. A seguir, bastaria ' apenas ficar "rodando a matriz", isto , pegar o primeiro elemento e guardar ' ele em uma varivel, e em seguida pegar o segundo elemento e armazenar no ' lugar do primeiro, e assim em diante, sendo que finalmente o elemento ' que guardamos logo no incio ser armazenado no ultimo elemento, e podemos ' atualizar o display. Do Waitms 1000 Gosub Sai_max 'atualiza matrizes Loop
'---- sub-rotina para atualizar matrizes ----------------- Sai_max: For Y = 1 To 8 For X = 0 To N2 Base = X Shift Base , Left , 3 Numero = Y Shift Numero , Left , 8 Z = Base + Y Numero = Numero + Digitos(z) Shiftout Max_data , Max_clock , Numero , 1 Next X Max_load = 1 Max_load = 0 Next Y Return
'---- sub-rotina para enviar comandos aos Max7291 Init_max: For X = 1 To N Shiftout Max_data , Max_clock , Numero , 1 Next X Max_load = 1 Max_load = 0 Return
End
Este programa compilado tem o tamanho de 746 Bytes.
A seguir, o que voc veria nessas matrizes :
Repare que o programa prenche a matriz com os nmeros 1,2,3 e sucessivamente at 16 , e voc est vendo a sada, mostrando de 1 at 16 da esquerda para a direita, com os Leds correspondentes aos bits 1 acesos.
um excelente ponto de partida para voc fazer um display mostrador de Leds com mensagens de texto que ficam andando da direita para a esquerda!
Basta voc armazenar a mensagem, por exemplo, na Eeprom do microcontrolador ou numa Eeprom externa, e no incio do programa voc pegaria cada letra da mensagem, consulta uma tabela que mostra como seriam cada uma das colunas que fazem esse caracter, e armazenar todas as coluna na matriz.
A partir da, s ficar fazendo uma rotao da matriz, da direita para a esquerda, na velocidade que voc desejar, isto , o elemento Dgitos(n) toma o valor do elemento Dgitos(n+1) , para toda a matriz. Se quiser fazer com que o elemento mais esquerda volte ao final da matriz, voc vai ter sua mensagem circulando todo o tempo.
Quanto a tempos de execuo, eu fiz uma simulao para 31 matrizes, e demora cerca de 18,5 milisegundos para fazer toda a atualizao do display. Se quiser, pode usar um cristal oscilador externo, de 20 MHz, e nesse caso o tempo cairia para 7,4 milisegundos.
Creio que ao chegar at aqui voc j sabe tudo o que precisa saber para trabalhar com qualquer tipo de display de Leds.