Use Low-Power library and remove Analog Buttons library.

main
Joshua R. T. Purba 2022-02-06 23:57:37 +07:00
parent 59d043c1c6
commit 0f38115399
3 changed files with 152 additions and 83 deletions

View File

@ -20,4 +20,4 @@ lib_deps =
adafruit/DHT sensor library @ ^1.4.3
adafruit/Adafruit Unified Sensor @ ^1.1.4
teckel12/toneAC @ ^1.5.0
rlogiacco/Analog Buttons @ ^1.2.1
rocketscream/Low-Power @ ^1.81

View File

@ -9,6 +9,8 @@ With modification by Joshua Purba.
#define DEBUGUTILS_H
#ifdef DEBUG
#define DEBUG_SETUP() Serial.begin(9600)
#define DEBUG_TEARDOWN() Serial.end()
#ifndef DEBUG_PRINT
#define DEBUG_PRINT(...) Serial.print(__VA_ARGS__)
#endif
@ -16,11 +18,13 @@ With modification by Joshua Purba.
#define DEBUG_PRINTLN(...) Serial.println(__VA_ARGS__)
#endif
#else
#define DEBUG_SETUP(...) {}
#define DEBUG_TEARDOWN() {}
#ifndef DEBUG_PRINT
#define DEBUG_PRINT(...)
#define DEBUG_PRINT(...) {}
#endif
#ifndef DEBUG_PRINTLN
#define DEBUG_PRINTLN(...)
#define DEBUG_PRINTLN(...) {}
#endif
#ifndef UNUSED
#define UNUSED(v) (void) (v)

View File

@ -1,15 +1,12 @@
//#define DEBUG /* Uncomment this line to enable Serial debug output. */
// #define DEBUG /* Uncomment this line to enable Serial debug output. */
#include <AnalogButtons.h>
#define USE_STANDARD_LCD
#include <LcdMenu.h>
#include <ThreeWire.h>
#include <RtcDS1302.h>
#ifdef DEBUG
#define DHT_DEBUG
#endif
#include <DHT.h>
#include <toneAC.h> /* This means only pin 9 and 10 can be used by the buzzer. */
#include <LowPower.h>
#include "DebugUtil.h"
/* Command key for each button. This signifies which button is currently pressed. */
@ -26,8 +23,6 @@
#define SCREEN_SET_TIME 2 /* Currently executing menu item "Set Time". */
#define SCREEN_SET_ALARM_TIME 3 /* Currently executing menu item "Set Alarm Time". */
#define SCREEN_TRANSITION 250 /* Screen transition delay in millisecond. */
/* Edit positions. Used in SCREEN_SET_TIME and SCREEN_SET_ALARM_TIME. */
#define EDIT_YEAR 0 /* Editing year. */
#define EDIT_MONTH 1 /* Editing month. */
@ -36,13 +31,8 @@
#define EDIT_MINUTE 4 /* Editing minute. */
#define EDIT_SECOND 5 /* Editing second. */
void cbBtnEnter();
void cbBtnLeft();
void cbBtnUp();
void cbBtnDown();
void cbBtnRight();
void cbBtnBack();
void cbBtnNone();
void isrBtn();
void checkButtons();
void cbMenuSetTime();
void cbMenuToggleAlarm(uint8_t);
@ -53,8 +43,11 @@ void screenClock();
void screenMenu();
void screenSetTime();
void screenSetAlarmTime();
void powerDown(period_t);
void screenTransition();
void alarm();
void resetAlarmRun();
void sleep();
void showClock(const RtcDateTime&, uint8_t, uint8_t, uint8_t, uint8_t);
void showDHT();
@ -69,27 +62,13 @@ void restoreAlarm();
uint8_t rollOver(uint8_t, uint8_t, uint8_t, boolean);
#define BTN_HOLD_DURATION 250 /* Button hold duration in millisecond. */
#define BTN_HOLD_INTERVAL 100 /* Button hold interval in millisecond. */
AnalogButtons analogButtons(PIN_A0, INPUT, 1, 26);
Button btnEnter = Button(883, &cbBtnEnter, NULL, BTN_HOLD_DURATION, BTN_HOLD_INTERVAL);
Button btnLeft = Button(738, &cbBtnLeft , NULL, BTN_HOLD_DURATION, BTN_HOLD_INTERVAL);
Button btnUp = Button(584, &cbBtnUp , NULL, BTN_HOLD_DURATION, BTN_HOLD_INTERVAL);
Button btnDown = Button(439, &cbBtnDown , NULL, BTN_HOLD_DURATION, BTN_HOLD_INTERVAL);
Button btnRight = Button(293, &cbBtnRight, NULL, BTN_HOLD_DURATION, BTN_HOLD_INTERVAL);
Button btnBack = Button(144, &cbBtnBack , NULL, BTN_HOLD_DURATION, BTN_HOLD_INTERVAL);
/* alarmOn and alarmOff is only to prevent the compiler warning: ISO C++ forbids converting a string constant to 'char*' */
char alarmOn[] = "Yes";
char alarmOff[] = "No";
String alarmRunStr[] = { "1m", "5m", "10m", "15m" }; /* Array of allowable alarm runs (displayed in menu). */
uint8_t alarmRunMin[] = { 1, 5, 10, 15 }; /* Array of allowable alarm runs (actual minutes). */
MenuItem mainMenu[] = {
ItemHeader(),
ItemCommand("Date/Time", cbMenuSetTime),
ItemToggle("Alarm", alarmOn, alarmOff, cbMenuToggleAlarm),
ItemToggle("Alarm", "Yes", "No", cbMenuToggleAlarm),
ItemCommand("Alarm Time", cbMenuSetAlarm),
ItemList("Alarm Run", alarmRunStr, 4, cbMenuSetAlarmDuration),
ItemFooter()
@ -98,6 +77,8 @@ MenuItem mainMenu[] = {
#define LCD_ROWS 2
#define LCD_COLS 16
extern volatile unsigned long timer0_millis; /* DHT11 depends on millis(). */
volatile boolean btnPressed = false;
LcdMenu menu(LCD_ROWS, LCD_COLS);
ThreeWire rtcWire(7, 8, 6); // DAT, CLK, RST
RtcDS1302<ThreeWire> rtc(rtcWire);
@ -105,6 +86,7 @@ RtcDateTime clockTime; /* The currently displayed clock time. */
uint8_t prevSec = 61; /* Pick a value that's not 0 to 60. */
uint8_t cmdKey = CMD_IGNORE; /* Which button is currently pressed. */
uint8_t currScreen = SCREEN_CLOCK; /* Which screen is currenly active. */
boolean screenInTransit = false; /* Flag that the screen transition is in progress, so do not sleep. */
boolean editTimeInit = false; /* Is editTime already initialized? */
RtcDateTime editTime; /* The time shown when in SCREEN_SET_TIME and SCREEN_SET_ALARM_TIME mode. */
boolean alarmActive = false; /* Whether the alarm is currently sounding or not. */
@ -119,16 +101,14 @@ LiquidCrystal* lcd = NULL; /* Hold reference to menu.lcd .*/
#define DHT11_INIT 255 /* Value outside DHT11 range (and also not NaN) to signify "please read the sensor value". */
DHT dht(PIN_A2, DHT11);
DHT dht(A1, DHT11);
float temperature = DHT11_INIT;
float humidity = DHT11_INIT;
void setup() {
#ifdef DEBUG
Serial.begin(115200, SERIAL_8N1);
#endif
DEBUG_SETUP();
menu.setupLcdWithMenu(12, 11, 5, 4, 3, 2, mainMenu);
menu.setupLcdWithMenu(5, 4, 11, 12, A2, A3, mainMenu);
menu.hide();
lcd = menu.lcd;
@ -144,17 +124,29 @@ void setup() {
dht.begin();
analogButtons.add(btnEnter);
analogButtons.add(btnLeft);
analogButtons.add(btnUp);
analogButtons.add(btnDown);
analogButtons.add(btnRight);
analogButtons.add(btnBack);
pinMode(2, INPUT);
attachInterrupt(digitalPinToInterrupt(2), isrBtn, RISING);
pinMode(13, OUTPUT);
digitalWrite(13, LOW);
pinMode(A4, OUTPUT);
digitalWrite(A4, HIGH);
pinMode(A5, OUTPUT);
digitalWrite(A5, HIGH);
pinMode(A6, OUTPUT);
digitalWrite(A6, HIGH);
pinMode(A7, OUTPUT);
digitalWrite(A7, HIGH);
}
void loop() {
sleep();
checkButtons();
clockTime = rtc.GetDateTime(); /* Used by the clock display and the alarm trigger. */
analogButtons.check();
if (currScreen == SCREEN_CLOCK) {
screenClock();
} else if (currScreen == SCREEN_MENU) {
@ -168,47 +160,51 @@ void loop() {
cmdKey = CMD_IGNORE; /* Must be reset at the end of each loop to prevent button press "lock". */
}
/* Callback when the user pressed the ENTER button. */
void cbBtnEnter() {
cmdKey = CMD_ENTER;
DEBUG_PRINTLN(F("Pressed ENTER"));
void isrBtn() {
btnPressed = true;
digitalWrite(LED_BUILTIN, HIGH);
}
/* Callback when the user pressed the LEFT button. */
void cbBtnLeft() {
cmdKey = CMD_LEFT;
DEBUG_PRINTLN(F("Pressed LEFT"));
}
/* Callback when the user pressed the UP button. */
void cbBtnUp() {
cmdKey = CMD_UP;
DEBUG_PRINTLN(F("Pressed UP"));
}
/* Callback when the user pressed the DOWN button. */
void cbBtnDown() {
cmdKey = CMD_DOWN;
DEBUG_PRINTLN(F("Pressed DOWN"));
}
/* Callback when the user pressed the RIGHT button. */
void cbBtnRight() {
cmdKey = CMD_RIGHT;
DEBUG_PRINTLN(F("Pressed RIGHT"));
}
/* Callback when the user pressed the BACK button. */
void cbBtnBack() {
cmdKey = CMD_BACK;
DEBUG_PRINTLN(F("Pressed BACK"));
void checkButtons() {
if (btnPressed) {
const int val = analogRead(A0);
if (val >= 1000 && val <= 1023) {
cmdKey = CMD_ENTER;
DEBUG_PRINTLN(F("ENTER"));
} else if (val >= 910 && val <= 930) {
cmdKey = CMD_LEFT;
DEBUG_PRINTLN(F("LEFT"));
} else if (val >= 810 && val <= 830) {
cmdKey = CMD_UP;
DEBUG_PRINTLN(F("UP"));
} else if (val >= 710 && val <= 730) {
cmdKey = CMD_DOWN;
DEBUG_PRINTLN(F("DOWN"));
} else if (val >= 620 && val <= 640) {
cmdKey = CMD_RIGHT;
DEBUG_PRINTLN(F("RIGHT"));
} else if (val >= 530 && val <= 555) {
cmdKey = CMD_BACK;
DEBUG_PRINTLN(F("BACK"));
} else {
cmdKey = CMD_IGNORE;
DEBUG_PRINT(F("Button value = "));
DEBUG_PRINT(val);
DEBUG_PRINTLN();
}
btnPressed = false;
digitalWrite(LED_BUILTIN, LOW);
} else {
cmdKey = CMD_IGNORE;
}
screenInTransit = false;
}
/* Callback when the user activates the "Set Time" menu item. */
void cbMenuSetTime() {
menu.hide();
currScreen = SCREEN_SET_TIME;
delay(SCREEN_TRANSITION);
screenTransition();
}
/* Callback when the user toggles the "Alarm" enable/disable menu item. */
@ -227,7 +223,7 @@ void cbMenuToggleAlarm(const uint8_t yesNo) {
void cbMenuSetAlarm() {
menu.hide();
currScreen = SCREEN_SET_ALARM_TIME;
delay(SCREEN_TRANSITION);
screenTransition();
}
/* Callback when the user commits (pressed ENTER) the alarm duration in the menu system. */
@ -246,7 +242,7 @@ void screenClock() {
if (cmdKey == CMD_ENTER) {
currScreen = SCREEN_MENU;
lcd->clear(); /* Only necessary to make the transition uniform. */
delay(SCREEN_TRANSITION);
screenTransition();
menu.show();
return;
} else if (cmdKey == CMD_BACK) {
@ -285,7 +281,7 @@ void screenMenu() {
temperature = DHT11_INIT; /* If not reset, it will not be redrawn. */
humidity = DHT11_INIT; /* If not reset, it will not be redrawn. */
currScreen = SCREEN_CLOCK;
delay(SCREEN_TRANSITION);
screenTransition();
} else if (cmdKey == CMD_UP) {
DEBUG_PRINTLN(F("Menu UP"));
resetAlarmRun();
@ -314,7 +310,7 @@ void screenSetTime() {
editChanged = false;
currScreen = SCREEN_MENU;
lcd->clear(); /* Only necessary to make the transition uniform. */
delay(SCREEN_TRANSITION);
screenTransition();
menu.show();
return;
}
@ -461,7 +457,7 @@ void screenSetAlarmTime() {
editChanged = false;
currScreen = SCREEN_MENU;
lcd->clear(); /* Only necessary to make the transition uniform. */
delay(SCREEN_TRANSITION);
screenTransition();
menu.show();
return;
}
@ -512,6 +508,40 @@ void screenSetAlarmTime() {
}
}
void powerDown(period_t period) {
unsigned long addMillis;
if (period == SLEEP_15MS) { addMillis = 15; }
else if (period == SLEEP_30MS) { addMillis = 30; }
else if (period == SLEEP_60MS) { addMillis = 60; }
else if (period == SLEEP_120MS) { addMillis = 120; }
else if (period == SLEEP_250MS) { addMillis = 250; }
else if (period == SLEEP_500MS) { addMillis = 500; }
else if (period == SLEEP_1S) { addMillis = 1000; }
else if (period == SLEEP_2S) { addMillis = 2000; }
else if (period == SLEEP_4S) { addMillis = 4000; }
else if (period == SLEEP_8S) { addMillis = 8000; }
else if (period == SLEEP_FOREVER) { addMillis = 0; }
if (addMillis > 0) {
DEBUG_PRINT(F("Sleep for "));
DEBUG_PRINT(addMillis)
DEBUG_PRINTLN(F(" ms"));
} else {
DEBUG_PRINTLN(F("Sleep forever"));
}
DEBUG_TEARDOWN();
LowPower.powerDown(period, ADC_OFF, BOD_OFF);
const uint8_t oldSREG = SREG;
cli();
timer0_millis += addMillis; /* Ensure DHT11 behaves. */
SREG = oldSREG;
DEBUG_SETUP();
}
void screenTransition() {
powerDown(SLEEP_60MS);
screenInTransit = true;
}
/*
Start the alarm according to the alarmEnabled, alarmHour, and alarmMinute settings.
The alarm tone is played continuously until the user stopped the alarm, or the alarm runtime is over.
@ -520,7 +550,7 @@ void alarm() {
boolean stopAlarm = false;
const unsigned long now = millis();
if (alarmEnabled) {
if (clockTime.Hour() == alarmHour && clockTime.Minute() == alarmMinute && clockTime.Second() >= 00 && clockTime.Second() <= 1) {
if (!alarmActive && clockTime.Hour() == alarmHour && clockTime.Minute() == alarmMinute && clockTime.Second() >= 00 && clockTime.Second() <= 1) {
alarmActive = true;
alarmActiveStart = now;
DEBUG_PRINTLN(F("Alarm start"));
@ -551,6 +581,41 @@ void alarm() {
}
}
void sleep() {
if (alarmActive || screenInTransit) {
return;
}
RtcDateTime alarmStart = RtcDateTime(clockTime.Year(), clockTime.Month(), clockTime.Day(), alarmHour, alarmMinute, 0);
if (clockTime > alarmStart) {
alarmStart = RtcDateTime(alarmStart.TotalSeconds() + (((uint32_t) 24) * ((uint32_t) 60) * ((uint32_t) 60)));
}
const uint32_t as = alarmStart.TotalSeconds();
const uint32_t c = clockTime.TotalSeconds();
period_t period;
if (currScreen == SCREEN_CLOCK) {
if (c + 2 <= as) {
period = SLEEP_1S;
} else {
period = SLEEP_250MS;
}
} else {
if (c + 9 <= as) {
period = SLEEP_8S;
} else if (c + 5 <= as) {
period = SLEEP_4S;
} else if (c + 3 <= as) {
period = SLEEP_2S;
} else if (c + 2 <= as) {
period = SLEEP_1S;
} else {
period = SLEEP_250MS;
}
}
powerDown(period);
}
/*
Reset the menu if the selected alarm position is not committed yet.
Resetting is necessary because the menu system has no indication for committed/uncommitted list position.