#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/ledc.h"
#include "hal/adc_types.h"
#include "esp_adc/adc_oneshot.h"
#include "esp_err.h"
// Definiciones de pines y parámetros de configuración para PWM
#define LEDC_TIMER LEDC_TIMER_0 // Temporizador para PWM
#define LEDC_MODE LEDC_LOW_SPEED_MODE // Modo PWM (baja velocidad)
#define LEDC_OUTPUT_PIN (5) // Pin de salida PWM (para controlar un LED)
#define LEDC_CHANNEL LEDC_CHANNEL_0 // Canal de PWM
#define LEDC_DUTY_RES LEDC_TIMER_13_BIT // Resolución de 25 bits para el ciclo de trabajo
#define LEDC_FREQUENCY (5000) // Frecuencia de la señal PWM a 5 kHz
// Pines para controlar los LEDs y botones
#define PIN_LED_HORARIO 33 // Pin para el LED que indica el sentido horario
#define PIN_LED_ANTIHORARIO 26 // Pin para el LED que indica el sentido antihorario
#define PIN_BUTTON_HORARIO 12 // Pin para el botón de sentido horario
#define PIN_BUTTON_ANTIHORARIO 13 // Pin para el botón de sentido antihorario
#define PIN_BUTTON_OFF 15 // Pin para el botón de apagado
#define PIN_LED_HORARIO_BUTTON 32 // Pin para el LED que indica si el botón horario está presionado
#define PIN_LED_ANTIHORARIO_BUTTON 25 // Pin para el LED que indica si el botón antihorario está presionado
// Variables para controlar el estado de los botones
volatile bool button_state_horario = false;
volatile bool button_state_antihorario = false;
volatile bool button_state_off = false;
// Definición de retardo por rebote de botones (debounce)
#define DEBOUNCE_DELAY_MS 500
// Variables para almacenar el tiempo de la última interrupción de cada botón
volatile unsigned long last_interrupt_time_horario = 0;
volatile unsigned long last_interrupt_time_antihorario = 0;
volatile unsigned long last_interrupt_time_off = 0;
// Función para manejar las interrupciones de los botones
static void handle_button_interrupt(int button) {
unsigned long current_time = xTaskGetTickCountFromISR() * portTICK_PERIOD_MS;
unsigned long *last_interrupt_time = NULL;
// Determinamos qué botón fue presionado y actualizamos el estado
switch (button) {
case PIN_BUTTON_HORARIO:
last_interrupt_time = &last_interrupt_time_horario;
button_state_horario = true;
break;
case PIN_BUTTON_ANTIHORARIO:
last_interrupt_time = &last_interrupt_time_antihorario;
button_state_antihorario = true;
break;
case PIN_BUTTON_OFF:
last_interrupt_time = &last_interrupt_time_off;
button_state_off = true;
break;
}
// Verificamos si ha pasado suficiente tiempo desde la última interrupción (para evitar rebotes)
if (current_time - *last_interrupt_time > DEBOUNCE_DELAY_MS) {
*last_interrupt_time = current_time;
}
}
// Función para configurar los pines de los LEDs
void configure_leds() {
gpio_config_t config = {
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = (1ULL << PIN_LED_HORARIO) | (1ULL << PIN_LED_ANTIHORARIO) |
(1ULL << PIN_LED_HORARIO_BUTTON) | (1ULL << PIN_LED_ANTIHORARIO_BUTTON)
};
gpio_config(&config);
// Apagar todos los LEDs al inicio
gpio_set_level(PIN_LED_HORARIO, 0);
gpio_set_level(PIN_LED_ANTIHORARIO, 0);
gpio_set_level(PIN_LED_HORARIO_BUTTON, 0);
gpio_set_level(PIN_LED_ANTIHORARIO_BUTTON, 0);
}
// Función para configurar los pines de los botones
void configure_button_pins() {
gpio_set_direction(PIN_BUTTON_HORARIO, GPIO_MODE_INPUT); // El botón horario es una entrada
gpio_pullup_en(PIN_BUTTON_HORARIO); // Activamos la resistencia pull-up interna
gpio_set_direction(PIN_BUTTON_ANTIHORARIO, GPIO_MODE_INPUT); // El botón antihorario es una entrada
gpio_pullup_en(PIN_BUTTON_ANTIHORARIO); // Activamos la resistencia pull-up interna
gpio_set_direction(PIN_BUTTON_OFF, GPIO_MODE_INPUT); // El botón de apagado es una entrada
gpio_pullup_en(PIN_BUTTON_OFF); // Activamos la resistencia pull-up interna
}
// Función para configurar las interrupciones de los botones
void configure_button_interrupts() {
gpio_install_isr_service(0); // Instalamos el servicio de interrupciones
// Configuramos las interrupciones para los botones en flanco de bajada (presionados)
gpio_set_intr_type(PIN_BUTTON_HORARIO, GPIO_INTR_NEGEDGE);
gpio_isr_handler_add(PIN_BUTTON_HORARIO, (gpio_isr_t)handle_button_interrupt, (void*)PIN_BUTTON_HORARIO);
gpio_set_intr_type(PIN_BUTTON_ANTIHORARIO, GPIO_INTR_NEGEDGE);
gpio_isr_handler_add(PIN_BUTTON_ANTIHORARIO, (gpio_isr_t)handle_button_interrupt, (void*)PIN_BUTTON_ANTIHORARIO);
gpio_set_intr_type(PIN_BUTTON_OFF, GPIO_INTR_NEGEDGE);
gpio_isr_handler_add(PIN_BUTTON_OFF, (gpio_isr_t)handle_button_interrupt, (void*)PIN_BUTTON_OFF);
}
// Función para configurar el temporizador y canal de PWM
void configure_pwm() {
// Configuración del temporizador para PWM
ledc_timer_config_t ledc_timer = {
.speed_mode = LEDC_MODE,
.timer_num = LEDC_TIMER,
.duty_resolution = LEDC_DUTY_RES,
.freq_hz = LEDC_FREQUENCY,
.clk_cfg = LEDC_AUTO_CLK
};
ledc_timer_config(&ledc_timer);
// Configuración del canal PWM
ledc_channel_config_t ledc_channel = {
.speed_mode = LEDC_MODE,
.channel = LEDC_CHANNEL,
.timer_sel = LEDC_TIMER,
.intr_type = LEDC_INTR_DISABLE,
.gpio_num = LEDC_OUTPUT_PIN, // Pin para el LED controlado por PWM
.duty = 0, // Ciclo de trabajo inicial (apagado)
.hpoint = 0
};
ledc_channel_config(&ledc_channel);
}
// Función para cambiar la intensidad del LED controlado por PWM
void change_pwm_intensity(int duty_cycle) {
uint16_t led_duty = (uint16_t)(8191 * (duty_cycle / 2047.0)); // Calculamos el ciclo de trabajo
ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, led_duty); // Aplicamos el nuevo ciclo de trabajo
ledc_update_duty(LEDC_MODE, LEDC_CHANNEL); // Actualizamos el ciclo de trabajo
}
// Función para controlar los LEDs según el estado de los botones
void control_leds() {
// Control de los LEDs en función de los botones
if (button_state_horario) {
button_state_horario = false;
gpio_set_level(PIN_LED_HORARIO, 1); // Enciende el LED horario
gpio_set_level(PIN_LED_HORARIO_BUTTON, 1); // Enciende el LED del botón horario
}
if (button_state_antihorario) {
button_state_antihorario = false;
gpio_set_level(PIN_LED_ANTIHORARIO, 1); // Enciende el LED antihorario
gpio_set_level(PIN_LED_ANTIHORARIO_BUTTON, 1); // Enciende el LED del botón antihorario
}
if (button_state_off) {
button_state_off = false;
gpio_set_level(PIN_LED_HORARIO, 0); // Apaga el LED horario
gpio_set_level(PIN_LED_ANTIHORARIO, 0); // Apaga el LED antihorario
gpio_set_level(PIN_LED_HORARIO_BUTTON, 0); // Apaga el LED del botón horario
gpio_set_level(PIN_LED_ANTIHORARIO_BUTTON, 0); // Apaga el LED del botón antihorario
}
}
// Función principal que se ejecuta al iniciar el programa
void app_main(void) {
// Configuramos los pines y el PWM
configure_pwm();
configure_leds();
configure_button_pins();
configure_button_interrupts();
int adc_reading; // Variable para almacenar la lectura del ADC
adc_oneshot_unit_handle_t adc_controller;
// Configuración del ADC (ADC2) para leer valores de un canal
adc_oneshot_unit_init_cfg_t init_config = {
.unit_id = ADC_UNIT_2, // Usamos el ADC2
.ulp_mode = ADC_ULP_MODE_DISABLE // Deshabilitamos el modo ULP (ultra-low power)
};
adc_oneshot_new_unit(&init_config, &adc_controller);
// Configuración del canal del ADC para lectura de 11 bits
adc_oneshot_chan_cfg_t config = {
.bitwidth = ADC_BITWIDTH_11, // Resolución de 11 bits
.atten = ADC_ATTEN_DB_11, // Atenuación de 11dB (ideal para 3.3V)
};
adc_oneshot_config_channel(adc_controller, ADC_CHANNEL_2, &config);
// Bucle principal
while(1) {
adc_oneshot_read(adc_controller, ADC_CHANNEL_2, &adc_reading); // Leemos el valor del ADC
change_pwm_intensity(adc_reading); // Ajustamos la intensidad del LED según la lectura del ADC
control_leds(); // Controlamos los LEDs según el estado de los botones
vTaskDelay(100 / portTICK_PERIOD_MS); // Esperamos 100 ms antes de la siguiente iteración
}
}