/* neopixel_clock.c */ // Arduino UNO R3 // AVR_ATmega328P #define F_CPU 16000000UL #include // register names-addresses and bit names-numbers #include #define PIXELS 12 // 12 color palette #define GREEN 0 #define CHARTREUSE 1 #define YELLOW 2 #define ORANGE 3 #define RED 4 #define ROSE 5 #define MAGENTA 6 #define VIOLET 7 #define BLUE 8 #define AZURE 9 #define CYAN 10 #define SPRING 11 #define BLACK 12 /* NeoPixel connections */ /* Redefine if other pins are used */ #define NEOPIXEL_pin PD6 #define NEOPIXEL_DDR DDRD #define NEOPIXEL_PIN PIND #define NEOPIXEL_PORT PORTD void init_NeoPixel( void ); void sendBit( unsigned char bitVal ); void sendPixel( unsigned char * ptr ); void setPixelPalettColor( unsigned char *, unsigned char ); unsigned char OnePixel[3] = { 0x00, 0x00, 0x00 }; // grb-color bytes for one pixel // the ClockFace array to store grb-color bytes for all pixels (12*3=36 bytes) unsigned char ClockFace[ PIXELS*3 ]; unsigned char i, j, k; int main() { init_NeoPixel( ); _delay_us (6); // clock start values unsigned char Sec_5 = 0; unsigned char Min_5 = 0; unsigned char Hrs = 0; unsigned int loop_sec = 1 ; while(1) { for(i = 0; i < PIXELS; i++ ) setPixelPalettColor( ClockFace + i*3, BLUE ); // Background color setPixelPalettColor( ClockFace + Min_5 * 3 , GREEN); // Minutes color setPixelPalettColor( ClockFace + Hrs * 3 , RED); // Hours color for(i = 0; i < PIXELS ; i++ ) sendPixel( ClockFace + i*3 ); _delay_us (6); _delay_ms(2); // full speed 200 ms if( (loop_sec % 5) == 0 ) { setPixelPalettColor( ClockFace + Sec_5 * 3 , YELLOW); // Seconds color for(i = 0; i < PIXELS ; i++ ) sendPixel( ClockFace + i*3 ); _delay_us (6); _delay_ms(2); // actual speed should be 200 ms setPixelPalettColor( ClockFace + Min_5 * 3 , GREEN); // Minutes color for(i = 0; i < PIXELS ; i++ ) sendPixel( ClockFace + i*3 ); _delay_us (6); _delay_ms(2); // actual speed should be 200 ms } else _delay_ms(4); // actual speed should be 400 ms setPixelPalettColor( ClockFace + Min_5 * 3 , GREEN); // Minutes color setPixelPalettColor( ClockFace + Hrs * 3 , RED); // Hours color for(i = 0; i < PIXELS ; i++ ) sendPixel( ClockFace + i*3 ); _delay_us (6); _delay_ms(2); // actual speed should be 200 ms if( (loop_sec % 5) == 0 ) Sec_5 = ( ++ Sec_5) % 12; if( (loop_sec % 300) == 0 ) Min_5 = ( ++ Min_5) % 12; if( (loop_sec % 3600) == 0 ) Hrs = (++ Hrs) % 12; loop_sec++; } return 0; // never reached } /* *********************************** */ /* FUNCTIONS */ /* *********************************** */ void init_NeoPixel( void ) { NEOPIXEL_DDR |= ( 1 << NEOPIXEL_pin ); // Neopixel pin "1" is output NEOPIXEL_PORT &= ~( 1 << NEOPIXEL_pin ); // Neopixel pin "0" off } /* NeoPixel bit timing information. Processor f_clk = 16 MHz T = 62,5 ns. ______ "0": | |______________... T0H (400 ns) 07 Cycles, T0L (900 ns) 15 Cycles ______________ "1": | |_________... T1H (900 ns) 15 Cycles, T1L (600 ns) 10 Cycles */ // TLD 450 - 5000 ns interbit gap // TLL > 6000 ns, 6 us to latch (long delay) inline void sendBit( unsigned char bitVal ) { if ( bitVal != 0 ) // bit is 1 { asm volatile ( "sbi %[port], %[bitnr] \n\t" // output bit set port "nop \n\t" // T1H +13 NOP total 900 ns "nop \n\t" "nop \n\t" "nop \n\t" "nop \n\t" "nop \n\t" "nop \n\t" "nop \n\t" "nop \n\t" "nop \n\t" "nop \n\t" "nop \n\t" "nop \n\t" "cbi %[port], %[bitnr] \n\t" // output bit Clear port "nop \n\t" // T1L +8 NOP total 600 ns "nop \n\t" "nop \n\t" "nop \n\t" "nop \n\t" "nop \n\t" "nop \n\t" "nop \n\t" :: [port] "I" (_SFR_IO_ADDR(NEOPIXEL_PORT )), [bitnr] "I" (NEOPIXEL_pin) ); } else // bit is 0 { asm volatile ( "sbi %[port], %[bitnr] \n\t" // output bit set port "nop \n\t" // T0H +4 NOP total 400 ns - this is critical "nop \n\t" "nop \n\t" "nop \n\t" "cbi %[port], %[bitnr] \n\t" // output bit Clear port "nop \n\t" // T0L +13 NOP total 900 ns "nop \n\t" "nop \n\t" "nop \n\t" "nop \n\t" "nop \n\t" "nop \n\t" "nop \n\t" "nop \n\t" "nop \n\t" "nop \n\t" "nop \n\t" "nop \n\t" :: [port] "I" (_SFR_IO_ADDR(NEOPIXEL_PORT )), [bitnr] "I" (NEOPIXEL_pin) ); } } inline void sendPixel( unsigned char * ptr ) { unsigned char b, c, color; // send pixel 3*8=24 bits. Byte order green 0, red 1, blue 2. for ( c = 0; c < 3 ; c ++, ptr++ ) { // send next byte color = * ptr; // send 8 bits highest-to-lowest order for( b = 0; b < 8; b++) { // send one bit sendBit(color & 0x80); color <<= 1; } } } void setPixelPalettColor( unsigned char * ptr, unsigned char palettcolor ) { // MAX colorvalue is 255 but here reduced to 25 to get lower current consumption switch ( palettcolor ) { case GREEN: * ptr = 25; // max 255 green *(ptr+1) = 0; // 0 red *(ptr+2) = 0; // 0 blue break; case CHARTREUSE: * ptr = 25; // max 255 green *(ptr+1) = 12; // 127 red *(ptr+2) = 0; // 0 blue break; case YELLOW: * ptr = 25; // max 255 green *(ptr+1) = 25; // max 255 red *(ptr+2) = 0; // 0 blue break; case ORANGE: * ptr = 12; // 127 green *(ptr+1) = 25; // max 255 red *(ptr+2) = 0; // 0 blue break; case RED: * ptr = 0; // 0 green *(ptr+1) = 25; // max 255 red *(ptr+2) = 0; // 0 blue break; case ROSE: * ptr = 0; // 0 green *(ptr+1) = 25; // max 255 red *(ptr+2) = 12; // 127 blue break; case MAGENTA: * ptr = 0; // 0 green *(ptr+1) = 25; // max 255 red *(ptr+2) = 25; // max 255 blue break; case VIOLET: * ptr = 0; // 0 green *(ptr+1) = 12; // 127 red *(ptr+2) = 25; // max 255 blue break; case BLUE: * ptr = 0; // 0 green *(ptr+1) = 0; // 0 red *(ptr+2) = 25; // max 255 blue break; case AZURE: * ptr = 12; // 127 green *(ptr+1) = 0; // 0 red *(ptr+2) = 25; // max 255 blue break; case CYAN: * ptr = 25; // max 255 green *(ptr+1) = 0; // 0 red *(ptr+2) = 25; // max 255 blue break; case SPRING: * ptr = 25; // max 255 green *(ptr+1) = 0; // 0 red *(ptr+2) = 12; // 127 blue break; default: // BLACK * ptr = 0; // 0 green *(ptr+1) = 0; // 0 red *(ptr+2) = 0; // 0 blue } } /* *********************************** */ /* HARDWARE */ /* *********************************** */ /* Chip ATMega328 Arduino Uno R3 stackable header _______ Digital: _____/ \__ Analog: ______________ ______________ -|D00 >RXD A5|- | \/ | -|D01 6000 ns, 6 us to latch (long delay) NeoPixel 12 chain _____1____ _____2____ ____12____ | | | | | | GND ---| GND GND |---| GND GND |- ... -| GND GND |- D06->-470R-| >DIN >DO |---| >DIN >DO |- ... -| >DIN >DO |- POWER +5V -| +5V +5V |---| +5V +5V |- ... -| +5V +5V |- C 1000uF |__________| |__________| |__________| */