Кнопка остановки секундомера работает неправильно!

Я пытаюсь реализовать секундомер с жидкокристаллическим дисплеем, и предполагается, что я использую команду attachInterrupt для отслеживания нажатия кнопки. Часы работают отлично, но ввод кнопки вообще не улавливается и не обрабатывается.

В void setup()я настроил его следующим образом: attachInterrupt(digitalPinToInterrupt(buttonPin), buttonInterrupt, RISING);.

А функция buttonInterrupt выполняет только start = !start, так что в некотором смысле просто переворачивает начальную переменную.

Это обновленная версия кода:

#include <LiquidCrystal.h>

// инициализируйте библиотеку номерами интерфейсных контактов
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
int buttonPin = 7; 
volatile int buttonState; 
int lastButtonState;
long sec; 
long startTime;  

void setup() {
  lcd.begin(16, 2);
  pinMode(buttonPin, INPUT_PULLUP);
  lcd.setCursor(0,0);
  lcd.print("Push the button!");
  attachInterrupt(digitalPinToInterrupt(buttonPin),buttonInterrupt,HIGH);
}

void loop() {
  
  buttonState = digitalRead(buttonPin); 
  if(buttonState == LOW){
    startTime = millis(); 
  }
  
  while(buttonState == HIGH){
    long time = millis();
    long z = (time - startTime); 
    sec = (z/1000);
    long ms = z%1000; 
    lcd.setCursor(0,1); 
    lcd.print(sec); 
    lcd.print(".");
    lcd.print(ms);
    lcd.setCursor(8,1); 
    lcd.print("Secs");
    
    if(buttonState == LOW){
      break;   
    }
  }
}

void buttonInterrupt() {
  if(buttonState == LOW){
    buttonState = HIGH; 
  }else{
    buttonState = LOW; 
  }
}

Функция цикла работает в том, что касается подсчета времени, но не работает для остановки времени с помощью кнопки. Любая помощь приветствуется, я очень новичок в Arduino (буквально начал вчера). Моя схема выглядит следующим образом: https://i.imgur.com/yCR9fhP.png

Если есть какой-либо другой способ напечатать цифры, кроме printString, более чем рад их услышать!

Спасибо!

, 👍2

Обсуждение

На вашей схеме у кнопки есть подтягивающий резистор? Вы уверены, что этот резистор не подключен к земле? Также я не вижу ничего для устранения дребезга кнопки. Вы не получите хороших результатов без устранения дребезга, @chrisl

@chrisl, вы правы, он должен быть подключен к GND, но исправление этого также не решает мою проблему! И к сожалению я не знаю что значит дебаунс! Надо будет сейчас поискать. Спасибо!, @Raighley

является переменным запуском «изменчивым»?, @Juraj

@Юрай, нет, не было. Но даже переключаюсь на volatile, вроде не помогает., @Raighley

Вам нужно установить msStart в текущее значение millis() после цикла while. Лучше сделать код неблокирующим, как в примере с BlinkWithoutDelay. Также не ожидайте, что секундомер будет слишком точным, потому что код в вашем цикле while займет некоторое время, и поэтому sec=sec+1; не будет выполняться *ровно* каждые 1000 мс., @Sim Son

Еще один совет: соблюдайте тип данных start. Если это логическое значение, вам лучше использовать true\false. Если это целое число, лучше не использовать оператор НЕ (!). Если start становится 1 в какой-то момент, start=!start заставит его переключаться между 1 и 254, что, вероятно, не то, что вы хотели., @Sim Son

Вам лучше опубликовать весь ** компилируемый ** код, чтобы такие вещи, как тип данных start, были понятны людям, читающим вопрос., @Sim Son

@Sim Son, спасибо за ответ! Я попробовал другой способ перевернуть начальную переменную, теперь, когда вы упомянули логическое значение, мне ясно, что мой способ не имел никакого смысла переворачивать 0 на 1. При этом это решение не решило проблему, и я Я не уверен, как установить msAtStart в millis(), поскольку это приводит к тому, что секундомер отсчитывает 0,1 с, а затем возвращается к 0,0. Спасибо за вашу помощь! Я разместил весь компилируемый код в своем теле вопроса., @Raighley

А он запускается при нажатии на кнопку?, @ocrdu

@ocrdu нет, это не так! если я устанавливаю start = 0;, он вообще не запускается, а если я ставлю его в 1, таймер запускается, как только я запускаю программу., @Raighley

С кнопки то вообще ничего. С ответом, который вы получили от Эдгара Бонета, вы сможете заставить его работать. Сначала правильно подключите эту кнопку и посмотрите, что произойдет. Или я мог бы опубликовать рабочий код, но что в этом интересного?, @ocrdu

@ocrdu Я правильно подключил его и сейчас попробовал другой метод. Кнопочный ввод теперь работает - по нажатию кнопки таймер запускается, но второе нажатие не останавливает его. Итак, теперь проблема связана с устранением дребезга, возможно, или просто с моей функцией прерывания. Я до сих пор не совсем разобрался с дребезгом, так что придется немного почитать об этом, но, по крайней мере, кнопка и часы работают нормально., @Raighley

@ocrdu теперь я просто не могу понять, как получить «обновленное» состояние кнопки, которое остановит цикл while и позволит выводу остаться там. это то, что должно делать прерывание, но переключение состояния в функции прерывания с LOW на HIGH / HIGH на LOW, похоже, не достигает цикла while. Совсем запутался..., @Raighley

Loop() уже зацикливается. Потерять время. Если buttonState == HIGH, вычислить и отобразить прошедшее время. В противном случае ничего не делайте., @ocrdu

О, я вижу, вы изменили код. Не устанавливайте buttonState в цикле(), оставьте это для прерывания. Вы можете беспокоиться о сбросе startTime позже. И не используйте INPUT-PULLUP, если переключатель не подключает входной контакт к LOW., @ocrdu


1 ответ


3

Здесь есть несколько проблем. Прежде всего, ваша кнопка подключена неправильно. Если вы подключите один конец кнопки к + 5 В, то другой конец должен иметь нажатие на GND, как здесь:

Wiring of a button

(Изображение из примера кнопки Arduino).

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

Третья проблема - это хронометраж. Как объяснил Сим Сон, ваши секунды будут не очень точными. Лучше просто посчитать миллисекунды, прошедшие с момента нажатия кнопки, а затем разбить счет на полные секунды и оставшиеся миллисекунды.

,

Привет @edgarbonet - большое спасибо за ответ! Я исправил пару вещей, о которых вы говорили здесь. секундомер теперь запускается при нажатии кнопки, но второе нажатие кнопки не останавливает его. Я предполагаю, что это из-за функции прерывания, но я не вижу, в чем именно проблема. Любая помощь приветствуется! Спасибо. Я разместил обновленный код в основной части вопроса. Дебаунсинг я не совсем понял и еще не реализовал., @Raighley

@Raighley: код сейчас в беспорядке, и я не совсем понимаю, что он пытается сделать. Если вы используете INPUT_PULLUP, вам не нужно раскрывающееся меню, и кнопка активна, когда LOW. attachInterrupt() не поддерживает режим HIGH. Нет смысла использовать одновременно digitalRead() и attachInterrupt(). buttonState, кажется, служит двум несвязанным целям. lastButtonState никогда не используется... Предлагаю перезапустить с нуля: забыть о прерываниях, прочитать про "дребезг кнопок" и использовать библиотеку для устранения дребезга., @Edgar Bonet