/*********
Rui Santos
Complete project details at https://randomnerdtutorials.com
*********/
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2);
const char* menuOptions[] = {"Geolocation","Pump active time","Krumplifozelek fasirozottal","Borzsonyi csirkeszarnyak Egermama modra"};
int totalOptions = sizeof(menuOptions) / sizeof(menuOptions[0]);
int currentOption = 0;
// const int buttonPin =4;
bool scrollDirectionLeft = true;
unsigned long lastScrollTime = 0;
int scrollPos = 0;
bool isScrolling = false;
TaskHandle_t UIHandle;
TaskHandle_t CoreFunction;
// LED pins
const int led1 = 2;
const int led2 = 18;
struct Button {
const uint8_t PIN;
uint32_t numberSingleKeyPresses;
uint32_t numberLongKeyPresses;
uint32_t numberDoubleKeyPresses;
uint32_t numberKeyTransitions; // press and release
unsigned long int buttonPressDuration;
bool pressed;
bool longpressed;
bool doublepressed;
bool changed;
bool released;
};
Button button1 = {4, 0, 0, 0, 0, 0, false, false, false, false,false};
//variables to keep track of the timing of recent interrupts
unsigned long int button_time = 0;
unsigned long int last_button_time = 0; // last button event, press or release
unsigned long int llast_button_time = 0; // debug var
unsigned long int last_press_time = 0;
unsigned long int last_release_time = 0;
unsigned long int button_event_duration = 0;
unsigned long int button_press_duration = 0;
int currentState;
void IRAM_ATTR isr()
{
//Serial.println("ISR");
button_time = millis();
//error handling, filtering
button_event_duration = button_time - last_button_time;
if (button_event_duration > 20) // 20 milliseconds filter
{
button1.numberKeyTransitions++;
button1.changed = true;
currentState = digitalRead(button1.PIN);
switch(currentState)
{
case HIGH:
button1.released=true;
break;
case LOW:
button1.pressed=true;
button1.numberSingleKeyPresses++;
break;
default:
break;
}
last_button_time = button_time;
}
/*
if((button1.numberKeyTransitions%2 ==1)&&(currentState==1))
{
//unpaired, button press
last_press_time = button_time;
}
else
{
//paired, button release
//cases : single press, double press, long press
button_press_duration = button_time-last_press_time;
button1.buttonPressDuration = button_press_duration;
if (button_press_duration > 1000) // long press
{
button1.doublepressed = false;
button1.pressed = false;
button1.longpressed = true;
button1.numberLongKeyPresses++;
}
else
{
if(button_time - last_release_time <250) // double press
{
button1.doublepressed = true;
button1.pressed = false;
button1.longpressed = false;
button1.numberDoubleKeyPresses++;
button1.numberSingleKeyPresses--;
}
else // single press
{
button1.doublepressed = false;
button1.pressed = true;
button1.longpressed = false;
button1.numberSingleKeyPresses++;
}
}
last_release_time = button_time;
//button1.pressed = false;
}
last_button_time = button_time;
*/
}
void setup()
{
Wire.begin(13,14);
Serial.begin(115200);
pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);
lcd.init();
lcd.backlight();
lcd.setCursor(0,0);
//pinMode(buttonPin, INPUT_PULLUP);
pinMode(button1.PIN, INPUT_PULLUP);
//attachInterrupt(button1.PIN, isr, FALLING);
//create a task that will be executed in the Task1code() function, with priority 1 and executed on core 0
//LCD, buttons, menu, parameter settings, deepsleep semaphore 1
xTaskCreatePinnedToCore(
//Task1code, /* Task function. */
UIHandleCode,
//"Task1", /* name of task. */
"UIHandle",
10000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
//&Task1, /* Task handle to keep track of created task */
&UIHandle,
0); /* pin task to core 0 */
delay(500);
//create a task that will be executed in the Task2code() function, with priority 1 and executed on core 1
// Wifi communication, sensor reading, database communication, deepsleep semaphore 2
xTaskCreatePinnedToCore(
//Task2code, /* Task function. */
CoreFunctionCode,
//"Task2", /* name of task. */
"CoreFunction",
10000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
//&Task2, /* Task handle to keep track of created task */
&CoreFunction,
1); /* pin task to core 1 */
delay(500);
}
//Task1code: blinks an LED every 1000 ms
//void Task1code( void * pvParameters )
void UIHandleCode( void * pvParameters )
{
Serial.print("UI running on core ");
Serial.println(xPortGetCoreID());
lcd.print("SELECTED OPTION:");
updateMenu();
for(;;)
{
//if (button1.pressed || button1.doublepressed || button1.longpressed )
if (button1.changed)
{
//button_press_duration = button_time-last_press_time;
Serial.printf("\nButton has been single pressed %u times.\nNumber of button transitions: %u times.\n",
button1.numberSingleKeyPresses,button1.numberKeyTransitions);
button1.changed = false;
//Serial.printf("\nActual button press time: %u.\nPrevious button press time: %u.\nButton press duration: %u.\
//\nNumber of button transitions: %u times.\nButton has been single pressed %u times.\
//\nButton has been double pressed %u times.\nButton has been long pressed %u times.\nButton's current state is: %i.\n",
//button_time, last_press_time, button_press_duration, button1.numberKeyTransitions,
//button1.numberSingleKeyPresses, button1.numberDoubleKeyPresses,button1.numberLongKeyPresses,currentState);
//currentOption = (currentOption + 1) % totalOptions;
currentOption = (button1.numberSingleKeyPresses) % totalOptions;
//updateMenu();
//button1.pressed = false;
}
if (button1.pressed)
{
button1.pressed = false;
}
if (button1.longpressed)
{
button1.longpressed = false;
}
if (button1.doublepressed)
{
button1.doublepressed = false;
}
/*
if(digitalRead(buttonPin) == LOW)
{
delay(200);
while(digitalRead(buttonPin) == LOW);
currentOption = (currentOption + 1) % totalOptions;
updateMenu();
}
*/
if(isScrolling && millis() - lastScrollTime >= 300)
{
scrollText();
lastScrollTime = millis();
}
//digitalWrite(led1, HIGH);
//delay(1000);
//digitalWrite(led1, LOW);
//delay(1000);
}
}
//Task2code: blinks an LED every 700 ms
//void Task2code( void * pvParameters )
void CoreFunctionCode( void * pvParameters )
{
Serial.print("Base function running on core ");
Serial.println(xPortGetCoreID());
attachInterrupt(button1.PIN, isr, CHANGE);
currentState = digitalRead(button1.PIN);
Serial.printf("Button state at init (unpressed) is: %i\n",currentState);
for(;;)
{
/*
digitalWrite(led2, HIGH);
delay(700);
digitalWrite(led2, LOW);
delay(700);
*/
}
}
void loop()
{
}
void updateMenu()
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print("SELECTED OPTION:");
const char* text = menuOptions[currentOption];
String paddedText = String(text)+" "; // Add spaces for smooth scrolling
int textLength = paddedText.length();
if(textLength <= 16){
lcd.setCursor(0,1);
lcd.print(text);
isScrolling = false;
}
else {
lcd.setCursor(0,0);
lcd.print(paddedText.substring(0,16));
scrollPos =0;
isScrolling = true;
scrollDirectionLeft = true;
}
}
void scrollText()
{
const char* text = menuOptions[currentOption];
String paddedText = String(text)+""; // Ensure smooth scrolling
int textLength = paddedText.length();
if(scrollDirectionLeft)
{
if(scrollPos < textLength -16)
{
scrollPos++;
}
else
{
delay(2000);
scrollDirectionLeft = true;
}
}
lcd.setCursor(0,1);
lcd.print(paddedText.substring(scrollPos,scrollPos+16));
}