Cada frame é definido por três palavras de 16 bits, cada uma controlando os 9 LEDs de um plano:
- // Esta tabela define a animação
- // Cade frame determina o estado dos LEDs nos três planos
- uint16_t const frameTab[][3] PROGMEM =
- {
- { 0b100000000, 0b000000000, 0b000000000 },
- { 0b010000000, 0b000000000, 0b000000000 },
- { 0b001000000, 0b000000000, 0b000000000 },
- { 0b000100000, 0b000000000, 0b000000000 },
- { 0b000010000, 0b000000000, 0b000000000 },
- { 0b000001000, 0b000000000, 0b000000000 },
- { 0b000000100, 0b000000000, 0b000000000 },
- { 0b000000010, 0b000000000, 0b000000000 },
- { 0b000000001, 0b000000000, 0b000000000 },
- { 0b000000000, 0b000000000, 0b000000000 },
- { 0b111111111, 0b000000000, 0b000000000 },
- { 0b000000000, 0b111111111, 0b000000000 },
- { 0b000000000, 0b000000000, 0b111111111 },
- { 0b000000000, 0b000000000, 0b000000000 },
- { 0b111000000, 0b111000000, 0b111000000 },
- { 0b000111000, 0b000111000, 0b000111000 },
- { 0b000000111, 0b000000111, 0b000000111 },
- { 0b000000000, 0b000000000, 0b000000000 },
- { 0b100100100, 0b100100100, 0b100100100 },
- { 0b010010010, 0b010010010, 0b010010010 },
- { 0b001001001, 0b001001001, 0b001001001 },
- { 0b000000000, 0b000000000, 0b000000000 }
- };
- #define NUM_FRAMES (sizeof(frameTab)/sizeof(frameTab[0]))
- // Rotinas locais
- static void portInit(void);
- static void startTimer1(void);
- // Iniciação do sketch
- void setup ()
- {
- portInit();
- startTimer1();
- };
- // Laço principal do sketch
- void loop ()
- {
- // Nada a fazer - toda a ação ocorre na interrupção
- };
- /*
- * Copyright (c) 2011 - Rolf van Widenfelt, Mitch Altman. Some rights reserved.
- *
- * Note: This source code is licensed under a Creative Commons License, CC-by-nc-sa.
- * (attribution, non-commercial, share-alike)
- * see http://creativecommons.org/licenses/by-nc-sa/3.0/ for details.
- */
- // Inicia os ports de E/S
- static void portInit(void)
- {
- // note: these MUST be in sync with actual hardware!
- // note: DDR pins are set to "1" to be an output, "0" for input.
- // 76543210
- //PORTB = 0b00000001; // initial: set to enable pullups on inputs: BUT1 pullup
- //DDRB = 0b00100000; // inputs: BUT1 (PB0); outputs: SCK (PB5); reserved (PB6, PB7)
- PORTB = 0x01; // (see above)
- DDRB = 0x30; // (see above)
- // 76543210
- //PORTC = 0b00000000; // initial: no pullups on inputs
- //DDRC = 0b00111111; // outputs: CC33-CC12 (PC0-PC5)
- PORTC = 0x00; // (see above)
- DDRC = 0x3F; // (see above)
- // 76543210
- //PORTD = 0b00000000; // initial: no pullups on inputs
- //DDRD = 0b11111100; // outputs: PP3-PP1 (PD2-PD4), CC31-CC11 (PD5-PD7); reserved (PD0/RxD,PD1/TxD)
- PORTD = 0x00; // (see above)
- DDRD = 0xFC; // (see above)
- }
- //
- // set up timer1 in "fast PWM" mode 14 (see waveform generation, pg 137 of atmega168/328 doc - doc8271).
- //
- // note: this causes TIMER1 to interrupt every 1ms! (TIMER1_OVF)
- // note: it's super important to call this AFTER arduino environment does it's good (and bad)
- // things to various TIMER settings.
- //
- static void startTimer1(void)
- {
- // make sure interrupts are off
- cli();
- // initialize ICR1, which sets the "TOP" value for the counter to interrupt and start over
- // note: value of 125-1 ==> 1khz (assumes 8mhz clock, prescaled by 1/64)
- ICR1 = 125-1;
- OCR1A = 0; // needed?? (no)
- //
- // timer1 config:
- // fast pwm (mode 14) - set WGM13,WGM12,WGM11 bits
- // prescaler clock/64 - set CS11,CS10 bits
- //
- TCCR1A = _BV(WGM11);
- TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS11) | _BV(CS10);
- TCCR1C = 0; // not needed?
- TIMSK1 = _BV(TOIE1); // enable timer1 overflow interrupt.. now were running!
- sei();
- }
- // 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;
- // Pega na Flash o padrão do plano corrente do frame atual
- plane = pgm_read_word (&frameTab[iFrame][iPlane]);
- // Acende os LEDs
- //
- // 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;
- }
- // 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;
- }
- }
- }
- }
Com esta programação a animação é controlada pela estrutura de dados (frameTab), não é necessário alterar o código para mostrar uma animação diferente. Uma evolução (que fica como exercício ao leitor) é pegar os frames da E2Prom ao invés da Flash e acrescentar uma forma de receber a animação pela serial e gravá-la na E2Prom.
O vídeo abaixo mostra o programa em ação.
O sketch está nos arquivos do blog em LedCube2pt.zip.
Um comentário:
Olá gosto muito desse Blog ,
poderia me ajudar, vou começa meu TCC 1.Porém não tenho ideias, pode me dar uma ideia? que esteja dentro de eletrônica e automação
Postar um comentário