#include <Arduino_FreeRTOS.h>
#include <queue.h>
#include <task.h>
#include <semphr.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// Definições para o LCD
#define LCD_16X2_I2C_ADDRESS 0x27
#define LCD_16X2_COLS 16
#define LCD_16X2_ROWS 2
// Definição do pino do LED
#define LED_PIN 12
// Configurações ADC
#define ADC_MAX 1023.0
#define MAX_VOLTAGE_ADC 5.0
// Caracteres customizados para a exibição de níveis de bateria
byte battery_states[8][8] = {
{B01110, B10001, B10001, B10001, B10001, B10001, B10001, B11111}, // Vazio
{B01110, B10001, B10001, B10001, B10001, B10001, B11111, B11111}, // 1/4
{B01110, B10001, B10001, B10001, B10001, B11111, B11111, B11111}, // 1/2
{B01110, B10001, B10001, B10001, B11111, B11111, B11111, B11111}, // 3/4
{B01110, B10001, B10001, B11111, B11111, B11111, B11111, B11111}, // Cheio
{B01110, B10001, B11111, B11111, B11111, B11111, B11111, B11111}, // Sobrecarga
{B01110, B11111, B11111, B11111, B11111, B11111, B11111, B11111}, // Muito baixa
{B01110, B10001, B10101, B10101, B10101, B10101, B10001, B11111} // Contorno
};
// Protótipos das tarefas
void task_breathing_light(void *pvParameters);
void task_serial(void *pvParameters);
void task_lcd(void *pvParameters);
void task_sensor(void *pvParameters);
void task_led(void *pvParameters);
// Instância do LCD
LiquidCrystal_I2C lcd(LCD_16X2_I2C_ADDRESS, LCD_16X2_COLS, LCD_16X2_ROWS);
// Handles para filas e semáforos
QueueHandle_t xQueue_LCD;
SemaphoreHandle_t xSerial_semaphore;
void setup() {
Serial.begin(9600);
while (!Serial) // Aguarda a inicialização da porta serial
;
lcd.init();
// Cria os caracteres customizados
for (int i = 0; i < 8; i++) {
lcd.createChar(i, battery_states[i]);
}
lcd.backlight();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("VOLTIMETRO ===");
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
xQueue_LCD = xQueueCreate(1, sizeof(float));
xSerial_semaphore = xSemaphoreCreateMutex();
xTaskCreate(task_sensor, "SENSOR", 128, NULL, 3, NULL);
xTaskCreate(task_lcd, "LCD", 156, NULL, 2, NULL);
xTaskCreate(task_led, "LED", 128, NULL, 1, NULL);
}
void loop() {
// Nada a fazer no loop principal quando usar o FreeRTOS
}
void task_sensor(void *pvParameters) {
int adc_read = 0;
float voltage = 0.0;
while (1) {
adc_read = analogRead(0);
voltage = (adc_read / ADC_MAX) * MAX_VOLTAGE_ADC;
xQueueOverwrite(xQueue_LCD, &voltage);
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
void task_lcd(void *pvParameters) {
float voltage_rcv = 0.0;
while (1) {
xQueueReceive(xQueue_LCD, &voltage_rcv, portMAX_DELAY);
update_displays(voltage_rcv);
vTaskDelay(pdMS_TO_TICKS(100));
}
}
void task_led(void *pvParameters) {
while (1) {
digitalWrite(LED_PIN, HIGH);
vTaskDelay(pdMS_TO_TICKS(250));
digitalWrite(LED_PIN, LOW);
vTaskDelay(pdMS_TO_TICKS(250));
}
}
void update_displays(float voltage) {
// Mapeia 0-5V para 0-6 (índices do array)
int battery_state = static_cast<int>(map_float(voltage, 0.0, 5.0, 0, 6));
lcd_battery_status(battery_state, 0); // Exibe o status da bateria na primeira linha
lcd.setCursor(0, 1);
lcd.print("Tensao: ");
lcd.setCursor(11, 1);
lcd.print(voltage, 2); // Exibe com duas casas decimais
lcd.print("V ");
}
void lcd_battery_status(int state, int row) {
lcd.setCursor(15, row); // Posiciona no final da primeira linha
lcd.write(state); // Escreve o estado da bateria como um caractere customizado
}
float map_float(float x, float in_min, float in_max, float out_min, float out_max) {
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}