#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <OneWire.h>
#include <DallasTemperature.h>
LiquidCrystal_I2C lcd(0x27,16,2);
OneWire oneWire(A1);
DallasTemperature sensors(&oneWire);
#define LED_RED 6
#define LED_GREEN 5
#define LED_BLUE 3
#define RED_BUTTON 2
#define GREEN_BUTTON 4
#define ENCODERA 8
#define ENCODERB 9
#define DEBOUNCING_PERIOD 100
int pointer = 0;
int subPointer = 0;
const char *menuOptions[] = {"LED options", "Display", "Temperature", "About"};
const char *submenu1[] = {"Power", "Red", "Green", "Blue"};
const char *submenu2[] = {"Backlight", "Selector"};
const char *submenu3[] = {"SensorIN", "SensorOUT", "Units"};
const char *submenu4[] = {"Clemens", "Theisen"};
char **submenu[] = {submenu1, submenu2, submenu3, submenu4};
int submenuLengths[] = {sizeof(submenu1)/sizeof(submenu1[0]),
sizeof(submenu2)/sizeof(submenu2[0]),
sizeof(submenu3)/sizeof(submenu3[0]),
sizeof(submenu4)/sizeof(submenu4[0])
};
//interrupt
volatile int counter = 0;
volatile long lastInterruptTime = 0;
volatile int change = 0;
int currentStateA;
bool counterModified = false;
void setupPCI(){
//Here we activate pin change interruptions on pin A2
PCICR |= (1 << PCIE0); //enable PCMSK0 scan
PCMSK0 |= (1 << PCINT0); //Pin 8 interrupt. Set pin 8 to trigger an interrupt on state change.
}
//LED properties
bool LEDPower;
int LEDIntensity[] = {100, 100, 100};
//Display Properties
bool backlight;
byte customSelector[8] = {
B00000,
B00100,
B01110,
B11111,
B01110,
B00100,
B00000,
B00000
};
unsigned char selectors[] = {B00111110, B01111110, 0};
int selectorPointer = 0;
//temperature properties
bool celsius = true;
int tempIN = 25;
int tempOUT = 19;
int tempINF = 77;
int tempOUTF = 66;
unsigned long lastChangeTimestamp = 0UL;
int lastEnA = LOW;
void initLCD()
{
lcd.init();
lcd.clear();
lcd.backlight();
}
void initRGB()
{
pinMode(LED_RED, OUTPUT);
pinMode(LED_GREEN, OUTPUT);
pinMode(LED_BLUE, OUTPUT);
}
void initButtons()
{
pinMode(RED_BUTTON, INPUT_PULLUP);
pinMode(GREEN_BUTTON, INPUT_PULLUP);
}
void initEncoder()
{
pinMode(ENCODERA, INPUT_PULLUP);
pinMode(ENCODERB, INPUT_PULLUP);
}
/*int getEncoderChange(){
int currentChange = 0;
noInterrupts();
if(counterModified){
counterModified = false;
currentChange = change;
}
interrupts();
return currentChange;
}*/
void scrollMenu(int change){
pointer = (pointer + change + 4) % 4;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("MENU");
lcd.setCursor(0, 1);
lcd.print(pointer + 1);
lcd.setCursor(1, 1);
lcd.write(selectors[selectorPointer]);
lcd.setCursor(2, 1);
lcd.print(menuOptions[pointer]);
}
void scrollSubmenu(int change){
int menuLength = submenuLengths[pointer];
subPointer = (subPointer + change + menuLength) % menuLength;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(menuOptions[pointer]);
lcd.setCursor(0, 1);
lcd.print(subPointer + 1);
lcd.setCursor(1, 1);
lcd.write(selectors[selectorPointer]);
lcd.setCursor(2, 1);
lcd.print(submenu[pointer][subPointer]);
showOption();
}
void updateLED(){
if(LEDPower){
analogWrite(LED_RED, LEDIntensity[0]);
analogWrite(LED_GREEN, LEDIntensity[1]);
analogWrite(LED_BLUE, LEDIntensity[2]);
} else {
analogWrite(LED_RED, 0);
analogWrite(LED_GREEN, 0);
analogWrite(LED_BLUE, 0);
}
}
void openLEDIntensityOption(){
lcd.setCursor(1, 1);
lcd.write(B00100011);
int redB = digitalRead(RED_BUTTON);
int value = LEDIntensity[subPointer - 1];
while(redB == HIGH){
int encoderChange = getEncoderChange();
if(encoderChange != 0){
int newIntensity = value - encoderChange * 10;
if(newIntensity >= 0 && newIntensity <= 254){
value = newIntensity;
lcd.setCursor(10, 1);
lcd.print(" ");
lcd.setCursor(10, 1);
lcd.print(value);
}
}
int greenB = digitalRead(GREEN_BUTTON);
if(greenB == LOW){
LEDIntensity[subPointer - 1] = value;
updateLED();
break;
}
redB = digitalRead(RED_BUTTON);
}
}
void updateBacklight(){
if(backlight){
lcd.backlight();
return;
}
lcd.noBacklight();
}
void showOption(){
switch (pointer) {
case 3:
return;
case 0:
switch (subPointer) {
case 0:
lcd.setCursor(10, 1);
if(LEDPower){
lcd.print("ON");
} else {
lcd.print("OFF");
}
break;
default:
lcd.setCursor(10, 1);
lcd.print(LEDIntensity[subPointer - 1]);
}
break;
case 1:
switch (subPointer) {
case 0:
lcd.setCursor(12, 1);
if(backlight){
lcd.print("ON");
} else {
lcd.print("OFF");
}
break;
default:
lcd.setCursor(11, 1);
lcd.write(selectors[0]);
lcd.setCursor(13, 1);
lcd.write(selectors[1]);
lcd.setCursor(15, 1);
lcd.write(selectors[2]);
}
break;
default:
switch (subPointer) {
case 0:
lcd.setCursor(12, 1);
if(celsius){
lcd.print(tempIN);
lcd.write(B11011111);
lcd.write(B01000011);
} else {
lcd.print(tempINF);
lcd.write(B11011111);
lcd.write(B01000110);
}
break;
case 1:
lcd.setCursor(12, 1);
if(celsius){
lcd.print(tempOUT);
lcd.write(B11011111);
lcd.write(B01000011);
} else {
lcd.print(tempOUTF);
lcd.write(B11011111);
lcd.write(B01000110);
}
break;
default:
lcd.setCursor(10, 1);
if(celsius){
lcd.write(B11011111);
lcd.write(B01000011);
} else {
lcd.write(B11011111);
lcd.write(B01000110);
}
}
}
}
void openOption(){
delay(50);
int greenB = digitalRead(GREEN_BUTTON);
while(greenB == LOW){
greenB = digitalRead(GREEN_BUTTON);
}
switch (pointer) {
case 3:
return;
case 0:
switch (subPointer) {
case 0:
LEDPower = !LEDPower;
updateLED();
break;
default:
openLEDIntensityOption();
}
break;
case 1:
switch (subPointer) {
case 0:
backlight = !backlight;
updateBacklight();
break;
default:
selectorPointer = (selectorPointer + 4) % 3;
}
break;
default:
switch (subPointer) {
case 0:
break;
case 1:
break;
default:
celsius = !celsius;
}
}
delay(100);
int redB = digitalRead(RED_BUTTON);
while(redB == LOW){
redB = digitalRead(RED_BUTTON);
}
scrollSubmenu(0);
}
void openSubmenu(){
subPointer = 0;
scrollSubmenu(0);
int redB = digitalRead(RED_BUTTON);
while(redB == HIGH){
int encoderChange = getEncoderChange();
if(encoderChange != 0){
scrollSubmenu(encoderChange);
}
redB = digitalRead(RED_BUTTON);
int greenB = digitalRead(GREEN_BUTTON);
if(greenB == LOW){
openOption();
}
}
scrollMenu(0);
}
void setup()
{
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(9600);
lcd.setCursor(0, 1);
lcd.begin(16, 2);
lcd.createChar(0, customSelector);
setupPCI();
initLCD();
initRGB();
initButtons();
LEDPower = true;
backlight = true;
updateLED();
scrollMenu(0);
}
void loop()
{int redB = digitalRead(RED_BUTTON);
int greenB = digitalRead(GREEN_BUTTON);
int encoderChange = getEncoderChange();
if(encoderChange != 0){
scrollMenu(encoderChange);
}
if(greenB == LOW){
delay(DEBOUNCING_PERIOD);
while(greenB == LOW){
greenB = digitalRead(GREEN_BUTTON);
};
openSubmenu();
}
}
int getEncoderChange(){
int enA = digitalRead(ENCODERA);
int enB = digitalRead(ENCODERB);
unsigned long timestamp = millis();
if (enA == LOW && lastEnA == HIGH && timestamp > lastChangeTimestamp + DEBOUNCING_PERIOD){
lastEnA = enA;
if (enB == HIGH){
return -1;
}
else{
return 1;
}
lastChangeTimestamp = timestamp;
}
lastEnA = enA;
return 0;
}
ISR(PCINT0_vect){
currentStateA = digitalRead(ENCODERA);
if(currentStateA != LOW)
return;
noInterrupts();
unsigned long interruptTime = millis();
if(interruptTime - lastInterruptTime > DEBOUNCING_PERIOD){
if(digitalRead(ENCODERB) == LOW)
change = 1;
else
change = -1 ;
lastInterruptTime = interruptTime;
}
counterModified = true;
interrupts();
}