O primeiro passo é examinar o circuito e determinar onde estão conectados o controlador e as chaves. Para facilitar, gerei um arquivo .h com esta informação:
#ifndef _JYMCU3208_H #define _JYMCU3208_H // Clock da CPU (clock internio de 8MHz dividido por 8) #define CLK_CPU 1000000 // 1.0 MHz // Conexões do controlador HT1632C // Três sinais: CS, RD, WR e DT(DATA) #define HT_CS_DDR DDRB #define HT_WR_DDR DDRB #define HT_DT_DDR DDRB #define HT_CS_PORT PORTB #define HT_WR_PORT PORTB #define HT_DT_PORT PORTB #define HT_CS_BIT _BV(PB3) #define HT_WR_BIT _BV(PB4) #define HT_DT_BIT _BV(PB5) // Conexão das Teclas #define TEC_DDR DDRD #define TEC_PIN PIND #define TEC_KEY1 _BV(PD7) #define TEC_KEY2 _BV(PD6) #define TEC_KEY3 _BV(PD5) #endifA documentação do controlador do display, informa como enviar comandos e escrever na memória. Basicamente:
- Em repouso os sinais CS e WR devem estar em nível 1
- O sinal CS é colocado em zero para sinalizar o início da comunicação
- Para cada bit enviado do microcontrolador para o controlador
- O sinal WR é colocado em zero
- O valor do bit é colocado no sinal DATA
- O sinal WR é retornado ao nível 1
- Ao final dos bits o sinal CS é retornado ao nível 1
Cada comando é composto por 9 bits: os primeiros 8 determinam o comando e o final é irrelevante. Logo após ligar o display é necessário enviar alguns comandos de configuração.
Na escrita na memória deve ser enviado o endereço inicial (7 bits) e os valores a escrever (cada posição da memória armazena 4 bits de dados).
O módulo abaixo implementa as operações básicas. Uma vez que não é possível ler a memória do controlador, ela é duplicada na memória do microcontrolador. Neste primeiro teste a escrita será feita sobre esta memória "shadow" que depois é copiada no controlador.
#include <stdio.h> #include <stdlib.h> #include <inttypes.h> #include <avr/io.h> #include "jymcu3208.h" #include "ht1632c.h" // Comandos do controlador HT1632C // Os comandos possuem 8 bits e devem ser precedidos pelos 3 bits de ID e seguidos de // um bit adicional (0 ou 1, tanto faz) #define HT_ID_CMD 0b100 #define HT_STARTSYS 0b00000001 // start system oscillator #define HT_STOPSYS 0b00000000 // stop sytem oscillator and LED duty #define HT_SETCLOCK 0b00011000 // set clock to master with internal RC #define HT_SETLAYOUT 0b00100000 // N-MOS open-drain output and 32 ROW * 8 COM #define HT_LEDON 0b00000011 // start LEDs #define HT_LEDOFF 0b00000010 // stop LEDs #define HT_SETBRIGHT 0b10100000 // set brightness 0b1010xxxx xxxx = brightness #define HT_BLINKON 0b00001001 // blinking on #define HT_BLINKOFF 0b00001000 // blinking off // Escrita de dado no controlador HT1632C // Enviar 3 bits de ID, 7 bits do endereço inicial e os 4 bits de dados // 101-aaaaaaa-dddd-dddd-dddd-dddd-dddd-... #define HT_ID_WRITE 0b101 // Copia da Ram do controlador // Usa apenas os 4 bits menos significativos de cada byte // volatile uint8_t ht1632c_shadowram [(HT_COLS*HT_ROWS)/4]; // Comandos de iniciacao do controlador static uint8_t cmd_init[] = { HT_STOPSYS, HT_SETLAYOUT, HT_SETCLOCK, HT_STARTSYS, HT_LEDON, HT_SETBRIGHT | 3, HT_BLINKOFF }; // Rotinas internas static void ht1632c_send_commands (uint8_t *pCmds, int8_t nCmds); static void ht1632c_send_command (uint8_t cmd); static void ht1632c_send (uint8_t valor, int8_t nBits); // Inicia o controlador void ht1632c_init () { // Inicia as direçoes dos pinos de conexão HT_CS_DDR |= HT_CS_BIT; HT_WR_DDR |= HT_WR_BIT; HT_DT_DDR |= HT_DT_BIT; // Default para o CS e WR é alto (inativo) HT_CS_PORT |= HT_CS_BIT; HT_WR_PORT |= HT_WR_BIT; HT_DT_PORT |= HT_DT_BIT; // Efetua a configuração ht1632c_send_commands (cmd_init, sizeof(cmd_init)); } // Atualiza a memoria do controlador com o conteudo // da shadow mempory void ht1632c_send_screen () { uint8_t addr; HT_CS_PORT &= ~HT_CS_BIT; // seleciona o controlador ht1632c_send (HT_ID_WRITE, 3); ht1632c_send (0, 7); // endereço inicial for(addr = 0; addr < (HT_COLS*HT_ROWS)/4; addr++) { ht1632c_send (ht1632c_shadowram[addr], 4); } HT_CS_PORT |= HT_CS_BIT; // libera o controlador } // Envia uma série de comandos ao controlador static void ht1632c_send_commands (uint8_t *pCmds, int8_t nCmds) { int8_t i; HT_CS_PORT &= ~HT_CS_BIT; // seleciona o controlador ht1632c_send (HT_ID_CMD, 3); // envia ID de comando for (i = 0; i < nCmds; i++) { ht1632c_send (pCmds[i], 8); ht1632c_send (0, 1); } HT_CS_PORT |= HT_CS_BIT; // libera o controlador } // Envia um comando ao controlador static void ht1632c_send_command (uint8_t cmd) { HT_CS_PORT &= ~HT_CS_BIT; // seleciona o controlador ht1632c_send (HT_ID_CMD, 3); // envia ID de comando ht1632c_send (cmd, 8); ht1632c_send (0, 1); HT_CS_PORT |= HT_CS_BIT; // libera o controlador } // Envia uma sequencia de bits ao controlador static void ht1632c_send (uint8_t valor, int8_t nBits) { int8_t i; uint8_t mask = 1 << (nBits-1); // enviar mais significativo primeiro for (i = nBits; i > 0; i--) { HT_WR_PORT &= ~HT_WR_BIT; if (valor & mask) HT_DT_PORT |= HT_DT_BIT; else HT_DT_PORT &= ~HT_DT_BIT; HT_WR_PORT |= HT_WR_BIT; mask = mask >> 1; } }Para finalizar, vamos fazer um programa simples de teste, que vai acendendo os LEDs um a um, seguindo a ordem dos bits na memória. Aproveitamos que o display possui um cristal de 32KHz para implementar uma rotina de delay,
#include <stdio.h> #include <stdlib.h> #include <inttypes.h> #include <avr/io.h> #include <avr/interrupt.h> #include "jymcu3208.h" #include "ht1632c.h" // Variaveis static volatile uint8_t cnt_delay; // Rotinas static void delay_seg (uint8_t seg); static void tempo_init (void); // Programa principal int main(void) { uint8_t addr, bit; ht1632c_init(); // inicia o controlador do display ht1632c_send_screen (); // limpa o display tempo_init(); // inicia a contagem de tempo // Acende um LED a cada segundo for (addr = 0; addr < (HT_COLS*HT_ROWS)/4; addr++) { for (bit = 0x01; bit < 0x10; bit = bit << 1) { ht1632c_shadowram [addr] |= bit; ht1632c_send_screen (); delay_seg (1); } } // nada mais a fazer for (;;) ; } // Aguarda um certo número de segundos (1 a 64) static void delay_seg (uint8_t seg) { cnt_delay = seg << 2; while (cnt_delay) ; } // Inicia a contagem de tempo static void tempo_init (void) { ASSR |= (1<<AS2); // timer2 async from external quartz TCCR2 = 0b00000011; // normal,off,/32; 32768Hz/256/32 = 4 Hz TIMSK |= (1<<TOIE2); // enable timer2 overflow int sei(); // enable interrupts } // Interrupção do Timer2 ISR(TIMER2_OVF_vect) { if (cnt_delay) cnt_delay--; }No próximo post veremos como compilar este código e gravar na Flash do ATmega8. Veremos também o resultado, o que nos revela o mapeamento dos LEDs.
3 comentários:
Hola
Encontré este código que parece ser el original del JY-MCU 3608
https://code.google.com/p/buxiaoyang-project/source/browse/trunk/AVR/?r=23#AVR%2FLED3208V1
Logré cargarlo pero veo sólo caracteres chinos :-(
¿Me darían una mano tratando de adaptarlo para usar caracteres occidentales?
Saludos !
Não parece ser o software original, pois pega a data e hora de um DS1302 que não vem montado no display. Pretendo fazer um firmware de relógio para o display, mas ainda deve demorar algumas semanas.
Postar um comentário