#include <LiquidCrystal.h>
#include <freertos/FreeRTOS.h>
static constexpr uint8_t rs_pin = 19;
static constexpr uint8_t e_pin = 18;
static constexpr uint8_t d4_pin = 5;
static constexpr uint8_t d5_pin = 17;
static constexpr uint8_t d6_pin = 16;
static constexpr uint8_t d7_pin = 4;
struct display_content_t {
String line1 = "";
String line2 = "";
bool clear = false;
};
class DisplayCtl {
private:
static LiquidCrystal lcd;
static SemaphoreHandle_t lcd_mutex;
public:
static void init() {
lcd_mutex = xSemaphoreCreateMutex();
lcd.begin(16, 2);
}
static void print(const display_content_t& c) {
xSemaphoreTake(lcd_mutex, portMAX_DELAY);
if(c.clear) {
lcd.clear();
}
if(c.line1 != "") {
lcd.setCursor(0, 0);
lcd.print(c.line1);
}
if(c.line2 != "") {
lcd.setCursor(0, 1);
lcd.print(c.line2);
}
xSemaphoreGive(lcd_mutex);
}
};
class OutputCtl {
private:
static constexpr uint8_t led_pin = 13;
static TaskHandle_t main_task_handle;
static void main_task(void* param) {
static uint8_t out_state { 0 };
while(1) {
display_content_t dc;
out_state = !out_state;
dc = {!out_state? "LED ON " : "LED OFF", "", false};
digitalWrite(led_pin, out_state? HIGH : LOW);
DisplayCtl::print(dc);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
public:
static void init() {
pinMode(led_pin, OUTPUT);
xTaskCreate(main_task,
"LED Task",
1024 * 3,
NULL,
1,
&main_task_handle
);
}
};
class InputCtl {
private:
static constexpr uint8_t button_pin = 33;
static TaskHandle_t action_task_handle;
static SemaphoreHandle_t action_semaphore;
static TimerHandle_t debounce_timer;
static void buttonISR() {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xTimerStartFromISR(debounce_timer, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
static void debounce_callback(TimerHandle_t xTimer) {
if (digitalRead(button_pin) == LOW) {
xSemaphoreGive(action_semaphore);
}
}
static void button_action(void* param) {
static uint32_t counter { 0 };
while(1) {
display_content_t dc;
xSemaphoreTake(action_semaphore, portMAX_DELAY);
++counter;
dc = {"", String("BTN CNT: ") + String(counter), false};
DisplayCtl::print(dc);
}
}
public:
static void init() {
pinMode(button_pin, INPUT_PULLUP);
action_semaphore = xSemaphoreCreateBinary();
xSemaphoreTake(action_semaphore, 0);
xTaskCreate(button_action,
"CB Task",
1024 * 3,
NULL,
1,
&action_task_handle
);
debounce_timer = xTimerCreate("DebounceTimer",
pdMS_TO_TICKS(50),
pdFALSE,
NULL,
debounce_callback
);
attachInterrupt(digitalPinToInterrupt(button_pin), buttonISR, FALLING);
}
};
LiquidCrystal DisplayCtl::lcd { rs_pin, e_pin, d4_pin, d5_pin, d6_pin, d7_pin };
TaskHandle_t OutputCtl::main_task_handle { NULL };
TaskHandle_t InputCtl::action_task_handle { NULL };
SemaphoreHandle_t InputCtl::action_semaphore { NULL };
SemaphoreHandle_t DisplayCtl::lcd_mutex { NULL };
TimerHandle_t InputCtl::debounce_timer { NULL };
void setup() {
DisplayCtl::init();
OutputCtl::init();
InputCtl::init();
}
void loop() {
vTaskSuspend(NULL);
}