Originally this was built with the Atmega4808, and ran tests which worked just great. But I was able to get a set of 3208's for much lower price so I grabbed those and tested with the permanent lighting. They also worked great. Below are some gif animations of 4th of july. For any debugging, I do have TX out to a laptop with the UPDI also hooked up, So I can SSH into it and reprogram it and or see whats going on with minicom. This set up has an LDR that is mounted in a white 3d print in the window that averages the light over 1 minute and sets the brightness to how dark it is. Then when true daylight will shut off in auto mode. In Manual mode you can go dimmer or brighter then auto will allow and it will ignore LDR and stay on.
I will probably be changing this to 3 buttons, 1-Brightness/auto, 2-Theme, 3-effects, then add an oled to display what theme and effect is going on. Currently the led's on this PCB gives you the option to quickly select a theme, then toggle through the effects. New years is now Custom Theme which allows for other effects not in normal themes/effects.
Light sensor (LDR) in window with outer case as black, the rest white facing outward, so if I turn on the garage light it does not affect the sensor to much.
/* gcc4808-WS2812-controller (also works with 3208)
* main.c
*
* Created: 6/20/26
* Author : Sherman Stebbins
*
* Atmega4808
* --
* PA7 1| |28 PA6
* PC0 2| |27 PA5
* PC1 3| |26 PA4
* PC2 4| |25 PA3
* PC3 5| |24 PA2
* PD0 6| |23 PA1
* PD1 7| |22 PA0
* PD2 8| |21 GND
* PD3 9| |20 VDD
* PD4 10| |19 UPDI
* PD5 11| |18 PF6 (RESET)
* PD6 12| |17 PF1
* PD7 13| |16 PF0
* AVDD 14| |15 GND
* --
* PD0-PD7 & PF0-PF1 Analog (all others digital only)
* from 402:
* PA1 - brightModeChange
* PA2 - eeprom button
* PA3 - Data out to WS2812
* //PA6 - color Mode change now PD0
* PD7 - ADC
*
* buttons: (multi-press for changing modes within the season)
* PD0 - b-other
* PD1 - b-valentines
* PD2 - b-stpatricks
* PD3 - b-easter
* PD4 - b-4th
* PD5 - b-haloween
* PD6 - b-thanks
* PF0 - b-christmas
*
* indicator lights:
* PA4 - 4th
* PA5 - haloween
* PA6 - thanks
* PA7 - christmas
* PC0 - other
* PC1 - valintines
* PC2 - stpatricks
* PC3 - easter
*
*
* Updated 6/25/26:
* Added more status lights, for auto brightness and on status
*
* Updated 6/26/26:
* Adding themes and updated functions to change depending on season theme.
*
* Updated 6/30/26 added many custom effects:
* Birthday, Birthday flash, white, warm white, very warm white, police, fire
*
* Updated 7/2/26 added FIREFLY custum effect.
*/
#define F_CPU 20000000UL
#define USART0_BAUD_RATE(BAUD_RATE) ((float)(F_CPU * 64 / (16 * (float)BAUD_RATE)) + 0.5)
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#include <string.h>
#include <avr/eeprom.h>
//1-1023: lights on off and dim
#define LIGHTLOW 10 //any number < then this and lights stay on lowest setting.
#define LIGHTMID 80
#define LIGHTHIGH 200
#define LIGHTHIGHHIGH 400
#define LIGHTSON 600 //< then this number and lights go on.
#define LIGHTSOFF 800 //> this number and its off
#define LED_PORT PORTA
#define LED_PIN PIN3_bm
#define LED_PORT PORTA
#define LED_PIN PIN3_bm
#define BUTTON_PIN PIN1_bm
#define MAXBRIGHTMODES 8
//#define MAXCOLORMODES 6
//scroll:
#define COLOR_WIDTH 8
#define PATTERN_LEN (COLOR_WIDTH * 3)
#define FADE_STEPS 7 //for birthday funcs
#define NUM_LEDS 624 //may need to add +16 more leds for side.
//#define NUM_LEDS 48 //may need to add +16 more leds for side.
#define AUTO_BRIGHTNESS_MODE 7
//count how many of the first lights to be used for status display:
#define STATUS_LIGHTS_BRIGHTNESS 6 //first lights to be used for bright status
#define STATUS_LIGHTS_AUTO_BRIGHTNESS 1 //lights used to show AUTO_BRIGHTNESS status
#define STATUS_BRIGHTNESS_LEDS 6
#define STATUS_AUTO_LED 6
#define STATUS_LIGHTS_LED 7
#define STATUS_BLANK_LED 8
#define STATUS_LED_COUNT 9
///////////////firefly/////////////////////////////
#define NUM_FIREFLIES 40 //was 50
#define FIREFLY_SPACING 4
#define FF_MIN_BRIGHTNESS 40
#define FF_MAX_BRIGHTNESS 230
#define FF_SPEED_MIN 1 // was 12 lower is slower
#define FF_SPEED_RANDOM 3 //bit mask leave along
#define FF_RESET 1000 //how many loops till it clears all to fix stuck FF.
//not used yet:
#define FF_HOLD_MIN 5
#define FF_HOLD_RANDOM 8
#define FF_SLEEP_MIN 2
#define FF_SLEEP_RANDOM 15
typedef struct
{
uint16_t position;
uint8_t brightness;
uint8_t state;
uint8_t timer;
uint8_t speed;
uint16_t random;
uint8_t maxBrightness;
uint8_t flashMode;
} FIREFLY;
//FIREFLY fireflies[50];
FIREFLY fireflies[NUM_FIREFLIES];
uint8_t fireMap[NUM_LEDS];
uint8_t ffLoopCount=0;
uint16_t countFireFlyLoopsToClear=0;
enum
{
FF_SLEEP = 0,
FF_RISE,
FF_HOLD,
FF_FALL
};
//////////////////////////////////////////////////////////
volatile uint8_t BRIGHTNESS = 30; //overwrittent with brightMode NOTE none < 2
volatile uint8_t brightnessAuto = 1;//brightness in auto mode true or false.
volatile uint8_t someButtonPressed = 0;
volatile uint8_t brightnessButtonPress = 0;//brightness button
volatile uint8_t saveButtonPress = 0; //button to save to eeprom
volatile uint8_t brightMode = 0; //start up brightness mode
volatile uint16_t loopCount= 0; //used in multiple modes for counting
uint8_t FADE_Default = 0;
uint8_t offset = 0;
uint8_t centerExpandCount = 0;
uint8_t adcCheckFlag=0; //set to 1 when it is safe to run adc.
uint8_t tick = 0;
uint16_t width = 0;
uint16_t ldr_value = 0;
uint8_t scrollLoopCount = 0;
uint8_t lightsOffFlag=0;
//uint8_t led_buffer[NUM_LEDS][3]; // [LED][R,G,B]
uint16_t ldr_average[40] ={};
uint8_t ldr_count = 0;
//Custom Themes: /////////////////
typedef enum
{
CUSTOM_BIRTHDAY = 0,
CUSTOM_BIRTHDAY_FLASH,
CUSTOM_WHITE,
CUSTOM_WARMWHITE,
CUSTOM_WARMERWHITE,
CUSTOM_POLICE,
CUSTOM_MEDICAL,
CUSTOM_FIRE,
//CUSTOM_FRONTDOOR,
//CUSTOM_AMBULANCE,
//CUSTOM_RANDOM,
//CUSTOM_CANDYCANE,
//CUSTOM_METEOR,
//CUSTOM_LIGHTNING,
CUSTOM_FIREFLIES,
CUSTOM_MAX
} CUSTOM_EFFECT;
volatile CUSTOM_EFFECT currentCustomEffect = CUSTOM_BIRTHDAY;
//Themes: ////////////////////////
typedef struct {
uint8_t g;
uint8_t r;
uint8_t b;
} COLOR;
COLOR patrioticTheme[3] = {
{0,255,0}, //red
{255,255,255},//white
{0,0,255}//blue
};
COLOR christmasTheme5[5] = {
{0, 255, 0}, // Red
{255, 0, 0}, // Green
{255, 255, 0}, //yellow
{0, 0, 255}, // blue
{0, 105, 255}, // purple
};
COLOR christmasTheme[3] = {
{0, 255, 0}, // Red
{255, 0, 0}, // Green
{0, 0, 0} // red
};
COLOR halloweenTheme[3] = {
{80, 255, 0}, // Orange
{0, 105, 255}, // Purple
{30, 0, 0} // Dim Green
};
COLOR valentineTheme[3] = {
{0, 255, 70}, // Pink
{0, 255, 10}, // Red
{255, 255, 255} //white
};
COLOR stPatricksTheme[3] = {
{255, 0, 0}, //green
{255, 155, 155}, //white
{255, 100, 0} //lt green
};
COLOR easterTheme[3] = {
{0, 255, 255}, //pink
{0, 125, 255}, //purple
{255, 255, 0} //yellow
};
COLOR thanksgivingTheme[3] = {
{200, 255, 0}, //yellowish
{80, 255, 0}, //orangeish
{20, 255, 0} //red/mauve
};
COLOR policeTheme[3] = {
{0, 0, 0}, //blank
{0, 255, 0}, //red
{0, 0, 255} //blue
};
COLOR medicalTheme[3] = {
{0, 0, 0}, //blank
{0, 255, 0}, //red
{255, 255, 255} //white
};
COLOR fireTheme[3] = {
{0, 0, 0}, //blank
{0, 255, 0}, //red
{255, 255, 255} //white
};
COLOR whiteTheme[3] = {
{255, 255, 255}, //white
{155, 155, 155}, //white
{255, 255, 255} //white
};
//yellow-255,255,0
//mauve-125,255,125
//orange-125,255,0
//magenta-0,255,255 //pinkish
//purple-0,125,255
//skyblue-255,0,255
//
typedef enum
{
THEME_CUSTOM = 0,
THEME_VALENTINE,
THEME_STPATRICK,
THEME_EASTER,
THEME_PATRIOTIC,
THEME_HALLOWEEN,
THEME_THANKSGIVING,
THEME_CHRISTMAS,
THEME_MAX
} THEME_ID;
typedef enum
{
EFFECT_SCROLL = 0,
EFFECT_FADE,
EFFECT_SOLID,
EFFECT_CENTER,
EFFECT_SPARKLE,
EFFECT_PAINT_FRONTDOOR,
EFFECT_COMBINATION,
EFFECT_OFF,
EFFECT_MAX
} EFFECT_ID;
typedef enum
{
BUTTON_NONE = 0,
BUTTON_CUSTOM,
BUTTON_VALENTINE,
BUTTON_STPATRICK,
BUTTON_EASTER,
BUTTON_PATRIOTIC,
BUTTON_HALLOWEEN,
BUTTON_THANKSGIVING,
BUTTON_CHRISTMAS,
//BUTTON_BRIGHTNESS,
//BUTTON_SAVE,
BUTTON_MAX
} BUTTON_ID;
COLOR *currentTheme = valentineTheme;
volatile uint8_t combinationMode = 0;//combinationMode 1-2-3-....
volatile THEME_ID currentThemeID = THEME_CUSTOM;
volatile EFFECT_ID currentEffect = EFFECT_SCROLL;
volatile BUTTON_ID themeButtonPressed = BUTTON_NONE;
//////////////////EEprom stuff////////////////////////
// Initialize with a default value (e.g., 0xFF)
//uint8_t EEMEM eeprom_data_location = 0x01;
uint8_t EEMEM eeBrightMode = 2; // Default brightness
uint8_t EEMEM eeBrightnessAuto = 1; // Default to auto
uint8_t EEMEM eeTheme = THEME_CUSTOM; // Default theme
uint8_t EEMEM eeEffect = EFFECT_SCROLL; // Default effect
uint8_t EEMEM eeCustomMode = CUSTOM_BIRTHDAY;
//Util funcs///////////////////////////////////////////////////////
void adc_init(void);
uint16_t adc_read(void);
void USART0_init(void);
void USART0_sendChar(char c);
void USART0_sendString(char *str);
void sendUsart(uint16_t stuff);
void brightModeChange(void);
void readLightADC(void);
void sendBiteStatus(uint8_t i); //used to change status lights (first 8 lights)
static inline void send_bit_1(void);
static inline void send_bit_0(void);
void send_byte(uint8_t byte);
void send_color(uint8_t r, uint8_t g, uint8_t b);
void delayMs(uint16_t ms);
void setTheme(THEME_ID theme, COLOR *themePtr);
void clearLedIndicators(void);
void ledIndicators(void);
//theme funcs:
static inline void sendThemeColor(COLOR c);
void send_scroll(uint8_t offset, COLOR theme[3]);
void center_expand_implementation(COLOR theme[3], uint8_t combinationModeON);
void center_expand_direct(uint16_t width, COLOR color);
void solidPattern5(COLOR theme[5]);
void solidPattern(COLOR theme[3]);
void fadeColor(COLOR theme[3], uint8_t colorNumber);
void sparkle(COLOR theme[3]);
//custom modes:
void birthday(uint8_t modulas,uint8_t bright);
void birthdayFadeFlash(uint8_t space);
void fireflyInit();
void fireflyUpdate(void);
void fireflyBuildMap(void);
void fireflyRender(void);
void fireflyEffect();
void paintFrontDoor(COLOR theme[3]);
int main(void) {
// ---- Clock setup: force 8 MHz internal oscillator ----
CCP=0xD8;
CLKCTRL.MCLKCTRLB = 0x00;
// Wait a moment for clock to stabilize
for (volatile uint16_t i = 0; i < 1000; i++);
// ---- Clock setup: force 8 MHz internal oscillator ----
//set PA1&PA2&PD0 to falling for button
PORTA.PIN1CTRL = PORT_PULLUPEN_bm | PORT_ISC_FALLING_gc;
PORTA.PIN2CTRL = PORT_PULLUPEN_bm | PORT_ISC_FALLING_gc;
PORTD.PIN0CTRL = PORT_PULLUPEN_bm | PORT_ISC_FALLING_gc;
PORTD.PIN1CTRL = PORT_PULLUPEN_bm | PORT_ISC_FALLING_gc;
PORTD.PIN2CTRL = PORT_PULLUPEN_bm | PORT_ISC_FALLING_gc;
PORTD.PIN3CTRL = PORT_PULLUPEN_bm | PORT_ISC_FALLING_gc;
PORTD.PIN4CTRL = PORT_PULLUPEN_bm | PORT_ISC_FALLING_gc;
PORTD.PIN5CTRL = PORT_PULLUPEN_bm | PORT_ISC_FALLING_gc;
PORTD.PIN6CTRL = PORT_PULLUPEN_bm | PORT_ISC_FALLING_gc;
PORTF.PIN0CTRL = PORT_PULLUPEN_bm | PORT_ISC_FALLING_gc;
PORTC.DIR = PIN0_bm|PIN3_bm|PIN2_bm|PIN1_bm;
PORTA.DIR = PIN4_bm|PIN5_bm|PIN6_bm|PIN7_bm;
PORTC.OUTCLR = PIN0_bm|PIN1_bm|PIN2_bm|PIN3_bm;
PORTA.OUTCLR = PIN4_bm|PIN5_bm|PIN6_bm|PIN7_bm;
PORTA.DIRSET = PIN3_bm;
sei(); //Set enable interrupt
//read eeprom:
brightMode = eeprom_read_byte(&eeBrightMode);
brightnessAuto = eeprom_read_byte(&eeBrightnessAuto);
currentThemeID = eeprom_read_byte(&eeTheme);
currentEffect = eeprom_read_byte(&eeEffect);
currentCustomEffect = eeprom_read_byte(&eeCustomMode);
if(brightMode >= MAXBRIGHTMODES)brightMode = 2;
if(brightnessAuto > 1)brightnessAuto = 0; //auto off on start after firmware
if(currentThemeID >= THEME_MAX)currentThemeID = THEME_CUSTOM;
if(currentEffect >= EFFECT_MAX)currentEffect = EFFECT_SCROLL;
if(currentCustomEffect >= CUSTOM_MAX)
currentCustomEffect = CUSTOM_FIREFLIES;
switch(currentThemeID)
{
case THEME_CUSTOM:
currentTheme = NULL;//THEME_CUSTOM;//wrong
break;
case THEME_VALENTINE:
currentTheme = valentineTheme;
break;
case THEME_STPATRICK:
currentTheme = stPatricksTheme;
break;
case THEME_EASTER:
currentTheme = easterTheme;
break;
case THEME_PATRIOTIC:
currentTheme = patrioticTheme;
break;
case THEME_HALLOWEEN:
currentTheme = halloweenTheme;
break;
case THEME_THANKSGIVING:
currentTheme = thanksgivingTheme;
break;
case THEME_CHRISTMAS:
currentTheme = christmasTheme;
break;
default:
currentThemeID = THEME_PATRIOTIC;
currentTheme = patrioticTheme;
break;
}
//brightModeChange();
if(brightMode >MAXBRIGHTMODES){
brightMode=0;
}
brightModeChange();
char string[10];
//PORTA.DIRSET = PIN3_bm;
USART0_init();
USART0_sendString("BOOT\r\n");
adc_init();
send_color(BRIGHTNESS,0,0);
_delay_ms(400);
send_color(0,BRIGHTNESS,0);
_delay_ms(400);
send_color(0,0,BRIGHTNESS);
_delay_ms(400);
ledIndicators();
fireflyInit();
while (1) {
/////////////////////adc Check/////////////////////////
if(adcCheckFlag){
adcCheckFlag=0;
readLightADC();
}
///////////////////// Button Press ///////////////////////////
if(someButtonPressed)
{
someButtonPressed = 0;
////////////////// Brightness //////////////////
if(brightnessButtonPress)
{
brightnessButtonPress = 0;
brightMode++;
if(brightnessAuto)brightMode = 0;
if(brightMode >= MAXBRIGHTMODES)brightMode = 0;
if(brightMode != AUTO_BRIGHTNESS_MODE)
{
brightnessAuto = 0;
lightsOffFlag = 0;
}
brightModeChange();
sendUsart(1);//brightness button is 1
}
////////////////// Save //////////////////
else if(saveButtonPress)
{
saveButtonPress = 0;
eeprom_update_byte(&eeBrightMode, brightMode);
eeprom_update_byte(&eeBrightnessAuto, brightnessAuto);
eeprom_update_byte(&eeTheme, currentThemeID);
eeprom_update_byte(&eeEffect, currentEffect);
eeprom_update_byte(&eeCustomMode, currentCustomEffect);
sendUsart(2);//save button is 2
// Flash lights to show saved
send_color(0,0,0);
_delay_ms(300);
send_color(0,BRIGHTNESS,0);
_delay_ms(300);
}
////////////////// Theme Buttons //////////////////
else if(themeButtonPressed)
{
switch(themeButtonPressed)
{
////////////////// OTHER //////////////////
itoa(themeButtonPressed, string, 10);
USART0_sendString(string);
USART0_sendString(" button press\r\n");
case BUTTON_CUSTOM:
if(currentThemeID != THEME_CUSTOM){
currentThemeID = THEME_CUSTOM;
currentCustomEffect = CUSTOM_BIRTHDAY;
}else{
currentCustomEffect++;
if(currentCustomEffect >= CUSTOM_MAX)
currentCustomEffect = CUSTOM_BIRTHDAY;
}
USART0_sendString("Custom Effect: ");
itoa(currentCustomEffect, string, 10);
USART0_sendString(string);
USART0_sendString("\r\n");
//setTheme(THEME_CHRISTMAS, christmasTheme);
break;
////////////////// VALENTINE //////////////////
case BUTTON_VALENTINE:
setTheme(THEME_VALENTINE, valentineTheme);
break;
////////////////// ST PATRICKS //////////////////
case BUTTON_STPATRICK:
setTheme(THEME_STPATRICK, stPatricksTheme);
break;
////////////////// EASTER //////////////////
case BUTTON_EASTER:
setTheme(THEME_EASTER, easterTheme);
break;
////////////////// PATRIOTIC //////////////////
case BUTTON_PATRIOTIC:
setTheme(THEME_PATRIOTIC, patrioticTheme);
break;
////////////////// HALLOWEEN //////////////////
case BUTTON_HALLOWEEN:
setTheme(THEME_HALLOWEEN, halloweenTheme);
break;
////////////////// THANKSGIVING //////////////////
case BUTTON_THANKSGIVING:
setTheme(THEME_THANKSGIVING, thanksgivingTheme);
break;
////////////////// CHRISTMAS //////////////////
case BUTTON_CHRISTMAS:
setTheme(THEME_CHRISTMAS, christmasTheme);
break;
}
themeButtonPressed = BUTTON_NONE;
ledIndicators();
sendUsart(3);//theme button is 2
}
}
/////////////////////light check set flag//////////////
if(lightsOffFlag)
{
send_color(0,0,0);
adcCheckFlag = 1;
delayMs(800);
USART0_sendString("lights off\r\n");
continue;
}
/////////////////////custom effects ///////////////////////////
if(currentThemeID == THEME_CUSTOM){
uint8_t spaces =7;
//uint8_t FADE_STEPS = 8;
switch(currentCustomEffect){
case CUSTOM_BIRTHDAY:
birthday(1,BRIGHTNESS);
delayMs(500);
adcCheckFlag=1;
break;
case CUSTOM_BIRTHDAY_FLASH:
birthdayFadeFlash(spaces);
readLightADC();
birthday(1,BRIGHTNESS);
delayMs(1000);
readLightADC();
delayMs(1000);
readLightADC();
delayMs(1000);
adcCheckFlag=1;
break;
case CUSTOM_WHITE:
send_color(BRIGHTNESS,BRIGHTNESS,BRIGHTNESS);
delayMs(500);
adcCheckFlag=1;
break;
case CUSTOM_WARMWHITE:
send_color(BRIGHTNESS/2,BRIGHTNESS,BRIGHTNESS/10);
delayMs(500);
adcCheckFlag=1;
break;
case CUSTOM_WARMERWHITE:
send_color(BRIGHTNESS/2,BRIGHTNESS,0);
delayMs(500);
adcCheckFlag=1;
break;
case CUSTOM_POLICE:
send_scroll(offset, policeTheme);
offset++;
if(offset >= PATTERN_LEN)
offset = 0;
delayMs(30);
scrollLoopCount++;
if(scrollLoopCount >= 20)
{
scrollLoopCount = 0;
adcCheckFlag = 1;
}
break;
case CUSTOM_MEDICAL:
send_scroll(offset, medicalTheme);
offset++;
if(offset >= PATTERN_LEN)
offset = 0;
delayMs(30);
scrollLoopCount++;
if(scrollLoopCount >= 20)
{
scrollLoopCount = 0;
adcCheckFlag = 1;
}
break;
case CUSTOM_FIREFLIES:
fireflyEffect();
delayMs(5); //was 30
break;
default:
birthday(1,BRIGHTNESS);
adcCheckFlag=1;
break;
}
//////////////current effects////////////////////////////
}else{
switch(currentEffect)
{
case EFFECT_SCROLL:
send_scroll(offset, currentTheme);
offset++;
if(offset >= PATTERN_LEN)
offset = 0;
delayMs(30);
scrollLoopCount++;
if(scrollLoopCount >= 20)
{
scrollLoopCount = 0;
adcCheckFlag = 1;
}
break;
case EFFECT_FADE:
fadeColor(currentTheme,0);
fadeColor(currentTheme,1);
fadeColor(currentTheme,2);
//readLightADC();
adcCheckFlag=1;
break;
case EFFECT_SOLID:
solidPattern(currentTheme);
delayMs(1000);
// send_color(0,0,0);
//delayMs(500);
break;
case EFFECT_CENTER:
center_expand_implementation(currentTheme,0);
delayMs(1);
tick++;
if(tick%40==0){
adcCheckFlag=1;
}
break;
case EFFECT_SPARKLE:
tick++;
sparkle(currentTheme);
delayMs(40);
if(tick%18==0){ //makes it check about 1 sec intervals
adcCheckFlag = 1;
}
break;
case EFFECT_PAINT_FRONTDOOR:
paintFrontDoor(currentTheme);
delayMs(1000);
adcCheckFlag=1;
break;
case EFFECT_COMBINATION:
if(combinationMode == 0){//scroll
send_scroll(offset,currentTheme);
offset++;
if(offset >= PATTERN_LEN)
{
offset = 0;
adcCheckFlag = 1;
}
delayMs(30);
if(loopCount++ > 140)
{
loopCount = 0;
combinationMode = 1;
adcCheckFlag = 1;
}
}
else if(combinationMode == 1){//fade
fadeColor(currentTheme,0);
fadeColor(currentTheme,1);
fadeColor(currentTheme,2);
readLightADC();
adcCheckFlag = 1;
if(++loopCount > 1)
{
loopCount = 0;
combinationMode = 2;
}
}
else if(combinationMode == 2){//sparkle
tick++;
sparkle(currentTheme);
if(++loopCount > 120)
{
loopCount = 0;
combinationMode = 3;
adcCheckFlag = 1;
}
delayMs(40);
if(tick%18==0){ //makes it check about 1 sec intervals
adcCheckFlag = 1;
}
}
else if(combinationMode == 3){//center expand
center_expand_implementation(currentTheme,1);
delayMs(1);
tick++;
if(tick%40==0){
adcCheckFlag=1;
}
}else if(combinationMode == 4){ //paint frontDoor
paintFrontDoor(currentTheme);
delayMs(300);
send_color(0,0,0);
delayMs(300);
paintFrontDoor(currentTheme);
delayMs(300);
send_color(0,0,0);
readLightADC();
paintFrontDoor(currentTheme);
delayMs(2000);
readLightADC();
delayMs(2000);
adcCheckFlag=1;
combinationMode=5;
}else{ //solid flash then still
for(uint8_t i=0;i<3;i++)
{
send_color(0,0,0);
delayMs(300);
solidPattern(currentTheme);
delayMs(500);
adcCheckFlag = 1;
}
for(uint8_t i=0;i<3;i++)
{
solidPattern(currentTheme);
delayMs(800);
adcCheckFlag = 1;
}
combinationMode = 0;
}
break;
case EFFECT_OFF: //lights off (used with AUTO_BRIGHTNESS_MODE)
send_color(0,0,0);
delayMs(1000);
adcCheckFlag = 1;
break;
default:
currentEffect = EFFECT_SCROLL;
break;
}
}
}
}
//brightMode's for manual and auto light settings
//never put BRIGHTNESS <2
void brightModeChange(void){
if(brightMode >= MAXBRIGHTMODES){ brightMode = 0;}
switch (brightMode){
case 0:
BRIGHTNESS=5;
break;
case 1:
BRIGHTNESS=15;
break;
case 2:
BRIGHTNESS=30;
break;
case 3:
BRIGHTNESS=50;
break;
case 4:
BRIGHTNESS=90;
break;
case 5:
BRIGHTNESS=120;
break;
case 6:
BRIGHTNESS=155;
break;
case AUTO_BRIGHTNESS_MODE:
//set auto light mode here
brightnessAuto=1;
break;
default:
BRIGHTNESS=30;
break;
}
}
/////////////////////Custom Modes////////////////////////////////////
void paintFrontDoor(COLOR c[3]){
cli();
for(uint16_t led = 0; led < NUM_LEDS; led++)
{
if(someButtonPressed){
sei();
_delay_us(80);
return;
}
if(led < STATUS_LED_COUNT)
{
sendBiteStatus(led);
}else{
char string[10];
if(led>405 && led<458){
sendThemeColor(c[0]);
}else if(led<305 || led> 560){
sendThemeColor(c[1]);
}else{
sendThemeColor(c[2]);
}
}
}
sei();
}
void birthdayFadeFlash(uint8_t spaces){
for(uint8_t i=1;i<spaces;i++){
for(uint8_t step=0; step<=FADE_STEPS; step++){
uint8_t bright =
1 + ((uint16_t)(BRIGHTNESS-1) * step) / FADE_STEPS;
birthday(i, bright);
delayMs(5);
}
for(int8_t step=FADE_STEPS; step>=0; step--){
uint8_t bright =
1 + ((uint16_t)(BRIGHTNESS-1) * step) / FADE_STEPS;
birthday(i, bright);
delayMs(5);
}
}
readLightADC();
for(uint8_t i=spaces;i>=1;i--){
for(uint8_t step=0; step<=FADE_STEPS; step++){
uint8_t bright =
1 + ((uint16_t)(BRIGHTNESS-1) * step) / FADE_STEPS;
birthday(i, bright);
delayMs(5);
}
for(int8_t step=FADE_STEPS; step>=0; step--){
uint8_t bright =
1 + ((uint16_t)(BRIGHTNESS-1) * step) / FADE_STEPS;
birthday(i, bright);
delayMs(5);
}
}
readLightADC();
}
void birthday(uint8_t space,uint8_t brightlevel){
uint8_t colorCount = 0;
cli();
for(uint16_t led = 0; led < NUM_LEDS; led++)
{
if(someButtonPressed){
sei();
_delay_us(80);
return;
}
if(led < STATUS_LED_COUNT)
{
sendBiteStatus(led);
}
else
{
if(led%space!=0){
send_byte(0);
send_byte(0);
send_byte(0);
}else{
// sendThemeColor(theme[colorCount]);
switch(colorCount){
case 0: //green
send_byte(brightlevel);
send_byte(0);
send_byte(0);
break;
case 1: //red
send_byte(0);
send_byte(brightlevel);
send_byte(0);
break;
case 2: //blue
send_byte(0);
send_byte(0);
send_byte(brightlevel);
break;
case 3: //yellow
send_byte(brightlevel);
send_byte(brightlevel);
send_byte(0);
break;
case 4: //pinkish purple
send_byte(0);
send_byte(brightlevel);
send_byte(brightlevel);
break;
case 5: //orange
send_byte(brightlevel/2);
send_byte(brightlevel);
send_byte(0);
break;
}
colorCount++;
if(colorCount > 5)colorCount = 0;
}
}
}
sei();
_delay_us(80);
adcCheckFlag = 1;
}
void fireflyInit(void)
{
uint16_t seed = 0xACE1;
for(uint8_t i = 0; i < NUM_FIREFLIES; i++)
{
uint16_t lsb = seed & 1;
seed >>= 1;
if(lsb)seed ^= 0xB400;
if(seed == 0)seed = 0xACE1;
fireflies[i].position =
STATUS_LED_COUNT +
(((uint32_t)seed * (NUM_LEDS - STATUS_LED_COUNT)) / 65535UL);
// (((uint16_t)seed * (NUM_LEDS - STATUS_LED_COUNT)) / 255);
fireflies[i].brightness = 0;
fireflies[i].state = FF_SLEEP;
fireflies[i].timer = 20 + (seed & 31);
//fireflies[i].speed = 8 + (seed & 3);
//fireflies[i].speed = FF_SPEED_MIN + (seed & 3);
fireflies[i].speed = FF_SPEED_MIN + (seed & FF_SPEED_RANDOM);
//fireflies[i].maxBrightness = FF_MAX_BRIGHTNESS - (seed & 15);
fireflies[i].maxBrightness =
FF_MIN_BRIGHTNESS +
(seed % (FF_MAX_BRIGHTNESS - FF_MIN_BRIGHTNESS + 1));
fireflies[i].random = seed;
fireflies[i].flashMode = seed % 4;
}
}
void fireflyBuildMap(void)
{
// Clear the entire map
memset(fireMap, 0, sizeof(fireMap));
for(uint8_t i = 0; i < NUM_FIREFLIES; i++)
{
FIREFLY *f = &fireflies[i];
if(f->state == FF_SLEEP)
continue;
//added 7/8 per ai
if(f->position < NUM_LEDS){
fireMap[f->position] = f->brightness;
}
}
}
void fireflyRender(void)
{
cli();
for(uint16_t led = 0; led < NUM_LEDS; led++)
{
if(someButtonPressed)
{
sei();
_delay_us(80);
return;
}
if(led < STATUS_LED_COUNT)
{
sendBiteStatus(led);
}
else
{
uint8_t b = fireMap[led];
// Warm yellow
send_byte((b * 120) / 255); //green
send_byte(b); // red
send_byte(0); // Blue
}
}
sei();
_delay_us(80);
//put clear stuck FF here:
if(++countFireFlyLoopsToClear>FF_RESET){
countFireFlyLoopsToClear=0;
send_color(0,0,0);
}
}
void fireflyEffect(void)
{
fireflyUpdate();
fireflyBuildMap();
fireflyRender();
delayMs(5); //was 30
ffLoopCount++;
if(ffLoopCount>40){
adcCheckFlag = 1;
ffLoopCount=0;
}
}
void fireflyUpdate(void)
{
for(uint8_t i = 0; i < NUM_FIREFLIES; i++)
{
FIREFLY *f = &fireflies[i];
switch(f->state){
case FF_SLEEP:
if(f->timer)
{
f->timer--;
}
else
{
f->state = FF_RISE;
f->brightness = 0;
}
break;
case FF_RISE:
f->brightness += f->speed;
if(f->brightness >= f->maxBrightness){
f->brightness = f->maxBrightness;
f->state = FF_HOLD;
//f->timer = 8 + (seed & 7);
f->timer = 8 + (f->random & 7);
}
break;
case FF_HOLD:
if(f->timer){
f->timer--;
switch(f->flashMode){
case 0:
// Never flicker
break;
case 1:
// Small chance of one quick blink
if((f->random & 0x1F) == 0)
f->brightness = f->maxBrightness / 3;
else
f->brightness = f->maxBrightness;
break;
case 2:
// Moderate flickering
if(f->random & 1)
f->brightness = f->maxBrightness;
else
f->brightness = f->maxBrightness / 2;
break;
case 3:
// Lots of flickering
switch(f->random & 3){
case 0:
f->brightness = f->maxBrightness;
break;
case 1:
f->brightness = f->maxBrightness / 4;
break;
case 2:
f->brightness = f->maxBrightness / 2;
break;
default:
f->brightness = (f->maxBrightness * 3) / 4;
break;
}
break;
}
// Advance this firefly's random generator every frame
uint16_t lsb = f->random & 1;
f->random >>= 1;
if(lsb)
f->random ^= 0xB400;
}else{
f->brightness = f->maxBrightness;
f->state = FF_FALL;
}
break;
// break;
case FF_FALL:
if(f->brightness > f->speed){
f->brightness -= f->speed;
}else{
f->brightness = 0;
f->state = FF_SLEEP;
/* Wait before next flash */
//f->timer = 15 + (seed & 63);
f->timer = 15 + (f->random & 63);
/* Update this firefly's own random number */
uint16_t lsb = f->random & 1;
f->random >>= 1;
if(lsb)
f->random ^= 0xB400;
if(f->random == 0)
f->random = 0xACE1;
/* Pick a completely new position */
uint8_t retry;
do{
retry = 0;
/* New random number */
// f->random = (f->random >> 1) ^ (-(f->random & 1u) & 0xB8);
f->random = (f->random >> 1) ^ (-(f->random & 1u) & 0xB400);
if(f->random == 0)f->random = 37;
/* Pick a new position */
f->position =
STATUS_LED_COUNT +
(((uint32_t)f->random * (NUM_LEDS - STATUS_LED_COUNT)) / 65535UL);
/* Check if another ACTIVE firefly is too close */
for(uint8_t j = 0; j < NUM_FIREFLIES; j++){
if(j == i)continue;
//if(fireflies[j].state == FF_SLEEP)
// continue;
int16_t d = (int16_t)fireflies[j].position -
(int16_t)f->position;
if(d < 0)
d = -d;
//if(d < 3) // Less than 3 LEDs apart
if(d < FIREFLY_SPACING){ // Less than FIREFLY_SPACING LEDs apart
retry = 1;
break;
}
}
} while(retry);
// New fade speed
//f->speed = 1 + (seed & 3);
//f->speed = 4 + (f->random & 3);
f->speed = FF_SPEED_MIN + (f->random & FF_SPEED_RANDOM);
//f->maxBrightness = BRIGHTNESS - (f->random & 15);
//f->maxBrightness = FF_MAX_BRIGHTNESS - (f->random & 15);
f->maxBrightness = FF_MIN_BRIGHTNESS +
(f->random % (FF_MAX_BRIGHTNESS -
FF_MIN_BRIGHTNESS + 1));
}
break;
}
}
}
/////// current effects /////////////////////////////////////////
void center_expand_direct(uint16_t width, COLOR color)
{
uint16_t center = NUM_LEDS / 2;
cli();
for(uint16_t led = 0; led < NUM_LEDS; led++){
uint16_t distance;
if(someButtonPressed){
sei();
_delay_us(80);
return;
}
if(led >= center){
distance = led - center;
}else{
distance = center - led;
}
if(led < STATUS_LED_COUNT){
sendBiteStatus(led);
}
else if(distance <= width){
sendThemeColor(color);
}else{
send_byte(0);
send_byte(0);
send_byte(0);
}
}
sei();
_delay_us(80);
}
void center_expand_implementation(COLOR theme[3], uint8_t combinationModeON)
{
if(someButtonPressed) return;
center_expand_direct(width, theme[centerExpandCount]);
width += 2; // twice as fast now
if(width > (NUM_LEDS / 2))
{
width = 0;
centerExpandCount++;
if(combinationModeON)
{
if(++loopCount > 2)
{
loopCount = 0;
combinationMode = 4;
centerExpandCount = 0;
adcCheckFlag = 1;
return;
}
}
if(centerExpandCount > 2)
{
centerExpandCount = 0;
}
adcCheckFlag = 1;
}
}
void sparkle(COLOR theme[3])
{
uint8_t lfsr = tick; // tick increments each frame
cli();
// Send status LEDs first
for(uint8_t i = 0; i < STATUS_LED_COUNT; i++)
{
sendBiteStatus(i);
}
// Now send the sparkle groups
for(uint16_t group = 0; group < (NUM_LEDS / 3); group++)
{
if(someButtonPressed){
sei();
_delay_us(80);
return;
}
// Update random number
lfsr = (lfsr >> 1) ^ (-(lfsr & 1u) & 0xB8);
uint8_t fire = (lfsr & 0x03) == 0; // ~25% chance
uint8_t which_led = lfsr % 3;
lfsr = (lfsr >> 1) ^ (-(lfsr & 1u) & 0xB8);
uint8_t color = lfsr % 3;
uint8_t bright = (lfsr & 0x1F) + 10;
for(uint8_t led = 0; led < 3; led++)
{
if(fire && (led == which_led))
{
COLOR c = theme[color];
send_byte(((uint16_t)c.g * bright) / 255);
send_byte(((uint16_t)c.r * bright) / 255);
send_byte(((uint16_t)c.b * bright) / 255);
}
else
{
send_byte(0);
send_byte(0);
send_byte(0);
}
}
}
sei();
_delay_us(80);
}
void solidPattern5(COLOR theme[5]){
uint8_t colorCount = 0;
cli();
for(uint16_t led = 0; led < NUM_LEDS; led++){
if(someButtonPressed){
sei();
_delay_us(80);
return;
}
if(led < STATUS_LED_COUNT){
sendBiteStatus(led);
}else{
sendThemeColor(theme[colorCount]);
colorCount++;
if(colorCount >= 5)
colorCount = 0;
}
}
sei();
_delay_us(80);
adcCheckFlag = 1;
}
void solidPattern(COLOR theme[3]){
uint8_t colorCount = 0;
cli();
for(uint16_t led = 0; led < NUM_LEDS; led++)
{
if(someButtonPressed){
sei();
_delay_us(80);
return;
}
if(led < STATUS_LED_COUNT){
sendBiteStatus(led);
}else{
sendThemeColor(theme[colorCount]);
colorCount++;
if(colorCount >= 3)
colorCount = 0;
}
}
sei();
_delay_us(80);
adcCheckFlag = 1;
}
void send_scroll(uint8_t offset, COLOR theme[3]){
cli();
for(uint16_t led = 0; led < NUM_LEDS; led++)
{
if(someButtonPressed){
sei();
_delay_us(80);
return;
}
// Keep the first 8 LEDs for status
if(led < STATUS_LED_COUNT){
sendBiteStatus(led);
continue;
}
uint8_t p = (led + offset) % PATTERN_LEN;
if(p < COLOR_WIDTH){
sendThemeColor(theme[0]);
}
else if(p < (COLOR_WIDTH * 2)){
sendThemeColor(theme[1]);
}else{
sendThemeColor(theme[2]);
}
}
sei();
_delay_us(80);
}
void fadeColor(COLOR theme[3], uint8_t colorNumber)
{
FADE_Default = (256 / BRIGHTNESS) + 1;
for(uint8_t i = 0; i < BRIGHTNESS; i++)
{
if(someButtonPressed) return;
COLOR c = theme[colorNumber];
send_color(
((uint16_t)c.g * i) / 255,
((uint16_t)c.r * i) / 255,
((uint16_t)c.b * i) / 255
);
delayMs(FADE_Default);
}
readLightADC();
for(uint8_t i = BRIGHTNESS; i > 1; i--){
if(someButtonPressed) return;
COLOR c = theme[colorNumber];
send_color(
((uint16_t)c.g * i) / 255,
((uint16_t)c.r * i) / 255,
((uint16_t)c.b * i) / 255
);
delayMs(FADE_Default);
}
readLightADC();
//adcCheckFlag = 1;
}
////// Status lights ws2812 /////////////////////////////////
void sendBiteStatus(uint8_t currentStatusLed){
//blank light:
if(currentStatusLed==STATUS_BLANK_LED){
send_byte(0);
send_byte(0);
send_byte(0);
return;
}else if(currentStatusLed==STATUS_LIGHTS_LED){
//on or off status
if(!lightsOffFlag){
send_byte(0);
send_byte(0);
send_byte(BRIGHTNESS);
}else{
send_byte(0);
send_byte(0);
send_byte(0);
}
return;
//}
//AUTO_BRIGHTNESS_MODE:
}else if(currentStatusLed==STATUS_AUTO_LED){
if(brightnessAuto){
send_byte(BRIGHTNESS);
send_byte(0);
send_byte(0);
}else{
send_byte(0);
send_byte(0);
send_byte(0);
}
return;
//}
//current brightness
}else if(currentStatusLed<brightMode){
send_byte(0);
send_byte(BRIGHTNESS);
send_byte(0);
}else{
send_byte(0);
send_byte(0);
send_byte(0);
}
}
///////////////LED Indicators and clear indicators/////////////////
void clearLedIndicators(void){
PORTC.OUTCLR = PIN0_bm|PIN1_bm|PIN2_bm|PIN3_bm;
PORTA.OUTCLR = PIN4_bm|PIN5_bm|PIN6_bm|PIN7_bm;
}
void ledIndicators(void){
//put indicator lights here:
//currentThemeID
clearLedIndicators();
switch(currentThemeID){
case THEME_CUSTOM:
PORTC.OUT |= PIN0_bm;
break;
case THEME_VALENTINE:
PORTC.OUT |= PIN1_bm;
break;
case THEME_STPATRICK:
PORTC.OUT |= PIN2_bm;
break;
case THEME_EASTER:
PORTC.OUT |= PIN3_bm;
break;
case THEME_PATRIOTIC:
PORTA.OUT |= PIN4_bm;
break;
case THEME_HALLOWEEN:
PORTA.OUT |= PIN5_bm;
break;
case THEME_THANKSGIVING:
PORTA.OUT |= PIN6_bm;
break;
case THEME_CHRISTMAS:
PORTA.OUT |= PIN7_bm;
break;
}
}
////////////send bit, send byte, send color, set theme, send theme///////
static inline void send_bit_1(void) {
//time now 700ns 1 nop=about 50ns //was 7
LED_PORT.OUTSET = LED_PIN;
__asm__ __volatile__(
"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"
);
//time now 600ns (need to test at 400ns per datasheet for c version)
//did approx and works, just need to test timing with scope.
LED_PORT.OUTCLR = LED_PIN;
__asm__ __volatile__("nop\n\t""nop\n\t""nop\n\t"
);//try 6 nops was 3
}
static inline void send_bit_0(void) {
//time now 350ns
LED_PORT.OUTSET = LED_PIN;
__asm__ __volatile__("nop\n\t""nop\n\t"); //was 3
//time now 660ns
LED_PORT.OUTCLR = LED_PIN;
__asm__ __volatile__(
"nop\n\t""nop\n\t""nop\n\t""nop\n\t"
"nop\n\t""nop\n\t"
"nop\n\t""nop\n\t"
);
}
void send_byte(uint8_t byte) {
for (uint8_t i = 0; i < 8; i++) {
if (byte & 0x80) {
send_bit_1();
} else {
send_bit_0();
}
byte <<= 1;
}
}
void send_color(uint8_t g, uint8_t r, uint8_t b) {
cli(); // Disable interrupts
//for(uint16_t i=0;i<=NUM_LEDS;i++){
for(uint16_t i=0;i<NUM_LEDS;i++){
//adding <= instead of < sort of works but adds extra space on
//both sides
//if(i<=STATUS_LIGHTS_BRIGHTNESS+STATUS_LIGHTS_AUTO_BRIGHTNESS+1){
if(i<STATUS_LED_COUNT){
sendBiteStatus(i);
}else{
// WS2812 expects GRB order
send_byte(g);
send_byte(r);
send_byte(b);
}
}
sei(); // Enable interrupts
_delay_us(80); // Reset latch
}
void setTheme(THEME_ID theme, COLOR *themePtr)
{
if(currentThemeID == theme)
{
currentEffect++;
if(currentEffect >= EFFECT_MAX)
currentEffect = EFFECT_SCROLL;
}
else
{
currentThemeID = theme;
currentTheme = themePtr;
currentEffect = EFFECT_SCROLL;
combinationMode = 0;
}
//put indicator lights here:
ledIndicators();
}
static inline void sendThemeColor(COLOR c)
{
send_byte(((uint16_t)c.g * BRIGHTNESS) / 255);
send_byte(((uint16_t)c.r * BRIGHTNESS) / 255);
send_byte(((uint16_t)c.b * BRIGHTNESS) / 255);
}
//////////////////delayMs////////////////////////////////////////
void delayMs(uint16_t ms) {
while (ms--) {
if (someButtonPressed) return;
_delay_ms(1);
}
}
///////////////USART///////////////////////////////////////////////
void USART0_init(void)
{
PORTMUX.USARTROUTEA = PORTMUX_USART0_DEFAULT_gc;
PORTA.DIRSET = PIN0_bm; // TX
//PORTA.DIRCLR = PIN1_bm; // RX
USART0.BAUD = (uint16_t)USART0_BAUD_RATE(9600);
USART0.CTRLB = USART_TXEN_bm;
}
void USART0_sendChar(char c)
{
//make sure usart is available
while (!(USART0.STATUS & USART_DREIF_bm)){;}
USART0.TXDATAL = c; //Send char
}
void USART0_sendString(char *str)
{
for(size_t i = 0; i < strlen(str); i++){
USART0_sendChar(str[i]);
}
}
void sendUsart(uint16_t stuff){
char string[10];
if(stuff==1){
USART0_sendString(" Brightness Button pushed -");
}else if(stuff==2){
USART0_sendString(" Save Button pushed -");
}else if(stuff==3){
USART0_sendString(" Theme Button pushed -");
}
USART0_sendString(" THEME_ID: ");
switch (currentThemeID){
case THEME_CUSTOM:
USART0_sendString("THEME_CUSTOM: ");
switch (currentCustomEffect){
case CUSTOM_BIRTHDAY:
USART0_sendString("CUSTOM_BIRTHDAY ");
break;
case CUSTOM_BIRTHDAY_FLASH:
USART0_sendString("CUSTOM_BIRTHDAY_FLASH ");
break;
case CUSTOM_WHITE:
USART0_sendString("CUSTOM_WHITE ");
break;
case CUSTOM_WARMWHITE:
USART0_sendString("CUSTOM_WARMWHITE ");
break;
case CUSTOM_WARMERWHITE:
USART0_sendString("CUSTOM_WARMERWHITE ");
break;
case CUSTOM_POLICE:
USART0_sendString("CUSTOM_POLICE ");
break;
case CUSTOM_MEDICAL:
USART0_sendString("CUSTOM_MEDICAL");
break;
case CUSTOM_FIREFLIES:
USART0_sendString("CUSTOM_FIREFLIES ");
break;
}
break;
case THEME_VALENTINE:
USART0_sendString("THEME_VALENTINE ");
break;
case THEME_STPATRICK:
USART0_sendString("THEME_STPATRICK ");
break;
case THEME_EASTER:
USART0_sendString("THEME_EASTER ");
break;
case THEME_PATRIOTIC:
USART0_sendString("THEME_PATRIOTIC ");
break;
case THEME_HALLOWEEN:
USART0_sendString("THEME_HALLOWEEN ");
break;
case THEME_THANKSGIVING:
USART0_sendString("THEME_THANKSGIVING ");
break;
case THEME_CHRISTMAS:
USART0_sendString("THEME_CHRISTMAS ");
break;
}
if(currentThemeID != THEME_CUSTOM){
switch (currentEffect){
case EFFECT_SCROLL:
USART0_sendString(" EFFECT_SCROLL ");
break;
case EFFECT_FADE:
USART0_sendString(" EFFECT_FADE ");
break;
case EFFECT_SOLID:
USART0_sendString(" EFFECT_SOLID ");
break;
case EFFECT_CENTER:
USART0_sendString(" EFFECT_CENTER ");
break;
case EFFECT_SPARKLE:
USART0_sendString(" EFFECT_SPARKLE ");
break;
case EFFECT_PAINT_FRONTDOOR:
USART0_sendString(" EFFECT_PAINT_FRONTDOOR ");
break;
case EFFECT_COMBINATION:
USART0_sendString(" EFFECT_COMBINATION ");
break;
case EFFECT_OFF:
USART0_sendString(" EFFECT_OFF ");
break;
default:
USART0_sendString(" Unknown ");
break;
}
}
if(brightnessAuto){
USART0_sendString(" Auto mode - ");
USART0_sendString("ldr avr: ");
itoa(ldr_value,string,10);
USART0_sendString(string);
USART0_sendString(" ldr now: ");
itoa(ldr_average[ldr_count],string,10);
USART0_sendString(string);
USART0_sendString(" ldr_count:");
itoa(ldr_count,string,10);
USART0_sendString(string);
}else{
USART0_sendString(" Manual mode - ");
USART0_sendString("ldr now: ");
itoa(ldr_value,string,10);
USART0_sendString(string);
}
USART0_sendString(" brightMode:");
itoa(brightMode,string,10);
USART0_sendString(string);
USART0_sendString("\r\n");
}
////////////////ADC//////////////////////////////////////////////
void adc_init(void) {
ADC0.MUXPOS = ADC_MUXPOS_AIN7_gc;
VREF.CTRLA = VREF_ADC0REFSEL_1_bm;
ADC0.CTRLC = ADC_PRESC_DIV32_gc;//works with 20mhz
ADC0.CTRLA = ADC_ENABLE_bm; // Enable ADC
}
uint16_t adc_read(void) {
// 1. Start conversion by writing 1 to STCONV
ADC0.COMMAND = ADC_STCONV_bm;
while (!(ADC0.INTFLAGS & ADC_RESRDY_bm));
ADC0.INTFLAGS = ADC_RESRDY_bm;
return ADC0.RES;
}
void readLightADC(void){
//read and average readings:
ldr_value=0;
for(uint8_t i=0;i<12;i++){
ldr_value=ldr_value + adc_read();
}
ldr_value=ldr_value/12;
if(brightnessAuto){
//load imidiate average into long average:
//ldr_average[ldr_count]=ldr_value;
ldr_count++;
if(ldr_count>39){ldr_count=0;}
ldr_average[ldr_count]=ldr_value;
ldr_value=0;
for(uint8_t i =0;i<40;i++){
ldr_value=ldr_value+ldr_average[i];
}
//calc long average and put back into ldr_value:
ldr_value=ldr_value/40;
if(ldr_value>LIGHTSOFF){
lightsOffFlag=1;
}else if(ldr_value<LIGHTLOW){
brightMode=1;
brightModeChange();
}else if(ldr_value >LIGHTLOW && ldr_value<LIGHTMID-2){
brightMode=2;
brightModeChange();
}else if(ldr_value >LIGHTMID && ldr_value<LIGHTHIGH-2){
brightMode=3;
brightModeChange();
}else if(ldr_value >LIGHTHIGH && ldr_value<LIGHTHIGHHIGH-2){
brightMode=4;
brightModeChange();
}else if(ldr_value >LIGHTHIGHHIGH && ldr_value<LIGHTSOFF-2){
brightMode=5;
brightModeChange();
}
if(ldr_value<LIGHTSON){
if(lightsOffFlag){
lightsOffFlag=0;
}
}
sendUsart(0);
}else{
sendUsart(0);
}
}
////////////////ISR/////////////////////////////////////////////
ISR(PORTA_PORT_vect){
if (PORTA.INTFLAGS & PIN1_bm){
PORTA.INTFLAGS = PIN1_bm; // clear PA1 flag
brightnessButtonPress = 1;
}else if (PORTA.INTFLAGS & PIN2_bm){
PORTA.INTFLAGS = PIN2_bm; // clear PA2 flag
saveButtonPress = 1;
}
someButtonPressed=1;
}
ISR(PORTD_PORT_vect)
{
if(PORTD.INTFLAGS & PIN0_bm){
PORTD.INTFLAGS = PIN0_bm;
themeButtonPressed=BUTTON_CUSTOM;
}else if(PORTD.INTFLAGS & PIN1_bm){
PORTD.INTFLAGS = PIN1_bm;
themeButtonPressed=BUTTON_VALENTINE;
}else if(PORTD.INTFLAGS & PIN2_bm){
PORTD.INTFLAGS = PIN2_bm;
themeButtonPressed=BUTTON_STPATRICK;
}else if(PORTD.INTFLAGS & PIN3_bm){
PORTD.INTFLAGS = PIN3_bm;
themeButtonPressed=BUTTON_EASTER;
}else if(PORTD.INTFLAGS & PIN4_bm){
PORTD.INTFLAGS = PIN4_bm;
themeButtonPressed=BUTTON_PATRIOTIC;
}else if(PORTD.INTFLAGS & PIN5_bm){
PORTD.INTFLAGS = PIN5_bm;
themeButtonPressed=BUTTON_HALLOWEEN;
}else if(PORTD.INTFLAGS & PIN6_bm){
PORTD.INTFLAGS = PIN6_bm;
themeButtonPressed=BUTTON_THANKSGIVING;
}
someButtonPressed = 1;
PORTD.INTFLAGS = 0b01111111;
}
ISR(PORTF_PORT_vect){
PORTF.INTFLAGS = PIN0_bm; // clear PA1 flag
themeButtonPressed=BUTTON_CHRISTMAS;
someButtonPressed=1;
}