Почему мне нужно помещать функцию millis() внутри основного цикла для запуска ISR?

Я пытаюсь воспроизвести функциональность наушников, заключающуюся в многофункциональной кнопке. Если вы нажмете эту кнопку x количество раз за определенный период времени, наушник сделает что-то в зависимости от того, сколько раз вы нажмете кнопку. Проблема в том, что мне нужно поместить millis() внутри основного цикла, чтобы вызвать ISR. это увеличивает переменную миллис: ISR (TIMER0_COMPA_vect), и я не понимаю, почему

Это мой основной код и библиотеки.

#include <mcu_init.h>
#include <millis.h>
#include <button.h>

int main() {

    GPIO_init();

    cli();

    INT0_init();
    TMR0_init();

    sei();

    while (1) {

        // If I put millis() here, ISR (TIMER0_COMPA_vect) starts triggering
        handleButton();
        
    }

    return 0;

}
#include <millis.h>

static volatile uint32_t miliseconds = 0;

ISR (TIMER0_COMPA_vect) {
    miliseconds++;
    PORTA |= (1 << 1);

}

uint32_t millis() {

    uint32_t time;
    uint8_t oldSREG = SREG;

    cli();

    time = miliseconds;
    SREG = oldSREG;

    return time;

}

Это логика кнопки, на всякий случай.

#include <button.h>

volatile uint8_t count = 0;
volatile uint32_t lastPressTime = 0;

ISR (INT0_vect) {

    if (millis() - lastPressTime >= 200) {
        count++;
      lastPressTime = millis();

    }

}

void handleButton() {
  
  if (millis() - lastPressTime >= 1500) {
    lastPressTime = millis();

    switch (count) {

      case 2:
        PORTA ^= (1 << 1);
        count = 0;
        break;

      case 3:
        PORTA ^= (1 << 3);
        count = 0;
        break;

      default:
        count = 0;

    }

    }

    return;

}

Это заголовочные файлы

#ifndef MILLIS_H_
#define MILLIS_H_

#include <avr/interrupt.h>

uint32_t millis();

#endif
#ifndef BUTTON_H_
#define BUTTON_H_

#include <millis.h>

void handleButton();

#endif

Пожалуйста, покажите минимальные воспроизводимые примеры всех вариантов кода, которые вы хотите обсудить. «Это работает… но почему это… не работает?» кажется более приемлемым вопросом, чем вопрос, содержащий «Я попробовал все», потому что вы, вероятно, не можете себе представить, какие пользователи, например. тот, у кого более 20 лет профессионального программирования встраиваемых систем, учитывает «все», и это заставляет вас и потенциально ценного союзника говорить о разных вещах. Подумайте о том, чтобы отправиться в тур и прочитать Как спросить.

Yunnosch 27.06.2024 08:00

Вам нужно измерить время между дребезжащими чтениями кнопки.

Lundin 27.06.2024 08:13

Вы объяснили, что должен делать код, но не описали, что он делает неправильно, и не задали вопрос. Если вы не знаете конкретно, что мы ищем, вам придется разобраться с большим количеством кода. Более того, вместо того, чтобы описывать изменение кода, которое, по-видимому, заставляет его работать, опубликуйте и этот код.

Clifford 27.06.2024 08:59
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
135
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В вашей функции handleButton вы сбрасываете переменную count каждый раз, когда входите в блок if ().

Если вы не используете функцию millis(), т.е. выполняете функцию switch() в каждом основном цикле, переменная count, вероятно, снова будет сброшена в ноль основной функцией, как только ваша подпрограмма прерывания увеличит ее с нуля и вернет результат. , и основной цикл выполняется снова.

Если вы хотите сбросить счетчик переменных после истечения тайм-аута и больше не нажимать в первый раз, вам необходимо обработать некоторые состояния, как в следующем коде:

// as in your code, the minimum acceptable time between press events
#define def_click_debounce_ms 200
// after a press event occurs, if no more press events occur after this time, we assume that the user press sequence has completed
#define def_pause_validate_click_ms (def_click_debounce_ms + 1000)

// your ISR for the press event, just enriched with a signal on too short press
ISR (INT0_vect) {

    if (millis() - lastPressTime >= def_click_debounce_ms) {
        // increment the number of press detected
        count++;
        lastPressTime = millis();
    }
    else
    {
        // signal to main that an invalid press happened
        reset_wait_release_request++;
    }
}

// the status of handleButton check 
typedef enum _enum_check_button_press_status
{
    enum_check_button_press_status_init = 0,
    enum_check_button_press_status_check_press_sequence,
    enum_check_button_press_status_numof
}enum_check_button_press_status;

// our check button press status variable
enum_check_button_press_status e_check_button_press_status = enum_check_button_press_status_init;
// we use this variable to keep the number of press events handleButton detects
uint8_t num_consecutive_press_detected = 0;

void handleButton() {
    // store the current time
    const uint32_t now_ms = millis();
    switch(e_check_button_press_status)
    {
    case enum_check_button_press_status_init:
    default:
    {
        // no press detected at this moment
        num_consecutive_press_detected = 0;
        // check for a press sequence
        e_check_button_press_status = enum_check_button_press_status_check_press_sequence;
        break;
    }
    case enum_check_button_press_status_check_press_sequence:
    {
        // has the interrupt routine detected a new press?
        if (count != main_count)
        {
            // align our own press counter
            main_count = count;
            // increment the number of press detected by the main
            num_consecutive_press_detected++;
            // mark the time of the last press detected by the main
            start_wait_release_ms = now_ms;
        }
        // if an invalid press happened, let's restart our release timer
        else if (reset_wait_release_request != reset_wait_release_ack)
        {
            reset_wait_release_ack = reset_wait_release_request;
            // we restart the time of the last press detected by the main
            start_wait_release_ms = now_ms;
        }
        // if a timeout happens waiting for next press, let's check if it was a valid press sequence
        else if ((num_consecutive_press_detected > 0) && (now_ms - start_wait_release_ms >= def_pause_validate_click_ms))
        {
            // do your stuff
            switch(num_consecutive_press_detected)
            {
            case 0:
            {
                // should never happen...
                break;
            }
            case 2:
            {
                // do the 2-clicks stuff
                PORTA ^= (1 << 1);
                break;
            }
            case 3:
            {
                // do the 3-clicks stuff
                PORTA ^= (1 << 3);
                break;
            }
            
            case 1:
            default:
            {
                printf("Invalid number of press detected: %u\n", (unsigned int)num_consecutive_press_detected);
                break;
            }
            }
            
            // go back to the init state
            e_check_button_press_status = enum_check_button_press_status_init;
        }
        break;
    }
    }   

}

Я могу понять эту часть. Но как мой код входит в блок if, если ISR не срабатывает, поэтому millis() всегда равен нулю. Прочитал первые комментарии и постарался прояснить свой пост и вопрос. Приносим извинения за неудобства.

Carlos Leonel Rivas Pimentel 29.06.2024 04:10

Возможно, если прерывание int0 срабатывает на уровне, оно не оставит места для выполнения таймера 0; не могли бы вы проверить настройку int0?

michele sponchiado 30.06.2024 13:21

Я только что закомментировал прерывание INT0 и попробовал его, но TMR0 еще не срабатывает.

Carlos Leonel Rivas Pimentel 30.06.2024 21:34

Пробовал включить светодиод до дребезга кнопки на ISR INT0, но он не включается. То есть, когда я нажимаю кнопку, он включается несколько раз подряд и быстро, но в конце концов гаснет. Я могу понять, что это может произойти, если вместо включения светодиода я его переключу. Но я просто включаю его с помощью PORTA |= (1 << 1);

Carlos Leonel Rivas Pimentel 30.06.2024 21:38

Интересно, не будете ли вы так любезны опубликовать INT0_init(); и TMR0_init(); код тоже

michele sponchiado 01.07.2024 10:03

Я просматривал каждую часть проекта и наконец нашел решение. Моя IDE компилировала некоторые зависимости непосредственно из Arduino, такие как Wiring.c и Hooks.c, которые мне не нужно было использовать в моем проекте. Эти зависимости мешали моему коду, вызывая его сбои.

Carlos Leonel Rivas Pimentel 03.07.2024 17:50

Огромное тебе спасибо, чувак. Этот конечный автомат стал большим улучшением моего кода, и ваши вопросы заставили меня задуматься, и это было действительно хорошо.

Carlos Leonel Rivas Pimentel 03.07.2024 17:51

Мамочка, спасибо тебе! Хорошего дня!

michele sponchiado 03.07.2024 18:26

Другие вопросы по теме