#include "stdio.h"
#include "pico/stdlib.h"
#include "hardware/clocks.h"
#include "hardware/pll.h"
#include "hardware/timer.h"
#include "hardware/irq.h"
#include "hardware/adc.h"
#include "ssd1306.h"
// Definição dos pinos GPIO
#define LED_RED_PIN 11 // Pino do LED vermelho
#define LED_GREEN_PIN 13 // Pino do LED verde
#define PIR_SENSOR_PIN 27 // Pino do PIR (sensor de movimento)
#define BUZZER_PIN 2 // Pino do buzzer
#define OLED_SDA_PIN 14 // Pino SDA do display OLED
#define OLED_SCL_PIN 15 // Pino SCL do display OLED
#define MICROPHONE_PIN 26 // Pino do microfone (simulado por um potenciômetro)
// Definição de constantes
#define SOUND_THRESHOLD 3800 // Limite de som para ativar uma ação
#define ALERT_BLINK_TIME 300 // Tempo de piscar do LED em modo ALERTA
#define IDLE_BLINK_TIME 400 // Tempo de piscar do LED em modo INATIVO
#define BUZZER_BEEP_DELAY 100 // Tempo de delay do beep do buzzer
#define CLOCK_MHZ 1000000 // Frequência do clock em MHz
#define ALARM_DURATION_MS 10000 // Duração do alarme em milissegundos
#define OLED_WIDTH 128 // Largura do display OLED
#define OLED_HEIGHT 64 // Altura do display OLED
#define OLED_I2C_ADDR 0x3C // Endereço do display OLED
#define OLED_I2C_INSTANCE i2c1 // Instância I2C para o display
// Variáveis globais de controle
volatile bool isMessageBeingSent = false; // Indica se a mensagem está sendo enviada
volatile bool isAlarmActive = false; // Indica se o alarme está ativado
ssd1306_t display; // Variável que representa o display OLED
// Função para inicializar os pinos GPIO
void init_gpio_pins()
{
// Inicializa LED vermelho
gpio_init(LED_RED_PIN);
gpio_set_dir(LED_RED_PIN, GPIO_OUT);
// Inicializa LED verde
gpio_init(LED_GREEN_PIN);
gpio_set_dir(LED_GREEN_PIN, GPIO_OUT);
// Inicializa sensor de movimento PIR
gpio_init(PIR_SENSOR_PIN);
gpio_set_dir(PIR_SENSOR_PIN, GPIO_IN);
gpio_pull_down(PIR_SENSOR_PIN);
// Inicializa buzzer
gpio_init(BUZZER_PIN);
gpio_set_dir(BUZZER_PIN, GPIO_OUT);
// Inicializa display OLED SSD1306 via I2C
i2c_init(i2c1, 400000);
gpio_set_function(OLED_SDA_PIN, GPIO_FUNC_I2C);
gpio_set_function(OLED_SCL_PIN, GPIO_FUNC_I2C);
gpio_pull_up(OLED_SDA_PIN);
gpio_pull_up(OLED_SCL_PIN);
// Inicializa o microfone (simulado por um potenciômetro)
adc_gpio_init(MICROPHONE_PIN);
adc_select_input(0); // Seleciona ADC0 (pino GP26)
}
// Função para configurar o clock do sistema
void configure_clock(uint frequency)
{
pll_init(pll_sys, 1, frequency * CLOCK_MHZ, 12 * CLOCK_MHZ, frequency * CLOCK_MHZ);
clock_configure(clk_sys,
CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX,
CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS,
frequency * CLOCK_MHZ,
frequency * CLOCK_MHZ);
}
// Função para piscar os LEDs (vermelho e verde)
void blink_leds(bool red, bool green, uint32_t delay_ms)
{
gpio_put(LED_RED_PIN, red);
gpio_put(LED_GREEN_PIN, green);
sleep_ms(delay_ms);
gpio_put(LED_RED_PIN, false);
gpio_put(LED_GREEN_PIN, false);
sleep_ms(delay_ms);
}
// Função para emitir som do buzzer
void beep_buzzer()
{
gpio_put(BUZZER_PIN, 1);
sleep_ms(BUZZER_BEEP_DELAY);
gpio_put(BUZZER_PIN, 0);
}
// Função para desenhar texto no display OLED
void display_text(const char *message)
{
ssd1306_clear(&display);
int text_width = strlen(message) * 6;
int text_height = 8;
// Calcula as posições para centralizar o texto
int posX = (OLED_WIDTH - text_width) / 2;
int posY = (OLED_HEIGHT - text_height) / 2;
ssd1306_draw_string(&display, posX, posY, 1, message); // Desenha o texto centralizado
ssd1306_show(&display); // Atualiza o display
}
// Função para limpar o texto no display OLED
void clear_display_text()
{
ssd1306_clear(&display);
ssd1306_show(&display);
}
// Callback que é chamado após o envio da mensagem
bool on_message_sent_callback(alarm_id_t id, void *user_data)
{
display_text("Mensagem Enviada!!!");
printf("Mensagem Enviada com Sucesso!!!\n");
isMessageBeingSent = false;
return false;
}
// Função que simula o envio de uma mensagem para um dispositivo remoto
void send_message_to_base()
{
uint32_t current_time_ms = to_ms_since_boot(get_absolute_time());
uint32_t seconds = current_time_ms / 1000;
uint32_t minutes = seconds / 60;
uint32_t hours = minutes / 60;
uint32_t days = hours / 24;
uint32_t hour_of_day = hours % 24;
uint32_t minute_of_hour = minutes % 60;
uint32_t second_of_minute = seconds % 60;
isMessageBeingSent = true;
printf("Tentando enviar mensagem para o dispositivo remoto: Dia %d, Hora %02d:%02d:%02d\n", days, hour_of_day, minute_of_hour, second_of_minute);
add_alarm_in_ms(6000, on_message_sent_callback, NULL, false);
}
// Callback chamado quando o tempo do alarme se esgota
bool on_alarm_timeout_callback()
{
isAlarmActive = false;
printf("O tempo do alarme acabou!\n");
display_text("O alarme acabou!");
return false;
}
// Função para disparar o alarme
void trigger_alarm()
{
isAlarmActive = true;
add_alarm_in_ms(ALARM_DURATION_MS, on_alarm_timeout_callback, NULL, false);
printf("Alarme Disparado!\n");
display_text("Alarme Disparado!");
}
// Função de callback para as interrupções dos GPIOs
void gpio_irq_handler(int gpio, uint32_t events)
{
if (!isMessageBeingSent && !isAlarmActive)
{
if (gpio == PIR_SENSOR_PIN)
{
printf("--------------------------------------------\n");
printf("Movimento Detectado!!!\n");
trigger_alarm();
send_message_to_base();
}
}
}
// Função que verifica o valor do ADC (potenciômetro)
bool adc_check_callback(struct repeating_timer *t)
{
if (!isMessageBeingSent && !isAlarmActive)
{
uint16_t adc_value = adc_read(); // Lê o valor do ADC
// Verifica se o valor ultrapassa o limite de som permitido
if (adc_value > SOUND_THRESHOLD)
{
printf("--------------------------------------------\n");
printf("Som alto detectado!\n");
trigger_alarm();
send_message_to_base();
}
return true; // Retorna true para manter o temporizador ativo
}
}
int main()
{
stdio_init_all(); // Inicializa a comunicação serial
configure_clock(125); // Configura o clock do sistema para 133 MHz
init_gpio_pins(); // Inicializa os pinos GPIO
adc_init(); // Inicializa o potenciômetro
ssd1306_init(&display, OLED_WIDTH, OLED_HEIGHT, OLED_I2C_ADDR, OLED_I2C_INSTANCE); // Inicializa o display OLED
// Configura as interrupções dos GPIOs
gpio_set_irq_enabled_with_callback(PIR_SENSOR_PIN, GPIO_IRQ_EDGE_RISE, true, gpio_irq_handler);
// Configura o temporizador para chamar o ADC a cada 100ms
struct repeating_timer timer;
add_repeating_timer_ms(100, adc_check_callback, NULL, &timer);
// Mensagem de Inicialização do sistema
printf("Sistema iniciado...\n");
display_text("Sistema iniciando...");
// Loop principal
while (true)
{
// Verifica se o alarme está tocando ou se a mensagem ainda está sendo enviada
if (isAlarmActive || isMessageBeingSent)
{
// Emite som no buzzer e faz o LED piscar enquanto o alarme ou o envio da mensagem não terminam
beep_buzzer();
display_text("Sistema em Alerta!");
blink_leds(true, false, ALERT_BLINK_TIME);
clear_display_text();
}
else
{
// Exibe a mensagem "Sistema funcionando" no display
display_text("Sistema Funcionando!");
// Quando o alarme terminar ou a mensagem for enviada, pisca o LED verde
blink_leds(false, true, IDLE_BLINK_TIME);
}
// Faz uma pequena pausa para evitar sobrecarga no loop
sleep_ms(100);
}
return 0;
}