Button counter with interrupt

DEsp3286
Posts: 13
Joined: Sat Sep 29, 2018 11:30 am

Button counter with interrupt

Postby DEsp3286 » Thu Apr 02, 2020 11:53 am

I want to increment a variable every second when an interrupt is triggered. Code on esp32, esp-idf. I have connected a button, when the button is pressed I want to count the number of seconds.

I did this using polling function, but I want to learn how to do it with interrupt, so counting and polling only when the button is pressed and not checking every second for a button pushed

Code: Untitled.c Select all

#include <stdio.h>
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"

#define ESP_INTR_FLAG_DEFAULT 0

#define BLINK_LED 13
#define GPIO_INPUT_IO_0 33
int buttonCount = 0;
int i = 0;

SemaphoreHandle_t xSemaphore = NULL;

TaskHandle_t printVariableTask = NULL;

void printVariable(void *pvParameter) {

int a = (int) pvParameter;
while (1) {

printf("A is a: %d \n", a++);
vTaskDelay(1000 / portTICK_RATE_MS);
}
}
// interrupt service routine, called when the button is pressed
void IRAM_ATTR button_isr_handler(void* arg) {

// notify the button task
xSemaphoreGiveFromISR(xSemaphore, NULL);

}
// task that will react to button clicks
void button_task(void* arg) {

// infinite loop
for(;;) {

// wait for the notification from the ISR
if(xSemaphoreTake(xSemaphore,portMAX_DELAY) == pdTRUE) {
int buttonState = gpio_get_level(GPIO_INPUT_IO_0);

while(buttonState == 1){ //code stucks here!!!!
buttonCount++;
printf("GPIO_INPUT_IO_0 %d\n", buttonState);
printf("Button pressed! %d \n", i++);
gpio_set_level(BLINK_LED, buttonState);
vTaskDelay(1000 / portTICK_RATE_MS);
}
}
}
}

void app_main()
{
// create the binary semaphore
xSemaphore = xSemaphoreCreateBinary();

// configure button and led pins as GPIO pins
gpio_pad_select_gpio(GPIO_INPUT_IO_0);
gpio_pad_select_gpio(BLINK_LED);

// set the correct direction
gpio_set_direction(GPIO_INPUT_IO_0, GPIO_MODE_INPUT);
gpio_set_direction(BLINK_LED, GPIO_MODE_OUTPUT);

// enable interrupt on falling (1->0) edge for button pin
gpio_set_intr_type(GPIO_INPUT_IO_0, GPIO_INTR_POSEDGE);

// start the task that will handle the button
xTaskCreate(button_task, "button_task", 2048, NULL, 10, NULL);

// install ISR service with default configuration
gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);

// attach the interrupt service routine
gpio_isr_handler_add(GPIO_INPUT_IO_0, button_isr_handler, NULL);

int pass = 25;
xTaskCreate(&printVariable, "printVariable", 2048, (void*) pass, 5, &printVariableTask);

}
It works, but when the code enter in the while(buttonState == 1) the loop never ends.

What am I doing wrong?

User avatar
martinayotte
Posts: 141
Joined: Fri Nov 13, 2015 4:27 pm

Re: Button counter with interrupt

Postby martinayotte » Fri Apr 03, 2020 2:05 pm

Your while loop doesn't check buttonState anymore after entering the loop ...
You should do that instead :

Code: Select all

            while(gpio_get_level(GPIO_INPUT_IO_0) == 1) {

DEsp3286
Posts: 13
Joined: Sat Sep 29, 2018 11:30 am

Re: Button counter with interrupt

Postby DEsp3286 » Sat Apr 04, 2020 8:41 am

OMG! what a stupid error!

Of course now it works correctly, thank you.
I would like to check the state of the button only when the interrupt is fired.

Is this a correct method to handle interrupt on a GPIO or in general call a function only when an interrupt is fired/triggered?

Thanks

DEsp3286
Posts: 13
Joined: Sat Sep 29, 2018 11:30 am

Re: Button counter with interrupt

Postby DEsp3286 » Fri Apr 10, 2020 6:16 am

Any advice?
Thanks

Sprite
Espressif staff
Espressif staff
Posts: 10636
Joined: Thu Nov 26, 2015 4:08 am

Re: Button counter with interrupt

Postby Sprite » Fri Apr 10, 2020 7:29 am

Your question doesn't quite make sense; I'm having a hard time figuring out what you want to know. Is it communication between an interrupt and a task? If so, you could take a look at semaphores, for instance.

DEsp3286
Posts: 13
Joined: Sat Sep 29, 2018 11:30 am

Re: Button counter with interrupt

Postby DEsp3286 » Tue Apr 14, 2020 6:46 am

Sorry for that.

I was wondering if this approach is correct.
I want to know when a button is pressed ( i.e. for 3 seconds and when it's pressed for more than 10 ).

I could poll every second and check for the status of the GPIO, or I could use interrupt.
My question is:

when the interrupt is triggered/fired ( void IRAM_ATTR button_isr_handler(void* arg) ), is it ok to call a function (void button_task(void* arg) ) and add a while conditions inside this function where i.e. I could increment a variable

Code: Select all

printf("Button pressed! %d \n", i++);
 gpio_set_level(BLINK_LED, buttonState);
 vTaskDelay(1000 / portTICK_RATE_MS
);

I mean, is it ok how the function are called in my code?

Hope is clear enough

thanks

Sprite
Espressif staff
Espressif staff
Posts: 10636
Joined: Thu Nov 26, 2015 4:08 am

Re: Button counter with interrupt

Postby Sprite » Tue Apr 14, 2020 2:53 pm

The biggest issue with that code is that you can't call blocking functions anywhere in an interrupt. vTaskDelay is blocking. Printf is also blocking. Suggest you solve this problem by spinning up a task that blocks on a semaphore, then give the semaphore from the interrupt. In a task, you *can* use vTaskDelay and printf without issues.

espmich
Posts: 41
Joined: Tue Jan 16, 2024 8:32 pm

Re: Button counter with interrupt

Postby espmich » Thu Dec 12, 2024 5:00 pm

Too bad that ESP-IDF/examples/peripherals/gpio/generic_gpio/ doesn't use a semaphore, which would be perfect to solve the problem you are experiencing.

Who is online

Users browsing this forum: Amazon [Bot], Google [Bot] and 1 guest