Класс для чтения резисторной клавиатуры

Здравствуйте.
К аналоговому входу ардуины подключен подтягивающий резистор 10к.
К этому же входу, через кнопки, подключены стягивающие резисторы разного номинала.
Соответственно при нажатии разных кнопок будут разные показания в порту.
Для удобства я написала класс обработки показаний с порта, а так же сделала функцию антидребезга, удержания кнопки.
Всё ли верно?

Спойлер
#define REMOTE_PIN    A2
#define BUTTONS_PIN   A3

class Resistive_keyboard {
  public:
    Resistive_keyboard(uint16_t min, uint16_t max, uint8_t pin, uint16_t delay);
    bool get();
  private:
    uint16_t _min;//Минимальные показания
    uint16_t _max;//Максимальные показания
    uint8_t _pin;//Номер аналогового порта
    uint16_t _delay;//АнтиДребезг'
    uint32_t _tmr;
    uint8_t _stage;
    bool _status;
};

Resistive_keyboard::Resistive_keyboard(uint16_t min, uint16_t max, uint8_t pin, uint16_t delay) {
  _min = min;
  _max = max;
  _pin = pin;
  _delay = delay;
}

bool Resistive_keyboard::get() {
  uint16_t _sensor = analogRead(_pin);
  _status = false;
  switch (_stage) {
    case 0:
      if (_sensor > _min && _sensor < _max) {
        _stage = 1;
        _tmr = millis();
      }
      break;

    case 1:
      if (_sensor > _min && _sensor < _max) {
        if (millis() - _tmr >= _delay) _status = true;
      } else {
        _stage = 0;
      }
      break;
  }
  return _status;
}

Resistive_keyboard Up(80,100,3,500);
Resistive_keyboard Down(270,300,2,1000);

void setup() {

}

void loop() {
if (Up.get()){}
if (Down.get()){}
}

Мне кажется,в таком деле нужно усреднять показания АЦП. Это не совсем антидребезг.
А кнопки 2 только? Ну может прокатит.

Кнопок будет 6 штук.

Resistive_keyboard Up(80, 100, BUTTONS_PIN, 500);

Почему срабатывает только один раз при старте прогаммы?

Спойлер
#define REMOTE_PIN    A2
#define BUTTONS_PIN   A3
#define MOTOR1_PIN    1//Вверх
#define MOTOR2_PIN    2//Вниз

#define MOTOR1_ON digitalWrite(MOTOR1_PIN, HIGH)
#define MOTOR1_OFF digitalWrite(MOTOR1_PIN, LOW)
#define MOTOR2_ON digitalWrite(MOTOR2_PIN, HIGH)
#define MOTOR2_OFF digitalWrite(MOTOR2_PIN, LOW)

#define MAX_TIME_UP 2000
#define MAX_TIME_DOWN 2000

bool motor_flag;
uint32_t motor_tmr;
uint32_t motor_off;


class Resistive_keyboard {
  public:
    Resistive_keyboard(uint16_t min, uint16_t max, uint8_t pin, uint16_t delay);
    bool get();
  private:
    uint16_t _min;
    uint16_t _max;
    uint8_t _pin;
    uint16_t _delay;
    uint32_t _tmr;
    uint8_t _stage;
    bool _status;
};

Resistive_keyboard::Resistive_keyboard(uint16_t min, uint16_t max, uint8_t pin, uint16_t delay) {
  _min = min;
  _max = max;
  _pin = pin;
  _delay = delay;
}


bool Resistive_keyboard::get() {
  uint16_t _sensor = analogRead(_pin);
  _status = false;
  switch (_stage) {
    case 0:
      if (_sensor > _min && _sensor < _max) {
        _stage = 1;
        _tmr = millis();
      }
      break;

    case 1:
      if (_sensor > _min && _sensor < _max) {
        if (millis() - _tmr >= _delay) _status = true;
      } else {
        _stage = 0;
      }
      break;
  }
  return _status;
}

Resistive_keyboard Up(80, 100, BUTTONS_PIN, 500);
Resistive_keyboard Down(270, 300, BUTTONS_PIN, 500);

void setup() {
  pinMode(MOTOR1_PIN, OUTPUT);
  pinMode(MOTOR2_PIN, OUTPUT);
  MOTOR1_OFF;
  MOTOR2_OFF;
}

void loop() {

  if (Up.get()) {
    MOTOR1_ON;
    MOTOR2_OFF;
    motor_flag = true;
    motor_tmr = millis();
    motor_off = MAX_TIME_UP;
  }


  if (Down.get()) {
    MOTOR1_OFF;
    MOTOR2_ON;
    motor_flag = true;
    motor_tmr = millis();
    motor_off = MAX_TIME_DOWN;
  }


  if (motor_flag && millis() - motor_tmr >= motor_off ) {
    motor_flag = false;
    MOTOR1_OFF;
    MOTOR2_OFF;
  }

}


Лучше как-то так:


private:
  uint8_t counter = 0x00;
  bool  buttonActive = false;
.... 
read() {
...
counter = counter << 1 | (_sensor > _min && _sensor < _max); 
if (counter == 0xFF) { buttonActive = true; }
if (counter == 0x00) { buttonActive = false; }

}

Только внутри read() по типу “блинк без дилей” читать и анализировать каждую 1мс.

1 лайк

Очевидно,потому что где-то какой-то флаг не сбрасывается обратно. Сложно сказать,не совсем понятна логика работы.

Если я свои показания (80-100 и 270-300) передаю в класс непосредственно в loop, то всё работает правильно.

Спойлер
#define REMOTE_PIN    A2
#define BUTTONS_PIN   A3
#define MOTOR1_PIN    1
#define MOTOR2_PIN    2

#define MOTOR1_ON digitalWrite(MOTOR1_PIN, HIGH)
#define MOTOR1_OFF digitalWrite(MOTOR1_PIN, LOW)
#define MOTOR2_ON digitalWrite(MOTOR2_PIN, HIGH)
#define MOTOR2_OFF digitalWrite(MOTOR2_PIN, LOW)

#define MAX_TIME_UP 2000
#define MAX_TIME_DOWN 2000

bool motor_flag;
uint32_t motor_tmr;
uint32_t motor_off;


class Resistive_keyboard {
  public:
    Resistive_keyboard(uint8_t pin, uint16_t delay);
    bool get(uint16_t min, uint16_t max);
  private:
    uint8_t _pin;
    uint16_t _delay;
    uint32_t _tmr;
    uint8_t _stage;
    bool _status;
};

Resistive_keyboard::Resistive_keyboard(uint8_t pin, uint16_t delay) {
  _pin = pin;
 _delay = delay;
}


bool Resistive_keyboard::get(uint16_t min, uint16_t max) {
  uint16_t _sensor = analogRead(_pin);
  _status = false;
  switch (_stage) {
    case 0:
      if (_sensor > min && _sensor < max) {
        _stage = 1;
        _tmr = millis();
      }
      break;

    case 1:
      if (_sensor > min && _sensor < max) {
        if (millis() - _tmr >= _delay) _status = true;
      } else {
        _stage = 0;
      }
      break;
  }
  return _status;
}

Resistive_keyboard Up(BUTTONS_PIN, 500);
Resistive_keyboard Down(BUTTONS_PIN, 500);

void setup() {
  pinMode(MOTOR1_PIN, OUTPUT);
  pinMode(MOTOR2_PIN, OUTPUT);
  MOTOR1_OFF;
  MOTOR2_OFF;
}

void loop() {

  if (Up.get(80,100)) {
    MOTOR1_ON;
    MOTOR2_OFF;
    motor_flag = true;
    motor_tmr = millis();
    motor_off = MAX_TIME_UP;
  }


  if (Down.get(270,300)) {
    MOTOR1_OFF;
    MOTOR2_ON;
    motor_flag = true;
    motor_tmr = millis();
    motor_off = MAX_TIME_DOWN;
  }


  if (motor_flag && millis() - motor_tmr >= motor_off ) {
    motor_flag = false;
    MOTOR1_OFF;
    MOTOR2_OFF;
  }

}

Иринка, если Вы не пожадничаете поставить SPDT кнопки и к ним микросхему CD4043BE в качестве RS-триггера (одной хватает на 4 кнопки), то можете использовать классическую схему R-2-R и напрочь забыть о дребезге - его не будет просто по определению.

Вот тема с объяснением про R-2-R, а вот продолжение, где и появляется эта микросхема.

У меня работает на ура.

Большое спасибо.
А можно попросить схему подключения?


Такие не подойдут, вместо CD4043?
Я себе на будущие проекты хочу заказть.

А в данной ситуации, резисторы уже распаяны на плате.

нет, 4043 это RS тригер, а 4011 это логика 4 - 2И-НЕ.

1 лайк

Да, конечно. Тут смотрите по распиновке слева пины S (1-4), R (1-4) и Q(1-4). А справа нарисовано как подключить одну SDPT кнопку в пинам S, R и Q.
Т.е. на одну микросхему 4 кнопки.

Сама микросхема не редкая. Сейчас посмотрел - и на ali навалом и в России. Если Вас не смущает корпус SOP, то вон в чипедипе всего по 11 рублей. В корпусе DIP подороже, но на ali есть по 17 рублей.

1 лайк

Косячный у меня класс получился. Добавила третью кнопку, и задержка на первой не работает. При нажатии сразу срабатывает.

В автомобильной кнопке для управления стеклоподъемником два положения туда и два обратно. Я её не разбирал, но там, вроде, делитель с переменным плечом. При переключении в воздухе контакт не болтается совсем уж беспредельно. Со счётчиком фильтруется нормально.

У меня на UNO в протеусе работает не один раз (наверно как задумано). Код из поста номер 3, без изменений. Кнопки R3 и R4

Работает.
Значит какие-то проблемы с аттини13 в протеусе.

Возможно просто оперативки не хватает, и протеус не виноват.

1 лайк

Ресурсов ПК точно хватает, с UNO всё правильно работает в протеусе, проверила.

Спойлер

Я про память ОЗУ аттини13 писал. (Наверное зря применил термин “оперативки”)

1 лайк

Поняла. Проверю по устройстве. Спасибо.

А как вы это планируете проверить на устройстве?

ПРОВЕРЯТЬ можно в поротеусе. Ставите условие прерывания для порогового значения указателя стека и смотрите. (Сам правда на практике к такому не прибегал).

1 лайк

Так то да, иде даже писала что недостаточно памяти)