#include <RTClib.h>
#define ALR_HOUR 6
#define ALR_MIN 0
#define LCD_BACKLIGHT_TIME 3000L
#define FADE_EXTRA_TIME 600000L
#define RED_PIN 3
#define GREEN_PIN 5
#define BLUE_PIN 6
#define BUTTON_PIN 2
RTC_DS1307 RTC;
typedef struct {
byte red;
byte green;
byte blue;
unsigned int seconds;
} color_seq_item;
color_seq_item col0 = { 12, 1, 0, 300};
color_seq_item col1 = { 50, 1, 0, 300};
color_seq_item col2 = { 80, 10, 0, 300};
color_seq_item col3 = { 255, 60, 0, 180};
color_seq_item color_seq[] = {col0, col1, col2, col3};
int color_seq_size = sizeof(color_seq) / sizeof(color_seq_item);
void set_color(byte red, byte green, byte blue) {
analogWrite(RED_PIN, red);
analogWrite(GREEN_PIN, green);
analogWrite(BLUE_PIN, blue);
}
void lcd_init() {
Serial.write(0x7C);
Serial.write(0x0D); // 9600 bauds
delay(5);
Serial.write(0x7C);
Serial.write(0x04); // 16 char
delay(5);
Serial.write(0x7C);
Serial.write(0x06); // 2 lines
delay(5);
}
void lcd_clear() {
Serial.write(0xFE);
Serial.write(0x01);
delay(5);
}
void lcd_back_on() {
Serial.write(0x7C);
Serial.write(157);
delay(5);
}
void lcd_back_off(){
Serial.write(0x7C);
Serial.write(128);
delay(5);
}
void update_lcd_time() {
static enum {WAITING, UPDATING} state = WAITING;
static unsigned long prev_millis = millis();
DateTime time;
switch(state) {
case WAITING:
if (millis() - prev_millis >= 1000) {
prev_millis = millis();
state = UPDATING;
}
break;
case UPDATING:
time = RTC.now();
Serial.print("Hora: ");
if (time.hour() < 10) Serial.print("0");
Serial.print(time.hour());
Serial.print(":");
if (time.minute() < 10) Serial.print("0");
Serial.print(time.minute());
Serial.print(":");
if (time.second() < 10) Serial.print("0");
Serial.print(time.second());
Serial.print(" ");
Serial.print("Alarma: ");
if (ALR_HOUR < 10) Serial.print("0");
Serial.print(ALR_HOUR);
Serial.print(":");
if (ALR_MIN < 10) Serial.print("0");
Serial.print(ALR_MIN);
Serial.print(" ");
state = WAITING;
break;
}
}
void update_lcd_backlight() {
static enum {OFF, ON, DELAYING} state = OFF;
static unsigned long prev_millis;
switch(state) {
case OFF:
if (digitalRead(BUTTON_PIN) == LOW) {
state = ON;
}
break;
case ON:
lcd_back_on();
prev_millis = millis();
state = DELAYING;
break;
case DELAYING:
if (millis() - prev_millis >= LCD_BACKLIGHT_TIME) {
lcd_back_off();
state = OFF;
}
break;
}
}
void update_wake_up() {
static enum {WAITING, RUNNING, DELAYING, CANCELLED} state = WAITING;
static unsigned long prev_millis = millis();
static int seq_index;
static int step_index;
color_seq_item cur_item;
color_seq_item next_item;
unsigned long time_step_ms;
int red, green, blue;
DateTime time;
switch(state) {
case WAITING:
if (millis() - prev_millis >= 1000) {
prev_millis = millis();
time = RTC.now();
if ((time.hour() == ALR_HOUR) && (time.minute() == ALR_MIN) && (time.second() < 3)) {
seq_index = 0;
step_index = 0;
state = RUNNING;
}
}
break;
case RUNNING:
if (digitalRead(BUTTON_PIN) == LOW) {
state = CANCELLED;
} else {
if (step_index == 256) {
if (seq_index == (color_seq_size - 2)) {
prev_millis = millis();
state = DELAYING;
} else {
seq_index += 1;
step_index = 0;
}
} else {
cur_item = color_seq[seq_index];
next_item = color_seq[seq_index + 1];
time_step_ms = (cur_item.seconds * 1000UL) / 256UL;
if (time_step_ms == 0) {
set_color(cur_item.red, cur_item.green, cur_item.blue);
step_index = 256;
} else {
if (millis() - prev_millis >= time_step_ms) {
prev_millis = millis();
red = ((cur_item.red * (255 - step_index)) + (next_item.red * step_index)) / 255;
green = ((cur_item.green * (255 - step_index)) + (next_item.green * step_index)) / 255;
blue = ((cur_item.blue * (255 - step_index)) + (next_item.blue * step_index)) / 255;
set_color(red, green, blue);
step_index += 1;
}
}
}
}
break;
case DELAYING:
if (digitalRead(BUTTON_PIN) == LOW) {
state = CANCELLED;
} else {
if (millis() - prev_millis >= FADE_EXTRA_TIME) {
prev_millis = millis();
set_color(0, 0, 0);
state = WAITING;
}
}
break;
case CANCELLED:
prev_millis = millis();
set_color(0, 0, 0);
state = WAITING;
break;
}
}
void setup() {
Wire.begin();
RTC.begin();
pinMode(BUTTON_PIN, INPUT_PULLUP);
Serial.begin(9600);
lcd_init();
lcd_clear();
lcd_back_off();
set_color(0, 0, 0);
if (color_seq_size < 2) {
while(1) {
Serial.print("ERROR: color > 2");
delay(1000);
}
}
}
void loop() {
update_lcd_time();
update_lcd_backlight();
update_wake_up();
}
If the answers is incorrect or not given, you can answer the above question in the comment box. If the answers is incorrect or not given, you can answer the above question in the comment box.