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

Ну, давайте смотреть.

Схема приведена в том же посте, не буду её повторять. Как видим, на пин заводится напряжение с делителя. В верхнем плече делителя резисторы всех нажатых кнопок, соединённые параллельно, а в нижнем – pull-down резистор.

Формула делителя известна:

Чтобы не пересчитывать потом в попугаи, положим, что напряжение питания равно 1024 вольта, тогда по этой формуле получим сразу готовые попугаи.

Ну, вот я загнал в Excel эту формулу и посчитал для всех 15 комбинаций нажатых кнопок (предпоследний столбец – сопротивление параллельных “кнопочных резисторов”, а последний – собственно попугаи).

Pull-down R1 R2 R3 R4 Rupper Попугаи
10 11 11,00 488
10 18 18,00 366
10 11 18 6,83 609
10 36 36,00 223
10 11 36 8,43 556
10 18 36 12,00 465
10 11 18 36 5,74 651
10 68 68,00 131
10 11 68 9,47 526
10 18 68 14,23 423
10 11 18 68 6,20 632
10 36 68 23,54 305
10 11 36 68 7,50 585
10 18 36 68 10,20 507
10 11 18 36 68 5,29 670

Всё, как видите, совпало. А у Вас какая строка не совпала? Как считали?

2 лайка

На бумажке. Калькулятором. Но думаю мой бок. Завтра проверю. Утро вечера…

Так Excel и есть большой калькулятор. Жену приучил даже свою наработку считать.)

Да. Спасибо.

Ндя, я лучший((

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

Вчера час тупил над расчетами, сегодня глянул - сразу дошло.

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

1 лайк

Нет, я ведь умный, изобретаю свои формулы.
Ну и обоср@лся жиденьким в результате ((

1 лайк

Впполнне можнро изобрестти что-нибудь стоящее

Каждый исходит из своих представлений о мире(т.е. в меру своей…):wink:

bool Resistive_keyboard::get() {
  const uint16_t _sensor = analogRead(_pin) / 4;
  const uint8_t nowMillis = millis();
  bool _status = false;
  if (_sensor >= _min && _sensor < _max) {
    if (static_cast<uint8_t>(nowMillis - _tmr) >= 50) {
.
.
.
}

Ещё вопросик. Пишем const uint16_t _sensor, а не uint16_t _sensor потому что в этой функции данная переменная более изменяться не будет?
Это как - то влияет на “быстродействие” и т.п. или так грамотнее?

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

Ну и это страховка от непредумышленного (на уровне описки) изменения.

Зачем 16? analogRead(_pin) / 4 гарантированно помещается в uint8_t.

Это я просто скопировала, чтобы уточнить про const

Помогите пожалуйста разобраться.

Код
#define BUTTON_00 A0
#define BUTTON_01 A1
#define ACP_COMPARISON 50

#include <SoftwareSerial.h>
#define RX 2
#define TX 3
SoftwareSerial DEBUGS(RX, TX);

class Analog_Read {
public:
  constexpr Analog_Read(const uint8_t pin, const uint8_t delay)
    : _pin(pin), _delay(delay), _tmr(0), _counts(0) {}
  bool get();
private:
  const uint8_t _pin;
  const uint8_t _delay;
  uint8_t _tmr;
  uint8_t _counts;
};


bool Analog_Read::get() {
  const uint8_t _sensor = analogRead(_pin) / 4;
  const uint8_t nowMillis = millis();
  bool _status = false;
  if (_sensor >= ACP_COMPARISON) {
    if (static_cast<uint8_t>(nowMillis - _tmr) >= 50) {
      _tmr = nowMillis;
      if (++_counts >= _delay) {
        _counts = 0;
        _status = true;
      }
    }
  } else {
    _counts = 0;
    _tmr = nowMillis;
  }
  return _status;
}

Analog_Read UP(BUTTON_00, 10);    //500ms
Analog_Read DOWN(BUTTON_01, 10);  //500ms


void setup() {
  DEBUGS.begin(9600);
  DEBUGS.println("Start");
}

void loop() {

  if (UP.get() && DOWN.get()) {
    DEBUGS.print("UP-DOWN ");
    DEBUGS.print(millis());
    DEBUGS.println("");
  }
  
}

При считывании состояния кнопок по отдельности, всё в порядке, функция “антидребезга” работает

if(UP.get())DEBUGS.print("UP");
if(DOWN.get())DEBUGS.print("DOWN");

А вот при таком условии

  if (UP.get() && DOWN.get()) {
    DEBUGS.print("UP-DOWN ");
    DEBUGS.print(millis());
    DEBUGS.println("");
  }

Я получаю результат каждые 5000 мс.
Проверяю в протеусе, обе кнопки нажаты, в монитор порта получаю UP-DOWN каждые 5000 мс.
Задача проверить если кнопка 00 удерживается не менее 500 мс и кнопка 01 удерживается не менее 500 мс - выполнить действие.

Добавить в класс ещё одну функцию

bool Analog_Read::get_double() {
  const uint8_t _sensor_01 = analogRead(BUTTON_00) / 4;
  const uint8_t _sensor_02 = analogRead(BUTTON_01) / 4;
  const uint8_t nowMillis = millis();
  bool _status = false;

  if (_sensor_01 >= ACP_COMPARISON && _sensor_02 >= ACP_COMPARISON) {
    if (static_cast<uint8_t>(nowMillis - _tmr) >= 50) {
      _tmr = nowMillis;
      if (++_counts >= _delay) {
        _counts = 0;
        _status = true;
      }
    }
  } else {
    _counts = 0;
    _tmr = nowMillis;
  }
  return _status;

}

И ещё вопрос
Как второй параметр, const uint8_t pin2, сделать необязательным?

Analog_Read UP(BUTTON_00, BUTTON_01, 10);  //100ms
Analog_Read DOWN(BUTTON_01, 10);           //100ms
class Analog_Read {
public:
  constexpr Analog_Read(const uint8_t pin, const uint8_t pin2, const uint8_t delay)
    : _pin(pin), _pin2(pin2), _delay(delay), _tmr(0), _counts(0) {}
    
  bool get();
  bool get_double();

Никак. Необязательным можно сделать один или более последних параметров (нужно задать ему (им) значения по умолчанию). А “из середки” - никак.

Можно перегрузить функцию - сделать ещё одну без этого параметра. А внутри эти функции могут вызывать друга, если надо.

1 лайк

Ну, всё правильно. У Вас такая логика. Прошло 500мс - фиксируем нажата. Если Вам нужно, чтобы нажатие фиксировалось только один раз сколько ни держи, то надо вводить флажок “фиксировать нажатие” Изначально он true, когда зафиксировано - становится false, а когда кнопка отпущена - становится снова true. И фиксировать нажатие только когда он true.

1 лайк

Спасибо.

От технологии изготовления конденсатора зависит. Проще говоря паразитное сопротивление таких конденсаторов выше. (ESR) При наличии прибора ESR, надо выбирать его пониже.