#include "Lamp2.h" #include "Input string.h" #include "Arduino_Code.h" /* Lamp.c Code for outdoor lanterns using CAN_D box Vs0.9 Allows for fading and flickering of the lantern using the RGB LED Special thanks to Keven at http://ledhacker.blogspot.com/2011/12/led-candle-light-flicker-with-arduino.html for the flickering algorithm */ //Pin numbers #define RED_PIN 1 #define GREEN_PIN 3 #define BLUE_PIN 5 //Alarm definitions #define ALARM_1_HOUR 18 #define ALARM_1_MIN 00 #define ALARM_1_MODE lamp_flicker #define ALARM_2_HOUR 01 #define ALARM_2_MIN 00 #define ALARM_2_MODE lamp_off //Color fading modes are still buggy typedef enum { fade_mode = 0, //Fade between colors color_mode //Switch between solid colors }fade_t; //Flicker states typedef enum { hold_low = 0, rising, hold_high, falling } flicker_mode_t; //Default lamp values static lamp_t lamp_reset = { .addr = 1, .mode = lamp_flicker, .brightness = 255, .brightness_hi_min = 230, .brightness_hi_max = 255, .brightness_lo_min = 96, .brightness_lo_max = 240, .hold_hi_min = 40, .hold_hi_max = 80, .hold_lo_min = 100, .hold_lo_max = 200, .G2R_slope = 0x50, .base_green_value = 02, .num_of_colors = 4, .rotate_speed = 10, .red[0] = 0xff, .green[0] = 0xff, .blue[0] = 0xff, .red[1] = 0xff, .green[1] = 0, .blue[1] = 0, .red[2] = 0, .green[2] = 0xff, .blue[2] = 0, .red[3] = 0, .green[3] = 0, .blue[3] = 0xff, }; static uint32_t flicker_timer; static uint32_t fade_timer; static lamp_t lamp; void Send_CAN_lamp_message(lamp_t * lamp, lamp_t * new_lamp_val); void Write_color(uint8_t red, uint8_t green, uint8_t blue); void Check4alarm(lamp_t * lamp); void Check4rotate(lamp_t * lamp); void Check4flicker(lamp_t * lamp); void Flicker(lamp_t * lamp); void Write_flame(lamp_t * lamp, uint32_t brightness); void setup() { //Setting current values to default lamp = lamp_reset; //Set up pins analogWriteResolution(8); pinMode(RED_PIN, OUTPUT); pinMode(POWER_PIN, OUTPUT); pinMode(GREEN_PIN, OUTPUT); pinMode(BLUE_PIN, OUTPUT); //Turn on power to LED digitalWrite(POWER_PIN, HI); //Set Clock Set_hr(17); Set_min(25); Set_sec(0); //Set lamp timers flicker_timer = millis(); fade_timer = millis(); } void loop() { lamp_t new_lamp_val; int32_t USB_return_val; Check4alarm(&lamp); //Check the timers switch (lamp.mode) { case lamp_solid: Write_color(lamp.red[0], lamp.green[0], lamp.blue[0]); break; case lamp_flicker: Check4flicker(&lamp); //Check to see if flicker timer has expired break; case lamp_rotate: Check4rotate(&lamp); //Check to see if rotate timer has expired break; case lamp_off: default: Write_color(0,0,0); //Turn off lamp } Check4USB_message(&lamp); //Gets new values from USB } } //Function writes color values to pins void Write_color(uint8_t red, uint8_t green, uint8_t blue) { analogWrite(RED_PIN,255 - red); analogWrite(GREEN_PIN, 255 - green); analogWrite(BLUE_PIN, 255 - blue); } //Function checks to see if the alarm went off and if the mode needs to be changed void Check4alarm(lamp_t * lamp) { if ((ALARM_1_HOUR == Get_hr()) && (ALARM_1_MIN == Get_min())) lamp->mode = ALARM_1_MODE; if ((ALARM_2_HOUR == Get_hr()) && (ALARM_2_MIN == Get_min())) lamp->mode = ALARM_2_MODE; } //Color rotating function void Check4rotate(lamp_t * lamp) { static fade_t mode = color_mode; static uint32_t fade_length, old_color = 0, new_color = 0; uint8_t RGB[3]; float fade_percent; if (color_mode == mode) { //If current mode is color if (millis() >= fade_timer) { //If color timer has timed out //Reset timer for fade mode = fade_mode; if (RANDOM_FADE_SPEED & lamp->randomize) //If fade speed bit is set in random fade_length = random(0, lamp->fade_speed * FADE_MULTIPLER); //Set new timer with a min of 0 and a max of fade speed else fade_length += lamp->fade_speed * FADE_MULTIPLER; //Else set to fade speed fade_timer += fade_length; //Fade length is needed for fading due to possible random nature of the fade time //Set next color old_color = new_color; //Copy new color to old color if (RANDOM_COLOR & lamp->randomize) //If next color is random { new_color = random(1, lamp->num_of_colors) - 1; } else //Get next color in the sequence { new_color ++; } if (lamp->num_of_colors <= new_color) //If the end of the list is reached new_color = 0; //Reset the counter } } else if (fade_mode == mode) { if (millis() >= fade_timer) { //If fade timer has timed out mode = color_mode; //Reset timer for color if (RANDOM_COLOR_SPEED & lamp->randomize) //If color speed bit is set in random fade_timer = random(0, lamp->rotate_speed * COLOR_SPEED_MULTIPLER); //Set new timer with a min of 0 and a max of color speed else fade_timer += lamp->rotate_speed * COLOR_SPEED_MULTIPLER; //Else set to fade speed Write_color(lamp->red[new_color], lamp->green[new_color], lamp->blue[new_color]); } else //Continue to fade { fade_percent = (fade_timer - millis())/(fade_length + 1); //Adding 1 to denominator to prevent div by 0 errors if (lamp->fade_2_black == FADE_BLACK) { if (.50f < fade_percent) { //Fade to black RGB[0] = lamp->red[old_color] * (1 - fade_percent * 2); //*2 makes 50% into 100% so its fully black RGB[1] = lamp->green[old_color] * (1 - fade_percent * 2); RGB[2] = lamp->blue[old_color] * (1 - fade_percent * 2); } else { //Fade to new color RGB[0] = lamp->red[new_color] * (fade_percent * 2 - 1); //100% * 2 - 1 = 100% RGB[1] = lamp->green[new_color] * (fade_percent * 2 - 1); RGB[2] = lamp->blue[new_color] * (fade_percent * 2 - 1); } } else //Fading to new color { //Mixing old and new red values to get intermediate RGB[0] = lamp->red[new_color] * fade_percent + lamp->red[old_color]*(1 - fade_percent); RGB[1] = lamp->green[new_color] * fade_percent + lamp->green[old_color]*(1 - fade_percent); RGB[2] = lamp->blue[new_color] * fade_percent + lamp->blue[old_color]*(1 - fade_percent); } Write_color (RGB[0], RGB[1], RGB[2]); } } } //Function checks to see if the flicker timer has timed out and on timeout calls the flicker function void Check4flicker(lamp_t * lamp) { if (millis() >= flicker_timer) //If timer has expired run flicker Flicker(lamp); //Timer resets in flicker function } //Main function for flickering //Uses a state machine format with 4 different states //hold_low - flame stays at a low brightness value //rising - flame is going from the low value to a high value //hold_high - flame stays at a high brightness value //falling - flame is going from the high value to a low value void Flicker(lamp_t * lamp) { static flicker_mode_t flicker_mode = hold_low; static uint32_t flicker_level; static uint32_t brightness = 0; switch(flicker_mode) { case hold_low: //If timer expired and current mode is hold_low flicker_mode = rising; //Go to next state //Set level for max value flicker_level = random(lamp->brightness_hi_min, lamp->brightness_hi_max); brightness ++; //Start rising the flame flicker_timer ++; //Step up every 1mS break; case rising: if (brightness < flicker_level) //If the flame is still rising { //Increase flame and reset timer brightness ++; flicker_timer ++; } else //The flame has reached its max { flicker_mode = hold_high; //Go to next state flicker_timer = millis() + random(lamp->hold_hi_min, lamp->hold_hi_max); //Reset timer //Using millis instead of += due to possibility of falling behind every tick from task saturation } break; case hold_high: flicker_mode = falling; //Go to next state //Set level for min value flicker_level = random(lamp->brightness_lo_min, lamp->brightness_lo_max); brightness --; //Start lowering the flame flicker_timer ++; //Step ever 1mS break; case falling: if (brightness > flicker_level) //If the flame is still falling { //Decrease flame and reset timer brightness --; flicker_timer ++; } else //The flame has reached its min { flicker_mode = hold_low; //Go to next state flicker_timer = millis() + random(lamp->hold_lo_min, lamp->hold_lo_max); //Reset timer //Using millis instead of += due to possibility of falling behind every tick from task saturation } break; } Write_flame(lamp, brightness); //Write flame brightness } //Function takes the desired brightness and adjusts the red and green values linearly so that higher brightness = more green(and look more yellow) void Write_flame(lamp_t * lamp, uint32_t brightness) { //Red = users desired brightness(0-255) * brightness of the flame(0-255) / max value of red (255) uint32_t red = lamp->brightness * brightness / 255; //Green is a linear function of brightness so that low brightness values are more red // and high brightness values are more yellow //Green = actual brightness * slope ( "/ 255" due to slope values of 0-255) + base value uint32_t green = red * lamp->G2R_slope / 255 + lamp->base_green_value; green = limit(green, 0 ,255); Write_color(red, green, 0); }