Я пытаюсь воспроизвести функциональность наушников, заключающуюся в многофункциональной кнопке. Если вы нажмете эту кнопку 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
Вам нужно измерить время между дребезжащими чтениями кнопки.
Вы объяснили, что должен делать код, но не описали, что он делает неправильно, и не задали вопрос. Если вы не знаете конкретно, что мы ищем, вам придется разобраться с большим количеством кода. Более того, вместо того, чтобы описывать изменение кода, которое, по-видимому, заставляет его работать, опубликуйте и этот код.
В вашей функции 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() всегда равен нулю. Прочитал первые комментарии и постарался прояснить свой пост и вопрос. Приносим извинения за неудобства.
Возможно, если прерывание int0 срабатывает на уровне, оно не оставит места для выполнения таймера 0; не могли бы вы проверить настройку int0?
Я только что закомментировал прерывание INT0 и попробовал его, но TMR0 еще не срабатывает.
Пробовал включить светодиод до дребезга кнопки на ISR INT0, но он не включается. То есть, когда я нажимаю кнопку, он включается несколько раз подряд и быстро, но в конце концов гаснет. Я могу понять, что это может произойти, если вместо включения светодиода я его переключу. Но я просто включаю его с помощью PORTA |= (1 << 1);
Интересно, не будете ли вы так любезны опубликовать INT0_init(); и TMR0_init(); код тоже
Я просматривал каждую часть проекта и наконец нашел решение. Моя IDE компилировала некоторые зависимости непосредственно из Arduino, такие как Wiring.c и Hooks.c, которые мне не нужно было использовать в моем проекте. Эти зависимости мешали моему коду, вызывая его сбои.
Огромное тебе спасибо, чувак. Этот конечный автомат стал большим улучшением моего кода, и ваши вопросы заставили меня задуматься, и это было действительно хорошо.
Мамочка, спасибо тебе! Хорошего дня!
Пожалуйста, покажите минимальные воспроизводимые примеры всех вариантов кода, которые вы хотите обсудить. «Это работает… но почему это… не работает?» кажется более приемлемым вопросом, чем вопрос, содержащий «Я попробовал все», потому что вы, вероятно, не можете себе представить, какие пользователи, например. тот, у кого более 20 лет профессионального программирования встраиваемых систем, учитывает «все», и это заставляет вас и потенциально ценного союзника говорить о разных вещах. Подумайте о том, чтобы отправиться в тур и прочитать Как спросить.