O display possui 8 dígitos de 7 segmentos (mais o ponto), 8 LEDs bi-colores e 8 botões. O que precisamos descobrir é como estes componentes estão ligados ao TM1638.
O display possui 2 conectores de 10 pinos, na própria placa estão indicados os sinais presentes. Além da alimentação, CLK e DIO, o conector da esquerda (para quem vê a placa de frente) possui 6 sinais de strobe (STB0 a STB5). O sinal STB0 é o sinal de strobe do TM1638 que está na placa. O conector da direita possui somente 5 sinais de strobe (STB1 a STB5) que são os sinais da entrada deslocados de uma posição do conector. Isto permite ligar em cadeia até 6 placas usando cabos do tipo 1:1 (isto é, que ligam o pino 1 ao pino 1, o 2 ao 2, etc).
Nos meus testes, eu liguei a alimentação do display aos pinos Gnd e +5 do Arduino e os sinais STB0, DIO e CLK aos sinais digitais 7, 8 e 9 (respectivamente). Você pode, é claro, ligar os sinais a outros sinais digitais, usei estes apenas porque são os usados nos exemplos da biblioteca TM-1638. Aliás, é desta biblioteca (de autoria do português Ricardo Batista), que extraí as rotinas básicas de comunicação com o TM-1638. Para simplificar o meu teste, converti a classe em rotinas e variáveis; aproveitei para colocar alguns comentários adicionais:
// Pinos usados na conexão do display
byte TM16XX_dataPin; // DIO
byte TM16XX_clockPin; // CLK
byte TM16XX_strobePin; // STB
// Códigos dos comandos do TM1638
#define TM1638_CMD_WRDISPA 0x40 // Escrita no display, auto incremento
#define TM1638_CMD_WRDISPF 0x44 // Escrita no display, endereço fixo
#define TM1638_CMD_RDKEYS 0x42 // Leitura das teclas
#define TM1638_CMD_SETADDR 0xC0 // Programa endereço
#define TM1638_CMD_DISPON 0x88 // Liga display e ajusta intensidade
// Iniciação
void TM16XX_setup(byte dataPin, byte clockPin, byte strobePin)
{
// salva a configuração
TM16XX_dataPin = dataPin;
TM16XX_clockPin = clockPin;
TM16XX_strobePin = strobePin;
// Configura os pinos
pinMode(TM16XX_dataPin, OUTPUT);
pinMode(TM16XX_clockPin, OUTPUT);
pinMode(TM16XX_strobePin, OUTPUT);
digitalWrite(TM16XX_strobePin, HIGH);
digitalWrite(TM16XX_clockPin, HIGH);
// Faz a configuração inicial
TM16XX_sendCommand(TM1638_CMD_WRDISPA);
TM16XX_sendCommand(TM1638_CMD_DISPON | 7);
// Limpa a memória
// Posiciona no endereço 0 e usa auto-incremento
digitalWrite(TM16XX_strobePin, LOW);
TM16XX_send(TM1638_CMD_SETADDR | 0);
for (int i = 0; i < 16; i++)
TM16XX_send(0x00);
digitalWrite(TM16XX_strobePin, HIGH);
}
// Lê as teclas
void TM16XX_readButtons(byte *keys)
{
digitalWrite(TM16XX_strobePin, LOW);
TM16XX_send(TM1638_CMD_RDKEYS);
for (int i = 0; i < 4; i++) {
*keys++ = TM16XX_receive();
}
digitalWrite(TM16XX_strobePin, HIGH);
}
// Escreve um dado em um endereço da memória
void TM16XX_sendData(byte address, byte data)
{
TM16XX_sendCommand(TM1638_CMD_WRDISPF);
digitalWrite(TM16XX_strobePin, LOW);
TM16XX_send(TM1638_CMD_SETADDR | address);
TM16XX_send(data);
digitalWrite(TM16XX_strobePin, HIGH);
}
// Envia um comando
void TM16XX_sendCommand(byte cmd)
{
digitalWrite(TM16XX_strobePin, LOW);
TM16XX_send(cmd);
digitalWrite(TM16XX_strobePin, HIGH);
}
// Envia um byte
void TM16XX_send(byte data)
{
for (int i = 0; i < 8; i++) {
digitalWrite(TM16XX_clockPin, LOW);
digitalWrite(TM16XX_dataPin, data & 1 ? HIGH : LOW);
data >>= 1;
digitalWrite(TM16XX_clockPin, HIGH);
}
}
// Recebe um byte
byte TM16XX_receive()
{
byte temp = 0;
// Vira DIO para dentro e liga o pull-up
pinMode(TM16XX_dataPin, INPUT);
digitalWrite(TM16XX_dataPin, HIGH);
// Le os bits
for (int i = 0; i < 8; i++)
{
temp >>= 1;
digitalWrite(TM16XX_clockPin, LOW);
if (digitalRead(TM16XX_dataPin))
temp |= 0x80;
digitalWrite(TM16XX_clockPin, HIGH);
}
// Volta DIO para saida
pinMode(TM16XX_dataPin, OUTPUT);
digitalWrite(TM16XX_dataPin, LOW);
return temp;
}
Estas rotinas implementam a comunicação serial com o TM1638. Embora alguns se refiram a esta comunicação como sendo SPI, ela não segue este padrão (que utiliza sinais separados para entrada e saída de dados, fazendo a comunicação simultânea nos dois sentidos). É uma comunicação a três fios, semelhante à usada no relógio/calendário DS1302. O mestre (o Arduino) fornece sempre o sinal CLK, que comanda a transferência de um bit. O sinal strobe sinaliza o início e fim das transferências de dados e comandos.O programa principal recebe pela serial comandos para escrever na memória, alterar a intensidade e ler as chaves:
// Variáveis para tratamento dos comandos na serial
byte cmd[10];
int iCmd = 0;
// Tabela para mostrar valores em hexadecimal
char hexa[] = "0123456789ABCDEF";
// Iniciacao do Arduino
void setup ()
{
Serial.begin (9600);
TM16XX_setup (8, 9, 7);
}
// Execução
void loop ()
{
if (Serial.available())
{
// Monta o comando
int car = Serial.read();
if (car == ';')
{
// Completou um comando
cmd [iCmd] = 0;
trataCmd();
iCmd = 0;
}
else if (iCmd < (sizeof(cmd)-2))
{
if ((car >= 'a') && (car <= 'z'))
car -= 0x20; // converte para maiúscula
cmd [iCmd++] = car;
}
}
}
// Trata comando
// R -> lê chaves
// Wadd -> escreve dd no endereço a (dado e endereços em hexa)
// In -> intensidade (n de 0 a 7)
void trataCmd (void)
{
if (cmd[0] == 'R')
{
byte chaves[4];
TM16XX_readButtons (chaves);
Serial.print ("Chaves = 0x");
for (int i = 0; i < 4; i++)
{
Serial.print(hexa[chaves[i] >> 4]);
Serial.print(hexa[chaves[i] & 0xF]);
}
Serial.println();
}
else if ((cmd[0] == 'I') && (iCmd == 2))
{
TM16XX_sendCommand(TM1638_CMD_DISPON + (cmd[1] & 0x7));
}
else if ((cmd[0] == 'W') && (iCmd == 4))
{
byte ender, dado;
ender = htoi (cmd[1]);
dado = (htoi (cmd[2]) << 4) + htoi (cmd[3]);
TM16XX_sendData (ender, dado);
Serial.print ("Mem[");
Serial.print (ender, HEX);
Serial.print ("] = 0x");
Serial.print (dado, HEX);
Serial.println ();
}
else
Serial.println ("ERRO");
}
// Decodifica um dígito hexadecimal
int htoi (char car)
{
if ((car >= '0') && (car <= '9'))
return car - '0';
if ((car >= 'A') && (car <= 'F'))
return car - 'A' + 10;
return 0;
}
Usando este programa (que está nos arquivos do blog em Explora_LKM1638.zip) fica fácil descobrir o mapeamento dos LEDs e chaves nos displays:- Os segmentos dos dígitos são controlados pelas posições pares das memória. Partindo da esquerda para a direita do display, as posições correspondentes são 0, 2, 4, ... 14.
- Em cada posição par, o bit mais significativo (7) corresponde ao ponto decimal. Os bits 0 a 6 correspondem aos segmentos 'a' a 'g' (ver figura abaixo).
- As posições ímpares da memória controlam os LEDs bicolores. Partindo da esquerda para a direita, os LEDs são controlados pelas posições 1, 3, 5, ... 15.
- Lembrando, no TM1638 apenas os dois bits menos significativos estão disponíveis nas posições ímpares. O bit 0 acende o LED na cor vermelha vermelho e o bit 1 na cor verde. Se você ativar simultaneamente os dois bits o LED acenderá nas duas cores resultando em um laranja (muito parecido com o vermelho para o meu gosto).
- As primeiras quatro chaves correspondem ao bit menos significativos (bit 0) dos quatro bytes de leitura das chaves. As quatro últimas chaves correspondem ao bit 3 dos mesmos byte.



2 comentários:
Seria possivel implementar um relógio com um display desses?
Sou novo na area do arduino e gostaria de fazer um relógio com meu display. Voce não teria o codigo para essa finalidade?
Obrigado
Não é difícil implementar um relógio, mas eu prefiro usar o JY-MEGA3208 que já tem embutido o microcontrolador. Uma limitação dos dois é que não tem um relógio de tempo real propriamente dito, o ideal seria ter um com uma bateria para manter a data e hora, como fiz em outro projeto.
Postar um comentário