Проект управления 5 реле аналоговой клавиатурой

Доброго времени суток уважаемые форумчане.

Возникла необходимость управлять 5 реле аналоговой клавиатурой.
Клавиатура состоит из 6 кнопок, которые сидят на аналоговом пине А2. Сигналы 6 кнопок дают следующие значения: 557, 594, 637, 686, 743, 811.
Задача следующая: 5 кнопок при нажатии должны включать/отключать 5 реле. При нажатии кнопки 6 все реле должны разом отключаться/включаться.
Собрал схему, загрузил скетч, но почему то реле отрабатывают через раз. Прошу глянуть скетч, может я что то накосячил в нем.

unsigned const short int KEYPAD_PIN = A2; // аналоговый порт для клавиатуры
const int relayPin1 = 2;
const int relayPin2 = 3;
const int relayPin3 = 4;
const int relayPin4 = 5;
const int relayPin5 = 6;

boolean relay1On = false; // текущее состояние реле
boolean relay2On = false; // текущее состояние реле
boolean relay3On = false; // текущее состояние реле
boolean relay4On = false; // текущее состояние реле
boolean relay5On = false; // текущее состояние реле

void setup() {
  Serial.begin(9600);
  
  pinMode(relayPin1, OUTPUT);
  pinMode(relayPin2, OUTPUT);
  pinMode(relayPin3, OUTPUT);
  pinMode(relayPin4, OUTPUT);
  pinMode(relayPin5, OUTPUT);
  digitalWrite(relayPin1, HIGH); 
  digitalWrite(relayPin2, HIGH);
  digitalWrite(relayPin3, HIGH);
  digitalWrite(relayPin4, HIGH);
  digitalWrite(relayPin5, HIGH);
}

void loop() {
  int sensorValue = analogRead(KEYPAD_PIN);
  int pressedButton = getPressedKeypadButton();
  
  if (pressedButton == 1) {
    relay1On = !relay1On;
    digitalWrite(relayPin1, relay1On ? HIGH : LOW);
  } else if (pressedButton == 2) {
    relay2On = !relay2On;
    digitalWrite(relayPin2, relay2On ? HIGH : LOW);
  } else if (pressedButton == 3) {
    relay3On = !relay3On;
    digitalWrite(relayPin3, relay3On ? HIGH : LOW);
  } else if (pressedButton == 4) {
    relay4On = !relay4On;
    digitalWrite(relayPin4, relay4On ? HIGH : LOW);
  } else if (pressedButton == 5) {
    relay5On = !relay5On;
    digitalWrite(relayPin5, relay5On ? HIGH : LOW);
  } else if (pressedButton == 6) {
    // Включаем или выключаем все реле одновременно
    relay1On = !relay1On;
    relay2On = !relay2On;
    relay3On = !relay3On;
    relay4On = !relay4On;
    relay5On = !relay5On;

    digitalWrite(relayPin1, relay1On ? HIGH : LOW);
    digitalWrite(relayPin2, relay2On ? HIGH : LOW);
    digitalWrite(relayPin3, relay3On ? HIGH : LOW);
    digitalWrite(relayPin4, relay4On ? HIGH : LOW);
    digitalWrite(relayPin5, relay5On ? HIGH : LOW);
  }

  Serial.print("Analog Value: ");
  Serial.print(sensorValue); // выводим значение аналогового сигнала в монитор порта
  Serial.print("     Pressed Button: ");
  Serial.println(pressedButton); // выводим номер нажатой кнопки в монитор порта
  
  delay(500); // добавляем небольшую задержку для стабилизации и избежания множественных срабатываний
}

int getPressedKeypadButton() {
  const int OCCURACY = 25;
  int sensorValue = analogRead(KEYPAD_PIN);
  int keys[] = {557, 594, 637, 686, 743, 811};

  if(sensorValue > -OCCURACY && sensorValue < OCCURACY) {
    return 0;
  }

  for (short int i = 0; i < 6; i++) {
    if (sensorValue > (keys[i] - OCCURACY) && sensorValue < (keys[i] + OCCURACY)) {
      return i + 1;
    }
  }

  return 0;
}

Буду признателен за советы и предложения.

был не прав

А он что делает, по Вашему?

1 лайк

У вас диапазоны кнопок с учетом вашего “оккураси” пересекаются.
Например 557 + 50 - больше чем следующее значение 594.

А смысл этого я вовсе не понял:

Что такое, по вашему, “-OCCURACY” ? И как значение сенсора может быть меньше нуля, если возвращаемое значение аналогового пина - unsigned?

ЗЫ Если не знаете английского - выбирайте лучше имена переменных транслитом - например Tochnost

А чего Вы ждали? Если нажатие попадает на Вашу

то оно игнорируется.

Держите кнопку нажатой не менее полусекунды - будет срабатывать.

Но сравнивать надо не с окупаси, а с серединой между центральными значениями кнопок.

И, кстати, давайте схему. Я вот например, не знаю, если ли у Вас конденсатор на пине кнопок - от него тут много чего зависит. Да и вообще, без схемы трудно.

Как-то у Вас плохо подобраны кнопки. Значения должны начинаться 0 и следовать с примерно одинаковым интервалом.
Ну и, кроме того, Вам нужно сравнивать не с этими величинами, а с границами между кнопок, т.е. примерно с средним арифметическим между этими значениями.

Кнопки наверно покупные. И китайцы рассчитали на нажатия по комбинациям :slight_smile: тоже.

А так? (кнопки Китай):

static uint8_t getKey() {
  uint16_t adc_key = ain(KEY_PIN);
  if (adc_key < RIGHT_VAL)  return RIGHT_CODE;
  if (adc_key < UP_VAL)     return UP_CODE;
  if (adc_key < DOWN_VAL)   return DOWN_CODE;
  if (adc_key < LEFT_VAL)   return LEFT_CODE;
  if (adc_key < SELECT_VAL) return SELECT_CODE;
  if (adc_key > NONE_VAL)   return NONE_CODE;
  return ERROR_CODE;
}

#define RIGHT_VAL         50            //v1.0
#define UP_VAL            195
#define DOWN_VAL          380
#define LEFT_VAL          555
#define SELECT_VAL        790
#define NONE_VAL          1000

#define RIGHT_CODE        0
#define UP_CODE           1
#define DOWN_CODE         2
#define LEFT_CODE         3
#define SELECT_CODE       4
#define NONE_CODE         5
#define ERROR_CODE        -1

Красиво. Китайцы вроде на обороте платы модуля пишут значения кнопок.

Тут, конечно, enum напрашивается, но у меня так, почему то.)

Я “точность” начинал с 10, 15, 20 и в последний раз пробовал 25.
Схему попробую нарисовать. Конденсатора нет вообще никаких.

Кнопки просто обычные тактовые кнопки китайские в количестве 6 шт…

У меня не готовый модуль. А обычные кнопки с резисторами 1К между кнопками.

При правильной резистивной матрице у меня работают 12 кнопок, без глюков, нажатие двух и более кнопок возможно, диапазоны значений:
35-70, 75-110, 115-150, 180-220, 290-330, 390-450, 530-580, 675-720, 770-810, 855-900, 905-945, 950-1023

Да, какие были резисторы в наличии. Вроде посчитал, что разница 40-50 единиц между значениями разных кнопок. Думал этого будет достаточно для корректной отработки. В принципе если оставляю только отработку кнопок и вывод в сериал значения кнопок - то значения кнопок отрабатывались вполне корректно, но когда в скетч добавляю обработку реле - тут уже начинает какая то туфта.
И такой вариант пробовал:

const int relayPin1 = 2;
const int relayPin2 = 3;
const int relayPin3 = 4;
const int relayPin4 = 5;
const int relayPin5 = 6;

boolean relay1On = false;
boolean relay2On = false;
boolean relay3On = false;
boolean relay4On = false;
boolean relay5On = false;

byte key() {  
    int val = analogRead(A2);
    if (val < 250) return 0;
    else if (val < 574) return 1;
    else if (val < 617) return 2;
    else if (val < 660) return 3;
    else if (val < 700) return 4;
    else if (val < 760) return 5;
    else if (val < 830) return 6;
    else return 0;  
}

void setup() {
    Serial.begin(9600);
    pinMode(relayPin1, OUTPUT);
    pinMode(relayPin2, OUTPUT);
    pinMode(relayPin3, OUTPUT);
    pinMode(relayPin4, OUTPUT);
    pinMode(relayPin5, OUTPUT);
}

void loop() {
    int button = key();
    Serial.print("Кнопка ");
    Serial.println(button);

    switch (button) {
        case 1:
            relay1On = !relay1On;
            digitalWrite(relayPin1, !relay1On); 
            break;
        case 2:
            relay2On = !relay2On;
            digitalWrite(relayPin2, !relay2On); 
            break;
        case 3:
            relay3On = !relay3On;
            digitalWrite(relayPin3, !relay3On); 
            break;
        case 4:
            relay4On = !relay4On;
            digitalWrite(relayPin4, !relay4On); 
            break;
        case 5:
            relay5On = !relay5On;
            digitalWrite(relayPin5, !relay5On); 
            break;
        case 6:
            relay1On = false;
            relay2On = false;
            relay3On = false;
            relay4On = false;
            relay5On = false;
            digitalWrite(relayPin1, !relay1On); 
            digitalWrite(relayPin2, !relay2On); 
            digitalWrite(relayPin3, !relay3On); 
            digitalWrite(relayPin4, !relay4On);
            digitalWrite(relayPin5, !relay5On);
            break;
    }

    delay(100);
}

Но тоже нет стабильности.

Схема то есть?
Может питание просаживается, при включении реле, и от этого показания плывут.

При работе с кнопками операторов delay() в коде не должно быть вовсе.

Схему рисовать не знаю где и как.
Выкладываю макет платы.

Питание осуществляется от блока питания 12 В 10 А.
На плате есть пока не задействованные модули, на них прошу пока не обращать внимание.

Delay ставил, чтобы значения кнопок успевать увидеть. А то нажал и в мониторе 100-500 значений пролетело, что даже не понятно что отображается.

используйте миллис