#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 2
#define BUTTON_DOWN 19
#define BUTTON_LEFT 3
#define BUTTON_RIGHT 18
// 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;
// Flags para indicar se os botoes estao sendo pressionados
volatile bool buttonUpPressed = false;
volatile bool buttonDownPressed = false;
volatile bool buttonLeftPressed = false;
volatile bool buttonRightPressed = false;
volatile bool buttonUpHeld = false;
volatile bool buttonDownHeld = false;
// 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;
// Estrutura de dados para alarmes
struct Alarm {
DateTime timestamp;
};
#define MAX_ALARMS 10
Alarm alarms[MAX_ALARMS];
int alarmCount = 0;
void setup() {
Serial.begin(9600);
// configura pinos para botoes
pinMode(BUTTON_UP, INPUT_PULLUP);
pinMode(BUTTON_DOWN, INPUT_PULLUP);
pinMode(BUTTON_LEFT, INPUT_PULLUP);
pinMode(BUTTON_RIGHT, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(BUTTON_UP), buttonUpPress, FALLING);
attachInterrupt(digitalPinToInterrupt(BUTTON_DOWN), buttonDownPress, FALLING);
attachInterrupt(digitalPinToInterrupt(BUTTON_LEFT), buttonLeftPress, FALLING);
attachInterrupt(digitalPinToInterrupt(BUTTON_RIGHT), buttonRightPress, FALLING);
// inicializa o LCD, backlight e limpa tela.
lcd.init();
lcd.backlight();
lcd.clear();
init_icons(lcd);
lcd.setCursor(4,0);
lcd.println("BEM-VINDO!");
/* 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
);
// Criação da task para os botoes
xTaskCreate(
buttonTask,
"Button Task",
256,
NULL,
1,
&buttonTaskHandle
);
// Inicia o scheduler do FreeRTOS
vTaskStartScheduler();
}
void loop() {
// put your main code here, to run repeatedly:
}
void buttonUpPress() {
buttonUpPressed = true;
}
void buttonDownPress() {
buttonDownPressed = true;
}
void buttonLeftPress() {
buttonLeftPressed = true;
}
void buttonRightPress() {
buttonRightPressed = true;
}
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;
default:
break;
}
vTaskDelay(200 / 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 = SCREEN_MAIN;
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:
if (menuSelection == 0) currentScreen = SCREEN_READINGS;
else if (menuSelection == 1) currentScreen = SCREEN_ALARMS;
else if (menuSelection == 2) currentScreen = SCREEN_OPERATION_MODE;
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("EMPRESA");
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);
opMode();
lcd.setCursor(4, 0);
lcd.print(" | ");
opState();
lcd.setCursor(16, 0);
lcd.print(getTemperature());
lcd.write(ICON_DEGREE);
lcd.print("C");
lcd.setCursor(0, 1);
lcd.print("VBAT: ");
lcd.print(getBatteryVoltage());
lcd.setCursor(10, 1);
lcd.print("VCON: ");
lcd.print(getConverterVoltage());
lcd.setCursor(0, 2);
lcd.print("IBAT: ");
lcd.print(getBatteryCurrent());
lcd.setCursor(10, 2);
lcd.print("ICON: ");
lcd.print(getConverterCurrent());
lcd.setCursor(0, 3);
lcd.write(ICON_DOWN_CHAR);
lcd.print(" AA: 3");
}
void displayMenuScreen() {
lcd.clear();
lcd.setCursor(8, 0);
lcd.print("MENU");
lcd.setCursor(0, 0);
lcd.write(ICON_UP_CHAR);
lcd.setCursor(0, 1);
lcd.print(menuSelection == 0 ? "> LEITURAS" : " LEITURAS");
lcd.setCursor(0, 2);
lcd.print(menuSelection == 1 ? "> ALARMES" : " ALARMES");
lcd.setCursor(0, 3);
lcd.print(menuSelection == 2 ? "> MODO DE OPERACAO" : " MODO DE OPERACAO");
}
void opMode(){
lcd.print("AUTO");
}
void opState(){
lcd.print("RECARGA");
}
int getBatteryVoltage() {
// Retorne o valor da tensão da bateria (dummy value por enquanto)
return 124;
}
int getBatteryCurrent() {
// Retorne o valor da corrente da bateria (dummy value por enquanto)
return 100;
}
int getConverterVoltage() {
// Retorne o valor da tensão da bateria (dummy value por enquanto)
return 130;
}
int getConverterCurrent() {
// Retorne o valor da corrente da bateria (dummy value por enquanto)
return 150;
}
int getTemperature() {
// Retorne o valor da corrente da bateria (dummy value por enquanto)
return 28;
}
void addAlarm(DateTime timestamp) {
if (alarmCount < MAX_ALARMS) {
alarms[alarmCount].timestamp = timestamp;
alarmCount++;
}
}
void getAlarm(int *count, DateTime *lastAlarmTime) {
*count = alarmCount;
if (alarmCount > 0) {
*lastAlarmTime = alarms[alarmCount - 1].timestamp;
}
}