#include <Arduino_FreeRTOS.h>
#include <queue.h>
#include <task.h>
#include <semphr.h>
#include <LiquidCrystal_I2C.h>
#include <RTClib.h>
#include "icons.h"
#define LCD_CLEAN_LINE " "
#define LCD_I2C_ADRRESS 0x27
#define LCD_COLS 20
#define LCD_ROWS 4
#define BUTTON_UP 3
#define BUTTON_DOWN 2
#define BUTTON_LEFT 4
#define BUTTON_RIGHT 5
// Set the LCD address to 0x27 for a 16 chars and 2 line display
LiquidCrystal_I2C lcd(LCD_I2C_ADRRESS,
LCD_COLS,
LCD_ROWS);
RTC_DS1307 rtc;
// protótipo da função
// variáveis globais
volatile int counter = 0; // Contador
unsigned long lastDebounceTime = 0; // Tempo da última debounce
const unsigned long debounceDelay = 200; // Delay de debounce (200ms)
unsigned long buttonPressTime = 0; // Tempo que o botão está pressionado
volatile bool buttonUpPressed = false;
volatile bool buttonDownPressed = false;
volatile bool buttonLeftPressed = false;
volatile bool buttonRightPressed = false;
volatile bool buttonUpHeld = false; // Flag para indicar se o botão UP está sendo pressionado
volatile bool buttonDownHeld = false; // Flag para indicar se o botão DOWN está sendo pressionado
// Estrutura do Menu
enum Screen {
SCREEN_WELCOME,
SCREEN_MAIN,
SCREEN_MENU,
SCREEN_READINGS,
SCREEN_ALARMS,
SCREEN_OPERATION_MODE,
SCREEN_READINGS_AC,
SCREEN_READINGS_DC,
SCREEN_READINGS_BATTERY
};
volatile Screen currentScreen = SCREEN_WELCOME;
volatile Screen previousScreen = SCREEN_WELCOME;
int menuSelection = 0; // Para rastrear a posição da seta no menu
// Handle da task
TaskHandle_t displayTaskHandle;
TaskHandle_t buttonTaskHandle;
/* semaforos utilizados */
SemaphoreHandle_t xSerial_semaphore;
void setup()
{
// configura pinos para botoes
pinMode(BUTTON_UP, INPUT_PULLUP);
pinMode(BUTTON_DOWN, INPUT_PULLUP);
pinMode(BUTTON_LEFT, INPUT_PULLUP);
pinMode(BUTTON_RIGHT, INPUT_PULLUP);
// configura interrupcao nos pinos 2 e 3
attachInterrupt(digitalPinToInterrupt(BUTTON_UP), buttonUpPress, FALLING);
attachInterrupt(digitalPinToInterrupt(BUTTON_DOWN), buttonDownPress, FALLING);
// attachInterrupt(digitalPinToInterrupt(BUTTON_UP), buttonLeftPress, FALLING);
// attachInterrupt(digitalPinToInterrupt(BUTTON_DOWN), buttonRightPress, FALLING);
// inicializa o LCD, backlight e limpa tela.
lcd.init();
lcd.backlight();
lcd.clear();
init_icons(lcd);
/* Criação dos semaforos */
xSerial_semaphore = xSemaphoreCreateMutex();
// Criação da task para mostrar o valor do contador no display LCD
xTaskCreate(
displayTask, // Função da task
"Display Task", // Nome da task
256, // Tamanho da stack (em palavras)
NULL, // Parâmetro para a função da task
1, // Prioridade da task
&displayTaskHandle // Handle da task
);
//lcd.setCursor(0, 3);
//lcd.write(ICON_UNLOCKED_CHAR);
xTaskCreate(
buttonTask,
"Button Task",
256,
NULL,
1,
&buttonTaskHandle
);
// Simulação de alarmes
//addAlarm(DateTime(2024, 7, 22, 12, 0, 0));
//addAlarm(DateTime(2024, 7, 23, 15, 30, 0));
// Inicia o scheduler do FreeRTOS
vTaskStartScheduler();
}
void loop()
{
}
/*
void buttonUp() {
unsigned long currentTime = millis();
if ((currentTime - lastDebounceTime) > debounceDelay) {
lastDebounceTime = currentTime;
buttonPressTime = millis();
buttonUpHeld = true;
// Incrementa o contador para pressionamentos normais
counter++;
}
}
*/
/*
void buttonDown() {
unsigned long currentTime = millis();
if ((currentTime - lastDebounceTime) > debounceDelay) {
lastDebounceTime = currentTime;
buttonPressTime = millis();
buttonDownHeld = true;
// Incrementa o contador para pressionamentos normais
counter--;
}
}
*/
void buttonUpPress() {
buttonUpPressed = true;
}
void buttonDownPress() {
buttonDownPressed = true;
}
void buttonLeftPress() {
buttonLeftPressed = true;
}
void buttonRightPress() {
buttonRightPressed = true;
}
/* displaytask de teste com contador
void displayTask(void *pvParameters) {
while (1) {
// Exibe o valor do contador no display LCD
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Contador:");
lcd.setCursor(0, 1);
lcd.print(counter);
// Incrementa o contador a cada 200ms se o botão UP estiver sendo pressionado por mais de 1 segundos
if (buttonUpHeld && (millis() - buttonPressTime > 1000)) {
counter = counter + 10;
vTaskDelay(200 / portTICK_PERIOD_MS);
} else {
vTaskDelay(100 / portTICK_PERIOD_MS); // Verifica o estado do botão a cada 100ms
}
// Incrementa o contador a cada 200ms se o botão DOWN estiver sendo pressionado por mais de 1 segundos
if (buttonDownHeld && (millis() - buttonPressTime > 1000)) {
counter = counter - 10;
vTaskDelay(200 / portTICK_PERIOD_MS);
} else {
vTaskDelay(100 / portTICK_PERIOD_MS); // Verifica o estado do botão a cada 100ms
}
if (digitalRead(BUTTON_UP) == HIGH) {
buttonUpHeld = false; // Reseta a flag se o botão não estiver pressionado
}
if (digitalRead(BUTTON_DOWN) == HIGH) {
buttonDownHeld = false; // Reseta a flag se o botão não estiver pressionado
}
}
}
*/
void displayTask(void *pvParameters) {
while (1) {
switch (currentScreen) {
case SCREEN_WELCOME:
displayWelcomeScreen();
vTaskDelay(2000 / portTICK_PERIOD_MS);
currentScreen = SCREEN_MAIN;
break;
case SCREEN_MAIN:
displayMainScreen();
break;
case SCREEN_MENU:
displayMenuScreen();
break;
case SCREEN_READINGS:
displayReadingsMenu();
break;
case SCREEN_ALARMS:
displayAlarmsScreen();
break;
case SCREEN_OPERATION_MODE:
displayOperationModeScreen();
break;
case SCREEN_READINGS_AC:
displayReadingsACScreen();
break;
case SCREEN_READINGS_DC:
displayReadingsDCScreen();
break;
case SCREEN_READINGS_BATTERY:
displayReadingsBatteryScreen();
break;
default:
break;
}
vTaskDelay(100 / portTICK_PERIOD_MS); // Atualiza a tela a cada 100ms
}
}
void buttonTask(void *pvParameters) {
while (1) {
if (buttonUpPressed) {
handleButtonUp();
buttonUpPressed = false;
}
if (buttonDownPressed) {
handleButtonDown();
buttonDownPressed = false;
}
if (buttonLeftPressed) {
handleButtonLeft();
buttonLeftPressed = false;
}
if (buttonRightPressed) {
handleButtonRight();
buttonRightPressed = false;
}
vTaskDelay(100 / portTICK_PERIOD_MS); // Verifica os botões a cada 100ms
}
}
void handleButtonUp() {
switch (currentScreen) {
case SCREEN_MENU:
menuSelection--;
if (menuSelection < 0) menuSelection = 2;
break;
case SCREEN_READINGS:
currentScreen = SCREEN_MENU;
break;
case SCREEN_ALARMS:
currentScreen = SCREEN_MENU;
break;
case SCREEN_OPERATION_MODE:
currentScreen = SCREEN_MENU;
break;
case SCREEN_READINGS_AC:
currentScreen = SCREEN_READINGS;
break;
case SCREEN_READINGS_DC:
currentScreen = SCREEN_READINGS;
break;
case SCREEN_READINGS_BATTERY:
currentScreen = SCREEN_READINGS;
break;
default:
break;
}
}
void handleButtonDown() {
switch (currentScreen) {
case SCREEN_MAIN:
currentScreen = SCREEN_MENU;
break;
case SCREEN_MENU:
menuSelection++;
if (menuSelection > 2) menuSelection = 0;
break;
case SCREEN_READINGS:
currentScreen = SCREEN_ALARMS;
break;
case SCREEN_ALARMS:
currentScreen = SCREEN_OPERATION_MODE;
break;
case SCREEN_OPERATION_MODE:
currentScreen = SCREEN_MENU;
break;
default:
break;
}
}
void handleButtonLeft() {
switch (currentScreen) {
case SCREEN_MENU:
currentScreen = previousScreen;
break;
case SCREEN_READINGS_AC:
currentScreen = SCREEN_READINGS;
break;
case SCREEN_READINGS_DC:
currentScreen = SCREEN_READINGS;
break;
case SCREEN_READINGS_BATTERY:
currentScreen = SCREEN_READINGS;
break;
default:
break;
}
}
void handleButtonRight() {
switch (currentScreen) {
case SCREEN_MENU:
currentScreen = SCREEN_READINGS;
break;
case SCREEN_READINGS:
currentScreen = SCREEN_READINGS_AC;
break;
case SCREEN_READINGS_AC:
currentScreen = SCREEN_READINGS_DC;
break;
case SCREEN_READINGS_DC:
currentScreen = SCREEN_READINGS_BATTERY;
break;
default:
break;
}
}
void displayWelcomeScreen() {
lcd.clear();
lcd.setCursor(6, 0);
lcd.print("ENERSYS");
lcd.setCursor(0, 1);
lcd.print("RETIFICADOR 6 PULSOS");
lcd.setCursor(2, 2);
lcd.print("MODELO 125V 200A");
lcd.setCursor(4, 3);
lcd.print("VERSAO 0.0.1");
}
void displayMainScreen() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" M. RECARGA 120oC");
lcd.setCursor(0, 1);
lcd.print("VBAT: ");
lcd.print(getBatteryVoltage());
lcd.setCursor(10, 1);
lcd.print("VCON: ");
lcd.print(getBatteryVoltage());
lcd.setCursor(0, 2);
lcd.print("IBAT: ");
lcd.print(getBatteryCurrent());
lcd.setCursor(10, 2);
lcd.print("ICON: ");
lcd.print(getBatteryCurrent());
lcd.setCursor(0, 3);
lcd.write(ICON_DOWN_CHAR);
lcd.print(" AA:");
}
void displayMenuScreen() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(menuSelection == 0 ? "> LEITURAS" : " LEITURAS");
lcd.setCursor(0, 1);
lcd.print(menuSelection == 1 ? "> ALARMES" : " ALARMES");
lcd.setCursor(0, 2);
lcd.print(menuSelection == 2 ? "> MODO DE OPERACAO" : " MODO DE OPERACAO");
}
void displayReadingsMenu() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("ENTRADA CA");
lcd.setCursor(0, 1);
lcd.print("ENTRADA CC");
lcd.setCursor(0, 2);
lcd.print("BATERIA");
}
void displayAlarmsScreen() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Alarmes");
}
void displayOperationModeScreen() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Modo de Operacao");
}
void displayReadingsACScreen() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Leituras Entrada CA");
}
void displayReadingsDCScreen() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Leituras Entrada CC");
}
void displayReadingsBatteryScreen() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Leituras Bateria");
}
int getBatteryVoltage() {
// Retorne o valor da tensão da bateria (dummy value por enquanto)
return 120;
}
int getBatteryCurrent() {
// Retorne o valor da corrente da bateria (dummy value por enquanto)
return 101;
}