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