#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "pico/stdlib.h"
#include "pico/binary_info.h"
#include "ssd1306.h"
#include "hardware/i2c.h"
#include "hardware/adc.h"
// Definição dos pinos I2C
const uint I2C_SDA = 14;
const uint I2C_SCL = 15;
// Definição dos pinos do Joystick
#define JOY_X 26
#define JOY_Y 27
#define JOY_SW 22
// Definição dos pinos dos LEDs RGB
#define LED_R_PIN 13
#define LED_G_PIN 11
#define LED_B_PIN 12
// Definição dos botões
#define btn_A 5
#define btn_B 6
// Função para configurar os LEDs RGB (vermelho, verde e azul) com os valores de entrada
void set_rgb(uint r, uint g, uint b) {
gpio_put(LED_R_PIN, r);
gpio_put(LED_G_PIN, g);
gpio_put(LED_B_PIN, b);
}
// Vetor para armazenar o estado de cada opção do menu
int menu_states[4] = {0, 0, 0, 0}; // 0 = desativado, 1 = ativado
// Função para exibir um menu no display OLED, destacando a opção selecionada
void display_oled(char *menu[], int selected_option) {
struct render_area frame_area = {
.start_column = 0,
.end_column = ssd1306_width - 1,
.start_page = 0,
.end_page = ssd1306_n_pages - 1
};
calculate_render_area_buffer_length(&frame_area);
uint8_t ssd[ssd1306_buffer_length];
memset(ssd, 0, ssd1306_buffer_length);
//Marca a opçao
for (int i = 0; i < 4; i++) {
int y_offset = 14 + i * 14;
int text_offset_x = (128 - strlen(menu[i]) * 8) / 2;
ssd1306_draw_string(ssd, text_offset_x, y_offset, menu[i]);
if ((i) == selected_option) {
ssd1306_draw_string(ssd, text_offset_x - 20, y_offset, "x"); // Marca a seleção
}
// Exibe o estado da opção
char state_str[3];
snprintf(state_str, sizeof(state_str), "%d", menu_states[i]);
ssd1306_draw_string(ssd, text_offset_x + strlen(menu[i]) * 8 + 5, y_offset, state_str);
}
render_on_display(ssd, &frame_area);
}
// Função para exibir mensagens no display OLED
void display_messages(const char *messages[], int count) {
struct render_area frame_area = {
.start_column = 0,
.end_column = ssd1306_width - 1,
.start_page = 0,
.end_page = ssd1306_n_pages - 1
};
calculate_render_area_buffer_length(&frame_area);
uint8_t ssd[ssd1306_buffer_length];
memset(ssd, 0, ssd1306_buffer_length);
for (int i = 0; i < count; i++) {
int text_offset_x = (128 - strlen(messages[i]) * 8) / 2;
int y_offset = 32 + i * 10;
ssd1306_draw_string(ssd, text_offset_x, y_offset, (char *)messages[i]);
}
render_on_display(ssd, &frame_area);
}
// Função para limpar todo o conteudo do display OLED
void clear_display() {
struct render_area frame_area = {
.start_column = 0,
.end_column = ssd1306_width - 1,
.start_page = 0,
.end_page = ssd1306_n_pages - 1
};
calculate_render_area_buffer_length(&frame_area);
uint8_t ssd[ssd1306_buffer_length];
memset(ssd, 0, ssd1306_buffer_length);
render_on_display(ssd, &frame_area);
}
// Função para ler o eixo X do joystick (retorna -1, 0 ou 1)
int read_joy_x() {
adc_select_input(0);
int joy_x = adc_read();
if (joy_x < 1200) return 1; // Joystick movido para direita
else if (joy_x > 2800) return -1; // Joystick movido para esquerda
return 0;
}
// Função para ler o estado do botão do joystick (pressionado ou não) com debouncing
int read_joy_button_debounce() {
static int last_state = 1; // Último estado do botão
int current_state = gpio_get(JOY_SW); // Lê o estado atual do botão
// Se o estado do botão mudou de "não pressionado" (1) para "pressionado" (0)
if (current_state == 0 && last_state == 1) {
sleep_ms(200); // Atraso de debounce
return 1; // Botão foi pressionado
}
last_state = current_state;
return 0; // Botão não foi pressionado
}
// Função de inicialização do joystick
void init_joystick() {
gpio_init(JOY_X);
gpio_set_dir(JOY_X, GPIO_IN);
gpio_init(JOY_SW);
gpio_set_dir(JOY_SW, GPIO_IN);
gpio_pull_up(JOY_SW);
adc_init();
}
// Função para exibir um menu interativo baseado na posição do joystick
void menu_interativo() {
int selected_option = 0; // Índice do menu atual
char *menu[] = { "GR", "HO", "DI", "PT"};
display_oled(menu, selected_option);
while (true) {
int joy_x = read_joy_x();
if (joy_x == -1) selected_option--; //navegação
else if (joy_x == 1) selected_option++; // navegação
// Rolagem do menu
if (selected_option < 0) selected_option = 3;
if (selected_option > 3) selected_option = 0;
display_oled(menu, selected_option);
// Detecta clique no botão
if (read_joy_button_debounce() == 1) {
// Alterna o estado da opção selecionada
menu_states[selected_option] = !menu_states[selected_option];
display_oled(menu, selected_option); // Redesenha o menu após a alteração
sleep_ms(200); // Atraso para evitar múltiplos cliques rápidos
}
sleep_ms(100);
int GR = menu_states[0];
int HO = menu_states[1];
int DI = menu_states[2];
int PT = menu_states[3]; // 0 = liberação manual
// Expressão booleana: CT = !PT || (GR && HO && DI)
int CT = (!PT) || (GR && HO && DI);
if (CT) {
set_rgb(0, 1, 0); // LED verde = catraca liberada
printf("Catraca LIBERADA (CT = 1). LED verde ON.\n");
} else {
set_rgb(1, 0, 0); // LED vermelho = catraca bloqueada
printf("Catraca BLOQUEADA (CT = 0). LED vermelho ON.\n");
}
}
}
int main() {
stdio_init_all();
//inicialização dos botões e leds
gpio_init(btn_A);
gpio_set_dir(btn_A, GPIO_IN);
gpio_pull_up(btn_A);
gpio_init(btn_B);
gpio_set_dir(btn_B, GPIO_IN);
gpio_pull_up(btn_B);
gpio_init(LED_G_PIN);
gpio_set_dir(LED_G_PIN, GPIO_OUT);
gpio_init(LED_R_PIN);
gpio_set_dir(LED_R_PIN, GPIO_OUT);
gpio_init(LED_B_PIN);
gpio_set_dir(LED_B_PIN, GPIO_OUT);
// Inicializa comunicação I2C para o display OLED
i2c_init(i2c1, ssd1306_i2c_clock * 1000);
gpio_set_function(I2C_SDA, GPIO_FUNC_I2C);
gpio_set_function(I2C_SCL, GPIO_FUNC_I2C);
gpio_pull_up(I2C_SDA);
gpio_pull_up(I2C_SCL);
ssd1306_init(); // Inicializa o display OLED
clear_display(); // Limpa a tela inicialmente
init_joystick(); // Inicializa o joystick
menu_interativo(); // Começa o menu
return 0;
}