Не редко в процессе разработки на arduino приходиться использовать больше количество пинов для считывания событий. Это могут быть кнопки, концевики, цифровые датчики и тд. Но ардуино имеет ограниченное количество пинов, что может стать проблемой для больших проектов. В этой статье описано, как выйти из ситуации с нехваткой входов arduino.
Добавление пинов arduino
Чтобы увеличить количество пинов есть несколько способов. Самый простой, это подключить кнопки или датчики к одному аналоговому пину через резисторы разного сопротивления, тогда в коде можно добавить условия для каждого уровня сигнала. Второй способ – использовать сдвиговый регистр, который позволяет принимать до восьми цифровых сигналов. А так же регистры можно выстраивать каскадами, один за другим, каждый раз добавляя 8 новых пинов.
Ниже будет рассмотрен второй вариант с использованием сдвигового регистра 74HC165. Я уже как-то описывал работу со сдвиговым регистром 74HC595, который может передавать данные. Сегодняшний регистр работает наоборот – принимает сигналы.
Подключение сдвигового регистра 74HC165 к arduino
Для подключения 74HC165 потребуется четыре пина ардуино, 5V и GND. Таким образом, при занятых четырех пинах появляется возможность считывать данные с восьми кнопок. А при составлении каскадов из регистров, количество возможных подключений кнопок, увеличивается на 8 штук, при тех же занятых 4х пинах. Ниже приведена схема подключения одного 74HC165 и восьми кнопок к arduino.
Каждая кнопка как обычно притянута к земле через резистор 10 кОм.
Примечание: Если количество кнопок будет меньше восьми, то свободные входы регистра нужно соединить с землей.
Пример использования 74HC165
В качестве примера я спаял а «макетке» простенький джойстик с восемью кнопками. А также напечатал для него простенький корпус на 3D принтере. Возможно, в следующих статьях и проектах он пригодится. Вот что получилось:

Скетч для arduino, который считывает данные с регистра 74HC165
В завершение прикладываю код, для считывания сигналов с регистра. Скетч с подробными комментариями, описывать что-то еще нет смысла, поэтому приведу просто листинг:
#define NUMBER_OF_SHIFT_CHIPS 1 // количество регистров
#define DATA_WIDTH NUMBER_OF_SHIFT_CHIPS * 8 // количество входов
#define PULSE_WIDTH_USEC 5 // задержка при считывании данных
// для хранения считаных байт
// если регистров больше двух, то int меняется на long
#define BYTES_VAL_T unsigned int
// пины для подключения регистра
int ploadPin = 8;
int clockEnablePin = 9;
int dataPin = 11;
int clockPin = 12;
BYTES_VAL_T pinValues; // текущее значение пинов
BYTES_VAL_T oldPinValues; // предыдущее значение пинов
// функция для считывания пинов
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 i = 0; i < DATA_WIDTH; i++){
bitVal = digitalRead(dataPin);
bytesVal |= (bitVal << ((DATA_WIDTH-1) - i));
digitalWrite(clockPin, HIGH);
delayMicroseconds(PULSE_WIDTH_USEC);
digitalWrite(clockPin, LOW);
}
// возвращяем результат опроса регистра
return(bytesVal);
}
// функция для вывода состояния пинов
void display_pin_values(){
// перебор всех пинов
for(int i = 0; i < DATA_WIDTH; i++){
Serial.print(" Button-");
Serial.print(i);
Serial.print(": ");
if((pinValues >> i) & 1){
Serial.print("ON");
}else{
Serial.print("OFF");
}
Serial.println();
}
Serial.println();
}
void setup(){
// для вывода данных в монитор порта
Serial.begin(9600);
// установка режима работа пинов
pinMode(ploadPin, OUTPUT);
pinMode(clockEnablePin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, INPUT);
digitalWrite(clockPin, LOW);
digitalWrite(ploadPin, HIGH);
// считываем значения с пинов
pinValues = read_shift_regs();
// выводим результат
display_pin_values();
// сохраняем текущее значение
oldPinValues = pinValues;
}
void loop(){
// считываем значения с пинов
pinValues = read_shift_regs();
// если значения изменились, то выводим их
if(pinValues != oldPinValues){
// выводим результат в монитор порта
display_pin_values();
// сохраняем текущее значение
oldPinValues = pinValues;
}
delay(50);
}
Что использовалось:
- Arduino (я использовал arduino nano, но можно любую другую). Покупал тут: arduino nano
- Сдвиговый регистр 74HC165. Покупал тут: сдвиговые регистры 74HC165 10 штук
- Резисторы сопротивлением 10 кОм. Покупал тут:набор резисторов 700 шт. От 10 Ом до 1 МОм
- Тактовые кнопки 6x6x5мм. Покупал тут: Тактовые кнопки 6x6x5мм, 100шт
Послесловие
В этой статье не было описания составления каскадов из регистров. Если кому-то необходимо, то можете найти распиновку 74HC165 и самостоятельно собрать каскад. Подключается все довольно просто: необходимо соединить последовательный ввод SER одного регистра с последовательным выходом QH другого. Если кому-то тема интересна, то можете писать мне на почту или в комментарии, тогда я напишу отдельную статью про каскады из регистров.

С каскадным подключением более 4х штук начинаются большие проблемы. Единственное рабочее решение на 6 регистров нашёл тут — http://josvolkers.blogspot.com/2013/09/interpretator-orgelpatch-playnote.html и то с помощью костылика сделано.
Коллега! можно электрическую схему подключения