//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#include <TimerOne.h>
#include <ezButton.h>
#include <ArduinoTrace.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
//----------------- OLED ----------------------------------------------
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Clock Variables Declaration (7:27 as default time)
#define ON 1
#define OFF 0
bool ClockPoint = true;
unsigned char Update;
unsigned char halfsecond = 0;
unsigned char second;
unsigned char hour = 7;
unsigned char minute = 27;
char Time[] = " : ";
// Alarm Variables Declaration (00:00 as default)
unsigned char alarm_hour=0;
unsigned char alarm_minute=0;
// IMPORTANT CONTROL VARIABLES THAT DEFINES WHAT SHOWS ON DISPLAY
#define TIME 1
#define ALARM 0
bool displayMode = TIME;
// led variables
int rled = 12; // Pin PWN 11 para led rojo
// buzzeer variable
int buzzer1 = 13;
// switch variable
int switch1 = 8;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Button Declarations
ezButton alarmSetBtn(4); // create ezButton object that attach to pin 4;
ezButton timeSetBtn(5); // create ezButton object that attach to pin 5;
ezButton hourBtn(6); // create ezButton object that attach to pin 6;
ezButton minuteBtn(7); // create ezButton object that attach to pin 7;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Variables for miliseconds calculations
unsigned long pm1;
unsigned long pm2;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 'clk', 25x25px
const unsigned char epd_bitmap_clk [] PROGMEM = {
0x00, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x3c, 0x1e, 0x00, 0x78, 0x0f, 0x00, 0x73, 0xe7, 0x00, 0x64,
0x13, 0x00, 0x48, 0x89, 0x00, 0x10, 0x84, 0x00, 0x20, 0x82, 0x00, 0x20, 0x82, 0x00, 0x20, 0x82,
0x00, 0x20, 0x42, 0x00, 0x20, 0x22, 0x00, 0x10, 0x04, 0x00, 0x08, 0x08, 0x00, 0x04, 0x10, 0x00,
0x03, 0xe0, 0x00
};
void setup(){
// Set serial monitor frecuency
Serial.begin(9600);
//------ initialize and clear display ---------------------
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;);
}
// Clear the buffer.
display.clearDisplay();
// Timer for clock init
Timer1.initialize(500000);//timing for 500ms
Timer1.attachInterrupt(TimingISR);//declare the interrupt serve routine:TimingISR
// Debounce times and pin configuration for buttons
alarmSetBtn.setDebounceTime(50);
timeSetBtn.setDebounceTime(50); // set debounce time to 50 milliseconds
hourBtn.setDebounceTime(50);
minuteBtn.setDebounceTime(50);
//buttons ports
pinMode(4, INPUT_PULLUP);
pinMode(5, INPUT_PULLUP);
pinMode(6, INPUT_PULLUP);
pinMode(7, INPUT_PULLUP);
pinMode(8, INPUT_PULLUP);
//Led pins in output mode
pinMode(12, OUTPUT);
display.setTextColor (WHITE);
display.setTextSize(2);
}
void loop(){
display.clearDisplay();
Time[2] = (ClockPoint==1) ? 58 : 32;
// Update Clock
if (Update == ON) TimeUpdate();
// Always display time, clockpoint bool defines if dots
// show or not, no need for extra code in TimeUpdate func
if(displayMode==TIME){
Time[4] = minute % 10 + 48;
Time[3] = minute / 10 + 48;
Time[1] = hour % 10 + 48;
Time[0] = hour / 10 + 48;
//if mode is TIME the led is off
draw_text(25, 1, "Time:", 2);
}else{
Time[4] = alarm_minute % 10 + 48;
Time[3] = alarm_minute / 10 + 48;
Time[1] = alarm_hour % 10 + 48;
Time[0] = alarm_hour / 10 + 48;
//if mode is ALARM led is on
draw_text(25, 1, "Alarm:", 2);
}
if(digitalRead(switch1)){
display.drawBitmap(100,-2,epd_bitmap_clk,17,17,WHITE);
}
draw_text(5, 25, Time, 4);
// Button functions
alarmSetBtn.loop();
timeSetBtn.loop();
hourBtn.loop();
minuteBtn.loop();
// Changing time with buttons
incrementHours_Time();
incrementMinute_Time();
// Changing the alarm time with buttons
incrementHours_Alarm();
incrementMinute_Alarm();
//alarm alert with buzzer
alarmalert();
// Making time into the right format
hour%=24;
minute%=60;
alarm_hour%=24;
alarm_minute%=60;
display.display();
}
void draw_text(byte x_pos, byte y_pos, char *text, byte text_size) {
display.setCursor(x_pos, y_pos);
display.setTextSize(text_size);
display.print(text);
}
// Clock functions and Calculations
void TimingISR(){
halfsecond ++;
Update = ON;
if(halfsecond == 2){
second ++;
if(second == 60)
{
minute ++;
if(minute == 60)
{
hour ++;
if(hour == 24)hour = 0;
minute = 0;
}
second = 0;
}
halfsecond = 0;
}
ClockPoint = !ClockPoint;
}
void TimeUpdate(void){
Update = OFF;
}
//Button functions to change time
void incrementHours_Time(){
enum {s0,s1,s2,s3};
static int state=s0;
switch(state)
{
case s0:
if(timeSetBtn.getState()==LOW)
{
state=s1;
displayMode=TIME;
}
break;
case s1:
if(hourBtn.getState()==LOW && timeSetBtn.getState()==LOW)
{
hour++;
pm1=millis();
state=s2;
}
else
{
state=s0;
}
break;
case s2:
if(hourBtn.getState()==LOW && timeSetBtn.getState()==LOW)
{
if((millis()-pm1)>800)
{
pm1=millis();
state=s3;
}
}
else
{
state=s0;
}
break;
case s3:
if(hourBtn.getState()==LOW && timeSetBtn.getState()==LOW)
{
if((millis()-pm1)>250)
{
pm1=millis();
hour++;
}
}
else
{
state=s0;
}
break;
}
}
void incrementMinute_Time(){
enum {s0,s1,s2,s3};
static int state=s0;
switch(state)
{
case s0:
if(timeSetBtn.getState()==LOW)
{
state=s1;
displayMode=TIME;
}
break;
case s1:
if(minuteBtn.getState()==LOW && timeSetBtn.getState()==LOW)
{
minute++;
pm2=millis();
state=s2;
}
else
{
state=s0;
}
break;
case s2:
if(minuteBtn.getState()==LOW && timeSetBtn.getState()==LOW)
{
if((millis()-pm2)>800)
{
pm2=millis();
state=s3;
}
}
else
{
state=s0;
}
break;
case s3:
if(minuteBtn.getState()==LOW && timeSetBtn.getState()==LOW)
{
if((millis()-pm2)>250)
{
pm2=millis();
minute++;
}
}
else
{
state=s0;
}
break;
}
}
//Button functions to change the alarm time
void incrementHours_Alarm(){
enum {s0,s1,s2,s3};
static int state=s0;
switch(state)
{
case s0:
if(alarmSetBtn.getState()==LOW)
{
state=s1;
displayMode=ALARM;
}
break;
case s1:
if(hourBtn.getState()==LOW && alarmSetBtn.getState()==LOW)
{
alarm_hour++;
pm1=millis();
state=s2;
}
else
{
state=s0;
}
break;
case s2:
if(hourBtn.getState()==LOW && alarmSetBtn.getState()==LOW)
{
if((millis()-pm1)>800)
{
pm1=millis();
state=s3;
}
}
else
{
state=s0;
}
break;
case s3:
if(hourBtn.getState()==LOW && alarmSetBtn.getState()==LOW)
{
if((millis()-pm1)>250)
{
pm1=millis();
alarm_hour++;
}
}
else
{
state=s0;
}
break;
}
}
void incrementMinute_Alarm(){
enum {s0,s1,s2,s3};
static int state=s0;
switch(state)
{
case s0:
if(alarmSetBtn.getState()==LOW)
{
state=s1;
displayMode=ALARM;
}
break;
case s1:
if(minuteBtn.getState()==LOW && alarmSetBtn.getState()==LOW)
{
alarm_minute++;
pm2=millis();
state=s2;
}
else
{
state=s0;
}
break;
case s2:
if(minuteBtn.getState()==LOW && alarmSetBtn.getState()==LOW)
{
if((millis()-pm2)>800)
{
pm2=millis();
state=s3;
}
}
else
{
state=s0;
}
break;
case s3:
if(minuteBtn.getState()==LOW && alarmSetBtn.getState()==LOW)
{
if((millis()-pm2)>250)
{
pm2=millis();
alarm_minute++;
}
}
else
{
state=s0;
}
break;
}
}
void alarmalert(){
//if the hour,minute is the same as the alarm hour,minute the switch is in 1 (on alarm)
// put the buzzer in a specific frecuence
if (hour==alarm_hour && minute==alarm_minute && digitalRead(switch1)){
tone(buzzer1,2000);
digitalWrite(rled,HIGH);
}
//if not the same, it return to a neutral state
else{
noTone(buzzer1);
digitalWrite(rled,LOW);
}
}