A troca do microcontrolador afeta pouco o hardware, são os mesmos componentes ligados em pinos diferentes. Para simplificar a mexida do software, usei PB0 e PB1 para a geração de vídeo (no ATtiny44 usei PA0 e PA1, portanto os bits são os mesmos, só mudam os endereços das portas):
Para rodar o software do post anterior no ATmega328 basta:
- Alterar no Makefile o modelo do processador e o valor dos fuses.
- Trocar PORTA por PORTB e DDRA por DDRB. No código assembler, trocar OUT 0x1B,R30 por OUT 0x05,R30.
- Trocar TIM1_COMPA_vect por TIMER1_COMPA_vect (isto me custou um bom tempo, pois com TIM1_COMPA_vect compila sem erros mas não funciona).
Cada linha passa a ser mapeada em 12 bytes, o que é acertado na macro byteblast. O delay antes desta macro, na rotina de interrupção do timer, precisa ser aumentado para compensar os 24 pontos iniciais que não serão enviados (outra alternativa seria alterar byteblast para enviar bytes fixos). Na vertical, basta alterar as definições de primeiralinha e ultimalinha. Por último, pontLinha deve apontar para o byte correto. O código da rotina de interrupção fica assim:
ISR (TIMER1_COMPA_vect) { static uint8_t syncON = VID_0V; static uint8_t syncOFF = VID_03V; // Gera o pulso de sync VID_PORT = syncON; linhaAtual++; if (linhaAtual == iniSyncV) { // Sync vertical é invertido syncON = VID_03V; syncOFF = VID_0V; } if (linhaAtual == fimSyncV) { // Voltar ao sync normal syncON = VID_0V; syncOFF = VID_03V; } if (linhaAtual == fimFrame) { // Fim do frame linhaAtual = 1; pontLinha = tela; } _delay_us(2); // Aguarda fim do tempo do pulso VID_PORT = syncOFF; // Gerar a imagem if ((linhaAtual <= ultLinha) && (linhaAtual >= primLinha)) { _delay_us(18); // tempo para centrar a linha byteblast(); pontLinha += nBytesLinha; } }Com isto a tela passa a apresentar o que estiver no vetor tela. As rotinas abaixo permitem acessar um ponto:
uint8_t lePto (uint8_t x, uint8_t y) { return tela[y*nBytesLinha + (x >> 3)] & (0x80 >> (x & 7)); } void acendePto (uint8_t x, uint8_t y) { tela[y*nBytesLinha + (x >> 3)] |= (0x80 >> (x & 7)); } void apagaPto (uint8_t x, uint8_t y) { tela[y*nBytesLinha + (x >> 3)] &= ~(0x80 >> (x & 7)); }Com esta infraestrutura, podemos montar uma pequena demo: o logotipo do Garoa Hacker Clube (um guarda chuva) com chuva caindo sobre ele. O logotipo é copiado da Flash para Ram no início da execução. A chuva é composta de 48 pingos em colunas alternadas. Um vetor de 48 bytes contém a linha atual de cada pingo. Este vetor é iniciado de forma pseudo-aleatória:
for (i = 0; i < NCHUVA; i++) { chuva[i] = rand() & 0x1F; }A cada retraço seis pingos são atualizados:
- O pingo é apagado na posição atual
- A linha é incrementada
- Se a nova posição estiver ocupada ou fora da tela, voltar o pingo para a primeira linha
- Se a nova posição estiver livre, desenhar o pingo nela
for (j = 0; j < 6; j++) { apagaPto ((i << 1)+1, chuva[i]); chuva[i]++; if ((chuva[i] == nLinhas) || lePto ((i << 1)+1, chuva[i])) { chuva[i] = 0 } acendePto ((i << 1)+1, chuva[i]); if (++i == NCHUVA) i = 0; }O vídeo abaixo mostra o programa em funcionamento.
O projeto completo pode ser baixado dos arquivos do blog (aquivo vidbpchuva.zip)
Nenhum comentário:
Postar um comentário