Кнопка остановки секундомера работает неправильно!
Я пытаюсь реализовать секундомер с жидкокристаллическим дисплеем, и предполагается, что я использую команду 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, более чем рад их услышать!
Спасибо!
@Raighley, 👍2
Обсуждение1 ответ
Здесь есть несколько проблем. Прежде всего, ваша кнопка подключена неправильно. Если вы подключите один конец кнопки к + 5 В, то другой конец должен иметь нажатие на GND, как здесь:
(Изображение из примера кнопки Arduino).
Вторая проблема - это отсутствие развенчания. Вы должны игнорировать нарастающие фронты, которые вы ощущаете, в течение нескольких миллисекунд после их записи.
Третья проблема - это хронометраж. Как объяснил Сим Сон, ваши секунды будут не очень точными. Лучше просто посчитать миллисекунды, прошедшие с момента нажатия кнопки, а затем разбить счет на полные секунды и оставшиеся миллисекунды.
Привет @edgarbonet - большое спасибо за ответ! Я исправил пару вещей, о которых вы говорили здесь. секундомер теперь запускается при нажатии кнопки, но второе нажатие кнопки не останавливает его. Я предполагаю, что это из-за функции прерывания, но я не вижу, в чем именно проблема. Любая помощь приветствуется! Спасибо. Я разместил обновленный код в основной части вопроса. Дебаунсинг я не совсем понял и еще не реализовал., @Raighley
@Raighley: код сейчас в беспорядке, и я не совсем понимаю, что он пытается сделать. Если вы используете INPUT_PULLUP
, вам не нужно раскрывающееся меню, и кнопка активна, когда LOW
. attachInterrupt()
не поддерживает режим HIGH
. Нет смысла использовать одновременно digitalRead()
и attachInterrupt()
. buttonState
, кажется, служит двум несвязанным целям. lastButtonState
никогда не используется... Предлагаю перезапустить с нуля: забыть о прерываниях, прочитать про "дребезг кнопок" и использовать библиотеку для устранения дребезга., @Edgar Bonet
- Определение того, была ли нажата и отпущена кнопка
- Хорошая кнопка debouncing/Библиотека StateChange
- Остановить мигание светодиодов
- Интеграция 2 кнопок для включения и выключения светодиода.
- Код Arduino для управления 4 светодиодами с 4 кнопок
- Нужен ли подтягивающий/понижающий резистор для цепи светодиода кнопки?
- Как прервать функцию цикла и перезапустить ее?
- Как перезапустить счетчик в программе с помощью кнопки в настройке LDR Tripwire
На вашей схеме у кнопки есть подтягивающий резистор? Вы уверены, что этот резистор не подключен к земле? Также я не вижу ничего для устранения дребезга кнопки. Вы не получите хороших результатов без устранения дребезга, @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