Как вывести в консоль, сколько секунд нажата кнопка?

Всем привет!

Не получается сделать элементарную вещь!

Запустили программу. Ничего не происходит (тикает внутренний таймер).
Нажали кнопку.
Через секунду удержания кнопки нужно выдать “Программа запущена: 5 сек (если не сразу нажали, а спустя 5 сек), кнопка нажата, секунд: 1”.
Через две секунды удержания нужно выдать “Программа запущена: 6 сек, кнопка нажата, секунд: 2”.
Делитель 1000 мне нужно потом увеличить до 1 минуты (60000), но тестировать буду на секундах.

Отпустили кнопку - программа закончена и ждет нажатия кнопки.

Нажали кнопку - пошел новый отсчет от нуля, сколько секунд зажата кнопка.

В идеале вместо сообщения в порт сразу ближе к реальности быть - на одной секунде вместо сообщения в порт один раз еле заметно мигнуть встроенным диодом Nano (для теста пойдет HIGH, delay 50, LOW, delay 50(но delay - это зло, поэтому лучше без него, но без него я не знаю, как реализовать)), на второй секунде зажатой кнопки два раза, на третьей - три и так бесконечно до отпускания кнопки.

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

Так что от всех этих millis(); голова уже пухнет!
Светодиодами-то без delay я научился управлять, нет проблем, но тут задача-то другая.

Спасибо всем заранее!

за что? Вопросов у вас в сообщении нет и просьб тоже.
Это вам спасибо за то что зашли.

2 лайка

Вопрос есть в заголовке :slight_smile:

1 лайк

Так, если не пробовать, то и не получится :frowning:

1 лайк

Ах, простите.

Попробую ответить…
Наверно надо засечь время, когда кнопку только нажали - и потом выводить в консоль разницу между моментом нажатия кнопки и текущим временем…

ЕвгенийПетрович, я правильно говорю?

1 лайк

А где там у attiny13 консоль теперь?

1 лайк

Ну, можно и так. Только не раскрыта тема насчёт “засечь время”? Это как? По NTP запросить? Или юзеру мигнуть, чтобы глянул на часы и ввёл в мониторе порта. В общем, тут есть ещё над чем поработать.

1 лайк

“Садись, три” ? :slight_smile:

1 лайк

Да если б всё так просто было :slightly_smiling_face: пробовал раз 100.
Вот, например, один из вариантов, жутко кривой, но у меня иначе и не может быть.
К тому же не работает.

bool pressed = false;
int pressed_seconds = 0;
void setup() {
  Serial.begin(9600);
  pinMode(10, INPUT);
}
bool flag = false;
uint32_t btnTimer = 0;
void loop() {

  bool btnState = !digitalRead(10);
  if (btnState && !flag && millis() - btnTimer > 100) {
    flag = true;
    btnTimer = millis();

    if (!digitalRead(10) == 1 && !pressed) {
      pressed = true;
      pressed = false;

    }

    if (millis() - last_time > 1000 && !pressed) {            //  5 сек = 5000
      last_time = millis();
      pressed_seconds = pressed_seconds + 1;
      Serial.print("Кнопка нажата ");
      Serial.print(pressed_seconds);               //  Перевод из мсек в секунды.
      //Serial.print((millis() - last_time));               //  Перевод из мсек в секунды.
      Serial.println(" сек.");

      Serial.print("millis = "); Serial.print(millis()); Serial.print(", ");
      Serial.print("last_time = "); Serial.print(last_time); Serial.print(", ");
      Serial.print("pressed_seconds = "); Serial.print(pressed_seconds); Serial.print(", ");      
      Serial.print("btnTimer = "); Serial.print(btnTimer); Serial.print("\n");

      bool btnState = !digitalRead(10);
      if (!digitalRead(10) > 100) { // Кнопка нажата?
        //Serial.print("Кнопка нажата. \n");

        digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
        delay(500);                       // wait for a second

        digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
        delay(500);

      }

    }

  }
  if (!btnState && flag && millis() - btnTimer > 100) {
    flag = false;
    btnTimer = millis();
    last_time = 0;
    btnTimer = 0;
    pressed_seconds = 0;
  }
}```

Выдает всегда 
Кнопка нажата 1 сек.
millis = 4189, last_time = 4188, pressed_seconds = 1, btnTimer = 4188
Кнопка нажата 1 сек.
millis = 5427, last_time = 5426, pressed_seconds = 1, btnTimer = 5426
Кнопка нажата 1 сек.
millis = 8439, last_time = 8439, pressed_seconds = 1, btnTimer = 8439
Кнопка нажата 1 сек.
millis = 10155, last_time = 10153, pressed_seconds = 1, btnTimer = 10153

Время разное - это я пытался сохранить первое время, когда только чтоб была нажата кнопка, но все эти переменные перезаписываются один хрен и все одно и то же обозначают (+ - 1-2 миллисекунды - это мелочи).

в attiny13 я уберу вывод в консоль и вставлю цикл мигания диодом времени, сколько прошло секунд.

Я там чуть выше так и делал, засекал время, когда кнопку нажал, но, видимо, это время потом в перезаписалось миллион раз? Поэтому это время всё равно неверное и не отражает секунд зажатой кнопки.

Кстати, с удовольствием воспользуюсь платной услугой написания этого скетча, если Вы готовы.

А вот еще одна попытка сделать нужное (тоже неудачная):

bool pressed = false;
bool lock = true;
int pressed_seconds = 0;

void setup() {
  Serial.begin(9600);
  pinMode(10, INPUT);
}

bool working = true;
uint32_t btnTimer = 0;
uint32_t temp_time = 0;

void loop() {
  bool btnState = !digitalRead(10);

  if (btnState && working && millis() - btnTimer) {
    btnTimer = millis();

    temp_time = btnTimer;

    int n = 1000;

    if (!lock) {
      Serial.println(temp_time / 1000ul);
      lock = true;
    }

    if (!digitalRead(10) == 1 && !pressed && !lock) {
      pressed = true;
      Serial.print("Кнопка нажата !!!!!! \n");
      lock = true;
      pressed = false;
    }

    if (millis() - last_time > 1000 && !pressed) {            //  5 сек = 5000
      last_time = millis();
      pressed_seconds = pressed_seconds + 1;
      bool btnState = !digitalRead(10);
    }
  }

  if (!btnState && lock && millis() - btnTimer > 100) {
    working = true;
    btnTimer = millis();
    lock = false;
    last_time = 0;
    btnTimer = 0;
    pressed_seconds = 0;
  }

}```

Оно при нажатии просто однократно выдает мне, сколько секунд прошло с начала работы программы, что мне вообще не подходит. К тому же тут однократно, а мне нужно каждую секунду, пока нажата кнопка.

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

В любом случае рекомендую начинать с подробной записи алгоритма на русском. И только тогда, когда с этим алгоритмом будет полная ясность, переходить к переводу алгоритма на Си.

1 лайк

я думаю это чат гпт писал

1 лайк

Всё гораздо проще.

Спойлер
uint32_t btnTimer = 0;
uint32_t temp_time = 0;

void setup() {
  Serial.begin(9600);
  pinMode(10, INPUT_PULLUP);
}

void loop() {
  while(digitalRead(10)==HIGH);
  temp_time=millis();
  delay(50); //Ждем дребезг, всё равно быстрее палец нажать не способен 
  while(digitalRead(10)==LOW);
  btnTimer=millis()- temp_time;
  delay(50); //Ждем дребезг, всё равно быстрее палец нажать не способен 
  Serial.print("Кнопка нажата ");
  Serial.print(btnTimer);
  Serial.println(" mc.");
}
1 лайк

замечания нужны? :slight_smile:

1 лайк

Давай.

  • Код выдаст сообщение только после отпускания кнопки ( не соответствует ТЗ)
  • код выдаст сообщение только один раз ( не соответствует ТЗ)
  • строка 15 лишняя
1 лайк
  1. Да пох на ТЗ, ответ на заголовок темы. Функционал времени с начала программы добавляется выводом миллис.
    Во втором while можно крутить блинк без делея и каждую секунду выводить сообщение.

  2. Будет выдавать при каждом нажатии на кнопку.

  3. Если эту строку убрать, то при приличном дребезге программа может пролететь первый while повторно на дребезге и выдать дополнительное совсем непотребное значение.

1 лайк