/*
Instituto Federal do Maranhão - IFMA
Residência Tecnológica em Sistemas Embarcados - EmbarcaTech
SISTEMA DE GERENCIAMENTO SUSTENTÁVEL PARA FLUIDOS HÍDRICOS UTILIZANDO Raspberry Pi Pico
Alunos:
Gleiciane Mendes Ferreira
Marcelo Ribeiro da Silva
Michael Jamesson Almeida Nunes
Moisés Leocádio Reis Brito
*/
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/adc.h"
#include "hardware/gpio.h"
#include <math.h>
// ------------------- Pinos -------------------
// ADC (Potenciômetros)
#define ADC_GPIO_RES01 26 // Sensor de Nível do Reservatório 01 (Superior)
#define ADC_GPIO_RES02 27 // Sensor de Nível do reservatório 02 (Inferior)
// LEDs (Bombas)
#define PUMP_01_PIN 16 // Bomba 01 RES01->RES02
#define PUMP_02_PIN 17 // Bomba 02 RES02->RES01
// Botões físicos
#define BTN_FUNCAO_01_PIN 13 // Equilibrio
#define BTN_FUNCAO_02_PIN 14 // RES01 cheio
#define BTN_FUNCAO_03_PIN 15 // Ciclagem
// Onboard LED (status)
#define ONBOARD_LED_PIN 25
// ------------------- Parâmetros -------------------
#define ADC_MAX_VALUE 4095u
#define VREF 3.3f
#define FULL_RATIO 0.90f
#define EMPTY_RATIO 0.10f
#define TOLERANCE_RATIO 0.03f
#define FULL_VOLTAGE (VREF * FULL_RATIO)
#define EMPTY_VOLTAGE (VREF * EMPTY_RATIO)
#define TOLERANCE_VOLTAGE (VREF * TOLERANCE_RATIO)
#define LOOP_DELAY_MS 300
#define PUMP_ACTIVE_MS 250
typedef enum { FUNCAO_01 = 0, FUNCAO_02 = 1, FUNCAO_03 = 2 } system_mode_t;
// ------------------- Funções Auxiliares -------------------
static inline float adc_to_voltage(uint16_t raw) {
return ((float)raw * VREF) / (float)ADC_MAX_VALUE;
}
static inline float voltage_to_percent(float v) {
return (v / VREF) * 100.0f;
}
static inline bool almost_equal_percent(float a_pct, float b_pct) {
return fabsf(a_pct - b_pct) <= (TOLERANCE_RATIO * 100.0f);
}
static uint16_t read_adc_pin(uint gpio_pin) {
if (gpio_pin == ADC_GPIO_RES01) adc_select_input(0);
else if (gpio_pin == ADC_GPIO_RES02) adc_select_input(1);
else return 0;
return adc_read();
}
// ------------------- Controla LEDs das bombas -------------------
static void controlar_bombas(bool bomba1, bool bomba2) {
gpio_put(PUMP_01_PIN, bomba1);
gpio_put(PUMP_02_PIN, bomba2);
}
// ------------------- Inicialização GPIO -------------------
static void init_gpio() {
gpio_init(PUMP_01_PIN); gpio_set_dir(PUMP_01_PIN, GPIO_OUT); gpio_put(PUMP_01_PIN, 0);
gpio_init(PUMP_02_PIN); gpio_set_dir(PUMP_02_PIN, GPIO_OUT); gpio_put(PUMP_02_PIN, 0);
gpio_init(ONBOARD_LED_PIN); gpio_set_dir(ONBOARD_LED_PIN, GPIO_OUT); gpio_put(ONBOARD_LED_PIN, 0);
gpio_init(BTN_FUNCAO_01_PIN); gpio_set_dir(BTN_FUNCAO_01_PIN, GPIO_IN); gpio_pull_up(BTN_FUNCAO_01_PIN);
gpio_init(BTN_FUNCAO_02_PIN); gpio_set_dir(BTN_FUNCAO_02_PIN, GPIO_IN); gpio_pull_up(BTN_FUNCAO_02_PIN);
gpio_init(BTN_FUNCAO_03_PIN); gpio_set_dir(BTN_FUNCAO_03_PIN, GPIO_IN); gpio_pull_up(BTN_FUNCAO_03_PIN);
}
// ------------------- Leitura Botões -------------------
static bool button_pressed(uint gpio_pin) {
return gpio_get(gpio_pin) == 0;
}
// ------------------- Programa Principal -------------------
int main() {
stdio_init_all();
adc_init();
adc_gpio_init(ADC_GPIO_RES01);
adc_gpio_init(ADC_GPIO_RES02);
init_gpio();
system_mode_t mode = FUNCAO_01; // Função inicial
printf("=== Sistema Hidrico - Ciclagem Automatica ===\n");
while (true) {
// --- Detectar mudança de modo ---
if (button_pressed(BTN_FUNCAO_01_PIN)) { mode = FUNCAO_01; printf("\n*** MODO FUNCAO_01: EQUILIBRIO ***\n"); sleep_ms(300); }
if (button_pressed(BTN_FUNCAO_02_PIN)) { mode = FUNCAO_02; printf("\n*** MODO FUNCAO_02: RESERVATORIO SUPERIOR CHEIO ***\n"); sleep_ms(300); }
if (button_pressed(BTN_FUNCAO_03_PIN)) { mode = FUNCAO_03; printf("\n*** MODO FUNCAO_03: CICLAGEM AUTOMATICA ***\n"); sleep_ms(300); }
// --- Leitura ADCs ---
uint16_t raw_res01 = read_adc_pin(ADC_GPIO_RES01);
uint16_t raw_res02 = read_adc_pin(ADC_GPIO_RES02);
float v_res01 = adc_to_voltage(raw_res01);
float v_res02 = adc_to_voltage(raw_res02);
float pct_res01 = voltage_to_percent(v_res01);
float pct_res02 = voltage_to_percent(v_res02);
// --- Saída serial ---
printf("\n==============================\n");
printf("RES01: raw=%4u V=%.3f (%.1f%%)\n", raw_res01, v_res01, pct_res01);
printf("RES02: raw=%4u V=%.3f (%.1f%%)\n", raw_res02, v_res02, pct_res02);
printf("Função Atual: %d\n", mode);
// --- Variáveis de estado das bombas ---
bool bomba1_status = false;
bool bomba2_status = false;
// --- Executar função correspondente ---
switch(mode) {
case FUNCAO_01: // Equilibrio
if (!almost_equal_percent(pct_res01, pct_res02)) {
if (pct_res01 < pct_res02) {
bomba2_status = true;
printf(" -> Transferindo RES02 -> RES01\n");
} else {
bomba1_status = true;
printf(" -> Transferindo RES01 -> RES02\n");
}
} else {
printf(" -> Níveis equilibrados\n");
}
break;
case FUNCAO_02: // Manter RES01 cheio com limite de RES02
if (v_res02 <= EMPTY_VOLTAGE) {
bomba1_status = false;
bomba2_status = false;
printf(" -> RES02 vazio, nenhuma bomba acionada\n");
} else if (v_res01 < v_res02) {
bomba2_status = true; // Transferindo RES02 -> RES01
bomba1_status = false;
printf(" -> RES01 < RES02, transferindo RES02 -> RES01\n");
} else if (v_res01 >= v_res02) {
bomba1_status = false;
bomba2_status = false;
printf(" -> RES01 >= RES02, desligando bombas para evitar transbordamento\n");
}
break;
case FUNCAO_03: // Ciclagem Automática
if (v_res01 >= FULL_VOLTAGE) {
bomba1_status = true;
printf(" -> CICLAGEM: RES01 cheio -> RES01 -> RES02\n");
} else if (v_res01 <= EMPTY_VOLTAGE) {
printf(" -> RES01 vazio, esperando enchimento\n");
}
if (v_res02 >= FULL_VOLTAGE) {
bomba2_status = true;
printf(" -> CICLAGEM: RES02 cheio -> RES02 -> RES01\n");
} else if (v_res02 <= EMPTY_VOLTAGE) {
printf(" -> RES02 vazio, esperando enchimento\n");
}
break;
default: break;
}
// Atualiza LEDs das bombas
controlar_bombas(bomba1_status, bomba2_status);
printf("Bomba 1 (RES01->RES02): %s | Bomba 2 (RES02->RES01): %s\n",
bomba1_status ? "ON" : "OFF",
bomba2_status ? "ON" : "OFF");
printf("==============================\n");
sleep_ms(LOOP_DELAY_MS);
}
}
Função_1
Função_2
Função_3
Bomba_01
Bomba_02
Sensor de
Nível 01
FPGA
Sensor de
Nível 02