Эмуляция матричной клавиатуры

Zhekka
Offline
Зарегистрирован: 28.04.2016

Всем привет!

Имеется контроллер  с матричной клавиатурой 4х4. Есть возможность управления этим контроллером только через клавиатуру. Доступа к прошивке нет.

Стоит задача удаленно вводить команды на этот контроллер.

Для эмуляции клавиатуры решил взять ESP32s и подключить параллельно.

Написал прошивку, но както работает криво. Вводит значения невпопад.

//Сорри код не причесан и не оптимизирован. Писал для теста

char keys[4][4]={
 {'1','2','3','A'},
 {'4','5','6','B'},
 {'7','8','9','C'},
 {'*','0','#','D'}};

byte rowPin[4]={13,12,14,27};
byte colPin[4]={26,25,33,32};

char testInput[] = "123456789*0#";

int cur = 0; //Cursor

void setup() {
  Serial.begin(115200);
  Serial.println("Hello!");
  
  //Init pins
  for(byte row : rowPin) {
    pinMode(row, OUTPUT);
    digitalWrite(row, HIGH);
  }
  for(byte col : colPin) {
    pinMode(col, INPUT_PULLUP);
  }
}

int pos[2] = {-1, -1}; //Current position of char in keys matrix (row, column)

long delayTime = 100;
long startTime = 0;

void loop() {

  if (cur < sizeof(testInput)) {
    char toInput = testInput[cur];
    findPosition(toInput, pos);
    int row = pos[0];
    int column = pos[1];
    if (row >= 0) {
      if(!digitalRead(colPin[column])) {
        if (startTime == 0) {
          startTime = millis();
          digitalWrite(rowPin[row], LOW);
        } else {
          if (millis() - startTime > delayTime) {
            digitalWrite(rowPin[row], HIGH);
            startTime = 0;
            cur++;
          }
        }
      } else {
        digitalWrite(rowPin[row], HIGH);
      }
    } 
  }
}
  
void findPosition(char c, int result[]) {
  result[0] = -1;
  result[1] = -1;
  for(int row = 0; row < sizeof(keys); row++) {
    for(int col = 0; col < sizeof(keys[row]); col++) {
      if (c == keys[row][col]) {
        result[0] = row;
        result[1] = col;
      }
    }
  }
}

Решил попробовать другой подход - замыкать контакты транзисторами. Придется взять 16 транзисторов и задействовать 16 управляющих пинов на контроллере...

Можно както уменьшить количество задействованных пинов?

Заранее спасибо

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

Отца русской демокартии спасёт любой 16-битовый демультиплексор или сдвиговый регистр (например, SN54LS673), ну или два восьмибитовых (хоть тех же 74HC595) - каскадом.

bizzon
Offline
Зарегистрирован: 29.03.2016

Невпопад потому что несинхронно  с опросом рядов/колонок ?

Замыкать линии кнопок лучше не транзисторами, а оптронами. Делали уже не раз.Все 16 кнопок нужны? Тогда как писал ЕвгенийП.

SLKH
Offline
Зарегистрирован: 17.08.2015

Если там стандарная схема (по 4 выходным линиям бегает "1" или "0", которая замыкается кнопкой на одну из четырех входных), то никакие доп. детали не нужны. Считывайте ардуиной 4 бита и в нужное время подавайте 1 или 0 на соответствующую входную линию контроллера.

 

Добавлено: без мультиплексоров нужно 8 пинов.

ВН
Offline
Зарегистрирован: 25.02.2016

SLKH пишет:
Добавлено: без мультиплексоров нужно 8 пинов.

это для эха или эмуляции, для того и другого сразу нужно 12 пин

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

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

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

Ну, если переходить на последовательные, то может MCP23S17? 16 бит, двунаправленный на SPI

SLKH
Offline
Зарегистрирован: 17.08.2015

ВН пишет:

SLKH пишет:
Добавлено: без мультиплексоров нужно 8 пинов.

это для эха или эмуляции, для того и другого сразу нужно 12 пин

нафига 12? куда их пихать?

SLKH
Offline
Зарегистрирован: 17.08.2015

DetSimen пишет:

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

м.б., сначала читаешь ниббл из контроллера, потом переключаешь регистр на выход и подаешь 0 на соотв. вход контроллера?

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

м.б.

что совой об пень, что пнем об сову. 

Zhekka
Offline
Зарегистрирован: 28.04.2016

bizzon пишет:

Невпопад потому что несинхронно  с опросом рядов/колонок ?

Думаю да. Хотя почему так? Ведь я читаю состояние ряда и если на нем 0, то в этот же момент отправляю 0 нужному столбцу

bizzon пишет:

Замыкать линии кнопок лучше не транзисторами, а оптронами. Делали уже не раз.Все 16 кнопок нужны? Тогда как писал ЕвгенийП.

Почему оптроны? Чем они лучше транзисторов?

Zhekka
Offline
Зарегистрирован: 28.04.2016

SLKH пишет:

Если там стандарная схема (по 4 выходным линиям бегает "1" или "0", которая замыкается кнопкой на одну из четырех входных), то никакие доп. детали не нужны. Считывайте ардуиной 4 бита и в нужное время подавайте 1 или 0 на соответствующую входную линию контроллера.

В теории это правильно. Тогда почему не работает у меня? Я считываю состояние ряда и если там 0, то в этот же момент подаю 0 на столбец. Решил всетаки замыкать контакты транзисторами или оптронами. Так надежней. Малейший рассинхрон и может ввести чтото не то.

Zhekka
Offline
Зарегистрирован: 28.04.2016

DetSimen пишет:

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

Круто! Но считывать клавиатуру задача не стоит) Надо сделать как можно проще и надежней))

Zhekka
Offline
Зарегистрирован: 28.04.2016

Для управления, по совету ЕвгенийП, решил взять пару 74HC595(есть в наличии). В качестве ключей сначала подумал взять четыре транзисторных сборки ULN2003AN, но потом прикинул что по габаритам сборка больше чем 4 отдельных транзистора в корпусе ТО-92

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

Есть сборки на 8 транзисторов, например, ULN2803

Zhekka
Offline
Зарегистрирован: 28.04.2016

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

Есть сборки на 8 транзисторов, например, ULN2803

Там общий эмитер. Из восьми транзисторов получится использовать только 4 - общий на ряд и 4 вывода на каждый столбец

SLKH
Offline
Зарегистрирован: 17.08.2015

Zhekka пишет:

SLKH пишет:

Если там стандарная схема (по 4 выходным линиям бегает "1" или "0", которая замыкается кнопкой на одну из четырех входных), то никакие доп. детали не нужны. Считывайте ардуиной 4 бита и в нужное время подавайте 1 или 0 на соответствующую входную линию контроллера.

В теории это правильно. Тогда почему не работает у меня?

в программе что-то криво.

для начала добавь какой-нибудь делэй200 в цикл - м.б, контроллер просто не успевает за ардуиной. если не взлетит - попробуй вместо сомнительного цикла по testInput эмулировать одну кнопку и т.д.

Zhekka пишет:
Я считываю состояние ряда и если там 0, то в этот же момент подаю 0 на столбец. Решил всетаки замыкать контакты транзисторами или оптронами. Так надежней. Малейший рассинхрон и может ввести чтото не то.

сдается мне, что это лишнее.

Logik
Offline
Зарегистрирован: 05.08.2014

Zhekka пишет:

SLKH пишет:

Если там стандарная схема (по 4 выходным линиям бегает "1" или "0", которая замыкается кнопкой на одну из четырех входных), то никакие доп. детали не нужны. Считывайте ардуиной 4 бита и в нужное время подавайте 1 или 0 на соответствующую входную линию контроллера.

В теории это правильно. Тогда почему не работает у меня?

Это и есть самая интересная часть вопроса :) Наверно надо бы начать с определения параметров сканирования клавиатуры. строб там 0 или 1? какова его длительность? А электронику пилять в слепую не стоит.

Zhekka
Offline
Зарегистрирован: 28.04.2016

Logik пишет:

Это и есть самая интересная часть вопроса :) Наверно надо бы начать с определения параметров сканирования клавиатуры. строб там 0 или 1? какова его длительность? А электронику пилять в слепую не стоит.

Если там используется стандартная либа Keypad то пины столбцов инициализированы как OUTPUT, a ряды INPUT_PULLUP

При сканировании подается сигнал LOW

// Private : Hardware scan
void Keypad::scanKeys() {
	// Re-intialize the row pins. Allows sharing these pins with other hardware.
	for (byte r=0; r<sizeKpd.rows; r++) {
		pin_mode(rowPins[r],INPUT_PULLUP);
	}

	// bitMap stores ALL the keys that are being pressed.
	for (byte c=0; c<sizeKpd.columns; c++) {
		pin_mode(columnPins[c],OUTPUT);
		pin_write(columnPins[c], LOW);	// Begin column pulse output.
		for (byte r=0; r<sizeKpd.rows; r++) {
			bitWrite(bitMap[r], c, !pin_read(rowPins[r]));  // keypress is active low so invert to high.
		}
		// Set pin to high impedance input. Effectively ends column pulse.
		pin_write(columnPins[c],HIGH);
		pin_mode(columnPins[c],INPUT);
	}
}

В реальности  можно только гадать что там используется. Осцилографа нет.

SLKH
Offline
Зарегистрирован: 17.08.2015

Zhekka пишет:

Logik пишет:

Это и есть самая интересная часть вопроса :) Наверно надо бы начать с определения параметров сканирования клавиатуры. строб там 0 или 1? какова его длительность? А электронику пилять в слепую не стоит.

 

В реальности  можно только гадать что там используется. Осцилографа нет.

Угу.

Сделал эмулятор неизвестно чего, "Написал прошивку, но както работает криво. Вводит значения невпопад." - ну как же не удивиться?

 

Zhekka
Offline
Зарегистрирован: 28.04.2016

SLKH пишет:

ну как же не удивиться?

Реальный контроллер находится за 100 км от меня и это не простая ардуинка, а устройство на чипе ATmega 2560. Это устройство управляет топливо-раздаточной колонкой на АЗС склада. Там вэб сервер, БД, интерфейсы RS-232, RS-485, и контроль доступа по картам RFID. Взять его для изучения и тестов на долгое время не получится.

Я предположил что там используется стандартная либа Keypad и собрал макет из Arduino UNO и Esp23s. Програмно эмулировать клавиатуру не получилось, да и если б както получилось, то возможно, приехав на объект для тестирования пришлось бы удивляться что это не работает.

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

ВН
Offline
Зарегистрирован: 25.02.2016

Zhekka пишет:
Поэтому выбрал реально универсальное и надежное решение спаять схему на ключах.

схему этого универсального решения мы наверно так и не увидим

 

Logik
Offline
Зарегистрирован: 05.08.2014

Zhekka пишет:

в реальности  можно только гадать что там используется. Осцилографа нет.

Зачем же гадать. Подключаем ардуину к стробам. Считываем состояние стробов ардуиной и ждем изменений. Как только хоть один строб хоть как изменится - состояние стробов и время из миллиса выводим в сириал. Потом монитором принимаем этот поток и мозгами анализируем как и насколько быстро там стробирование идет. Пол часа и все понятно. Но если сильно быстро все работает, то будет затык, сириал не будет успевать. Не беда, обявляем буфер в 1К, сохраняем инфу в нем, как заполнится то неспеша выводим. 

krawa
Offline
Зарегистрирован: 07.04.2015

del

Zhekka
Offline
Зарегистрирован: 28.04.2016

ВН пишет:

схему этого универсального решения мы наверно так и не увидим