#include <util/atomic.h>
#include <LiquidCrystal_I2C.h>
#define LED_RED 6
#define LED_GREEN 5
#define LED_BLUE 3
#define ENCODER1 A2
#define ENCODER2 A3
#define RED_BUTTON 2
#define GREEN_BUTTON 4
#define DEBOUNCING_PERIOD 30
bool isInMenu = true;
int chosenPosition = 0;
int buttons[] = {RED_BUTTON, GREEN_BUTTON};
int led[] = {LED_RED, LED_BLUE, LED_GREEN};
int intensities[] = {0, 0, 0};
String menu[] = {"Red diode ", "Blue diode ", "Green diode"};
volatile unsigned long timestamps[] = {0UL, 0UL};
unsigned long previousTimestamps[] = {0UL, 0UL};
volatile int encoder1 = HIGH;
volatile int encoder2 = HIGH;
volatile unsigned long encoderTimestamp = 0UL;
unsigned long redPreviousButtonTimestamp = 0UL;
unsigned long redButtonTimestamp = 0UL;
unsigned long greenPreviousButtonTimestamp = 0UL;
unsigned long greenButtonTimestamp = 0UL;
LiquidCrystal_I2C lcd(0x27, 16, 2);
void initAll()
{
pinMode(LED_RED, OUTPUT);
digitalWrite(LED_RED, LOW);
pinMode(LED_BLUE, OUTPUT);
digitalWrite(LED_BLUE, LOW);
pinMode(LED_GREEN, OUTPUT);
digitalWrite(LED_GREEN, LOW);
pinMode(ENCODER1, INPUT_PULLUP);
pinMode(ENCODER2, INPUT_PULLUP);
pinMode(RED_BUTTON, INPUT_PULLUP);
pinMode(GREEN_BUTTON, INPUT_PULLUP);
lcd.init();
lcd.backlight();
}
void redPressed()
{
Serial.print("BBB");
timestamps[0] = millis();
redButtonTimestamp = millis();
}
void greenPressed()
{
Serial.print("AAA");
timestamps[1] = millis();
greenButtonTimestamp = millis();
}
void printMenu()
{
lcd.setCursor(2, 0);
lcd.print(menu[chosenPosition]);
lcd.setCursor(2, 1);
lcd.print(menu[(chosenPosition + 1) % 3]);
}
void printValues()
{
lcd.setCursor(2, 1);
char buffer[40];
sprintf(buffer, "Value: %3d ", intensities[chosenPosition]);
lcd.print(buffer);
}
void changeLed()
{
analogWrite(led[chosenPosition], intensities[chosenPosition]);
}
void encoderUpdated(int value){
if (isInMenu)
{
chosenPosition = value % 3;
printMenu();
}
else
{
intensities[chosenPosition] = value * 15;
printValues();
changeLed();
}
}
bool isRedPressed(){
noInterrupts();
unsigned long localButtonTimestamp = redButtonTimestamp;
interrupts();
if (localButtonTimestamp != redPreviousButtonTimestamp && millis() > localButtonTimestamp + DEBOUNCING_PERIOD)
{
if (digitalRead(RED_BUTTON) == LOW)
{
return true;
}
redPreviousButtonTimestamp = localButtonTimestamp;
}
return false;
}
bool isGreenPressed(){
noInterrupts();
unsigned long localButtonTimestamp = greenButtonTimestamp;
interrupts();
if (localButtonTimestamp != greenPreviousButtonTimestamp && millis() > localButtonTimestamp + DEBOUNCING_PERIOD)
{
if (digitalRead(GREEN_BUTTON) == LOW)
{
return true;
}
greenPreviousButtonTimestamp = localButtonTimestamp;
}
return false;
}
bool buttonPressed(int buttonID)
{
noInterrupts();
unsigned long localButtonTimestamp = timestamps[buttonID];
interrupts();
if (localButtonTimestamp != previousTimestamps[buttonID] && millis() > localButtonTimestamp + DEBOUNCING_PERIOD)
{
previousTimestamps[buttonID] = localButtonTimestamp;
return (digitalRead(buttons[buttonID]) == LOW);
}
return false;
}
void setup()
{
initAll();
lcd.setCursor(0, 0);
lcd.print(">");
printMenu();
attachInterrupt(digitalPinToInterrupt(RED_BUTTON), redPressed, FALLING);
PCICR |= (1 << PCIE2);
PCMSK2 |= (1 << PCINT20);
PCICR |= (1 << PCIE1);
PCMSK1 |= (1 << PCINT10);
}
ISR(PCINT2_vect)
{
greenButtonTimestamp = millis();
}
ISR(PCINT1_vect)
{
encoder1 = digitalRead(ENCODER1);
encoder2 = digitalRead(ENCODER2);
encoderTimestamp = millis();
}
int encoderValue = 0;
int lastEn1 = LOW;
unsigned long lastChangeTimestamp = 0UL;
void loop()
{
int en1;
int en2;
unsigned long timestamp;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
{
en1 = encoder1;
en2 = encoder2;
timestamp = encoderTimestamp;
}
if (en1 == LOW && timestamp > lastChangeTimestamp + DEBOUNCING_PERIOD)
{
if (en2 == HIGH)
{
if (encoderValue < 15)
encoderValue += 1;
}
else
{
if (encoderValue > 0)
encoderValue -= 1;
}
lastChangeTimestamp = timestamp;
encoderUpdated(encoderValue);
}
lastEn1 = en1;
if(buttonPressed(0))
{
if(!isInMenu)
{
isInMenu = true;
encoderValue = chosenPosition;
printMenu();
}
}
if(buttonPressed(1))
{
if(isInMenu)
{
isInMenu = false;
encoderValue = intensities[chosenPosition] / 15;
printValues();
}
}
}