/* neopixel_clock.c */
// Arduino UNO R3
// AVR_ATmega328P
#define F_CPU 16000000UL
#include <avr/io.h> // register names-addresses and bit names-numbers
#include <util/delay.h>
#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(16); // 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(16); // 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(16); // actual speed should be 200 ms
}
else _delay_ms(32); // 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(16); // 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 = 255; // max 255 green
*(ptr+1) = 0; // 0 red
*(ptr+2) = 0; // 0 blue
break;
case CHARTREUSE:
* ptr = 255; // max 255 green
*(ptr+1) = 127; // 127 red
*(ptr+2) = 0; // 0 blue
break;
case YELLOW:
* ptr = 255; // max 255 green
*(ptr+1) = 255; // max 255 red
*(ptr+2) = 0; // 0 blue
break;
case ORANGE:
* ptr = 127; // 127 green
*(ptr+1) = 255; // max 255 red
*(ptr+2) = 0; // 0 blue
break;
case RED:
* ptr = 0; // 0 green
*(ptr+1) = 255; // max 255 red
*(ptr+2) = 0; // 0 blue
break;
case ROSE:
* ptr = 0; // 0 green
*(ptr+1) = 255; // max 255 red
*(ptr+2) = 127; // 127 blue
break;
case MAGENTA:
* ptr = 0; // 0 green
*(ptr+1) = 255; // max 255 red
*(ptr+2) = 255; // max 255 blue
break;
case VIOLET:
* ptr = 0; // 0 green
*(ptr+1) = 127; // 127 red
*(ptr+2) = 255; // max 255 blue
break;
case BLUE:
* ptr = 0; // 0 green
*(ptr+1) = 0; // 0 red
*(ptr+2) = 255; // max 255 blue
break;
case AZURE:
* ptr = 127; // 127 green
*(ptr+1) = 0; // 0 red
*(ptr+2) = 255; // max 255 blue
break;
case CYAN:
* ptr = 255; // max 255 green
*(ptr+1) = 0; // 0 red
*(ptr+2) = 255; // max 255 blue
break;
case SPRING:
* ptr = 25; // max 255 green
*(ptr+1) = 0; // 0 red
*(ptr+2) = 127; // 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 <TXD A4|-
Res---|01 PC6/RES' ATM328 SCL/PC5 28|-(A5)- -|D02 A3|-
-(D00)-|02 PD0/RXD SDA/PC4 27|-(A4)- -|D03~ A2|-
-(D01)-|03 PD1/TXD PC3 26|-(A3)- -|D04 A1|-
-(D02)-|04 PD2/INT0 PC2 25|-(A2)- -|D05~ A0|-
-(D03)-|05 PD3/INT1/PWM PC1 24|-(A1)- DIN -<-|D06~ | Power:
-(D04)-|06 PD4 PC0 23|-(A0)- -|D07 Vin|-
+5V ---|07 VCC GND 22|--- Gnd | GND|--- GND
Gnd ---|08 GND AREF 21|--- Vin -|D08 GND|-
Xtal |X|--|09 PB6/OSC1 AVCC 20|--- +5V -|D09~ +5V|-
16MHz |X|--|10 PB7/OSC2 SCK/PB5 19|-(D13)- -|D10~ +3.3V|-
-(D05)-|11 PD5/PWM MISO/PB4 18|-(D12)- -|D11~ Res|-
DIN -<-(D06)-|12 PD6/PWM PWM/MOSI/PB3 17|-(D11)- -|D12 IOREF|-
-(D07)-|13 PD7 PWM/SS'/PB2 16|-(D10)- -|D13 LED --- |
-(D08)-|14 PB0 PWM/PB1 15|-(D09)- -|GND |
|______________________________| -|AREF |
-|SCL |
-|SDA |
|________________|
*/
/*
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 < 5000 ns interbit gap
TLL > 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 |__________| |__________| |__________|
*/