ARDUINO CD74HC4067 и EncButton.h

Chak

✩✩✩✩✩✩✩
6 Янв 2024
3
0
пытаюсь подключить 16 кнопок через CD74HC4067 к ардуино нано + библиотека EncButton
кнопки подключены через землю, EN от мультиплексора также подключён к земле

написал вот такой код

C++:
#include <Arduino.h>
#include <SPI.h>
#include <EncButton.h>
const int s0 = 9;
const int s1 = 10;
const int s2 = 11;
const int s3 = 12;
const int SIG_pin = 3;
const int numChannels = 16;

VirtButton buttons[numChannels];

void setup()
{
  pinMode(s0, OUTPUT);
  pinMode(s1, OUTPUT);
  pinMode(s2, OUTPUT);
  pinMode(s3, OUTPUT);
  pinMode(SIG_pin, INPUT_PULLUP);

  Serial.begin(9600);
}

byte readMux(byte channel)
{
  digitalWrite(s0, channel & 0x01);
  digitalWrite(s1, channel & 0x02);
  digitalWrite(s2, channel & 0x04);
  digitalWrite(s3, channel & 0x08);
  return digitalRead(SIG_pin);
}

void loop()
{
  for (int i = 0; i < numChannels; i++)
  {
    buttons[i].tick(readMux(i));

    if (buttons[i].click())
    {
      Serial.print("Button at channel ");
      Serial.print(i);
      Serial.println(" is clicked");
    }


  }
}
он работает, но есть проблема с тем, что в сериал порт не приходит первое нажатие каждой кнопки
порядок моих действий:
нажал кнопку номер 1 первый раз - сериал порт - пусто
нажал кнопку номер 1 второй\третий и тд раз - сериал порт - кнопка номер 1 нажата
нажал кнопку номер 2 первый раз - сериал порт - пусто
нажал кнопку номер 2 второй\третий и тд раз - сериал порт - кнопка номер 2 нажата
опять нажимаем кнопку номер 1
нажал кнопку номер 1 первый раз - сериал порт - пусто
нажал кнопку номер 1 второй\третий и тд раз - сериал порт - кнопка номер 1 нажата

вопрос скорее в том, как соединить этот мультиплексор и библиотеку с кнопками

да, мне принципиально использовать расщиритель и\о портов - если можете посоветовать какие-то другие варианты вместо CD74HC4067 - буду очень признателен
 

N360

✩✩✩✩✩✩✩
3 Янв 2024
4
0
В данный момент я тоже делаю подобный проект, но у меня знаний меньше чем у Вас и все до чего я додумался, это прописать каждый канал мультиплексора руками, а взаимодействие с помощью библиотеки CD74HC4067, в общем у меня 16 кнопок работают, но без EncButton, потому что я не понял пока как ее прикрутить нормально. Сейчас попробую Ваш код.
 

PiratFox

★★★★★✩✩
13 Фев 2020
1,706
474
если можете посоветовать какие-то другие варианты вместо CD74HC4067 - буду очень признателен
Да разные есть. Очень удобны те, что работают по I2C шине. Например, MCP23017. На Гитхабе библиотеки имеются.
 
Изменено:

Bruzzer

★★★✩✩✩✩
23 Май 2020
476
137
@Chak,
Или у Гайвера кривые виртуальные кнопки или мы не умеем ими пользоваться. По моему виртуальные кнопки кривые.
С обычными кнопками вроде работает нормально.
Дополнение: Был не прав, не кнопки кривые - просто надо добавить инверсию buttons.tick(! readMux(i));
Код с обычными кнопками удалять не стал.

C++:
#include "EncButton.h"

const int s0 = 9;
const int s1 = 10;
const int s2 = 11;
const int s3 = 12;
const int SIG_pin = 3;
const int numChannels = 16;

Button buttons[numChannels];

byte readMux(byte channel)
{
  digitalWrite(s0, channel & 0x01);
  digitalWrite(s1, channel & 0x02);
  digitalWrite(s2, channel & 0x04);
  digitalWrite(s3, channel & 0x08);
  return digitalRead(SIG_pin);
}

void setup()
{
  for(byte i =0; i < numChannels; i++)
      buttons[i].init(SIG_pin);

  pinMode(s0, OUTPUT);
  pinMode(s1, OUTPUT);
  pinMode(s2, OUTPUT);
  pinMode(s3, OUTPUT);
  pinMode(SIG_pin, INPUT_PULLUP);

  Serial.begin(9600);
}

void loop()
{
  for (int i = 0; i < numChannels; i++)
  {
    readMux(i);
    buttons[i].tick();

    if (buttons[i].click())
    {
      Serial.print("Button at channel ");
      Serial.print(i);
      Serial.println(" is clicked");
    }
  }
}
 
Изменено:

N360

✩✩✩✩✩✩✩
3 Янв 2024
4
0
@Bruzzer, Да Вы правы,это работает! а как кнопкам присвоить свои функции? Если я пишу
if (buttons[1].click()) то в порт валится сразу 16 одинаковых строк при нажатии кнопки 1.
А как прикрутить виртуальные энкодеры, вообще темный лес для меня (
 
Изменено:

Bruzzer

★★★✩✩✩✩
23 Май 2020
476
137
@N360,
Я не особо разбираюсь в этом вопросе. Поэтому и написал сначала "кнопки кривые".
Мне было просто интересно посмотреть, почему они работают странно.
Причем смотрел я не читая документацию, а методом тыка, поэтому много раз редактировал свое сообщение.
Оказалось на эту библиотеку есть довольно подробное описание.
Программно 16 одинаковых строк у вас могут быть, если вы 16 раз вызываете if (buttons[1].click()) между тиками этой кнопки buttons[1].tick(). Т.к. click() только считывает значение которое было установлено при tick().
 
  • Лойс +1
Реакции: N360

Vaqtincha

★✩✩✩✩✩✩
14 Ноя 2022
156
21
Uzbekistan, Fergana

 

Svod

✩✩✩✩✩✩✩
22 Апр 2022
17
8
Немного изменил вашу логику программы с устранением недочетов
C++:
#include <Arduino.h>
#include <EncButton.h>

#define s0  9
#define s1  10
#define s2  11
#define s3  12
#define SIG_pin  3
#define numChannels  16

VirtButton btn[numChannels];

bool readMux(uint8_t channel)
{
  digitalWrite(s0, channel & 0x01);
  digitalWrite(s1, channel & 0x02);
  digitalWrite(s2, channel & 0x04);
  digitalWrite(s3, channel & 0x08);
  return digitalRead(SIG_pin);
}

void setup()
{
  for (uint8_t i = 0; i < numChannels; i++)
  {
    //btn[i].setDebTimeout(0); // Добавить если нужно другое время на debounce, по умолчанию 50 мсек max 255
    btn[i].setBtnLevel(LOW);   // Кнопка замыкает на GND
  }
 
  pinMode(s0, OUTPUT);
  pinMode(s1, OUTPUT);
  pinMode(s2, OUTPUT);
  pinMode(s3, OUTPUT);
  pinMode(SIG_pin, INPUT);

  Serial.begin(9600);
}

void loop()
{
  for (uint8_t i = 0; i < numChannels; i++)
  {
    
    btn[i].tick(readMux(i));

    if (btn[i].click())
    {
      Serial.print("Button at channel ");
      Serial.print(i);
      Serial.println(" is clicked");
    }
    if(btn[i].hold())
    {
      Serial.print("Button at channel ");
      Serial.print(i);
      Serial.println(" is Hold");
    }
    if(btn[i].getClicks() == 2)
    {
      btn[i].clear();
      btn[i].reset();
      Serial.print("Button at channel ");
      Serial.print(i);
      Serial.println(" is Double click");
    }
  }
}
Неоходимо указать в каком режиме работает кнопка - 27 строка.
Нет необходимости подтягивать вход МК к высокому уровню - строка 34, так как он связан с мультиплексорной микросхемой, а вот 16 кнопок подключаемые к мультиплексору нужно подтягивать резисторами к высокому уровню а то в противном случае будут ловится помехи .
44 строка - передаем с мульплексора сигнал в обработку функции "tick" каждой кнопки.
 
  • Лойс +1
Реакции: N360

Svod

✩✩✩✩✩✩✩
22 Апр 2022
17
8
А как прикрутить виртуальные энкодеры, вообще темный лес для меня (
Как то так, возможно кто-то предложит лучше.
C++:
#include <Arduino.h>
#include <EncButton.h>

#define s0 9
#define s1 10
#define s2 11
#define s3 12
#define SIG_pin 3
#define enc_count 4

VirtEncButton enc[enc_count];

bool readMux(uint8_t channel)
{
  digitalWrite(s0, channel & 0x01);
  digitalWrite(s1, channel & 0x02);
  digitalWrite(s2, channel & 0x04);
  digitalWrite(s3, channel & 0x08);
  return digitalRead(SIG_pin);
}

void setup()
{
  for (uint8_t i = 0; i < enc_count; i++)
  {
    enc[i].setEncType(EB_STEP2);
    enc[i].setBtnLevel(LOW);
  }

  pinMode(s0, OUTPUT);
  pinMode(s1, OUTPUT);
  pinMode(s2, OUTPUT);
  pinMode(s3, OUTPUT);
  pinMode(SIG_pin, INPUT);

  Serial.begin(9600);
}

void loop()
{

  for (uint8_t i = 0; i < enc_count; i++)
  {
    uint8_t pin_enc = 3;
    uint8_t state[3];
    for (uint8_t b = (i * pin_enc), c = 0; b < (i * pin_enc + pin_enc), c < pin_enc; b++, c++)
    {
      state[c] = b;
    }
    enc[i].tick(readMux(state[0]), readMux(state[1]), readMux(state[2]));

    if (enc[i].left())
    {
      Serial.print("Encoder [");
      Serial.print(i);
      Serial.println("] Turn LEFT");
    }
    if (enc[i].right())
    {
      Serial.print("Encoder [");
      Serial.print(i);
      Serial.println("] Turn RIGHT");
    }
    if (enc[i].leftH())
    {
      Serial.print("Encoder [");
      Serial.print(i);
      Serial.println("] Pressed Turn LEFT");
    }
    if (enc[i].rightH())
    {
      Serial.print("Encoder [");
      Serial.print(i);
      Serial.println("] Pressed Turn RIGHT");
    }
    if (enc[i].click())
    {
      Serial.print("Encoder Button [");
      Serial.print(i);
      Serial.println("] CLICK");
    }
    if (enc[i].hold())
    {
      Serial.print("Encoder Button [");
      Serial.print(i);
      Serial.println("] HOLD");
    }
  }
}
 
  • Лойс +1
Реакции: N360

N360

✩✩✩✩✩✩✩
3 Янв 2024
4
0
@Svod, Спасибо, вроде работает. у меня 8 энкодеров (кнопку я не подключал, она не нужна мне) буду разбираться как из кода кнопку убрать. Еще раз Спасибо за помощь!