Recordando, no LEDcube nos controlamos os LEDs um plano por vez. No código anterior (e na biblioteca padrão) cada plano fica aceso por 1 ms e apagado por 2 (enquanto os outros planos são apresentados). A nossa visão faz a média e temos a impressão que os três planos estão acesos simultaneamente.
O controle dos LEDs é apenas aceso ou apagado, mas podemos simular um controle de intensidade, variando o tempo que ele permanece aceso. Vou implementar aqui algo bem simples, controlando junto a intensidade de todos os LEDs de um plano. Com mais trabalho seria possível controlar a intensidade de cada LED.
No código anterior cada plano ficava aceso 1ms em cada 3. Para reduzir o brilho, vou deixar de acender o plano em algumas ocasiões. Por exemplo, indicando por 1, 2 e 3 os planos e por - o display apagado, imagine a seguinte sequência:
1 2 3 1 - - 1 2 - 1 - -
Nestes 12 segundos o plano 1 ficou aceso por 4 ms (que era o que fazíamos no código anterior), o plano 2 ficou aceso por 2 ms e o plano 3 por apenas 1 ms. Repetindo isto várias vezes, a nossa vista vai considerar que os LEDs do plano estão mais intensos que os do plano 2, por sua vez mais intensos que os do plano 3.
Para implementar isto, codifiquei a intensidade dos planos em 2 bits na minha tabela de animação (11 sendo a intensidade mínima e 00 a máxima):
uint16_t const frameTab[][3] PROGMEM = { { 0b00000000000, 0b11000010000, 0b00000000000 }, { 0b00000000000, 0b10000010000, 0b00000000000 }, { 0b00000000000, 0b01000010000, 0b00000000000 }, { 0b00000000000, 0b00000010000, 0b00000000000 }, { 0b00000000000, 0b01000010000, 0b00000000000 }, { 0b00000000000, 0b10000010000, 0b00000000000 }, { 0b00000000000, 0b11000010000, 0b00000000000 }, { 0b11101000101, 0b11101000101, 0b11101000101 }, { 0b10101000101, 0b10101000101, 0b10101000101 }, { 0b01101000101, 0b01101000101, 0b01101000101 }, { 0b00101000101, 0b00101000101, 0b00101000101 }, { 0b01101000101, 0b01101000101, 0b01101000101 }, { 0b10101000101, 0b10101000101, 0b10101000101 }, { 0b11101000101, 0b11101000101, 0b11101000101 }, };A rotina de interrupção do timer passa a testar estes bits adicionais, deixando os LEDs apagados conforme estes bits e o número da repetição:
// Rotina de interrupção do timer1 // Executada a cada milisegundo ISR(TIMER1_OVF_vect) { static int iRep = 0; // repetições do frame static int iPlane = 0; // plano atual no frame static int iFrame = 0; // frame atual uint16_t plane; uint8_t dbits, cbits; boolean bShow; // Pega na Flash o padrão do plano corrente do frame atual plane = pgm_read_word (&frameTab[iFrame][iPlane]); // Verifica se mostra o plano 0 1 2 3 // 00xxxxxxxxx mostra sempre (brilho máximo) x x x x // 01xxxxxxxxx não mostra 1 vez em 4 x x x - // 10xxxxxxxxx não mostra metade das vezes x - x - // 11xxxxxxxxx não mostra 3 vezes em 4 x - - - bShow = true; if (((iRep & 3) == 1) && ((plane & 0b10000000000) != 0)) { bShow = false; } else if (((iRep & 3) == 2) && ((plane & 0b11000000000) == 0b11000000000)) { bShow = false; } if (((iRep & 3) == 3) && ((plane & 0b11000000000) != 0)) { bShow = false; } if (bShow) { // // pixels 0,1,2 go to IO pins D7,D6,D5 // also, add in 3 bits to turn off all the planes (PP1-PP3) by pulling them high // dbits = ((plane & 0x001) << 7) | ((plane & 0x002) << 5) | ((plane & 0x004) << 3) | (0x7 << 2); PORTD = dbits; // // pixels 3-8 go to IO pins C5-C0 // cbits = ((plane & 0x008) << 2) | ((plane & 0x010)) | ((plane & 0x020) >> 2) | ((plane & 0x040) >> 4) | ((plane & 0x080) >> 6) | ((plane & 0x100) >> 8); PORTC = cbits; // Seleciona o plano if (iPlane == 0) { PORTD &= ~0x10; } else if (iPlane == 1) { PORTD &= ~0x08; } else if (iPlane == 2) { PORTD &= ~0x04; } } else { PORTD = 0x7 << 2; } // Vai para o próximo plano if (++iPlane == 3) { // Repete o frame iPlane = 0; if (++iRep == (TIME_FRAME/3)) { // Próximo frame iRep = 0; if (++iFrame == NUM_FRAMES) { // De volta ao primeiro frame iFrame = 0; } } } }O vídeo abaixo mostra o resultado:
Nenhum comentário:
Postar um comentário