Одновременное нажатие 10 кнопок из любых 120

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

И Квон ещё. Щас подтянется и какой-нить класс скинет :)

MYFRIEND
MYFRIEND аватар
Offline
Зарегистрирован: 31.01.2017

bitVal выдает значение в битах 8 кнопок  0 0 0 0 0 0 0 1, как единицы оставить  

MYFRIEND
MYFRIEND аватар
Offline
Зарегистрирован: 31.01.2017

похоже действительно никто не знает, уже ответили бы если бы знали  

b707
Онлайн
Зарегистрирован: 26.05.2017

MYFRIEND пишет:

похоже действительно никто не знает, уже ответили бы если бы знали  

беда...

bwn
Offline
Зарегистрирован: 25.08.2014

Так вам биты ампутировать или в сериал их выводить?

anatoli_nik
Offline
Зарегистрирован: 17.01.2019

ТС нужно уяснить что ни одну матричную клавиатуру невозможно опросить мгновенно за один раз, опрос будет происходить по столбцам. Как вариант опрос всей клавиатуры (не забываем о индуктивности и емкости проводов от кнопок (ограничивают скорость опроса))  и, в конце, вывод состояния кнопок.

Второй вариант сдвиговый регистр на 120 входов, но все равно нужно время чтобы вывести из него все биты. ИМХО, это быстрее чем .опрос по столбцам, не нужно ждать нарастания напряжения, регистры можно засунуть возле кнопок, но сложнее схемотехнически.

MYFRIEND
MYFRIEND аватар
Offline
Зарегистрирован: 31.01.2017

bwn пишет:

Так вам биты ампутировать или в сериал их выводить?

в сериал не должно пролезть всё что не нажато, а только то что нажато, вот готовый результат:

"сериал" видим вот что нажав кнопку 1 и 2:  

Button1 pressed

Button2 pressed

-----------

 

 

 

 

bwn
Offline
Зарегистрирован: 25.08.2014

А зачем тогда ищите это в функции ввода, а не вывода? Или под фонарем искать светлей?

Schwarz78
Offline
Зарегистрирован: 19.01.2019

MYFRIEND пишет:

в сериал не должно пролезть всё что не нажато, а только то что нажато, вот готовый результат:

"сериал" видим вот что нажав кнопку 1 и 2:  

Button1 pressed

Button2 pressed

Serial = ~(всё_что_не_нажато) + кнопка1 + кнопка2;

b707
Онлайн
Зарегистрирован: 26.05.2017

MYFRIEND пишет:

результат летит в serial так: 

  Button-0: ON
  Button-1: OFF
  Button-2: OFF
  Button-3: OFF
  Button-4: OFF
  Button-5: OFF
  Button-6: OFF
  Button-7: OFF
 
как сделать что бы в serial летела лишь нажатая кнопка, а не целых 8 шт. ? 

в линуксе воспользуйтесь командой grep

| grep "ON"

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

b707 пишет:

в линуксе воспользуйтесь командой grep

| grep "ON"

+100'500!

MYFRIEND
MYFRIEND аватар
Offline
Зарегистрирован: 31.01.2017

Schwarz78 пишет:

Serial = ~(всё_что_не_нажато) + кнопка1 + кнопка2;

не пойму как, 

вместо сериал можно включить светодиоды каждый соответствующий кнопке нажатой из 8, нигде не нагуглилось, как будто коллайдер а не 165 регистр настолько секретно 

MYFRIEND
MYFRIEND аватар
Offline
Зарегистрирован: 31.01.2017

не пойму зачем в этом коде вобще сразу все биты вытащили и оставили, а не побитно, вот как например светодиоды подключить 8шт. к 8 кнопкам через 165 регистр, как из этих 8 бит высветить единицы светодиодами, а если регистров будет 10шт. это 80 единиц, вот толку что он пишет 1ON 2OFF 3OFF 4OFF 5OFF 6OFF 7OFF 8OFF что с этим делать массивом, цикл перебирал все ноги регистра, может при перебирании ног сразу сверять каждую ногу и в переменную сохранять, перебирает же цикл ноги регистра и накапливает все единицы и ноли, на том  этапе скорее всего нужно инъекцию делать в код. Может библиотека нужна? А это лишь пример считывания 8 ног сразу. Под shift 595 библиотека есть, там всё четко и проще некуда работает а 165 столько ответов писали и никто не вкурсе, как там нажатое высветить сразу светодиодом. Понятно что он там как и в случае столбцов и строк считывает линию, линия в данном случае одна, это 8 бит, 10101010 например, это число парсить по положению символов на ПК, но это же долго.  

bwn
Offline
Зарегистрирован: 25.08.2014

А в 595 вы только единицы запихиваете?

MYFRIEND
MYFRIEND аватар
Offline
Зарегистрирован: 31.01.2017

bwn пишет:

А в 595 вы только единицы запихиваете?

да, остальное библиотека запихиывает, если хочу зажечь или погасить светодиод пишу 1 команду так:

{Shifter.setRegisterPin(  63, HIGH);} и там 64 пина 

А здесь 1 регистр и 8 бит сразу выхлоп. Полуфабрикат из 8 бит. Автор примера кода не додумался побитно сделать и не задавал себе вопрос куда девать эти 8 бит. Вот интересно, как вообще все с 165 работают, если без SPI, может на SPI нацепить, там по другому возможно? Похоже сам пример не лучший. 

b707
Онлайн
Зарегистрирован: 26.05.2017

MYFRIEND пишет:

А здесь 1 регистр и 8 бит сразу выхлоп. Полуфабрикат из 8 бит.

этот "полуфабрикат" называется байт :)  Никогда не слышали?

Цитата:
Автор примера кода не додумался побитно сделать и не задавал себе вопрос куда девать эти 8 бит.

автору просто не пришло в голову, что есть люди, не знающее что такое байты и биты... По крайней мере среди программирующих ардуино это должны знать даже дети.

MYFRIEND
MYFRIEND аватар
Offline
Зарегистрирован: 31.01.2017

b707 пишет:

автору просто не пришло в голову

речь не о байте, а о 8 значениях, которые автор так и оставил в примере, который не пропарсил байт, не думая, что люди будут делать потом код, и из 10 сообщений на вопрос никто не даст ответа что с этим байтом делать. 

b707
Онлайн
Зарегистрирован: 26.05.2017

MYFRIEND пишет:

 из 10 сообщений на вопрос никто не даст ответа что с этим байтом делать. 

не даст, не рассчитывайте

MYFRIEND
MYFRIEND аватар
Offline
Зарегистрирован: 31.01.2017

b707 пишет:

не даст, не рассчитывайте

я и сам почти нашёл, и я тогда не дам) 

b707
Онлайн
Зарегистрирован: 26.05.2017

MYFRIEND пишет:

[и я тогда не дам) 

это будет огромной потерей для всего прогрессивного человечества

MYFRIEND
MYFRIEND аватар
Offline
Зарегистрирован: 31.01.2017

b707 пишет:

это будет огромной потерей для всего прогрессивного человечества

ему и так нечего терять) оно человек человеку волк 

MYFRIEND
MYFRIEND аватар
Offline
Зарегистрирован: 31.01.2017

сделал понятнее код, думаю BYTES_VAL_T это целый байт, может существует битовое значение?  

и  read_shift_regs() не даёт в скобки вписать аргумент, например номер пина 0-8, кто что подскажет? кроме шутников и флудеров? 

#define NUMBER_OF_SHIFT_CHIPS   1 //v количество регистров
#define DATA_WIDTH   NUMBER_OF_SHIFT_CHIPS * 8 //v количество входов
#define PULSE_WIDTH_USEC   5 //v задержка при считывании данных 
// для хранения считанного байта (считанных байт)
#define BYTES_VAL_T unsigned int //в отличие от int, тип unsigned int может хранить только положительные целые числа в диапазоне от 0 до 65535 (2^16)-1). если регистров больше двух, то int меняется на long
//v***********************************************
int ploadPin = 8;//shift load selector // пины для подключения регистра
int clockEnablePin = 9;
int dataPin = 11;//data GREEN 
int clockPin = 12;//clock 
//************************************************
BYTES_VAL_T VSEPINYSRAZY; // текущее значение пинов 
BYTES_VAL_T STAROEZNACHENIE; // предыдущее значение пинов
//v************************************************
void setup(){
Serial.begin(115200);
pinMode(ploadPin, OUTPUT);
pinMode(clockEnablePin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, INPUT);
digitalWrite(clockPin, LOW);
digitalWrite(ploadPin, HIGH);
// ***************************************************************** 
VSEPINYSRAZY = read_shift_regs();    // считываем значения с пинов
display_pin_values();   // выводим результат
STAROEZNACHENIE = VSEPINYSRAZY;    // сохраняем текущее значение
} 
BYTES_VAL_T read_shift_regs() {// функция для считывания пинов
    long bitVal;
BYTES_VAL_T bytesVal = 0; 
digitalWrite(clockEnablePin, HIGH);    // опрашиваем регистр о состоянии пинов
digitalWrite(ploadPin, LOW);
delayMicroseconds(PULSE_WIDTH_USEC);
digitalWrite(ploadPin, HIGH);
digitalWrite(clockEnablePin, LOW);
for(int MAKARON = 0; MAKARON < DATA_WIDTH; MAKARON++){// считываем полученные данные о пинах
bitVal = digitalRead(dataPin);
//Serial.println(bitVal);
bytesVal |= (bitVal << ((DATA_WIDTH-1) - MAKARON));
digitalWrite(clockPin, HIGH);
delayMicroseconds(PULSE_WIDTH_USEC);
digitalWrite(clockPin, LOW);
}
return(bytesVal); // возвращяем результат опроса регистра
}
void display_pin_values(){// функция для вывода состояния пинов
// перебор всех пинов 
for(int MAKARON = 0; 
MAKARON < DATA_WIDTH; 
MAKARON++)
{
//*******************************************
//    Serial.print("Button-");// 
//      Serial.print(i);
//      Serial.print(": ");
if((VSEPINYSRAZY >> MAKARON) & 1){
Serial.print(MAKARON); 
Serial.print("ON"); 
Serial.println(); 
}
//else{
//Serial.print("OFF"); 
//   }   
Serial.println();
}
  Serial.println();
}
void loop(){
VSEPINYSRAZY = read_shift_regs();// считываем значения с пинов
if(VSEPINYSRAZY != STAROEZNACHENIE){// если значения изменились, то выводим их (можно не выводить а выяснить
 
display_pin_values();// выводим результат в монитор порта
STAROEZNACHENIE = VSEPINYSRAZY;//состариваем значение
}
delay(5);
}

 

MYFRIEND
MYFRIEND аватар
Offline
Зарегистрирован: 31.01.2017
bitRead(x, n) читает побитовое значение но пока не получилось, ни одного совета за 2 дня, кроме флуда

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

MYFRIEND пишет:

bitRead(x, n) читает побитовое значение но пока не получилось, ни одного совета за 2 дня, кроме флуда

Помощь работает!

Вот уже про bitread узнал, а написали бы готовое решение сразу, так и не узнал бы никогда.

MYFRIEND
MYFRIEND аватар
Offline
Зарегистрирован: 31.01.2017

ЕвгенийП пишет:

Вот уже про bitread узнал, а написали бы готовое решение сразу, так и не узнал бы никогда.

Спасибо за поддержку, это важно! Хоть весело  с вами. Кода не добиться, но весело зато, узнал действительно много, что такое != узнал наконец то ) , да с 595 никто не помог особо был, пока сам все не сделал и всем не рассказал, и здесь туго совсем, жаль, но хоть весело и научным тыком никто не может тыкнуть, Adriano нет и неоткуда появиться ответу. 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

MYFRIEND пишет:

Кода не добиться

Это да. Но это специфика помощи на данном форуме (и на многих других).

А если бы дали код, то никогда бы НЕ

MYFRIEND пишет:

узнал действительно много

Я вот сразу даю готовый код (если даю - это нечасто бывает) только тем, кого не считаю способным дойти самостоятельно. Тем кого уважаю, я только подсказываю и даю возможность решить проблему самому. Ну, вот такое я дерьмо. И всех остальных (у каждого!) свои тараканы и свои соображения что и когда давать, а что и когда не давать.

MYFRIEND пишет:

Adriano нет и неоткуда появиться ответу. 

Как нет? И вчера и сегодня что-то постил. Видать, не заинтересовала его тема.

MYFRIEND
MYFRIEND аватар
Offline
Зарегистрирован: 31.01.2017

ЕвгенийП пишет:

даю возможность решить проблему самому. 

Зато вы всегда рядом, что хоть как то поддерживаете. Лучше чем ничего. Шутки помогают. Совет про большой скачок помог, хоть и ни слова про ардуино, но хоть такой форум чем никакого. 

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Фишка в том что дать готовый код не реально. Это как электроприбор под американскую элект сеть. Любая кнопка , если хотете что бы она влияла на работу программы требует обработчик этой кнопки. И чаще всего не один, так как желания у пользователя растут, а деньги на лишнюю кнопку не всегда находятся, или место, или ... {ну не любит лишние дырки в корпусе делать}.

MYFRIEND
MYFRIEND аватар
Offline
Зарегистрирован: 31.01.2017

держите, жаль что здесь не было "знатоков", одни "ешь один и в темноте" собрались, кнопки разделены между собой, причем это один единственный код здесь, не найти нигде ответ было, осталось только убрать повтор при отжатии, не знаю как. Может есть кто умный совет даст?    

#define NUMBER_OF_SHIFT_CHIPS   1 //v количество регистров
#define DATA_WIDTH   NUMBER_OF_SHIFT_CHIPS * 8 //v количество входов
#define PULSE_WIDTH_USEC   5 //v задержка при считывании данных 
// для хранения считанного байта (считанных байт)
#define BYTES_VAL_T unsigned int //в отличие от int, тип unsigned int может хранить только положительные целые числа в диапазоне от 0 до 65535 (2^16)-1). если регистров больше двух, то int меняется на long
//v***********************************************
int ploadPin = 8;//shift load selector // пины для подключения регистра
int clockEnablePin = 9;
int dataPin = 11;//data GREEN 
int clockPin = 12;//clock 
//************************************************
BYTES_VAL_T VSEPINYSRAZY; // текущее значение пинов 
BYTES_VAL_T STAROEZNACHENIE; // предыдущее значение пинов
//v************************************************
void setup(){
Serial.begin(115200);
pinMode(ploadPin, OUTPUT);
pinMode(clockEnablePin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, INPUT);
digitalWrite(clockPin, LOW);
digitalWrite(ploadPin, HIGH);
// ***************************************************************** 
VSEPINYSRAZY = read_shift_regs();    // считываем значения с пинов
display_pin_values();   // выводим результат
STAROEZNACHENIE = VSEPINYSRAZY;    // сохраняем текущее значение
} 
BYTES_VAL_T read_shift_regs() {// функция для считывания пинов
    long bitVal;
BYTES_VAL_T bytesVal = 0; 
digitalWrite(clockEnablePin, HIGH);    // опрашиваем регистр о состоянии пинов
digitalWrite(ploadPin, LOW);
delayMicroseconds(PULSE_WIDTH_USEC);
digitalWrite(ploadPin, HIGH);
digitalWrite(clockEnablePin, LOW);
for(int MAKARON = 0;
MAKARON < DATA_WIDTH;
MAKARON++)
{// считываем полученные данные о пинах
//если макарон меньше чем количество пинов 
bitVal = digitalRead(dataPin);
//Serial.println(bitVal);
bytesVal |= (bitVal << ((DATA_WIDTH-1)- MAKARON));
//Serial.println(bytesVal);
digitalWrite(clockPin, HIGH);
delayMicroseconds(PULSE_WIDTH_USEC);
digitalWrite(clockPin, LOW);
}
return(bytesVal); // возвращяем результат опроса регистра
}
void display_pin_values(){// функция для вывода состояния пинов
// перебор всех пинов 
for(int MAKARON = 0; 
MAKARON < DATA_WIDTH; 
MAKARON++)//делаем макарон больше на 1 оператором++ 
{
//*******************************************
//    Serial.print("Button-");// 
//      Serial.print(i);
//      Serial.print(": ");
if((VSEPINYSRAZY >> MAKARON) & 1){//побитовый сдвиг вправо 
Serial.print("ON"); 
Serial.println(); 
}
//else{
//Serial.print("OFF"); 
//  }   
Serial.println();
}
}
void loop() 
{ 
VSEPINYSRAZY = read_shift_regs();// считываем значения с пинов 
for(int i =0; i<8; i++) 
{ 
if(((VSEPINYSRAZY>>i)&1)!=((STAROEZNACHENIE>>i)&1))
{ 
Serial.print(i); 
Serial.print("button"); 
Serial.println();
}} 
STAROEZNACHENIE = VSEPINYSRAZY; 
//delay(5); 
}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

А обещал же не выкладывать? Передумал? :(((

MYFRIEND
MYFRIEND аватар
Offline
Зарегистрирован: 31.01.2017

ЕвгенийП пишет:

А обещал же не выкладывать? Передумал? :(((

Ничего не обещал. А лишь предложил как вы делаете сделать. Мне не жалко в отличие от вас. "Знающих". 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Что там сложного. Вот скетч для одной кнопки.

/**/
template <typename T> inline Print & operator << (Print &s, T n) { s.print(n); return s; }
const byte btn1Pin = 2;
bool btn1;
unsigned long btn1past;

//---------------------------------
void setup() {
  Serial.begin(9600);
  pinMode(btn1Pin, INPUT_PULLUP);
  btn1 = false;
  btn1past = millis();
}
void loop() {
  if (millis() - btn1past >= 100) {
    switch (btn1) {
      case false:
        if (!digitalRead(btn1Pin)) {
          btn1 = true;
          btn1past = millis();
          /*обработчик кнопки*/
          Serial << "Btn1\n";
        }
        break;
      case true:
        if (digitalRead(btn1Pin)) {
          btn1 = false;
          btn1past = millis();
          break;
        }
    }
  }
}
/**/

Повторим ее 120 раз. Для примера я привел только 3 раза и готово

/**/
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
typedef void (*pDo)();
unsigned long mill = 0;
//-----------------------------------
class Cl_btn {
  protected:
    const byte pin;
    pDo Do;
    bool state;
    unsigned long past;
  public:
    Cl_btn(byte p, pDo D): pin(p), Do(D) {}
    void init() {
      pinMode(pin, INPUT_PULLUP);
      state = false;
      past = mill;
    }
    void run() {
      if (mill - past >= 100) {
        switch (state) {
          case false:
            if (!digitalRead(pin)) {
              state = true;
              past = mill;
              Do();
            }
            break;
          case true:
            if (digitalRead(pin)) {
              state = false;
              past = mill;
              break;
            }
        }
      }

    }
};
//---------------------------
void Do1() {
  Serial << "Btn1\n";
}
void Do2() {
  Serial << "Btn2\n";
}
void Do3() {
  Serial << "Btn3\n";
}

Cl_btn Btn[] = {
  Cl_btn(/*пин*/2,/*обработчик*/Do1),
  Cl_btn(/*пин*/3,/*обработчик*/Do2),
  Cl_btn(/*пин*/4,/*обработчик*/Do3)
};
//---------------------------------
void setup() {
  Serial.begin(9600);
  for (int i = 0; i < 3; ++i)Btn[i].init();
}
void loop() {
  mill = millis();
  for (int i = 0; i < 3; ++i)Btn[i].run();
}
/**/

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

MYFRIEND пишет:

Ничего не обещал.

Значит, мне привиделась фраза из поста #119

MYFRIEND пишет:

я и сам почти нашёл, и я тогда не дам) 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Не хватает пинов . Делаете внешние пины и драйверы их обсуживания.

/**/
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
typedef void (*pDo)();
unsigned long mill = 0;
//-----------------------------------
const byte num = 3;
bool s[num];
bool _read(byte pin) {
  return s[pin];
}
void _init() {
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
  _run();
}
void _run() {
  s[0] = digitalRead(2);
  s[1] = digitalRead(3);
  s[2] = digitalRead(4);
}
//----------------------------------
class Cl_btn {
  protected:
    const byte pin;
    pDo Do;
    bool state;
    unsigned long past;
  public:
    Cl_btn(byte p, pDo D): pin(p), Do(D) {}
    void init() {
      pinMode(pin, INPUT_PULLUP);
      state = false;
      past = mill;
    }
    void run() {
      if (mill - past >= 100) {
        switch (state) {
          case false:
            if (!_read(pin)) {
              state = true;
              past = mill;
              Do();
            }
            break;
          case true:
            if (_read(pin)) {
              state = false;
              past = mill;
              break;
            }
        }
      }

    }
};
//---------------------------
void Do1() {
  Serial << "Btn1\n";
}
void Do2() {
  Serial << "Btn2\n";
}
void Do3() {
  Serial << "Btn3\n";
}

Cl_btn Btn[num] = {
  Cl_btn(/*пин*/0,/*обработчик*/Do1),
  Cl_btn(/*пин*/1,/*обработчик*/Do2),
  Cl_btn(/*пин*/2,/*обработчик*/Do3)
};
//---------------------------------
void setup() {
  Serial.begin(9600);
  _init();
  for (int i = 0; i < num; ++i)Btn[i].init();
}
void loop() {
  mill = millis();
  _run();
  for (int i = 0; i < num; ++i)Btn[i].run();
}
/**/

И ничего сложного в этом нет.

MYFRIEND
MYFRIEND аватар
Offline
Зарегистрирован: 31.01.2017

удалось сделать нажатие отдельных кнопок без повторов на регистрах hc165 держите: только нажатие ON кнопки 1й вариант 

#define NUMBER_OF_SHIFT_CHIPS   1 //v количество регистров
#define DATA_WIDTH   NUMBER_OF_SHIFT_CHIPS * 8 //v количество входов
#define PULSE_WIDTH_USEC   5 //v задержка при считывании данных 
// для хранения считанного байта (считанных байт)
#define BYTES_VAL_T unsigned int //в отличие от int, тип unsigned int может хранить только положительные целые числа в диапазоне от 0 до 65535 (2^16)-1). если регистров больше двух, то int меняется на long
//v***********************************************
int ploadPin = 8;//shift load selector // пины для подключения регистра
int clockEnablePin = 9;
int dataPin = 11;//data GREEN 
int clockPin = 12;//clock 
//************************************************
BYTES_VAL_T VSEPINYSRAZY; // текущее значение пинов 
BYTES_VAL_T STAROEZNACHENIE; // предыдущее значение пинов
//v************************************************
void setup(){
Serial.begin(115200);
pinMode(ploadPin, OUTPUT);
pinMode(clockEnablePin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, INPUT);
digitalWrite(clockPin, LOW);
digitalWrite(ploadPin, HIGH);
// ***************************************************************** 
VSEPINYSRAZY = read_shift_regs();    // считываем значения с пинов
display_pin_values();   // выводим результат
STAROEZNACHENIE = VSEPINYSRAZY;    // сохраняем текущее значение
} 
BYTES_VAL_T read_shift_regs() {// функция для считывания пинов
    long bitVal;
BYTES_VAL_T bytesVal = 0; 
digitalWrite(clockEnablePin, HIGH);    // опрашиваем регистр о состоянии пинов
digitalWrite(ploadPin, LOW);
delayMicroseconds(PULSE_WIDTH_USEC);
digitalWrite(ploadPin, HIGH);
digitalWrite(clockEnablePin, LOW);
for(int MAKARON = 0;
MAKARON < DATA_WIDTH;
MAKARON++)
{// считываем полученные данные о пинах
//если макарон меньше чем количество пинов 
bitVal = digitalRead(dataPin);
//Serial.println(bitVal);
bytesVal |= (bitVal << ((DATA_WIDTH-1)- MAKARON));
//Serial.println(bytesVal);
digitalWrite(clockPin, HIGH);
delayMicroseconds(PULSE_WIDTH_USEC);
digitalWrite(clockPin, LOW);
}
return(bytesVal); // возвращяем результат опроса регистра
}
void display_pin_values(){// функция для вывода состояния пинов
// перебор всех пинов 
for(int MAKARON = 0; 
MAKARON < DATA_WIDTH; 
MAKARON++)//делаем макарон больше на 1 оператором++ 
{
//*******************************************
//    Serial.print("Button-");// 
//      Serial.print(i);
//      Serial.print(": ");
if((VSEPINYSRAZY >> MAKARON) & 1){//побитовый сдвиг вправо 
Serial.print("ON"); 
Serial.println(); 
}
//else{
//Serial.print("OFF"); 
//  }   
Serial.println();
}
}
void loop() 
{ 
VSEPINYSRAZY = read_shift_regs();// считываем значения с пинов 
for(int i =0; i<8; i++) 
{ 
if((((VSEPINYSRAZY>>i)&1)!=((STAROEZNACHENIE>>i)&1))&&(((VSEPINYSRAZY>>i)&1)==1)) 
{ 
Serial.print(i); 
//Serial.print("1"); 
Serial.println(); 
} 
} 
STAROEZNACHENIE = VSEPINYSRAZY; 
delay(5); 
}

 

MYFRIEND
MYFRIEND аватар
Offline
Зарегистрирован: 31.01.2017

здесь 2й вариант для hc165 с ON OFF для любых сочетаний кнопок держите: 

#define NUMBER_OF_SHIFT_CHIPS   1 //v количество регистров
#define DATA_WIDTH   NUMBER_OF_SHIFT_CHIPS * 8 //v количество входов
#define PULSE_WIDTH_USEC   5 //v задержка при считывании данных 
// для хранения считанного байта (считанных байт)
#define BYTES_VAL_T unsigned int //в отличие от int, тип unsigned int может хранить только положительные целые числа в диапазоне от 0 до 65535 (2^16)-1). если регистров больше двух, то int меняется на long
//v***********************************************
int ploadPin = 8;//shift load selector // пины для подключения регистра
int clockEnablePin = 9;
int dataPin = 11;//data GREEN 
int clockPin = 12;//clock 
//************************************************
BYTES_VAL_T VSEPINYSRAZY; // текущее значение пинов 
BYTES_VAL_T STAROEZNACHENIE; // предыдущее значение пинов
//v************************************************
void setup(){
Serial.begin(115200);
pinMode(ploadPin, OUTPUT);
pinMode(clockEnablePin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, INPUT);
digitalWrite(clockPin, LOW);
digitalWrite(ploadPin, HIGH);
// ***************************************************************** 
VSEPINYSRAZY = read_shift_regs();    // считываем значения с пинов
display_pin_values();   // выводим результат
STAROEZNACHENIE = VSEPINYSRAZY;    // сохраняем текущее значение
} 
BYTES_VAL_T read_shift_regs() {// функция для считывания пинов
    long bitVal;
BYTES_VAL_T bytesVal = 0; 
digitalWrite(clockEnablePin, HIGH);    // опрашиваем регистр о состоянии пинов
digitalWrite(ploadPin, LOW);
delayMicroseconds(PULSE_WIDTH_USEC);
digitalWrite(ploadPin, HIGH);
digitalWrite(clockEnablePin, LOW);
for(int MAKARON = 0;
MAKARON < DATA_WIDTH;
MAKARON++)
{// считываем полученные данные о пинах
//если макарон меньше чем количество пинов 
bitVal = digitalRead(dataPin);
//Serial.println(bitVal);
bytesVal |= (bitVal << ((DATA_WIDTH-1)- MAKARON));
//Serial.println(bytesVal);
digitalWrite(clockPin, HIGH);
delayMicroseconds(PULSE_WIDTH_USEC);
digitalWrite(clockPin, LOW);
}
return(bytesVal); // возвращяем результат опроса регистра
}
void display_pin_values(){// функция для вывода состояния пинов
// перебор всех пинов 
for(int MAKARON = 0; 
MAKARON < DATA_WIDTH; 
MAKARON++)//делаем макарон больше на 1 оператором++ 
{
//*******************************************
//    Serial.print("Button-");// 
//      Serial.print(i);
//      Serial.print(": ");
if((VSEPINYSRAZY >> MAKARON) & 1){//побитовый сдвиг вправо 
Serial.print("ON"); 
Serial.println(); 
}
//else{
//Serial.print("OFF"); 
//  }   
Serial.println();
}
}
void loop() 
{ 
VSEPINYSRAZY = read_shift_regs();// считываем значения с пинов 
for(int i =0; i<8; i++) 
{ 
if(((VSEPINYSRAZY>>i)&1)!=((STAROEZNACHENIE>>i)&1)) 
{ 
if(((VSEPINYSRAZY>>i)&1)==1) 
{ 
Serial.print(i); 
Serial.print("1"); 
Serial.println(); 
} 
else 
{ 
Serial.print(i); 
Serial.print("0"); 
Serial.println(); 
} 
} 
} 
STAROEZNACHENIE = VSEPINYSRAZY; 
delay(5); 
}

 

MYFRIEND
MYFRIEND аватар
Offline
Зарегистрирован: 31.01.2017

здесь 3й вариант для hc165 с подсчетом времени между нажатиями кнопки 1 и 2 по парам, для миди клавиатуры держите: 

кто может улучшить пишите. 

#define NUMBER_OF_SHIFT_CHIPS   1 //v количество регистров
#define DATA_WIDTH   NUMBER_OF_SHIFT_CHIPS * 8 //v количество входов
#define PULSE_WIDTH_USEC   5 //v задержка при считывании данных 
// для хранения считанного байта (считанных байт)
#define BYTES_VAL_T unsigned int //в отличие от int, тип unsigned int может хранить только положительные целые числа в диапазоне от 0 до 65535 (2^16)-1). если регистров больше двух, то int меняется на long
//v***********************************************
int ploadPin = 8;//shift load selector // пины для подключения регистра
int clockEnablePin = 9;
int dataPin = 11;//data GREEN 
int clockPin = 12;//clock 
unsigned long time = 0; 
//************************************************
BYTES_VAL_T VSEPINYSRAZY; // текущее значение пинов 
BYTES_VAL_T STAROEZNACHENIE; // предыдущее значение пинов
//v************************************************
void setup(){
Serial.begin(115200);
pinMode(ploadPin, OUTPUT);
pinMode(clockEnablePin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, INPUT);
digitalWrite(clockPin, LOW);
digitalWrite(ploadPin, HIGH);
// ***************************************************************** 
VSEPINYSRAZY = read_shift_regs();    // считываем значения с пинов
display_pin_values();   // выводим результат
STAROEZNACHENIE = VSEPINYSRAZY;    // сохраняем текущее значение
} 
BYTES_VAL_T read_shift_regs() {// функция для считывания пинов
    long bitVal;
BYTES_VAL_T bytesVal = 0; 
digitalWrite(clockEnablePin, HIGH);    // опрашиваем регистр о состоянии пинов
digitalWrite(ploadPin, LOW);
delayMicroseconds(PULSE_WIDTH_USEC);
digitalWrite(ploadPin, HIGH);
digitalWrite(clockEnablePin, LOW);
for(int MAKARON = 0;
MAKARON < DATA_WIDTH;
MAKARON++)
{// считываем полученные данные о пинах
//если макарон меньше чем количество пинов 
bitVal = digitalRead(dataPin);
//Serial.println(bitVal);
bytesVal |= (bitVal << ((DATA_WIDTH-1)- MAKARON));
//Serial.println(bytesVal);
digitalWrite(clockPin, HIGH);
delayMicroseconds(PULSE_WIDTH_USEC);
digitalWrite(clockPin, LOW);
}
return(bytesVal); // возвращяем результат опроса регистра
}
void display_pin_values(){// функция для вывода состояния пинов
// перебор всех пинов 
for(int MAKARON = 0; 
MAKARON < DATA_WIDTH; 
MAKARON++)//делаем макарон больше на 1 оператором++ 
{
//*******************************************
//    Serial.print("Button-");// 
//      Serial.print(i);
//      Serial.print(": ");
if((VSEPINYSRAZY >> MAKARON) & 1){//побитовый сдвиг вправо 
Serial.print("ON"); 
Serial.println(); 
}
//else{
//Serial.print("OFF"); 
//  }   
Serial.println();
}
}

void loop() 
{ 
VSEPINYSRAZY = read_shift_regs();// считываем значения с пинов 
for(int i =0; i<8; i++) 
{ 
if(((VSEPINYSRAZY>>i)&1)!=((STAROEZNACHENIE>>i)&1)) 
{ 
if(i%2 == 0) 
{ 
if(((VSEPINYSRAZY>>i)&1)==1) 
{ 
time = millis(); 
Serial.print(i); 
Serial.print("1"); 
Serial.println(); 
} 
else 
{ 
Serial.print(i); 
Serial.print("0"); 
Serial.println(); 
} 
} 
else 
{ 
if(((VSEPINYSRAZY>i)&1)==1) 
{ 
time = millis() - time; 
Serial.print(i); 
Serial.print("1"); 
Serial.println(); 
Serial.print("Time: "); 
Serial.print(time); 
Serial.println(); 
} 
else 
{ 
Serial.print(i); 
Serial.print("0"); 
Serial.println(); 
} 
} 
} 
} 
STAROEZNACHENIE = VSEPINYSRAZY; 
delay(5); 
}

 

MYFRIEND
MYFRIEND аватар
Offline
Зарегистрирован: 31.01.2017

qwone пишет:

Что там сложного. Вот скетч для одной кнопки.

спасибо большое! 

подскажите насколько возможно минимальное измерение времени? 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

MYFRIEND пишет:
подскажите насколько возможно минимальное измерение времени? 

А смысл. Человек устройство медленное. Да и кнопка маханическая она с дребезгом.

/**/
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
typedef void (*pDo)();
unsigned long mill = 0;
//-----------------------------------
#include <SPI.h>
const byte REG_LATCH = 8;
const byte num = 8;
byte state;
bool _read(byte pin) {
  return (state >> pin) & 0x01;
}
void _init() {
  SPI.begin();
  pinMode(REG_LATCH, OUTPUT);
  digitalWrite(REG_LATCH, HIGH);
  _run();
}
void _run() {
  digitalWrite(REG_LATCH, LOW);
  digitalWrite(REG_LATCH, HIGH);
  state = SPI.transfer(0);
}
//----------------------------------
class Cl_btn {
  protected:
    const byte pin;
    pDo Do;
    bool state;
    unsigned long past;
  public:
    Cl_btn(byte p, pDo D): pin(p), Do(D) {}
    void init() {
      pinMode(pin, INPUT_PULLUP);
      state = false;
      past = mill;
    }
    void run() {
      if (mill - past >= 100) {
        switch (state) {
          case false:
            if (!_read(pin)) {
              state = true;
              past = mill;
              Do();
            }
            break;
          case true:
            if (_read(pin)) {
              state = false;
              past = mill;
              break;
            }
        }
      }

    }
};
//---------------------------
void Do1() {
  Serial << "Btn1\n";
}
void Do2() {
  Serial << "Btn2\n";
}
void Do3() {
  Serial << "Btn3\n";
}
void Do4() {
  Serial << "Btn4\n";
}
void Do5() {
  Serial << "Btn5\n";
}
void Do6() {
  Serial << "Btn6\n";
}
void Do7() {
  Serial << "Btn7\n";
}
void Do8() {
  Serial << "Btn8\n";
}
Cl_btn Btn[num] = {
  Cl_btn(/*пин*/0,/*обработчик*/Do1),
  Cl_btn(/*пин*/1,/*обработчик*/Do2),
  Cl_btn(/*пин*/2,/*обработчик*/Do3),
  Cl_btn(/*пин*/3,/*обработчик*/Do4),
  Cl_btn(/*пин*/4,/*обработчик*/Do5),
  Cl_btn(/*пин*/5,/*обработчик*/Do6),
  Cl_btn(/*пин*/6,/*обработчик*/Do7),
  Cl_btn(/*пин*/7,/*обработчик*/Do8)
};
//---------------------------------
void setup() {
  Serial.begin(9600);
  _init();
  for (int i = 0; i < num; ++i)Btn[i].init();
}
void loop() {
  mill = millis();
  _run();
  for (int i = 0; i < num; ++i)Btn[i].run();
}
/**/

http://robocraft.ru/blog/arduino/520.html

MYFRIEND
MYFRIEND аватар
Offline
Зарегистрирован: 31.01.2017

ЕвгенийП пишет:

И Квон ещё. Щас подтянется и какой-нить класс скинет :)

Большое спасибо! Подтянулся точно! Вы молодцы все! Весело с вами! 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Потом ставишь паровозом две микросхемы у Вас уже 16 клавиши.

/**/
template <typename T> inline Print & operator << (Print &s, T n) {
  s.print(n);
  return s;
}
typedef void (*pDo)();
unsigned long mill = 0;
//-----------------------------------
#include <SPI.h>
const byte REG_LATCH = 8;
const byte num = 16;
byte state[2];
bool _read(byte pin) {
  if (pin < 8)return (state[0] >> (pin & 0xF)) & 0x01;
  else        return (state[1] >> (pin & 0xF)) & 0x01;
}
void _init() {
  SPI.begin();
  pinMode(REG_LATCH, OUTPUT);
  digitalWrite(REG_LATCH, HIGH);
  _run();
}
void _run() {
  digitalWrite(REG_LATCH, LOW);
  digitalWrite(REG_LATCH, HIGH);
  state[0] = SPI.transfer(0);
  state[1] = SPI.transfer(0);
}
//----------------------------------
class Cl_btn {
  protected:
    const byte pin;
    pDo Do;
    bool state;
    unsigned long past;
  public:
    Cl_btn(byte p, pDo D): pin(p), Do(D) {}
    void init() {
      pinMode(pin, INPUT_PULLUP);
      state = false;
      past = mill;
    }
    void run() {
      if (mill - past >= 100) {
        switch (state) {
          case false:
            if (!_read(pin)) {
              state = true;
              past = mill;
              Do();
            }
            break;
          case true:
            if (_read(pin)) {
              state = false;
              past = mill;
              break;
            }
        }
      }

    }
};
//---------------------------

Cl_btn Btn[num] = {
  Cl_btn(/*пин*/0,/*обработчик*/[]{Serial << "Btn1\n";}),
  Cl_btn(/*пин*/1,/*обработчик*/[]{Serial << "Btn2\n";}),
  Cl_btn(/*пин*/2,/*обработчик*/[]{Serial << "Btn3\n";}),
  Cl_btn(/*пин*/3,/*обработчик*/[]{Serial << "Btn4\n";}),
  Cl_btn(/*пин*/4,/*обработчик*/[]{Serial << "Btn5\n";}),
  Cl_btn(/*пин*/5,/*обработчик*/[]{Serial << "Btn6\n";}),
  Cl_btn(/*пин*/6,/*обработчик*/[]{Serial << "Btn7\n";}),
  Cl_btn(/*пин*/7,/*обработчик*/[]{Serial << "Btn8\n";}),
  Cl_btn(/*пин*/8,/*обработчик*/[]{Serial << "Btn9\n";}),
  Cl_btn(/*пин*/9,/*обработчик*/[]{Serial << "Btn10\n";}),
  Cl_btn(/*пин*/10,/*обработчик*/[]{Serial << "Btn11\n";}),
  Cl_btn(/*пин*/11,/*обработчик*/[]{Serial << "Btn12\n";}),
  Cl_btn(/*пин*/12,/*обработчик*/[]{Serial << "Btn13\n";}),
  Cl_btn(/*пин*/13,/*обработчик*/[]{Serial << "Btn14\n";}),
  Cl_btn(/*пин*/14,/*обработчик*/[]{Serial << "Btn15\n";}),
  Cl_btn(/*пин*/15,/*обработчик*/[]{Serial << "Btn16\n";})
};
//---------------------------------
void setup() {
  Serial.begin(9600);
  _init();
  for (int i = 0; i < num; ++i)Btn[i].init();
}
void loop() {
  mill = millis();
  _run();
  for (int i = 0; i < num; ++i)Btn[i].run();
}
/**/

 

slider
Offline
Зарегистрирован: 17.06.2014

можно и по i2c растянуть гиглянду кнопок , различимо нажатие одновременно 128 кнопок из 128ми 
на подобие http://arduino.ru/forum/proekty/upravlenie-8kanalnymi-modulyami-rele-cherez-i2c-1602-pcf8574-dlya-novogodnei-elki

PCF8574 работают как на выход , так и на вход.

PCF8574T 8адресов до 0x3F , PCF8574AT 8адресов до 0x27  , отсюда и получаем   
8портов * 8модулей с выбором подадресов * 2разновидности PCF8574T(AT) = 128  .

 

// можно и по 1 проводу (1wire) все кнопки растянуть (1микросхемка 2 i/o ) , но это накладное решение, для других задач.

ежели растягивать не надо по 1му проводу , то да , HC595 идеально дешевый вариант.

MYFRIEND
MYFRIEND аватар
Offline
Зарегистрирован: 31.01.2017

сделал для hc165 красивый плакат, держите кому нужно 

бегущий человечек для подключения паровозом вагончиков к Datain 

Schwarz78
Offline
Зарегистрирован: 19.01.2019

Вот кусок кода, который обрабатывал одновременное нажатие хоть 400 кнопок, подключенных к 165-м регистрам:

{		
uint8_t InDiscretBuf[i], _InDiscretBuf[50], __InDiscretBuf[50];	// имеем три буфера кнопок

	HC165In( IOSetup.InDiscretAmount, __InDiscretBuf );	// ввод от нужного кол-ва HC165 в 3-й буфер
	for( i = 0; i < IOSetup.InDiscretAmount; i++)
	{
	uint8_t t1, t2;
		t1 = ~( InDiscretBuf[i] ^ _InDiscretBuf[i]);
		t2 = ~( _InDiscretBuf[i] ^ __InDiscretBuf[i]);
		t1 = t1 ^ t2;
		t2 = t2 & t1;	// только последовательности бит 0-1-1 и 1-0-0 дают единицы на выходе
						// это быстрая защита от дребезга
		if( t2 )
		{
			InputWasChanged = 1;
			break;
		}
	}
	for( i = 0; i < IOSetup.InDiscretAmount; i++) // меняем буферы местами
	{
	 	InDiscretBuf[i] = _InDiscretBuf[i];
	 	_InDiscretBuf[i] = __InDiscretBuf[i];
	}
}

Если InputWasChanged == 1 отсылаем все кнопки клиенту, если нет - ничего не делаем. В буфере InDiscretBuf получаются верные состояния кнопок.

Да, этот код работал 1 раз в 100мс.

sadman41
Offline
Зарегистрирован: 19.10.2016

Мне вот представляется, что никакие 1-0-0 и 0-1-1 не дают гарантированной защиты от дребезга, потому что само появление данных сигналов на входе не синхронизированно (и не может быть таковым) с проверкой этого входа. Поэтому всегда есть вероятность появления раздражающего и неуловимого "бага" с перекидыванием состояний.  Эффективней просто проверить повторно вход через некоторое время.  Не будет лишних чтений, перекладывания значений с места на место в памяти. 

MYFRIEND
MYFRIEND аватар
Offline
Зарегистрирован: 31.01.2017

hc165 плата паровоза гербер держите, подрисуете как вам удобнее, для китайцев 6 плат на одной плате, пилятся дремелем с алзамаными насадками из китая за 2$ 1 плата 72 входа hc165 на ошибки не проверялась, но ошибок не должно быть, "мамы" впаиваются разъемами к выходам и внешне выйдет как у ардуино цифровые и аналогвые разъемы такие же полностью. Питание кнопок берется не с этой платы, с этой платы только данные выведены от hc165. Питаются кнопки на одной шине все 5в, к ножкам кнопок всех с hc165 выводы. Ардуино отправляет в сериал номера нажатых отжатых кнопок с любым количеством одновременных нажатий скорее всего и парные кнопки возможно таймером отправлять значение второй пары, как силу нажатия.   

https://yadi.sk/d/QIsstDeCU55Lng

детали smd резисторы 10ком 4в1 8ножек и sop16 hc165 

если распилить платы выйдет всего 60 плат, хватит каждому активному участнику по 1 плате) 

Schwarz78
Offline
Зарегистрирован: 19.01.2019

sadman41 пишет:

Мне вот представляется, что никакие 1-0-0 и 0-1-1 не дают гарантированной защиты от дребезга, потому что само появление данных сигналов на входе не синхронизированно (и не может быть таковым) с проверкой этого входа. Поэтому всегда есть вероятность появления раздражающего и неуловимого "бага" с перекидыванием состояний.  Эффективней просто проверить повторно вход через некоторое время.  Не будет лишних чтений, перекладывания значений с места на место в памяти. 

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

Короче, считывание идёт 3 раза, чётко с интервалом 100мс. Если 1-0-0 или 0-1-1 значит значение изменилось, последнее измеренное - это и есть нынешнее состояние. Ещё это называется мажоритарный принцип.

sadman41
Offline
Зарегистрирован: 19.10.2016

Давайте представим, что я положил на край стола линейку и ударил по ней. Что вы можете сказать о частоте ее затухающих колебаний? Сможете ли вы моргать так, чтобы открывать глаза только в тот момент, когда линейка не изогнута ни на йоту?

Если считывание идет раз в 100мс - этого вполне может быть достаточно для того, чтобы дребезг прекратился между первой и второй проверками. Или я неправильно понимаю сущность трех проверок? 

Schwarz78
Offline
Зарегистрирован: 19.01.2019

sadman41 пишет:

Давайте представим, что я положил на край стола линейку и ударил по ней. Что вы можете сказать о частоте ее затухающих колебаний? Сможете ли вы моргать так, чтобы открывать глаза только в тот момент, когда линейка не изогнута ни на йоту?

Если считывание идет раз в 100мс - этого вполне может быть достаточно для того, чтобы дребезг прекратился между первой и второй проверками. Или я неправильно понимаю сущность трех проверок? 

Дело в том, что 1-0-1 или 0-1-0 нам не испортят обедни, на выходе получим "нет изменений". Я считал, что если сигнал изменился, и продержался 200мс - значит это не помехи. Не забывайте что кнопка - не линейка, там дребезг длится десятки мс, не более.

sadman41
Offline
Зарегистрирован: 19.10.2016

Вот и я о том же... 8мс на тактовой кнопке пережидает все помехи (ну, на моих - так). Так что я понял бы, если данный алгоритм защищал от случайного кратковременного тычка, но от физического дребезга при нажатии... Что-то мне предствляется, что это оверкилл. Но, может, это я на бытовом уровне так рассуждаю и есть научная основа применения мажоритарного принципа для подавления дребезга?