Условие «если» проблема/вопрос

Я новичок в Arduino, и мой вопрос скорее теоретический. У меня есть плата Arduino Nano (процессор Atmega168), кнопка, дисплей. Я написал обработчик кнопки, который не останавливает выполнение кода. Моя идея такова: опросить кнопку в "цикле" цикл, и если она нажата, выполнить k++. Когда k превышает указанное значение, выполните cnt++ и выведите его на дисплей.

Пример кода №1 работает корректно. Я получаю 1 -> 2 -> 3 -> ...:

void loop() {
 if (digitalRead(button_pd) == LOW) {
    k = k + 1;
    if (k >= 20) {
      k = 0;
      cnt = cnt + 1;
    }
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print(cnt);
  }
}

Пример кода №2 неверен. у меня 16 -> 27 -> 40 -> ... Вроде печатается не cnt, а k.

void loop() {
  if (digitalRead(button_pd) == LOW) {
    k = k + 1;
    if (k >= 20) {
      k = 0;
      cnt = cnt + 1;
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print(cnt);
    }
  }
}

Вот моя программа:

#include <LiquidCrystal_I2C.h>

#define button_pd 6

LiquidCrystal_I2C lcd(0x27, 16, 2);

int k = 0;
int cnt = 0;

void setup() {

  pinMode(button_pd, INPUT_PULLUP);

  lcd.init();
  lcd.backlight();
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print(cnt);

}

void loop() {

  // button handler

}

У меня вопрос. Почему примеры №1 и №2 работают по-разному?

, 👍4


2 ответа


Лучший ответ:

4

Время другое.

Каждая операция на ЖК-дисплее требует времени. Это:

lcd.clear();
lcd.setCursor(0, 0);
lcd.print(cnt);

требует некоторой связи I2C и, следовательно, требует на порядки больше времени время, чем k++;.

В первой версии вашего loop() эти операции выполняются каждую итерацию, пока кнопка нажата. На втором версии, они выполняются только тогда, когда k достигает 20, то есть двадцать раз. менее часто. Таким образом, вторая версия работает в двадцать раз быстрее... слишком быстро. чтобы ЖК-дисплей правильно обновлялся и отображал все текущие значения попросил показать.

Я рекомендую вам не полагаться на подсчет циклов для управления таймингами. Вместо этого используйте функцию Arduino, специально разработанную для времени. управление. Например, если вы хотите увеличивать счетчик каждые 200 мс, необходимо записать время нажатия кнопки (значок задний фронт сигнала) и увеличьте cnt через 200 мс:

uint8_t previous_state;  // предыдущее состояние кнопки
uint32_t press_timestamp;  // время нажатия кнопки

void loop() {
    uint32_t now = millis();
    uint8_t state = digitalRead(button_pd);
    if (previous_state == HIGH && state == LOW)  // спадающий фронт
        press_timestamp = now;
    previous_state = state;
    if (state == LOW && now - press_timestamp >= 200) {
        cnt = cnt + 1;
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print(cnt);
    }
}
,

А, понял... Спасибо!, @ONamaeWa

К сожалению, результат по-прежнему неверен. Например, 0 -> 10 -> 10 -> 10 -> 21..., @ONamaeWa

Я немного изменил ваш код. Модифицированная версия у меня сработала. Спасибо за идею!, @ONamaeWa


1

Спасибо. Каким-то образом пример кода №3 работает правильно. Я использовал библиотеку для таймера и упрощенный код из ответа выше.

#include <LiquidCrystal_I2C.h>
#include <millisDelay.h>       // Таймер

#define button_pd 6

LiquidCrystal_I2C lcd(0x27, 16, 2);

int k = 0;
int cnt = 0;

//uint8_t previous_state; // предыдущее состояние кнопки

millisDelay d;

void setup() {
  pinMode(button_pd, INPUT_PULLUP);

  lcd.init();
  lcd.backlight();
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print(cnt);
}

void loop() {

    uint8_t state = digitalRead(button_pd);
    if (state == LOW)
        d.start(300);
    //предыдущее_состояние = состояние;
    if (d.justFinished()) {
        cnt = cnt + 1;
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print(cnt);
    }

}

,