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