/*
references: Lesson_23, Lesson_17, https://forum.arduino.cc/t/using-millis-for-timing-a-beginners-guide/483573,
arduino documentation
*/
#include <Keypad.h>
#include <LiquidCrystal.h>
#include "UnorderedMap.h"
using namespace std;
//hardware setup
// set up buzzer
const int BUZZER = 21;
// set up keypad
const byte ROWS = 4;
const byte COLS = 4;
char hexaKeys[ROWS][COLS] =
{
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
byte rowPins[ROWS] = {13, 12, 11, 10};
byte colPins[COLS] = {9, 8, 7, 6};
Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);
// set up lcd
LiquidCrystal lcd(19, 18, 14, 15, 16, 17);
/*
* LCD RS pin to digital pin 19
* LCD Enable pin to digital pin 18
* LCD D4 pin to digital pin 14
* LCD D5 pin to digital pin 15
* LCD D6 pin to digital pin 16
* LCD D7 pin to digital pin 17
* LCD R/W pin to ground
* LCD VSS pin to ground
* LCD VCC pin to 5V
*/
// set up custom variables
bool settingsMode = false;
bool playTone = true;
unsigned int currentMs;
unsigned int startMs;
unsigned int settingsDelayMs = 2000;
int settingsDisplayMode = 1;
UnorderedMap<String, int> toneMap;
// setup methods
void setUpLCD() {
lcd.begin(16, 2);
lcd.clear();
}
void setUpBuzzer() {
pinMode(BUZZER, OUTPUT);
}
void startMonitoring() {
Serial.begin(9600);
}
void setUpToneMap() {
int count = 0;
int tones[] = {100, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700, 750, 800, 850};
for(int i = 0; i<4; i++) {
for(int j = 0; j<4; j++) {
String key = String(hexaKeys[i][j]);
key+="val";
//note: appending val prevents weird behavior.
toneMap.put(key, tones[count]);
count++;
}
}
}
// main methods
void setup() {
setUpBuzzer();
startMonitoring();
setUpLCD();
setUpToneMap();
delay(500);
}
void loop() {
HandleKeyPress();
}
// helper methods
void HandleKeyPress() {
char customKey = customKeypad.getKey();
if (customKey) {
Serial.print("Key pressed: ");
Serial.println(customKey);
PlayTone(customKey);
HandleKeyLogic(customKey);
}
}
void HandleKeyLogic(char customKey) {
if(settingsMode) {
HandleSettings(customKey);
} else
if(!CheckAndRunLetterKeys(customKey)) lcd.print(customKey);
}
bool CheckAndRunLetterKeys(char customKey) {
switch(customKey) {
case 'C':
lcd.clear();
return true;
case 'B':
lcd.noDisplay();
return true;
case 'A':
lcd.display();
return true;
case 'D':
ShowSettings();
return true;
default:
return false;
}
}
void ShowSettings() {
PlaySettingsTone();
settingsMode = true;
startMs = millis();
String options[2] = {"1: Toggle Tone", "2: Exit"};
ClearAndPrint("Settings");
PrintOnRowTwo(options[0]);
settingsDisplayMode = 1;
while(settingsMode) {
currentMs = millis();
if(EnoughTimeHasPassedForSettings()) {
ClearAndPrint("Settings");
PrintOnRowTwo(options[settingsDisplayMode]);
startMs = millis();
if(settingsDisplayMode == 0) settingsDisplayMode++; else settingsDisplayMode--;
}
HandleKeyPress();
}
}
void HandleSettings(char customKey) {
switch(customKey) {
case '1':
ToggleTone();
lcd.setCursor(0,0);
ClearAndPrint("Tone Enabled: ");
PrintOnRowTwo(IsToneEnabled());
startMs = millis(); //wait a moment before displaying menu again
break;
case '2':
settingsMode = false;
lcd.clear();
break;
default:
break;
}
}
void ClearAndPrint(String input) {
lcd.clear();
lcd.print(input);
}
bool EnoughTimeHasPassedForSettings() {
return (currentMs - startMs >= settingsDelayMs);
}
void PrintOnRowTwo(String text) {
lcd.setCursor(0, 1);
lcd.print(text);
}
void PlaySettingsTone() {
tone(BUZZER, 262, 1000);
delay(100);
tone(BUZZER, 587, 1000);
delay(100);
tone(BUZZER, 1319, 100);
}
void PlayTone(char key) {
if(playTone) {
int freq = toneMap.getValue(String(key)+"val");
tone(BUZZER, freq, 500);
}
}
String IsToneEnabled() {
if(playTone) return "True";
else return "False";
}
void ToggleTone() {
if(playTone) playTone = false;
else playTone = true;
}