Как уменьшать переменную каждую секунду
Я пытаюсь подсчитать переменную "bankValue" с определенным коэффициентом стоимости. Код, который я пробовал, отлично отсчитывает значение банка..но..
#define INTERVAL_MESSAGE1 1000
unsigned long time_1 = 0;
const float CostFactor = 1.0;
float bankValue = 10.00;
const float CostButton1 = 0.004167;
void setup() {
Serial.begin(115200);
}
void loop() {
if(millis() >= time_1 + INTERVAL_MESSAGE1){
bankValue = bankValue - (CostButton1 * CostFactor);
time_1 +=INTERVAL_MESSAGE1;
print_time(time_1);
Serial.print("€");
Serial.println(bankValue);
}
}
Я хочу использовать это в if. ЕСЛИ нажата кнопка 1, значение bankValue будет уменьшаться на стоимостной коэффициент каждую секунду.
Я пробовал это в if
if(Pushed == HIGH){
if(Pushed != StatePushed){
Serial.println("Button1 OFF");
}
digitalWrite(relayPin, LOW);
}else{
if(Pushed != StatePushed){
Serial.println("Button1 ON");
}
if(millis() >= time_1 + INTERVAL_MESSAGE1){
bankValue = bankValue - (Button1Value * CostFactor);
time_1 +=INTERVAL_MESSAGE1;
print_time(time_1);
Serial.print("€");
Serial.println(bankValue);
}
digitalWrite(relayPin, HIGH);
}
Если кнопка нажата, значение bankValue уменьшится. Но когда кнопка не активна....миллис-таймер продолжает работать. При повторном включении кнопки я вижу, что bankValue быстро уменьшается, а не каждую секунду.
Итак, главный вопрос: Как я могу уменьшать переменную каждую секунду, когда кнопка активна.
@Niles, 👍0
Обсуждение3 ответа
Ваша основная основная проблема заключается в том, что вы не знаете, когда была нажата кнопка. Ваш алгоритм синхронизации всегда работает с «последнего времени, когда значение было уменьшено» - и это может быть несколько часов назад. Когда вы нажимаете кнопку, разница между millis()
и time_1
может быть огромной, и она должна считать по одной секунде за раз до time_1
проходит millis()
.
Что вам действительно нужно сделать, так это отделить кнопку от действия. Это облегчает управление. Вам нужно найти время, когда кнопка переходит из состояния ВЫСОКИЙ в НИЗКИЙ (нажата) и из НИЗКОГО в ВЫСОКИЙ (отпущена). Вы почти делаете это прямо сейчас, но не совсем. Затем, когда вы найдете момент, когда вас нажимают, вы можете сказать: «С этого момента и далее вы должны считать».
Например, вы можете изменить первую часть кода следующим образом:
if (Pushed != StatePushed) {
StatePushed = Pushed; // Запоминаем текущее состояние на следующий раз
if (StatePushed == HIGH) { // Выпущено
Serial.println("Button1 OFF");
} else { // Нажато
Serial.println("Button1 ON");
time_1 = millis(); // Вспомним, сколько сейчас времени
}
}
Это одна атомарная операция, и теперь вы можете в любой момент проверить StatePressed
, чтобы увидеть, нажата кнопка или нет, а также в момент нажатия time_1
установлено текущее значение millis()
, так что теперь вы знаете, когда была нажата кнопка.
Теперь вы можете добавить вторую часть, используя StatePressed
в качестве триггера:
if (StatePressed == LOW) { // Кнопка нажата
if(millis() >= time_1 + INTERVAL_MESSAGE1){
bankValue = bankValue - (Button1Value * CostFactor);
time_1 +=INTERVAL_MESSAGE1;
print_time(time_1);
Serial.print("€");
Serial.println(bankValue);
}
}
Однако ваш метод сравнения времени не годится. Он не справляется с проблемой пролонгации миллисекунд. Вместо этого вы должны использовать что-то вроде:
if (millis() - time_1 >= INTERVAL_MESSAGE1) {
time_1 = millis();
... etc ...
}
попробовал ваше решение. Почти получилось :-), @Niles
Я попытался использовать сообщение Majenko о решении и придумал что-то вроде этого:
if(Pushed != StatePushed) {
if(Pushed == HIGH){
if(Pushed != StatePushed){
Serial.println("LED OFF");
}
digitalWrite(ledPin, LOW); // выключаем светодиод
}else{
if(Pushed != StatePushed){
Serial.println("LED ON");
time_1 = millis();
}
digitalWrite(ledPin, HIGH); // выключаем светодиод
}
}
StatePushed = Pushed;
delay(100);
if(Pushed == LOW){
if(millis() >= time_1 + INTERVAL_MESSAGE1){
time_1 = millis();
bankValue = bankValue - (coinValueB * CostFactor);
time_1 +=INTERVAL_MESSAGE1;
Serial.print("€");
Serial.println(bankValue);
Serial.println(INTERVAL_MESSAGE1);
}
}
Примерно так, как вы это предложили... но я понимаю, что абсолютно не понимаю, как именно работает millis().
Я понятия не имею, что это делает:
if(millis() >= time_1 + INTERVAL_MESSAGE1)
В каком-то смысле цикл работает. Но время действительно выключено. С моими настройками, каждую секунду вычитая 0,004167, должно получиться 0,25 — это одна минута. Но это было только около половины...0,13 или около того
Он выключен, потому что вы добавляете INTERVAL_MESSAGE1 с time_1. Просто удалите эту строку. И не используйте задержку., @Fahad
Это ответ на ответ Найлза, основанный на ответе Маженко (уф! Это было слишком многословно).
millis() возвращает количество миллисекунд, прошедших с момента запуска вашей программы.
И ваше время отключено, потому что вы добавляете INTERVAL_MESSAGE1 с time_1, то есть вместо того, чтобы ждать одну секунду, вы на самом деле вычитаете через каждые две секунды. Следовательно, вы получили половину стоимости, которую ожидали. Удалите эту строку. (А также не используйте задержку).
Я изолировал вашу часть кода, связанную с вычитанием. Запустите это, и вы должны увидеть результат (кнопка подключена к D4):
unsigned long PreviousTime = 0;
const unsigned long THRESHOLD = 1000;
const float CostFactor = 1.0;
float bankValue = 10.00;
const float CostButton1 = 0.004167;
void setup()
{
Serial.begin(9600);
pinMode(4, INPUT_PULLUP);
}
void loop()
{
if(digitalRead(4) == 0)
{
if((unsigned long)(millis() - PreviousTime) >= THRESHOLD) // Вам нужно проверять время таким образом, чтобы избежать переполнения
{
PreviousTime = millis();
bankValue = bankValue - (CostButton1 * CostFactor);
Serial.println(bankValue);
}
}
}
Обратите внимание, что millis() - PreviousTime
— это unsigned long
. Не надо его бросать., @Edgar Bonet
- Как использовать SPI на Arduino?
- Как решить проблему «avrdude: stk500_recv(): programmer is not responding»?
- Как создать несколько запущенных потоков?
- Как подключиться к Arduino с помощью WiFi?
- avrdude ser_open() can't set com-state
- Как узнать частоту дискретизации?
- Что такое Serial.begin(9600)?
- Я закирпичил свой Arduino Uno? Проблемы с загрузкой скетчей на плату
Вы обрабатываете
millis()
неправильно (должно бытьif(millis() - time_1 >= INTERVAL_MESSAGE1)
, чтобы избежать проблем с переполнением), хотя это не должно вызывать наблюдаемого поведения. Пожалуйста, покажите полный рабочий скетч для второй части кода, @chrislвы можете атаковать проблему не с той стороны ... вы проверяете состояние кнопки, а затем отсчитываете 1 секунду и уменьшаете счетчик ... вместо этого вы можете непрерывно измерять интервалы в 1 секунду ... на каждом интервале проверяйте кнопку и действовать соответственно ..... вы также можете замерить интервалы 1/10 секунды (тики) и накапливать их при нажатии кнопки .... если было подсчитано 10 тиков, затем уменьшить значение банка, @jsotola