#include <Arduino.h>
#include <LiquidCrystal_I2C.h>
#define RE_CLK (14)
#define RE_DT (12)
#define RE_SW (13)
#define NUM_INFO_PAGE (4)
#define NUM_SETTING_PAGE (4)
#define RELAY_PIN (25)
LiquidCrystal_I2C LCD = LiquidCrystal_I2C(0x27, 16, 2);
TaskHandle_t RotaryRollHandles[NUM_INFO_PAGE];
TaskHandle_t RotaryClickHandles;
TimerHandle_t timer;
volatile int8_t display = (NUM_INFO_PAGE - 1);
volatile bool SETTING_MODE = false;
void IRAM_ATTR rotaryRollISR() {
int8_t step = digitalRead(RE_DT) ? 1 : -1;
display = (NUM_INFO_PAGE + display + step) % NUM_INFO_PAGE;
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
vTaskNotifyGiveFromISR(RotaryRollHandles[display], &xHigherPriorityTaskWoken);
if (xHigherPriorityTaskWoken) {
portYIELD_FROM_ISR();
}
}
void IRAM_ATTR rotaryClickISR() {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
vTaskNotifyGiveFromISR(RotaryClickHandles, &xHigherPriorityTaskWoken);
if (xHigherPriorityTaskWoken) {
portYIELD_FROM_ISR();
}
}
void TaskRotaryRoll(void *param) {
uint8_t id = (uint8_t)(uint32_t)param;
for (;;) {
if (ulTaskNotifyTake(pdTRUE, portMAX_DELAY)) {
if (xTimerIsTimerActive(timer)) {
xTimerReset(timer, 0);
}
vTaskDelay(100 / portTICK_PERIOD_MS);
}
}
}
void TaskRotaryClick(void *param) {
for (;;) {
if (ulTaskNotifyTake(pdTRUE, portMAX_DELAY)) {
SETTING_MODE = true;
if (xTimerIsTimerActive(timer)) {
xTimerReset(timer, 0);
} else {
// Start the timer if it's not already running
xTimerStart(timer, 0);
}
}
}
}
void timer_callback(TimerHandle_t xTimer) {
SETTING_MODE = false;
xTimerStop(timer, 0);
}
void TaskDisplayOnLCD(void *param) {
for (;;) {
LCD.clear();
LCD.setCursor(0, 0);
if(SETTING_MODE){
LCD.println("SETTING");
} else{
char result[50];
sprintf(result, "Info Page : %d", display);
LCD.println(result);
}
vTaskDelay(30 / portTICK_PERIOD_MS);
}
}
void TaskRelayControl(void *param) {
for (;;) {
digitalWrite(RELAY_PIN, HIGH);
vTaskDelay(30 / portTICK_PERIOD_MS);
}
}
void setup() {
Serial.begin(9600);
pinMode(RE_CLK, INPUT_PULLUP);
pinMode(RE_DT, INPUT_PULLUP);
pinMode(RE_SW, INPUT_PULLUP);
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, LOW);
LCD.init();
LCD.backlight();
LCD.clear();
LCD.setCursor(0, 0);
timer = xTimerCreate("Timer", 5000 / portTICK_PERIOD_MS, pdTRUE, 0, timer_callback);
attachInterrupt(digitalPinToInterrupt(RE_CLK), rotaryRollISR, FALLING);
attachInterrupt(digitalPinToInterrupt(RE_SW), rotaryClickISR, FALLING);
for (uint8_t i = 0; i < NUM_INFO_PAGE; i++) {
xTaskCreate(TaskRotaryRoll, "task", 2048, (void *)(uint32_t)i, tskIDLE_PRIORITY+1, &RotaryRollHandles[i]);
}
xTaskCreate(TaskRotaryClick, "Setting Mode Task", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+1, &RotaryClickHandles);
xTaskCreate(TaskDisplayOnLCD, "DisplayOnLCD", 2048, NULL, tskIDLE_PRIORITY+1, NULL);
}
void loop() {}