Каскад входных сдвиговых регистров

Попросили тут помощи по теме, решил оформить постом.
Итак, я как-то писал о входных сдвиговых регистрах серии 74HC165 (далее — просто «регистры»), но как-то не учёл сложности включения их каскадом («гирляндой», daisy chain). Объясню, в чём суть. Допустим нам нужно обработать 24 кнопки, а у регистра всего 8 входов. Первое решение, которое приходит в голову — обработать данные с 3х регистров независимо. Но это решение плохо тем, что на каждый регистр нужно выделять свою линию SS для работы по SPI — по одной линии на каждый вывод SH/~LD, а использовать одну общую не получится, так как по шине SPI полезут биты сразу с трёх регистров, и программа прочитает мусор.

Для решения этой проблемы придумали каскадное подключение. Идея такова: раз при каждом дёргании CLK биты, захваченные со входов регистра, проталкиваются к выходу (QH и ~QH), то почему бы не заставить регистр проталкивать после своих битов ещё и биты, захваченные с внешнего источника — ещё одного сдвигового регистра:



При этом используется всего одна линия SS на все регистры, благодаря чему подключение к Arduino требует всего 3 провода — SS, SCK и MISO.
Проиллюстрирую такое подключение на примере 3х регистров (таких же, как и в предыдущей статье по ним). Смотрим на расположение выводов:



Соединяем регистры, как в предыдущей статье, добавив для каскада следущее:

  • Вывод SER третьего регистра соединяем с GND, чтобы с SER читались нули, а вывод QH подключем к SER второго.
  • Вывод QH второго регистра соединяем с SER первого.
  • Вывод QH первого регистра соединяем с MISO на Arduino (пин 12).

SCK (пин 13) и SS (пин 10) — общие для всех регистров. Ну и для проверки на вшивость соединим через резисторы 10 кОм (у меня под рукой были только 510 Ом, если что) выводы 1C, 2B и 3A с землёй, а выводы 1E, 2F и 3G — с питанием (+5 В) и напишем скетч, в котором будем проверять состояние только этих выводов, ибо с остальных будет читаться мусор — они же не подключены. Для проверки на изменение состояний входов можно потыкать их проводком, соединённым с землёй или питанием через резистор.

Как это выглядит у меня:



Теперь модифицируем чуток скетч, считывающий состояние входов регистра, чтобы он работал через библиотеку SPI_Bus (проще кодить) и опрашивал только указанные выше входы:

#include <LineDriver.h>
#include <SPI.h>
#include <SPI_Bus.h>

SPI_Bus reg
(_24bit, 10, MSBFIRST);


void setup()
{
 
Serial.begin(9600);
  reg
.setSelectionPolicy(SPI_Bus::SELECT_BEFORE);
}


void loop()
{
 
static uint32_t last_input_states = 0;
 
 
/* Читаем наши 24 бита разом. В C++ нет типов данных для 24-битных чисел,
   * поэтому используем read32bits(), который считает столько бит,
   * сколько мы указали при создании объекта reg (24 бита), но вернёт их
   * одним 32-битным значением.
   */

  uint32_t states
= reg.read32bits();

 
if (states != last_input_states)
 
{
    uint32_t changed
= states ^ last_input_states;
    last_input_states
= states;
   
   
for (int i = 0; i < reg.bandwidth() * 8; ++i)
   
{
     
/* А вот тут проверяем только нужные нам входы */
     
if ((i == 0   || // 3A
           i
== 6   || // 3G
           i
== 9   || // 2B
           i
== 13  || // 2F
           i
== 18  || // 1C
           i
== 20) && // 1E
         
(changed & 1))
     
{
       
Serial.print("#");
       
Serial.print(i);
       
Serial.print(" -> ");
       
Serial.println(states & 1);
     
}
     
      changed
>>= 1;
      states
>>= 1;
   
}
 
}
}
Последнее изменение: Понедельник, 30 Март 2020, 11:15