// IFMA - Embarcatech - jan-fev/2025
// Atividade Capítulos 05 a 08 - Clock e Temporizador
// Nome: Alberto Carlos de Oliveira Andrade
// Tarefa 2:
// 05 - Modifique o exemplo de código apresentado na videoaula (reproduzido abaixo) para
// controlar os três LEDs RGB da placa BitDogLab usando o módulo PWM e interrupções, seguindo
// as orientações a seguir:
// A. O LED vermelho deve ser acionado com um PWM de 1kHz.
// B. O duty cycle deve ser iniciado em 5% e atualizado a cada 2 segundos em incrementos de 5%.
// Quando atingir o valor máximo, deve ‐retornar a 5%.
// - O LED azul deve ser acionado com um PWM de 10kHz.
#include "pico/stdlib.h"
#include "hardware/pwm.h"
#include "hardware/clocks.h"
#include <stdio.h>
#define LED_R_PIN 13 // Pino do LED Vermelho
#define LED_G_PIN 11 // Pino do LED Verde
#define LED_B_PIN 12 // Pino do LED Azul
const uint16_t FREQ_R = 1000; // Frequência do PWM para o LED vermelho (1 kHz)
const uint16_t FREQ_B = 10000; // Frequência do PWM para o LED azul (10 kHz)
const uint16_t PASSO = 500; // Passo do ajuste do duty cycle
uint dutyc_red = 500; // Duty cycle inicial do LED vermelho (5% de brilho)
uint dutyc_blue = 10000; // Duty cycle inicial do LED azul (100% de brilho)
// Prototipação das funções
void init_rgb_leds();
void setup_pwm(uint pin, uint freq);
void pwm_irq_handler(); // Função de interrupção para controle de PWM
void main() {
stdio_init_all(); // Inicializa o sistema para comunicação serial (para debugar e exibir dados)
init_rgb_leds(); // Inicializa os pinos dos LEDs RGB (não está usando o LED verde)
// Configura o PWM para os LEDs vermelho e azul com as frequências especificadas
setup_pwm(LED_R_PIN, FREQ_R);
setup_pwm(LED_B_PIN, FREQ_B);
while (1) {
// O controle dos LEDs é feito via interrupção de PWM, sem necessidade de código adicional no loop
}
}
void init_rgb_leds() {
// Configura os pinos dos LEDs como saída
gpio_init(LED_R_PIN);
gpio_set_dir(LED_R_PIN, GPIO_OUT);
gpio_init(LED_G_PIN);
gpio_set_dir(LED_G_PIN, GPIO_OUT);
gpio_init(LED_B_PIN);
gpio_set_dir(LED_B_PIN, GPIO_OUT);
}
void setup_pwm(uint pin, uint freq) {
// Configura o pino para uso com PWM
gpio_set_function(pin, GPIO_FUNC_PWM);
uint slice_num = pwm_gpio_to_slice_num(pin); // Obtém o número do slice PWM para o pino
pwm_config config = pwm_get_default_config(); // Configuração padrão do PWM
float div = (float)clock_get_hz(clk_sys) / (freq * 10000); // Calcula o divisor para ajustar a frequência
pwm_config_set_clkdiv(&config, div); // Define o divisor de clock
pwm_config_set_wrap(&config, 10000); // Define o valor de wrap para o PWM (resolução de 10 bits)
pwm_init(slice_num, &config, true); // Inicializa o PWM para o pino com a configuração
// Configura a interrupção de PWM
irq_set_exclusive_handler(PWM_IRQ_WRAP, pwm_irq_handler); // Define o handler para a interrupção de PWM
pwm_clear_irq(slice_num); // Limpa qualquer interrupção pendente
pwm_set_irq_enabled(slice_num, true); // Habilita as interrupções para este slice de PWM
irq_set_enabled(PWM_IRQ_WRAP, true); // Habilita interrupções globais
}
void pwm_irq_handler() {
const uint32_t PWM_REFRESH_LEVEL = 40000; // Número de ciclos antes de atualizar os LEDs
static uint up_down = 1; // Flag que controla o aumento ou diminuição do brilho
static uint32_t count = 0; // Contador para controlar a frequência de atualização do PWM
uint32_t slice = pwm_get_irq_status_mask(); // Obtém o status da interrupção do PWM
pwm_clear_irq(slice); // Limpa a interrupção
if (count++ < PWM_REFRESH_LEVEL) return; // Se o contador não atingiu o limite, não faz nada
count = 0; // Reseta o contador para o próximo ciclo
// Atualiza o duty cycle dos LEDs vermelho e azul
pwm_set_gpio_level(LED_R_PIN, dutyc_red);
pwm_set_gpio_level(LED_B_PIN, dutyc_blue);
// Exibe o duty cycle dos LEDs no terminal (para depuração)
printf("Duty Cycle do LED Vermelho: %.f%% | Duty Cycle do LED Azul: %.f%%\n", dutyc_red * 100.0 / 10000, dutyc_blue * 100.0 / 10000);
// Ajusta o brilho do LED vermelho (com aumento ou diminuição gradual)
if (up_down) {
dutyc_red += PASSO; // Aumenta o brilho
if (dutyc_red >= 10000) // Se o brilho atingir o máximo (100%)
up_down = 0; // Muda a direção para diminuir o brilho
} else {
dutyc_red -= PASSO; // Diminui o brilho
if (dutyc_red <= 500) // Se o brilho atingir o mínimo (5%)
up_down = 1; // Muda a direção para aumentar o brilho
}
sleep_ms(2000); // Espera 2 segundos antes de ajustar novamente o brilho
}