#include "driver/pcnt.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "driver/gpio.h"
// Definições de pinos
#define INTERRUPT_PIN 12 // Pino de entrada para pulsos do gerador de função
#define LED1_PIN 23 // LED 1
#define LED2_PIN 22 // LED 2
// Configurações do PCNT
#define PCNT_UNIT PCNT_UNIT_0 // Unidade PCNT
#define PCNT_L_LIM -10 // Limite inferior do contador (para evitar problemas de underflow)
#define MEASURE_INTERVAL 100 // Intervalo de medição (ms), agora 100ms
// Variáveis globais
static const char *TAG = "Frequency Measure";
volatile int16_t lastPulseCount = 0; // Último valor lido do contador
volatile int16_t currentPulseCount = 0; // Valor atual do contador
// Flag para indicar a interrupção
volatile bool interruptOccurred = false;
// Configuração do PCNT
void configurePCNT() {
pcnt_config_t pcntConfig = {
.pulse_gpio_num = INTERRUPT_PIN, // Pino de entrada
.ctrl_gpio_num = -1, // Sem controle
.lctrl_mode = PCNT_MODE_KEEP, // Ignorar controle inferior
.hctrl_mode = PCNT_MODE_KEEP, // Ignorar controle superior
.pos_mode = PCNT_COUNT_INC, // Incrementar em bordas de subida
.neg_mode = PCNT_COUNT_DIS, // Ignorar bordas de descida
.counter_l_lim = PCNT_L_LIM, // Limite inferior
.unit = PCNT_UNIT, // Unidade PCNT
.channel = PCNT_CHANNEL_0 // Canal do contador
};
ESP_ERROR_CHECK(pcnt_unit_config(&pcntConfig));
// Inicializa o contador
pcnt_counter_pause(PCNT_UNIT);
pcnt_counter_clear(PCNT_UNIT);
// Ativa eventos de limite inferior
pcnt_event_enable(PCNT_UNIT, PCNT_EVT_L_LIM);
pcnt_counter_resume(PCNT_UNIT);
ESP_LOGI(TAG, "PCNT configurado.");
}
// Função para configurar a interrupção do pino 12
void IRAM_ATTR gpio_isr_handler(void* arg) {
// Seta a flag para indicar que a interrupção ocorreu
interruptOccurred = true;
}
// Tarefa para medir frequência
void measureFrequencyTask(void *arg) {
while (1) {
vTaskDelay(pdMS_TO_TICKS(MEASURE_INTERVAL)); // Aguarda o intervalo de medição
// Obtém o valor atual do contador
pcnt_get_counter_value(PCNT_UNIT, ¤tPulseCount);
// Calcula a diferença entre as contagens
int16_t pulseDifference = currentPulseCount - lastPulseCount;
// Ajusta para valores negativos em caso de underflow
if (pulseDifference < 0) {
pulseDifference += 32768; // Ajuste de acordo com o tamanho do contador
}
// Calcula frequência em Hz
float frequency = pulseDifference / (MEASURE_INTERVAL / 1000.0);
// Exibe a frequência no monitor serial
printf("Frequência medida: %.2f Hz\n", frequency);
// Atualiza o valor do último contador
lastPulseCount = currentPulseCount;
// Pisca o LED2 (pino 22) se a interrupção foi acionada
if (interruptOccurred) {
gpio_set_level(LED2_PIN, 1); // Acende o LED2
vTaskDelay(pdMS_TO_TICKS(100)); // Atraso de 100 ms
gpio_set_level(LED2_PIN, 0); // Apaga o LED2
printf("Botão de interrupção acionado\n");
// Reseta a flag de interrupção
interruptOccurred = false;
}
}
}
// Tarefa para o LED que pisca continuamente (pino 23)
void blinkLEDTask(void *arg) {
while (1) {
gpio_set_level(LED1_PIN, 1); // Acende o LED1 (pino 23)
vTaskDelay(pdMS_TO_TICKS(500)); // Atraso de 500 ms
gpio_set_level(LED1_PIN, 0); // Apaga o LED1 (pino 23)
vTaskDelay(pdMS_TO_TICKS(500)); // Atraso de 500 ms
}
}
// Função principal
void app_main() {
// Inicializa a comunicação serial
printf("Iniciando aplicação...\n");
// Configuração dos LEDs
gpio_config_t ledConfig = {
.pin_bit_mask = (1ULL << LED1_PIN) | (1ULL << LED2_PIN),
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE
};
gpio_config(&ledConfig);
// Configura o pino de interrupção (pino 12)
gpio_set_intr_type(INTERRUPT_PIN, GPIO_INTR_ANYEDGE); // Interrupção em qualquer borda (subida ou descida)
gpio_install_isr_service(ESP_INTR_FLAG_LEVEL1); // Instala o serviço de interrupção
gpio_isr_handler_add(INTERRUPT_PIN, gpio_isr_handler, NULL); // Adiciona a função de interrupção para o pino
// Configuração do PCNT
configurePCNT();
// Criação da tarefa de medição
xTaskCreate(measureFrequencyTask, "MeasureFrequencyTask", 2048, NULL, 5, NULL);
// Criação da tarefa para o LED que pisca continuamente
xTaskCreate(blinkLEDTask, "BlinkLEDTask", 2048, NULL, 5, NULL);
}