//EmbarcaTech
//Ana Classen #embarchip
#include <stdio.h>
#include "hardware/adc.h" //Biblioteca para manipulação do ADC no RP2040
#include "hardware/pwm.h" //Biblioteca para controle de PWM no RP2040
#include "pico/stdlib.h"
#include "hardware/timer.h"
#include "ss_oled.h"
#include "pico/binary_info.h"
#include "ws2812.pio.h"
#define BUTTON_A 5
#define BUTTON_B 6
const int ADC_CHANNEL_2 = 2;
#define ADC_MIC 28
#define ADC_VREF 3.3
#define ADC_RANGE (1 << 12) //100000000000b ou 4096d
#define ADC_CONVERT (ADC_VREF / (ADC_RANGE - 1)) // 3.3/4095 = 0,806 mV
#define NUM_PIXELS 25 // Número total de LEDs na matriz (8x8)
#define WS2812_PIN 7 // Pino de dados para os LEDs
#define SDA_PIN 16 // Pino SDA configurado no Wokwi
#define SCL_PIN 17 // Pino SCL configurado no Wokwi
#define RESET_PIN -1
int rc;
SSOLED oled;
static uint8_t ucBuffer[1024];
// Pinos dos componentes
const int LED_R = 13;
const int LED_B = 12; //Indicador de acionamento
const int LED_G = 11;
const int BUZZER1 = 10;
const float DIVIDER_PWM = 16.0; //Divisor fracional do clock para o PWM
const uint16_t PERIODO = 4096; //Período do PWM (valor máximo do contador)
uint16_t led_b_level, led_r_level = 100, buzz_1_level = 100; //Inicialização dos níveis de PWM
uint slice_led_b, slice_led_r, slice_led_g, slice_buzz_1; //Variáveis para armazenar os slices de PWM correspondentes
// Função para criar a cor no formato GRB
uint32_t urgb_u32(uint8_t r, uint8_t g, uint8_t b) {
return (g << 16) | (r << 8) | b;
}
// Sinal de ! na matriz
void draw_alerta(uint32_t *pixels) {
// Representação de um alerta em uma matriz 5x5
uint8_t alerta[5][5] = {
{0, 0, 1, 0, 0},
{0, 1, 0, 1, 0},
{1, 0, 0, 0, 1},
{0, 1, 1, 1, 0},
{0, 1, 1, 1, 0},};
// Define as cores para o alerta (vermelho) e fundo (apagado)
uint32_t alerta_color = urgb_u32(255, 0, 0); // Vermelho
uint32_t off_color = urgb_u32(0, 0, 0); // Apagado
// Preenche a matriz de pixels com base no alerta
for (int y = 0; y < 5; y++) {
for (int x = 0; x < 5; x++) {
int index = y * 5 + x; // Índice linear para a matriz 1D
pixels[index] = alerta[y][x] ? alerta_color : off_color;
}
}
}
// Apaga matriz
void apaga (uint32_t *pixels) {
uint8_t apaga[5][5];
uint32_t off_color = urgb_u32(0, 0, 0); // Apagado
for (int y = 0; y < 5; y++) {
for (int x = 0; x < 5; x++) {
int index = y * 5 + x; // Índice linear para a matriz 1D
pixels[index] = apaga[y][x] ? off_color : off_color;
}
}
}
// Função para configurar o PWM de um pin (Led rgb ou buzzer)
void setup_pwm(uint pin, uint *slice, uint16_t level, uint freq) {
gpio_set_function(pin, GPIO_FUNC_PWM); // Configura o pino como saída PWM
*slice = pwm_gpio_to_slice_num(pin); // Obtém o slice do PWM associado ao pino
pwm_set_clkdiv(*slice, DIVIDER_PWM); // Define o divisor de clock do PWM
pwm_set_wrap(*slice, PERIODO); // Configura o valor máximo do contador (período do PWM)
pwm_set_gpio_level(pin, level); // Define o nível inicial do PWM
pwm_set_enabled(*slice, true); // Habilita o PWM no slice correspondente
}
// Função para desativar o PWM
void stop_pwm(uint buzz) {
uint slice_num = pwm_gpio_to_slice_num(buzz); // Obtém o slice PWM
pwm_set_enabled(slice_num, false); // Desativa o PWM
gpio_set_function(buzz, GPIO_FUNC_SIO); // Restaura o pino para saída digital
gpio_put(buzz, false); // Garante que o pino fique em nível baixo
}
// Função de configuração geral
void setup() {
stdio_init_all(); // Inicializa a porta serial para saída de dados
// Inicializa o ADC e os pinos de entrada analógica
adc_init();
adc_gpio_init(ADC_MIC);
sleep_ms(1000);
printf("Aguarde...\n");
// Inicializa os LEDs como saídas
gpio_init(LED_G);
gpio_set_dir(LED_G, GPIO_OUT);
// Inicializa os botões como entradas com pull-up
gpio_init(BUTTON_A);
gpio_set_dir(BUTTON_A, GPIO_IN);
gpio_pull_up(BUTTON_A);
gpio_init(BUTTON_B);
gpio_set_dir(BUTTON_B, GPIO_IN);
gpio_pull_up(BUTTON_B);
sleep_ms(100); // Atraso para evitar múltiplas leituras
printf("Programa Inicializado\n");
}
// Função principal
int main() {
setup(); // Chama a função de configuração
// Variáveis de controle
bool buzzer_ative = false;
bool ative_MIC=false;
int cont=0;
static absolute_time_t last_press_time = 0; // Armazena o tempo da última pressão do botão.
//MICROFONE
uint adc_raw;
float MIC_decibeis;
// DISPLAY OLED
rc = oledInit(&oled, OLED_128x64, 0x3c, 0, 0, 1, SDA_PIN, SCL_PIN, RESET_PIN, 1000000L);
if (rc != OLED_NOT_FOUND)
{}
oledWriteString(&oled, 0,0,1,(char *)"Programa iniciado", FONT_SMALL,0,1);
//Matriz de LED
PIO pio = pio0;
int sm = 0;
uint offset = pio_add_program(pio, &ws2812_program);
ws2812_program_init(pio, sm, offset, WS2812_PIN, 800000, false);
uint32_t pixels[NUM_PIXELS] = {0}; //vetor de tamanho 25
// Loop principal
while (1) {
//Ativando Microfone
if (!gpio_get(BUTTON_B)) { //Troca de função na leitura ADC
ative_MIC = !ative_MIC;
sleep_ms(50);
}
//Após ativação com botão B inicia leitura do MIC
if(ative_MIC==true){
gpio_put(LED_G, 1); //LED para indicar ativação do microfone
sleep_ms(100);
adc_select_input(ADC_CHANNEL_2); // Seleciona o canal ADC para o MIC
sleep_us(2); // Pequeno delay para estabilidade
adc_raw = adc_read(); // raw voltage from ADC
printf(" %d\n", adc_raw);
sleep_us(250);
oledFill(&oled, 0, 1);
//conta se a leitura do microfone for alta (sons altos oscilam com amplitude alta)
if (adc_raw > 2400) cont ++; //valor de teste 2300 (valores acima de 3000)
// Campainha: 80dB e 90dB; bater as palmas: 120dB.
if (cont == 3){ //Após pelo menos umas 3 oscilações do som da campainha
oledWriteString(&oled, 0,0,1,(char *)"CAMPAINHA", FONT_NORMAL,0,1);
sleep_ms(100);
for(int i = 0; i < 5; i++){ //pisca o simbolo 5x
draw_alerta(pixels);
for (int i = 0; i < NUM_PIXELS; i++) {
pio_sm_put_blocking(pio, sm, pixels[i] << 8u);
}
sleep_ms(300);
apaga(pixels);
for (int i = 0; i < NUM_PIXELS; i++) {
pio_sm_put_blocking(pio, sm, pixels[i] << 8u);
}
sleep_ms(100);
}
cont=0; // Reinicia contagem
} else {
oledFill(&oled, 0, 1);
oledWriteString(&oled, 0,0,1,(char *)"SEM SOM", FONT_NORMAL,0,1);
}
} else{
gpio_put(LED_G, 0); //LED para indicar ativação do microfone
}
//Button A e buzzer 1 utilizados para testar leitura do microfone
if (!gpio_get(BUTTON_A)) { // Verifica se o botão foi pressionado
sleep_ms(10); // Debounce simples
if (!buzzer_ative) { // Ativa o buzzer se ele estiver desligado
buzzer_ative = true;
setup_pwm(BUZZER1, &slice_buzz_1, buzz_1_level, 3000);
}
} else if (buzzer_ative && absolute_time_diff_us(last_press_time, get_absolute_time()) > 4000000) { //Desativa o buzzer após 4s
last_press_time = get_absolute_time();
buzzer_ative = false;
stop_pwm(BUZZER1); // Desliga o buzzer
}
sleep_ms(100); // Pequeno delay para evitar mudanças muito rápidas
}
}