/**
Arduino Calculator
Copyright (C) 2020, Uri Shaked.
Released under the MIT License.
*/
/* Hello Wokwi! */
#include <Keypad.h>
#include <TM1637Display.h>
#include <LiquidCrystal_I2C.h>
#define CLOCK 0
#define SET_TIMER 1
#define COOKING 2
#define SET_MEAL 3
#define SET_DATE 4
#define SET_TIME 5
#define ERROR_MODE 6
#define STOP 6
#define MEAL_QTY 9
#define RELAY0 7
// Global variables
uint8_t mode;
uint8_t meal;
uint8_t timer_str_index;
uint32_t cookingTime;
uint32_t remaingTime;
uint32_t initial_time;
uint32_t timer_seconds = 0;
uint32_t timer_minutes = 0;
String timer_seconds_str= "";
String timer_minutes_str= "";
/* Keypad setup */
const byte KEYPAD_ROWS = 4;
const byte KEYPAD_COLS = 4;
byte rowPins[KEYPAD_ROWS] = {5, 4, 3, 2};
byte colPins[KEYPAD_COLS] = {A3, A2, A1, A0};
char keys[KEYPAD_ROWS][KEYPAD_COLS] = {
{'1', '2', '3', 'M'},
{'4', '5', '6', '-'},
{'7', '8', '9', '*'},
{'C', '0', 'S', 'T'}
};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, KEYPAD_ROWS, KEYPAD_COLS);
String memory = "";
String current = "";
/*
Rice 1-2
Fish ½ – 2
Chicken 10-15
Beef 20-30
Pasta 10-15
Pizza 8-10
Potatoes 5-7
Cooked Vegetables 1-3
Milk 5-10
*/
char *meal2str(uint8_t meal, char *psz, uint8_t len)
{
static const __FlashStringHelper* str[] =
{
F("Rice"), F("Fish"), F("Chicken"), F("Beef"),
F("Pasta"), F("Pizza"), F("Potatoes"), F("Cooked Vegetables"),
F("Milk")
};
strncpy_P(psz, (const char PROGMEM *)str[meal - 1], len);
psz[len] = '\0';
return (psz);
}
uint32_t getMealCookTime(uint8_t meal){
switch (meal) {
case 1:
return 1.5*60*1000L;
case 2:
return 1*60*1000L;
case 3:
return 12.5*60*1000L;
case 4:
return 25*60*1000L;
case 5:
return 12.5*60*1000L;
case 6:
return 9*60*1000L;
case 7:
return 6*60*1000L;
case 8:
return 2*60*1000L;
case 9:
return 7*60*1000L;
case 0:
return 1.5*60*1000L;
}
};
uint64_t value = 0;
// These are for the clock
#define DS1307_ADDRESS 0x68
#define TIMEDHT 1000
#define MAX_MESG 20
// Global variables
uint8_t wday, mday, month, year;
uint8_t hours, minutes, seconds;
char szMesg[MAX_MESG + 1] = "";
char szTime[9]; // mm:ss\0
uint8_t clear = 0x00;
uint32_t timerDHT = TIMEDHT;
LiquidCrystal_I2C lcd(0x27, 20, 4);
// Module connection pins (Digital Pins)
#define CLK 9
#define DIO 8
// The amount of time (in milliseconds) between tests
#define TEST_DELAY 2000
const uint8_t SEG_DONE[] = {
SEG_B | SEG_C | SEG_D | SEG_E | SEG_G, // d
SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F, // O
SEG_C | SEG_E | SEG_G, // n
SEG_A | SEG_D | SEG_E | SEG_F | SEG_G // E
};
TM1637Display display(CLK, DIO);
uint8_t data[] = { 0xff, 0xff, 0xff, 0xff };
uint8_t blank[] = { 0x00, 0x00, 0x00, 0x00 };
void getTimer(uint32_t time, char *psz, bool f = true)
{
uint8_t *arr;
timer_minutes = time/60000L;
//timer_seconds = (time/1000)%60;
timer_seconds= time/1000 - (timer_minutes * 60L);
//timer_seconds=5L;
arr=(uint8_t*) &timer_minutes;
minutes = arr[0];
arr=(uint8_t*) &timer_seconds;
seconds= arr[0];
//sprintf(psz, "%02d%c%02d", timer_minutes, (f ? ':' : ' '), timer_seconds);
sprintf(psz, "%02d%c%02d", minutes, (f ? ':' : ' '), seconds);
//sprintf(psz,"%.2x%.2x%2.x%.2x",arr[0],arr[1],arr[2],arr[3]);
}
int getDisplayTime(uint32_t time)
{
timer_minutes = time/60000L;
//timer_seconds = (time/1000)%60;
timer_seconds = time/1000 - (timer_minutes * 60L);
return (int)(timer_minutes * 100 + timer_seconds);
}
void beginDS1307()
{
// Read the values (date and time) of the DS1307 module
Wire.beginTransmission(DS1307_ADDRESS);
Wire.write(clear);
Wire.endTransmission();
Wire.requestFrom(DS1307_ADDRESS, 0x07);
seconds = bcdToDec(Wire.read());
minutes = bcdToDec(Wire.read());
hours = bcdToDec(Wire.read() & 0xff);
wday = bcdToDec(Wire.read());
mday = bcdToDec(Wire.read());
month = bcdToDec(Wire.read());
year = bcdToDec(Wire.read());
}
uint8_t decToBcd(uint8_t value)
{
return ((value / 10 * 16) + (value % 10));
}
uint8_t bcdToDec(uint8_t value)
{
return ((value / 16 * 10) + (value % 16));
}
// Code for reading clock time
void getTime(char *psz, bool f = true)
{
sprintf(psz, "%02d%c%02d", hours, (f ? ':' : ' '), minutes);
}
// Code for reading clock date
void getDate(char *psz)
{
char szBuf[10];
sprintf(psz, "%d %s %04d", mday , mon2str(month, szBuf, sizeof(szBuf) - 1), (year + 2000));
}
// Get a label from PROGMEM into a char array
char *mon2str(uint8_t mon, char *psz, uint8_t len)
{
static const __FlashStringHelper* str[] =
{
F("Ene"), F("Feb"), F("Mar"), F("Abr"),
F("May"), F("Jun"), F("Jul"), F("Ago"),
F("Sep"), F("Oct"), F("Nov"), F("Dic")
};
strncpy_P(psz, (const char PROGMEM *)str[mon - 1], len);
psz[len] = '\0';
return (psz);
}
char *dow2str(uint8_t code, char *psz, uint8_t len)
{
static const __FlashStringHelper* str[] =
{
F("Dom "), F("Lun "), F("Mar "),
F("Mie "), F("Jue "), F("Vie "),
F("Sab ")
};
strncpy_P(psz, (const char PROGMEM *)str[code - 1], len);
psz[len] = '\0';
return (psz);
}
void setup() {
lcd.init();
lcd.backlight();
lcd.setCursor(1, 0);
lcd.print("Hello, Wokwi!");
Wire.begin();
pinMode(RELAY0, OUTPUT);
}
void processInput(char key) {
switch (key) {
case 'S':
if (mode==SET_TIMER || mode==SET_MEAL)
{
cookingTime= millis() + initial_time;
mode=COOKING;
digitalWrite(RELAY0, HIGH);
delay(1000);
}
else if (mode==STOP)
{
cookingTime= millis() + remaingTime;
mode=COOKING;
digitalWrite(RELAY0, HIGH);
delay(1000);
}
else if (mode==COOKING)
{
mode=STOP;
digitalWrite(RELAY0, LOW);
delay(1000);
}
return;
case 'T':
if(mode ==CLOCK)
{
lcd.clear();
mode=SET_DATE;
lcd.setCursor(0, 0);
lcd.print("Set dd/mm/aaaa:");
timer_str_index=1;
}
return;
case 'C':
lcd.clear();
mode=CLOCK;
//Desactivar rele
return;
case 'M':
if(mode ==CLOCK)
{
mode=SET_MEAL;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Select a meal:");
lcd.setCursor(0, 1);
meal=1;
meal2str(meal, szMesg, MAX_MESG);
lcd.print(szMesg);
initial_time=getMealCookTime(meal);
return;
}
else if(mode ==SET_MEAL)
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Select a meal:");
lcd.setCursor(0, 1);
meal=1+meal%MEAL_QTY;
meal2str(meal, szMesg, MAX_MESG);
lcd.print(szMesg);
initial_time=getMealCookTime(meal);
return;
}
else
{
return;
}
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '0':
if(mode ==CLOCK)
{
timer_str_index=1;
mode=SET_TIMER;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Select min:sec");
lcd.setCursor(8, 1);
timer_seconds_str="0"+String(key);
timer_minutes_str="00";
current=timer_minutes_str+":"+timer_seconds_str;
lcd.print(current);
initial_time=timer_seconds_str.toInt()*1000L+timer_minutes_str.toInt()*60000L;
data[0] = display.encodeDigit(0);
data[1] = display.encodeDigit(0);
data[2] = display.encodeDigit(0);
data[3] = display.encodeDigit(key);
display.setSegments(data);
return;
}
if(mode ==SET_TIMER)
{
//.toInt()
//.substring(14,18)
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Timer min:sec");
if(timer_str_index==1)
{
/*
if('6' == key || '7' == key || '8' == key || '9' == key)
{
}
else
{
timer_seconds_str.setCharAt(0, timer_seconds_str.charAt(1));
timer_seconds_str.setCharAt(1, key);
timer_str_index++;
}
*/
timer_seconds_str.setCharAt(0, timer_seconds_str.charAt(1));
timer_seconds_str.setCharAt(1, key);
data[0] = display.encodeDigit(0);
data[1] = display.encodeDigit(0);
data[2] = display.encodeDigit(timer_seconds_str.charAt(0));
data[3] = display.encodeDigit(key);
display.setSegments(data);
timer_str_index++;
}
else if(timer_str_index==2)
{
timer_minutes_str.setCharAt(1, timer_seconds_str.charAt(0));
timer_seconds_str.setCharAt(0, timer_seconds_str.charAt(1));
timer_seconds_str.setCharAt(1, key);
timer_str_index++;
data[0] = display.encodeDigit(0);
data[1] = display.encodeDigit(timer_minutes_str.charAt(1));
data[2] = display.encodeDigit(timer_seconds_str.charAt(0));
data[3] = display.encodeDigit(key);
display.setSegments(data);
}
else if(timer_str_index==3)
{
/*
if('6' == key || '7' == key || '8' == key || '9' == key)
{
}
else
{
timer_minutes_str.setCharAt(0, timer_minutes_str.charAt(1));
timer_minutes_str.setCharAt(1, timer_seconds_str.charAt(0));
timer_seconds_str.setCharAt(0, timer_seconds_str.charAt(1));
timer_seconds_str.setCharAt(1, key);
timer_str_index++;
}
*/
timer_minutes_str.setCharAt(0, timer_minutes_str.charAt(1));
timer_minutes_str.setCharAt(1, timer_seconds_str.charAt(0));
timer_seconds_str.setCharAt(0, timer_seconds_str.charAt(1));
timer_seconds_str.setCharAt(1, key);
timer_str_index++;
data[0] = display.encodeDigit(timer_minutes_str.charAt(0));
data[1] = display.encodeDigit(timer_minutes_str.charAt(1));
data[2] = display.encodeDigit(timer_seconds_str.charAt(0));
data[3] = display.encodeDigit(key);
display.setSegments(data);
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Select min:sec");
lcd.setCursor(8, 1);
current=timer_minutes_str+":"+timer_seconds_str;
lcd.print(current);
initial_time=timer_seconds_str.toInt()*1000L+timer_minutes_str.toInt()*60000L;
return;
}
if(mode==SET_DATE)
{
if(timer_str_index==1)
{
if(key >= '4')
{
return;
}
current=String(key);
timer_str_index++;
}
else if(timer_str_index==2)
{
if((current.charAt(0)=='3' && key>='2')||(current.charAt(0)=='0' && key=='0'))
return;
current+=String(key)+"/";
timer_str_index++;
}
else if(timer_str_index==3)
{
if(key >= '2')
{
return;
}
current+=String(key);
timer_str_index++;
}
else if(timer_str_index==4)
{
if((current.charAt(3)=='1' && key>='3')||(current.charAt(3)=='0' && key=='0'))
return;
current+=String(key)+"/20";
timer_str_index++;
}
else if(timer_str_index==5)
{
current+=String(key);
timer_str_index++;
}
else if(timer_str_index==6)
{
current+=String(key);
mode=SET_TIME;
timer_str_index=1;
lcd.clear();
lcd.setCursor(4, 0);
lcd.print(current);
lcd.setCursor(0, 1);
lcd.print("Set hh/mm/ss");
mode=SET_TIME;
return;
}
lcd.setCursor(4, 1);
lcd.print(current);
return;
}
if(mode==SET_TIME)
{
if(timer_str_index==1)
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Set hh:mm:ss");
if(key >= '3')
{
return;
}
current=String(key);
timer_str_index++;
}
else if(timer_str_index==2)
{
if(current.charAt(0)=='2' && key>='4')
return;
current+=String(key)+":";
timer_str_index++;
}
else if(timer_str_index==3)
{
if(key >= '6')
{
return;
}
current+=String(key);
timer_str_index++;
}
else if(timer_str_index==4)
{
if(current.charAt(3)=='1' && key>='3')
return;
current+=String(key)+":";
timer_str_index++;
}
else if(timer_str_index==5)
{
if(key >= '6')
{
return;
}
current+=String(key);
timer_str_index++;
}
else if(timer_str_index==6)
{
current+=String(key);
mode=CLOCK;
lcd.clear();
return;
}
lcd.setCursor(4, 1);
lcd.print(current);
return;
}
}
}
void loop() {
display.setBrightness(0x0f);
// All segments on
//display.setSegments(SEG_DONE);
////delay(TEST_DELAY);
// Selectively set different digits
static uint32_t lastTime = 0; // Memory (ms)
//static uint8_t display = 0; // Current display mode
static bool flasher = false; // Seconds passing flasher
char key = keypad.getKey();
if (key) {
processInput(key);
}
if(mode==CLOCK)
{
digitalWrite(RELAY0, LOW); // turn the BULB on (HIGH is the voltage level)
delay(1000); // wait for a second
lcd.setCursor(0, 0);
//lcd.print(millis() / 1000);
dow2str(wday, szMesg, MAX_MESG);
lcd.print(szMesg);
lcd.setCursor(5, 0);
getDate(szMesg);
lcd.print(szMesg);
lcd.setCursor(7, 1);
beginDS1307();
if ((millis() - lastTime) >= 1000)
{
lastTime = millis();
getTime(szMesg, flasher);
flasher = !flasher;
lcd.print(szMesg);
}
}
else if(mode==COOKING)
{
remaingTime=cookingTime - millis();
if (remaingTime <= 1000)
{
digitalWrite(RELAY0, LOW); // turn the BULB on (HIGH is the voltage level)
delay(1000);
mode=CLOCK;
display.setSegments(SEG_DONE);
}
else
{
if ((millis() - lastTime) >= 1000)
{
lastTime = millis();
getTimer(remaingTime,szMesg, flasher);
flasher = !flasher;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Cooking...");
lcd.setCursor(7, 1);
lcd.print(szMesg);
// Create time format to display
int displaytime = getDisplayTime(remaingTime);
// display.showNumberDec(displaytime, true);
int seconds, minutes, showtime;
//seconds = (remaingTime/1000L % 60); // To display the countdown in mm:ss format
//minutes = ((NewTime / 60) % 60 );
minutes = remaingTime/60000L;
//timer_seconds = (time/1000)%60;
seconds = remaingTime/1000 - (minutes * 60L); //separate CountTime in two parts
display.showNumberDecEx(seconds, 0, true, 2, 2);
display.showNumberDecEx(minutes, 0b11100000, true, 2, 0);
//showtime= minutes*100+seconds;
//display.showNumberDec(showtime, flasher); // Display the seconds in the last two places
//display.showNumberDec(minutes, 0b11100000, true, 2, 0);
//display.showNumberDec(1301, true); // Expect: 0301
}
}
}
else if(mode==STOP)
{
lcd.setCursor(0, 0);
lcd.print("Paused...");
}
}