SPI и Arduino: плодим входы


SPI и Arduino:

  1. Теория
  2. Вывод
  3. Ввод

Теперь попробуем считать состояние нескольких кнопок через другой сдвиговый регистр, предназначенный для ввода — 74HC165, модель SN74HC165N от Texas Instruments. Этот регистр, в отличие от рассмотренного ранее 74HC595, работает наоборот — преобразует параллельный интерфейс в последовательный. Но порядок работы немного другой: сначала дёргается линия SS вниз-вверх — состояния входов «защёлкиваются» во внутренний регистр, а уже потом идёт тактирование по SCLK и передача данных по MISO.

Чтобы понять, как работает регистр, взглянем на его схему:

Вход SH/L͞D (сдвиг/загрузка) управляет занесением состояний входов в триггеры — так называемой параллельной загрузкой: стоит прижать его к «земле», как состояние входов регистра будет подано на S-входы триггеров. Чтобы отключить триггеры от входов регистра и иметь возможность читать из регистра, нужно установить SH/L͞D в 1. Тактирование происходит при переходе CLK из 0 в 1 при условии, что SH/L͞D = 1 (параллельная загрузка отключена), а CLK INH = 0 (тактирование включено). При каждом «тике» CLK каждый триггер проталкивает бит в следующий триггер, захватывая бит со своего 1D-входа. Так как к 1D-входу первого триггера подключен вход SER, то подаваемые на него биты проталкиваются в регистр, позволяя соединять регистры в цепочки. В конечном итоге проталкиваемые биты достигают выхода последнего регистра, где подаются сразу на два вывода — на QH и, через инвертор, на Q͞H.

А вот и сам регистр в DIP-корпусе:

Назначение выводов:

  • Vcc — питание
  • GND — земля
  • SH/L͞D — защёлка, SS (SPI)
  • CLK — тактовый вход, SCLK (SPI)
  • A-H — входы, состояние которых считывается в регистр
  • QH — последовательный вывод, MISO (SPI)
  • Q͞H — инверсный вывод, на нём идут биты с QH, но инвертированные
  • SER — последовательный ввод; к нему можно подсоединить вывод QH второго регистра, получив каскадное подключение
  • CLK INH — Clock Inhibit, или инвертированный Clock Enable; когда на нём 1, тактирование выключено

Попробуем считать состояние 8 кнопок, подключенных к выводам A-H регистра. Для этого подключим выводы следующим образом:

  • Vcc ⇨ +5 В
  • GND ⇨ GND
  • SH/L͞D ⇨ пин 8
  • CLK ⇨ пин 13
  • QH ⇨ пин 12
  • Q͞H оставим неподключенным
  • SER ⇨ GND
  • CLK INH ⇨ GND

Кнопки сажаем на выводы A-H, подтягивая к питанию резисторами на 10 кОм, и на землю:

Получилась такая каша из проводов, что мои mad skillz в делах рисовальных не помогли, так что постарайтесь как-нибудь догадаться, что куда идёт (:

Лепить на макетку ещё и светодиоды было бы слишком, поэтому состояния кнопок будем слать по UART и смотреть через Serial Monitor. Поехали:

#include <SPI.h>

enum { REG_LATCH = 8 };


void setup()
{
  /* Включаем UART и SPI */
  Serial.begin(9600);
  SPI.begin();
  /* Включаем защёлку */
  pinMode(REG_LATCH, OUTPUT);
  digitalWrite(REG_LATCH, HIGH);
}


void loop()
{
  static uint8_t last_input_states = 0;

  /* Выставим на защёлке сначала низкий, потом - высокий уровни.
   * Сдвиговый регистр запомнит уровни сигналов на входах и сможет
   * их нам потом отдать бит за битом.
   */
  digitalWrite(REG_LATCH, LOW);
  digitalWrite(REG_LATCH, HIGH);
  /* Читаем запомненные состояния входов. Ноль шлём просто потому,
   * что transfer() одновременно и шлёт, и принимает. Да и вообще,
   * MOSI не подключена (:
   */
  uint8_t states = SPI.transfer(0);

  /* Если состояние любого входа изменилось, расскажем по UART */
  if (states != last_input_states)
  {
    /* Старый добрый XOR даст нам битовую разницу между старым и новым состояниями. */
    uint8_t changed = states ^ last_input_states;
    last_input_states = states; // запоминаем текущие состояния

    for (int i = 0; i < 8; ++i)
    {
      if (changed & 1) // если состояние кнопки изменилось…
      {
        Serial.print("#");
        Serial.print(i); // шлём номер кнопки
        Serial.print(" -> ");
        Serial.println(states & 1); // … и новое состояние
      }

      /* Сдвигаем биты вправо. Теперь первый бит
       * будет указывать состояние следующей кнопки.
       */
      changed >>= 1;
      states >>= 1;
    }
  }
}

С каскадным подключением история такая же, как и с 74HC595, только здесь вывод QH второго регистра подключается к выводу SER первого и т.п. Или, как вариант, использовать выводы Q͞H вместо QH, если нужно считать много кнопок, подтянутых к питанию.

Исходник примера доступен для скачивания напрямую и на GitHub в репозитории.

Картинки из статьи лежат в альбоме на Яндекс.Фотках.

Использовалось железо:


0 комментариев на «“SPI и Arduino: плодим входы”»

    • Да, всё считается нормально: задержки никак не повлияют на считывание. Тут могут быть только проблемы с дребезгом контактов у кнопок.

    • угу, только если кто-то успеет нажать-отпусть кнопку в течении этой (односекундной)задержки нажатие потеряется=)

    • поэтому в любом коде больше чем на 3 строки задержки лучше делать через конечный автомат, а не через delay()

    • Конечные автоматы рулят: мы с коллегой на прошлой работе на КА весь «AI» в игрульке делали (казуальная, стиль time-management). Если приправить random()’ом, получается почти живое существо (:

    • думаю, живое существо — это и есть конечный автомат с random()-ом :)))

  1. а чем можно увеличить число входов на которые можно повесить прерывание?
    Ну что бы например понять какая из кнопок была нажата первой.

    • Для таких задач вам нужен мультиплексор прерываний вроде PCA9544A, но это дорогие микросхемы: минимальная цена, которую я видел — 3$.

    • SN54HC166/SN74HC166, CD4014B, SN74LS647, 74F676, SL74HC597, SN74LS395A/SN54ALS299/SN74ALS299 (универсальные сдвиговые регистры). У них ещё бывают всякие модификации с другими буквами — типа 74LS165 вместо 74HC165. Даже если ничего этого в вашем магазине нет, можете попросить у них на заказ, ну или заказать у нас, если не ломает доставка robocraft.ru/store/catalog/16 (:

  2. Ребята, спасайте всю голову затуркал не как не получается подрубить каскад из 4х HC165, пробовал и через SPI_Bus библеотеку из соседнего поста, помогите, подскажите плиз как это реализовать?
    ЗЫ. заранее благодарен.

  3. Использую в своем проекте M74HC595N. Прототип собран, работает отлично. Но! Их у меня там 18! Подскажите, какой-нить 16-битный регист, а еще лучше 32-битный, чтоб сократить кол-во элементов.
    Спасибо!

    • Нагугливаются только 16-битные 74F676, но они везде дорогие. Можно на alibaba.com посмотреть (там цены гуманные), но я сам оттуда не заказывал ничего, так что больше помочь ничем, увы, не могу.

    • Купил STP16CP05 — работают прекрасно.
      Но мне в итоге нужно в итоге нужно построить матрицу 3*60 и я решил еще сократить кол-во элементов. Хочу 1-им регистром (4-бит.) переключать строки и 4-мя регистрами (16-бит.) мигать светодиодами в этой строке.
      Нашел в инете инфу о 4-бит. регистре STP04CM05, того же производителя и из той же серии что и STP16CP05, но нигде не могу его купить.

      Соответственно вопрос: как вообще грамотно подобрать компоненты чтоб они без проблем работалм друг с другом, есть ли какие-то критерии, на какие параметры обращать внимание?

    • Тут я небольшой помощник — сам в электронике разбираюсь слабо: ничего, кроме описанного в моих статьях, толком не знаю (:

    • Обычно, достаточно посмотреть только напряжения питания и логические уровни. В случае ардуины — чтобы могли питаться от 5В, за лог. ноль понимали 0В за лог.еденицу 5В.

    • Спасибо.
      Я так и подбираю, но подумал вдруг еще есть какие-то важные параметры.

  4. подскажите на сколько принципиально будет отличаться схема при использовании hc166? и можно ли реализовать работу с ним не через spi или на ногах отличных от дефолтовых spi?

    • разобрался я со своим вопросом, что называется RTFM.

  5. Можно ли подключить к ардуине одновременно сдвиговый регистр ввода и вывода — и если да, то как правильно это сделать имея 74HC165 и 74HC595?

    Спасибо за ответ.

  6. Подскажите, пожалуйста, как в данном скетче обработать нажатие кнопки? То есть, как при нажатии на одну кнопку включить, например, светодиод?

  7. Здравствуйте!
    не знаю отзовётесь ли вы… Встал вопрос о подсоединении каскадом, не могу найти как программу написать… и ещё нужно чтоб каждая кнопка отзывалась светодиодом… Как совместить входящий тригер с выходящим? Как передавать данные?

    • Как передавать данные понял…
      Но вот каскад категорически не хочет работать… подсоединил, как везде в инете показывается и как написано в последних строках этой статьи: «С каскадным подключением история такая же, как и с 74HC595, только здесь вывод QH второго регистра подключается к выводу SER первого и т.п.»… но данные не поступают со второго регистра…
      Что-то нужно, я так понимаю изменить в коде… Но что?

Добавить комментарий

Arduino

Что такое Arduino?
Зачем мне Arduino?
Начало работы с Arduino
Для начинающих ардуинщиков
Радиодетали (точка входа для начинающих ардуинщиков)
Первые шаги с Arduino

Разделы

  1. Преимуществ нет, за исключением читабельности: тип bool обычно имеет размер 1 байт, как и uint8_t. Думаю, компилятор в обоих случаях…

  2. Добрый день! Я недавно начал изучать программирование под STM32 и ваши уроки просто бесценны! Хотел узнать зачем использовать переменную типа…

3D-печать AI Android Arduino Bluetooth CraftDuino DIY IDE iRobot Kinect LEGO OpenCV Open Source Python Raspberry Pi RoboCraft ROS swarm ИК автоматизация андроид балансировать бионика версия видео военный датчик дрон интерфейс камера кибервесна манипулятор машинное обучение наше нейронная сеть подводный пылесос работа распознавание робот робототехника светодиод сервомашинка собака управление ходить шаг за шагом шаговый двигатель шилд юмор

OpenCV
Робототехника
Будущее за бионическими роботами?
Нейронная сеть - введение