#include <stdio.h>
#include "pico/stdlib.h"
#include "display_lcd.h"
#include "hardware/gpio.h"
#include "hardware/timer.h"
#include "hardware/irq.h"
#include "hardware/adc.h" // <--- NOVO: Incluir a biblioteca do ADC
#include <string.h> // Para snprintf
/*****************************************************************************/
/******************************************************************************
Variaveis Globais
******************************************************************************/
uint16_t timer_display = 0;
// Low-level alarm infrastructure we'll be using
#define ALARM_NUM 0
#define ALARM_IRQ TIMER_IRQ_0
#define DELAY 50000 // 50ms (para 10Hz, precisamos alternar a cada 50ms)
#define btn1 16
#define btn2 15
#define btn3 14
#define btn4 13
#define btn5 12
#define btn6 11
#define btn7 10
#define btn8 9
#define led1 22
#define led2 21
#define led3 20
#define led4 19
#define led5 18
#define led6 17
#define led7 27
#define led8 28
uint8_t estado_btn1 = 0;
uint8_t estado_btn2 = 0;
uint8_t estado_btn3 = 0;
uint8_t estado_btn4 = 0;
uint8_t estado_btn5 = 0;
uint8_t estado_btn6 = 0;
uint8_t estado_btn7 = 0;
uint8_t estado_btn8 = 0;
bool led1_ligado = false; // Variáveis para controlar o estado dos LEDs
bool led2_ligado = false;
// --- NOVO: Variáveis para o ADC ---
#define ADC_CHANNEL 0 // Usando o canal 0 do ADC (GPIO26)
#define ADC_PIN 26 // GPIO26
#define ADC_MAX_VALUE 4095 // 12 bits ADC (2^12 - 1)
#define VREF_ADC 3.3f // Tensão de referência do ADC (3.3V do Pico)
uint16_t raw_adc_value = 0;
float voltage = 0.0f;
int percentage = 0;
// --- FIM NOVO ADC ---
/*****************************************************************************/
/******************************************************************************
Prototipos das funções
******************************************************************************/
void system_init(void);
void alarm_irq(void);
void button_callback(uint gpio);
void read_adc_and_display(void); // <--- NOVO: Protótipo da função para leitura do ADC
/*****************************************************************************/
/******************************************************************************
Funcao: int main(void)
Entrada: Nenhuma (void)
Saída: Nenhuma (void)
Descrição: Função principal
*****************************************************************************/
int main() {
uint8_t estado = 1;
uint8_t nome[] = "RODRIGO";
uint8_t ra[] = "RA:13027";
uint8_t nome_dois[] = "DENNER ";
uint8_t ra_dois[] = "RA:13039";
uint8_t nome_tres[] = "LEANDRO";
uint8_t ra_tres[] = "RA:13032";
uint8_t nome_quatro[] = "MOHAMED";
uint8_t ra_quatro[] = "RA:00000";
uint8_t nome_cinco[] = "PAULO ARAGAO";
uint8_t ra_cinco[] = "RA:00000";
uint8_t btnn[] = "1";
uint8_t btnn2[] = "2";
uint8_t btnn3[] = "3";
uint8_t btnn4[] = "4";
uint8_t btnn5[] = "5";
uint8_t btnn6[] = "6";
uint8_t btnn7[] = "7";
uint8_t btnn8[] = "8";
// Estas variáveis são para exibir o estado dos botões no LCD.
// Mantenho para consistência com o código original, mas o foco é o ADC.
uint8_t btn1_off[] = "1";
uint8_t btn1_on[] = "0";
uint8_t btn2_off[] = "1";
uint8_t btn2_on[] = "0";
uint8_t btn3_off[] = "1";
uint8_t btn3_on[] = "0";
uint8_t btn4_off[] = "1";
uint8_t btn4_on[] = "0";
uint8_t btn5_on[] = "1";
uint8_t btn5_off[] = "0";
uint8_t btn6_off[] = "0";
uint8_t btn6_on[] = "1";
uint8_t btn7_off[] = "0";
uint8_t btn7_on[] = "1";
uint8_t btn8_off[] = "0";
uint8_t btn8_on[] = "1";
stdio_init_all();
printf("Microcontroladores - Aula 15\n");
sleep_ms(250);
system_init();
posicao_cursor_lcd(1, 1);
escreve_frase_ram_lcd(nome);
posicao_cursor_lcd(2, 1);
escreve_frase_ram_lcd(ra);
sleep_ms(1000);
posicao_cursor_lcd(1, 1);
escreve_frase_ram_lcd(nome_dois);
posicao_cursor_lcd(2, 1);
escreve_frase_ram_lcd(ra_dois);
sleep_ms(1000);
posicao_cursor_lcd(1, 1);
escreve_frase_ram_lcd(nome_tres);
posicao_cursor_lcd(2, 1);
escreve_frase_ram_lcd(ra_tres);
sleep_ms(1000);
posicao_cursor_lcd(1, 1);
escreve_frase_ram_lcd(nome_quatro);
posicao_cursor_lcd(2, 1);
escreve_frase_ram_lcd(ra_quatro);
sleep_ms(1000);
posicao_cursor_lcd(1, 1);
escreve_frase_ram_lcd(nome_cinco);
posicao_cursor_lcd(2, 1);
escreve_frase_ram_lcd(ra_cinco);
sleep_ms(1000);
DesligaCursor();
sleep_ms(500);
LIMPA_DISPLAY();
while (1) {
estado_btn1 = gpio_get(btn1);
estado_btn2 = gpio_get(btn2);
estado_btn3 = gpio_get(btn3);
estado_btn4 = gpio_get(btn4);
estado_btn5 = gpio_get(btn5);
estado_btn6 = gpio_get(btn6);
estado_btn7 = gpio_get(btn7);
estado_btn8 = gpio_get(btn8);
// --- Lógica para LEDs 1 e 2 com frequência (mantida da versão anterior) ---
// O controle do piscar de LED1 e LED2 está na interrupção do timer (alarm_irq)
if (estado_btn1 == 0) { // Botão 1 Pressionado (Pull-up, então 0 é ON)
posicao_cursor_lcd(1, 0);
escreve_frase_ram_lcd(btnn);
posicao_cursor_lcd(2, 0);
escreve_frase_ram_lcd(btn1_off);
// O led1 é controlado na interrupção para piscar
} else {
posicao_cursor_lcd(1, 0);
escreve_frase_ram_lcd(btnn);
posicao_cursor_lcd(2, 0);
escreve_frase_ram_lcd(btn1_on);
gpio_put(led1, 0); // Garante que o LED 1 esteja OFF
}
if (estado_btn2 == 0) { // Botão 2 Pressionado
posicao_cursor_lcd(1, 2);
escreve_frase_ram_lcd(btnn2);
posicao_cursor_lcd(2, 2);
escreve_frase_ram_lcd(btn2_off);
// O led2 é controlado na interrupção para piscar
} else {
posicao_cursor_lcd(1, 2);
escreve_frase_ram_lcd(btnn2);
posicao_cursor_lcd(2, 2);
escreve_frase_ram_lcd(btn2_on);
gpio_put(led2, 0); // Garante que o LED 2 esteja OFF
}
// --- FIM da Lógica para LEDs 1 e 2 ---
// --- Lógica para LEDs 3 e 4 (do projeto anterior) ---
if (estado_btn3 == 0) { // Botão 3 Pressionado
posicao_cursor_lcd(1, 4);
escreve_frase_ram_lcd(btnn3);
posicao_cursor_lcd(2, 4);
escreve_frase_ram_lcd(btn3_off);
gpio_put(led3, 1);
} else {
posicao_cursor_lcd(1, 4);
escreve_frase_ram_lcd(btnn3);
posicao_cursor_lcd(2, 4);
escreve_frase_ram_lcd(btn3_on);
gpio_put(led3, 0);
}
// Lógica para LED 4 (depende de btn3 e btn4)
if (estado_btn4 == 0 && estado_btn3 == 0) { // Ambos OFF (botões pull-up, então 0 é ON)
posicao_cursor_lcd(1, 6);
escreve_frase_ram_lcd(btnn4);
posicao_cursor_lcd(2, 6);
escreve_frase_ram_lcd(btn4_off);
gpio_put(led4, 1); // LED 4 ON
} else {
posicao_cursor_lcd(1, 6);
escreve_frase_ram_lcd(btnn4);
posicao_cursor_lcd(2, 6);
escreve_frase_ram_lcd(btn4_on);
gpio_put(led4, 0); // LED 4 OFF
}
// --- FIM da Lógica para LEDs 3 e 4 ---
// --- Lógica para LED 5 (inverso do botão 5) ---
if (estado_btn5 == 0) { // Botão 5 Pressionado (OFF)
posicao_cursor_lcd(1, 8);
escreve_frase_ram_lcd(btnn5);
posicao_cursor_lcd(2, 8);
escreve_frase_ram_lcd(btn5_off);
gpio_put(led5, 0); // LED 5 OFF
} else { // Botão 5 Solto (ON)
posicao_cursor_lcd(1, 8);
escreve_frase_ram_lcd(btnn5);
posicao_cursor_lcd(2, 8);
escreve_frase_ram_lcd(btn5_on);
gpio_put(led5, 1); // LED 5 ON
}
// --- FIM da Lógica para LED 5 ---
// --- Lógica para LED 6 (todas chaves OFF acende, qualquer outra apaga) ---
if (estado_btn6 == 1 && estado_btn7 == 1 && estado_btn8 == 1) { // Todos botões soltos (OFF)
posicao_cursor_lcd(1, 10);
escreve_frase_ram_lcd(btnn6);
posicao_cursor_lcd(2, 10);
escreve_frase_ram_lcd(btn6_off);
gpio_put(led6, 1); // LED 6 ON
} else {
posicao_cursor_lcd(1, 10);
escreve_frase_ram_lcd(btnn6);
posicao_cursor_lcd(2, 10);
escreve_frase_ram_lcd(btn6_on);
gpio_put(led6, 0); // LED 6 OFF
}
// --- FIM da Lógica para LED 6 ---
// --- Lógica para LEDs 7 e 8 (assumindo que o código original era direto) ---
if (estado_btn7 == 0) { // Botão 7 Pressionado
posicao_cursor_lcd(1, 12);
escreve_frase_ram_lcd(btnn7);
posicao_cursor_lcd(2, 12);
escreve_frase_ram_lcd(btn7_off);
gpio_put(led7, 1);
} else {
posicao_cursor_lcd(1, 12);
escreve_frase_ram_lcd(btnn7);
posicao_cursor_lcd(2, 12);
escreve_frase_ram_lcd(btn7_on);
gpio_put(led7, 0);
}
if (estado_btn8 == 0) { // Botão 8 Pressionado
posicao_cursor_lcd(1, 14);
escreve_frase_ram_lcd(btnn8);
posicao_cursor_lcd(2, 14);
escreve_frase_ram_lcd(btn8_off);
gpio_put(led8, 1);
} else {
posicao_cursor_lcd(1, 14);
escreve_frase_ram_lcd(btnn8);
posicao_cursor_lcd(2, 14);
escreve_frase_ram_lcd(btn8_on);
gpio_put(led8, 0);
}
// --- FIM da Lógica para LEDs 7 e 8 ---
// --- NOVO: Leitura e Exibição do ADC ---
read_adc_and_display();
// --- FIM NOVO ADC ---
sleep_ms(5); // Um pequeno atraso no loop principal
}
}
/******************************************************************************
Funcao: void system_init(void)
Entrada: Nenhuma (void)
Saída: Nenhuma (void)
Descrição: Inicializa sistema (microcontrolador e periféricos)
*****************************************************************************/
void system_init(void) {
uint64_t target = 0;
printf("Init Hardware ....\n");
sleep_ms(10);
/* o trecho de codigo abaixo realiza a inicializacao da interrupt de timer */
// Enable the interrupt for the alarm (we're using Alarm 0)
hw_set_bits(&timer_hw->inte, 1u << ALARM_NUM);
// Associate an interrupt handler with the ALARM_IRQ
irq_set_exclusive_handler(ALARM_IRQ, alarm_irq);
// Enable the alarm interrupt
irq_set_enabled(ALARM_IRQ, true);
target = timer_hw->timerawl + DELAY;
// Write the lower 32 bits of the target time to the alarm register, arming it.
timer_hw->alarm[ALARM_NUM] = (uint32_t)target;
/* Fim da inicialização do interrupcao de timer */
init_lcd();
printf("Init Hardware ....\n");
sleep_ms(10);
// Inicialização dos LEDs
gpio_init(led1);
gpio_set_dir(led1, GPIO_OUT); // Certifique-se que são SAÍDAS
gpio_init(led2);
gpio_set_dir(led2, GPIO_OUT);
gpio_init(led3); // Você tinha apenas init, mas não set_dir para led3, 7, 8
gpio_set_dir(led3, GPIO_OUT);
gpio_init(led4);
gpio_set_dir(led4, GPIO_OUT);
gpio_init(led5);
gpio_set_dir(led5, GPIO_OUT);
gpio_init(led6);
gpio_set_dir(led6, GPIO_OUT);
gpio_init(led7); // Adicionado
gpio_set_dir(led7, GPIO_OUT);
gpio_init(led8); // Adicionado
gpio_set_dir(led8, GPIO_OUT);
// Inicialização dos Botões
gpio_init(btn1);
gpio_set_dir(btn1, GPIO_IN);
gpio_pull_up(btn1); // Enable pull-up resistor
gpio_init(btn2);
gpio_set_dir(btn2, GPIO_IN);
gpio_pull_up(btn2); // Enable pull-up resistor
gpio_init(btn3);
gpio_set_dir(btn3, GPIO_IN);
gpio_pull_up(btn3); // Enable pull-up resistor
gpio_init(btn4);
gpio_set_dir(btn4, GPIO_IN);
gpio_pull_up(btn4); // Enable pull-up resistor
gpio_init(btn5);
gpio_set_dir(btn5, GPIO_IN);
gpio_pull_up(btn5); // Enable pull-up resistor
gpio_init(btn6);
gpio_set_dir(btn6, GPIO_IN);
gpio_pull_up(btn6); // Enable pull-up resistor
gpio_init(btn7);
gpio_set_dir(btn7, GPIO_IN);
gpio_pull_up(btn7); // Enable pull-up resistor
gpio_init(btn8);
gpio_set_dir(btn8, GPIO_IN);
gpio_pull_up(btn8); // Enable pull-up resistor
gpio_set_irq_enabled_with_callback(btn1, GPIO_IRQ_EDGE_FALL, true, (gpio_irq_callback_t)&button_callback);
gpio_set_irq_enabled_with_callback(btn2, GPIO_IRQ_EDGE_FALL, true, (gpio_irq_callback_t)&button_callback);
gpio_set_irq_enabled_with_callback(btn3, GPIO_IRQ_EDGE_FALL, true, (gpio_irq_callback_t)&button_callback);
gpio_set_irq_enabled_with_callback(btn4, GPIO_IRQ_EDGE_FALL, true, (gpio_irq_callback_t)&button_callback);
gpio_set_irq_enabled_with_callback(btn5, GPIO_IRQ_EDGE_FALL, true, (gpio_irq_callback_t)&button_callback);
gpio_set_irq_enabled_with_callback(btn6, GPIO_IRQ_EDGE_FALL, true, (gpio_irq_callback_t)&button_callback);
gpio_set_irq_enabled_with_callback(btn7, GPIO_IRQ_EDGE_FALL, true, (gpio_irq_callback_t)&button_callback);
gpio_set_irq_enabled_with_callback(btn8, GPIO_IRQ_EDGE_FALL, true, (gpio_irq_callback_t)&button_callback);
// --- NOVO: Inicialização do ADC ---
adc_init();
adc_gpio_init(ADC_PIN); // Inicializa o GPIO como entrada ADC
adc_select_input(ADC_CHANNEL); // Seleciona o canal do ADC
// --- FIM NOVO ADC ---
}
/******************************************************************************
Funcao: void alarm_irq(void)
Entrada: Nenhuma (void)
Saída: Nenhuma (void)
Descrição: Função tratamento interrupcao do timer 0
*****************************************************************************/
void alarm_irq(void) {
printf("Timer interrupt occurred!\n");
// Clear the alarm irq
hw_clear_bits(&timer_hw->intr, 1u << ALARM_NUM);
uint64_t target = timer_hw->timerawl + DELAY;
// Write the lower 32 bits of the target time to the alarm register, arming it.
timer_hw->alarm[ALARM_NUM] = (uint32_t)target;
if (timer_display) timer_display--;
// Lógica para piscar o LED 1 (se btn1 estiver pressionado)
if (gpio_get(btn1) == 0) { // Botão 1 Pressionado
led1_ligado = !led1_ligado; // Inverte o estado
gpio_put(led1, led1_ligado); // Aplica o novo estado
} else {
gpio_put(led1, 0); // Garante que o LED 1 esteja OFF se o botão não estiver pressionado
}
// Lógica para piscar o LED 2 (se btn2 estiver pressionado)
if (gpio_get(btn2) == 0) { // Botão 2 Pressionado
led2_ligado = !led2_ligado; // Inverte o estado
gpio_put(led2, led2_ligado); // Aplica o novo estado
} else {
gpio_put(led2, 0); // Garante que o LED 2 esteja OFF se o botão não estiver pressionado
}
}
/******************************************************************************
Funcao: void button_callback(uint gpio)
Entrada: uint gpio - number of gpio
Saída: Nenhuma (void)
Descrição: Função tratamento interrupcao do botao
*****************************************************************************/
void button_callback(uint gpio) {
// Lógica de debounce simples pode ser adicionada aqui se necessário
// Por exemplo, checar tempo desde a última interrupção para o mesmo GPIO.
// No momento, apenas imprime e não altera o estado do LED aqui para btn1/2
// pois o controle é feito na ISR do timer.
if (gpio == btn1) {
// printf("Button 1 pressed!\n"); // Manter para debug se quiser
} else if (gpio == btn2) {
// printf("Button 2 pressed!\n"); // Manter para debug se quiser
} else if (gpio == btn3) {
// printf("Button 3 pressed!\n"); // Manter para debug se quiser
} else if (gpio == btn4) {
// printf("Button 4 pressed!\n"); // Manter para debug se quiser
} else if (gpio == btn5) {
// printf("Button 5 pressed!\n"); // Manter para debug se quiser
} else if (gpio == btn6) {
// printf("Button 6 pressed!\n"); // Manter para debug se quiser
} else if (gpio == btn7) {
// printf("Button 7 pressed!\n"); // Manter para debug se quiser
} else if (gpio == btn8) {
// printf("Button 8 pressed!\n"); // Manter para debug se quiser
}
}
/******************************************************************************
Funcao: void read_adc_and_display(void)
Entrada: Nenhuma (void)
Saída: Nenhuma (void)
Descrição: Lê o ADC e exibe no LCD
*****************************************************************************/
void read_adc_and_display(void) {
char lcd_buffer[17]; // Buffer para armazenar a string para o LCD (16 caracteres + null terminator)
// 1. Lê o valor bruto do ADC
raw_adc_value = adc_read();
// 2. Converte o valor bruto para tensão
// voltage = (raw_adc_value * VREF_ADC) / ADC_MAX_VALUE; // Forma mais direta
voltage = raw_adc_value * (VREF_ADC / (float)ADC_MAX_VALUE); // Melhor para evitar overflow se VREF for grande
// 3. Calcula a porcentagem (baseado na faixa de 0 a VREF_ADC)
percentage = (int)((voltage / VREF_ADC) * 100);
// 4. Exibe no LCD (linha 2)
// Limpa a linha 2 antes de escrever para evitar lixo
posicao_cursor_lcd(2, 0); // Posição (linha 2, coluna 0)
escreve_frase_ram_lcd(" "); // Limpa a linha (16 espaços)
// Formata a string para exibir tensão e porcentagem
// Exemplo: "V:2.50V 75%" ou "RAW: 1234 50%"
// Vou fazer "V: 2.50V P: 75%" se couber
// Ou pode ser apenas "75% (2.50V)" para focar na porcentagem
// Opção 1: Priorizando Porcentagem e Valor Numérico (linha 2 completa)
// Ex: "75% (2.50V)"
// snprintf(lcd_buffer, sizeof(lcd_buffer), "%d%% (%.2fV)", percentage, voltage);
// Opção 2: Separado para caber no LCD (pode ser "75% " e "2.50V")
// O problema é que a linha 2 já está sendo usada para o estado dos botões.
// Vamos consolidar em uma única linha como pediu o enunciado: "Indique no display (linha 2) em porcentagem o valor lido; Indique em valores numéricos;"
// Isso sugere que as infos dos botões na linha 2 talvez devam sair.
// Ou, podemos usar colunas diferentes. Vou usar colunas diferentes.
// Vamos exibir a porcentagem na coluna 0 da linha 2
// E o valor numérico (tensão) em outra coluna da linha 2
// Isso se as informações dos botões na linha 2 não estiverem mais lá.
// Se elas estiverem lá, o LCD ficará bagunçado.
// Assumindo que a linha 2 é exclusiva para o ADC agora:
// Limpa a linha 2 inteira primeiro para não ter conflito com os botões
posicao_cursor_lcd(2, 0);
escreve_frase_ram_lcd(" ");
// Exibe a porcentagem
snprintf(lcd_buffer, sizeof(lcd_buffer), "%3d%%", percentage); // %3d para alinhar 3 digitos
posicao_cursor_lcd(2, 0); // Linha 2, Coluna 0
escreve_frase_ram_lcd((uint8_t*)lcd_buffer);
// Exibe o valor numérico (tensão)
snprintf(lcd_buffer, sizeof(lcd_buffer), "%.2fV", voltage); // .2f para 2 casas decimais
posicao_cursor_lcd(2, 6); // Linha 2, Coluna 6 (para não sobrepor a porcentagem)
escreve_frase_ram_lcd((uint8_t*)lcd_buffer);
}