The core part of the project is twelve backlight white LED modules ( I bought them from the adafruit). LEDs are controlled by Atmega328 micro controller. The schematic of the project is fairly simple:
Adm here you can see project assembly with some internals visible:
Program to control the device is short enough to be present entirely in this blog:
/* * moon.c * Created: 10/22/2016 1:14:19 PM * Author: jumbleview */ #include <avr/io.h> #include <avr/interrupt.h> #include "./pt-1.4/pt.h" // http://dunkels.com/adam/pt/ typedef enum {OUT_LOW, OUT_HIGH} OutputLevel; volatile uint16_t pulses; #define pinOut(port, bit, outLevel) \ (DDR##port |= (1 << ( DD##port##bit)));\ switch(outLevel) \ {\ case OUT_LOW: (PORT##port &= ~(1 << (PORT##port##bit))); break;\ case OUT_HIGH: (PORT##port |= (1 << (PORT##port##bit))); break;\ } void clearAll() { // set all outputs low DDRB = 0xFF; PORTB = 0; DDRC = 0xFF; PORTC = 0; DDRD = 0xFF; PORTD = 0; } void activateTimer0() { cli(); pulses = 0; TCCR0A=0; // Normal operation TCCR0B=2; // f divider 64 : about 2 ms for interrupt ... TIMSK0 = 1; // for system clock f= 1Mhz (CKDIV8 set) sei(); } struct pt wpt; // protothread descriptor int moonlight(struct pt* mlpt) { PT_BEGIN(mlpt); // New Moon PT_YIELD(mlpt); pinOut(C,5,OUT_HIGH); pinOut(B,1,OUT_HIGH); PT_YIELD(mlpt); pinOut(D,0,OUT_HIGH); pinOut(B,2,OUT_HIGH); PT_YIELD(mlpt); pinOut(D,1,OUT_HIGH); pinOut(B,0,OUT_HIGH); PT_YIELD(mlpt); // First Quarter pinOut(D,2,OUT_HIGH); pinOut(D,7,OUT_HIGH); PT_YIELD(mlpt); pinOut(D,3,OUT_HIGH); pinOut(D,6,OUT_HIGH); PT_YIELD(mlpt); pinOut(D,4,OUT_HIGH); pinOut(D,5,OUT_HIGH); pinOut(C,0,OUT_HIGH); pinOut(C,1,OUT_HIGH); PT_YIELD(mlpt); // Full Moon + Red Eyes PT_YIELD(mlpt); pinOut(C,0,OUT_LOW); pinOut(C,1,OUT_LOW); pinOut(C,5,OUT_LOW); pinOut(B,1,OUT_LOW); PT_YIELD(mlpt); pinOut(D,0,OUT_LOW); pinOut(B,2,OUT_LOW); PT_YIELD(mlpt); pinOut(D,1,OUT_LOW); pinOut(B,0,OUT_LOW); PT_YIELD(mlpt); // Third Quarter pinOut(D,2,OUT_LOW); pinOut(D,7,OUT_LOW); PT_YIELD(mlpt); pinOut(D,3,OUT_LOW); pinOut(D,6,OUT_LOW); PT_YIELD(mlpt); pinOut(D,4,OUT_LOW); pinOut(D,5,OUT_LOW); PT_RESTART(mlpt); // New Moon PT_END(mlpt); } ISR(TIMER0_OVF_vect) { pulses++; uint16_t mod =pulses%750; if (mod == 0){ moonlight(&wpt); } } int main(void) { PT_INIT(&wpt); // initiate protothread structure... clearAll(); activateTimer0(); while(1) { } }
To compile and load program into the controller memory I used Atmel Studio 6.1. Code includes three header files.
- File "io.h" contains definitions to work with input/output (comes with Studio installation)
- File "interrupt.h" is defining interrupt vectors (comes with Studio installation)
- File "pt.h" is Adam Dunkels implementation of protothread library.
Protothred library deserves some additional notes. I included it to my programming tool box recently and nowadays use it any time I need to program embedded devices in "C ". It provides multitasking framework and allows to code device states efficiently and conveniently. I highly recommend to try it for any programmer who works with micro-controllers in "C".
As you can see device is simple to made and program. Some additional details you can find in my "Instructables" project.
The only problem I see is relatively high project price. Mostly it is the price of LED modules ($2.50 for each). Nothing could be done here. To gain some additional benefits I decided to substitute Bat with Reindeer so the device is quite usable as winter decor: