- 8 Битный сдвиговый регистр
- 8 Битный сдвиговый регистр
- 1) Сдвиговый регистр 74HC595 c SPI интерфейсом
- 2) Управление гирляндой светодиодов
- 3) SPI интерфейс в микроконтроллере ATmega8
- 4) Подключение семисегментного индикатора через сдвиговый регистр 74HC595
- 5) Подключение жидко-кристаллического дисплея HD44780 через сдвиговый регистр 74HC595
- Что такое регистр?
- Регистр. Регистр сдвига
- Сдвигающие регистры или регистры сдвига.
- Сдвиговый регистр 74HC595
- Записки программиста
- Больше чипов 74xx: сдвиговые регистры и декодеры
- SIPO сдвиговый регистр 74HC595
- PISO сдвиговый регистр 74HC165
- Декодер / демультиплексор 74HC138
- Полная версия кода
- Заключение
- Сдвиговый регистр 74hc595 Arduino
- Как работает регистр сдвига?
- Начинаем с 8 светодиодов
- Собираем схему
- Скетч для ардуино
- 16 светодиодов
- Схема соединения
- Скетч для ардуино
8 Битный сдвиговый регистр
8 Битный сдвиговый регистр
- Сдвиговые регистры, оглавление:
- ATmega8 + Proteus: работа со сдвиговыми регистром 74HC595
- ATmega8 + Proteus: входной сдвиговый регистр 74HC165, совместная работа с 74hc595
- ATmega8 + PCF8574: 8-битный сдвиговой регистр на I2C интерфейсе
Изучение модуля USI MSP430 странным образом(на самом деле закономерным) вывела меня на такую штуку, как сдвиговый регистр. Имея о них лишь общее представление, мне пришлось срочно разбираться c этой, довольно обширной темой. Итак.
Сдвиговый регистр, он же расширитель портов, он же шинный преобразователь, преобразует сигнал последовательной шины в параллельный или/и обратно.
В рамках этой статью я рассмотрю работу с популярным 8-и битовыми сдвиговым регистром на SPI интерфейсе 74HC595.
В качестве практических примеров, я рассмотрю подключение светодиодной гирлянды, семисегментных индикаторов и дисплея с параллельной шиной HD44780.
В качестве микроконтроллера я буду использовать ATmega8, а в качестве среды моделирования Proteus 8.5.
Кроме этого, я затрону организацию SPI интерфейса у ATmega8.
1) Сдвиговый регистр 74HC595 c SPI интерфейсом
Это один из самых простых регистров, который преобразует последовательную шину в параллельную. Он позволяет получить из трех выводов микроконтроллера — 8 ^n .
- Описание
- Микросхема принимает на вход последовательность 8-битных данных, которые затем преобразует в логические состояния на 8-пиновом выходе.
- Микросхема работает только на выход, т.е. мы можем с ее помощью управлять светодиодами или дисплеем HD44780, но не сможем с нее получать данные с датчиков например.
- Выходы могут принимать состояния: логический ноль, логическую единицу, высокоимпедансное состояние — HiZ.
- Микросхемы можно соединять каскадом для получения 16-битного выхода, 24-битного, и т.д.
- Питание микросхемы 74HC595N может варьироваться от двух до шести Вольт.
- Сдвиговый регистр 74HC595N может работать на частотах до 100MHz.
Микросхема часто используется как драйвер семисегментных индикаторов или дисплея HD44780. Документацию на чип можно скачать например отсюда.
Распиновка микросхемы выглядит следующим образом:
Здесь, Q0 — Q7 — это цифровые выходы. MR — это reset. OE — переводит выводы в HiZ режим. Q’7 — это бит переполнения, используется для соединения регистров каскадом. DS — линия передачи данных, SH — линия тактирования, ST — защелка(latch), но мне привычнее такие штуки называть Enter’ом.
В рабочем состоянии, OE должен быть соединен с землей, а MR подтянут к питанию. Ведущий микроконтроллер может менять состояние DS при низком уровне линии тактирования — SH. Чип считывает состояние линии DS при растущем фронте на линии тактирования SH.
Прием данных сдвиговым регистром происходит при низком уровне защелки — ST. При этом принимаемые данные идут во внутренний (теневой) регистр(на самом деле там одна цепочка триггеров). При выставлении защелки ST в высокий уровень, содержимое теневого регистра записывается в регистр вывода, и выходы Q0 — Q7 принимают состояние в соответствии с его содержимым.
Данные посылаются старшим вперед.
Временная диаграмма сигналов:
2) Управление гирляндой светодиодов
Для знакомства с работой сдвигового регистра 74HC595 , в Proteus соберем такую схему:
- Всего в передаче данных задействовано три пина.
- на PD2 — линия тактирования, SH;
- на PD3 — линия передачи данных, DS;
- на PD4 — линия синхронизации данных, ST.
Этими тремя пинами мы можем управлять теперь восемью светодиодами.
Составим программу бегущих огней:
Теперь, если мы хотим соединить регистры каскадом, чтобы получить 16 выводов, всего-то нужно лишь немного видоизменить принципиальную схему:
Для работы видоизмененной схемы в коде нужно будет поменять всего три константы:
Все это хорошо, но: «При чем тут SPI, и всякие шины?» — спросите вы?
А вот при чем. Эта короткая программка является программной реализацией протокола SPI.
3) SPI интерфейс в микроконтроллере ATmega8
То, что мы используем SPI, проверяется очень просто — переключением в коде на использование аппаратного SPI модуля.
В руководстве на ATmega8, SPI модуль описан следующей блок-схемой:
В блок-схеме можно увидеть внутренний сдвиговый регистр, блок контроля с флаговым и регистром управления, и блок тактирования.
Передача данных по SPI между двумя устройствами происходит по такой схеме:
Здесь мастером(ведущим) выступает микроконтроллер ATmega8, а ведомым в нашем случае выступает 74hc595. При передаче старший бит мастера записывается в младший бит слейва, и через восемь тактов, они обмениваются одним байтом.
В работе SPI модуля в ATmega8 задействовано всего три регистра: SPCR — регистр управления, SPSR — флаговый регистр, SPDR — регистр данных.
Регистр управления выглядит так:
Здесь SPIE — включает прерывания по завершении приема или передачи байта из SPDR, SPE — включает модуль SPI, DORD — переключает направление в сдвиговом регистре, MSTR — определяет режим работы микроконтроллера: ведущий или ведомый, CPOL — переключает полярность линии тактирования, CPHA — переключает фазу линии тактирования. Оставшиеся два бита SPR0, SPR1 и SPI2X из SPSR, устанавливают предделитель для линии тактирования.
Регистр SPSR имеет три служебных бита:
Здесь нам будет интересен флаг вызова перерывания SPIF.
В руководстве на ATmega8 имеются примеры работы с SPI-модулем на ассемблере и Си. В последнем случае пример выглядит так:
Для проверки программы нужно будет переподключить сдвиговый регистр к SPI порту ATmega8:
Тестовая программа с использованием SPI будет выглядеть так:
И если все сделать правильно, «бегущий огонь» должен работать через SPI.
4) Подключение семисегментного индикатора через сдвиговый регистр 74HC595
Сдвиговый регистр часто используется как драйвер семисегментного индикатора. Наличие бита переноса позволяет составлять каскад из нескольких разрядов.
Вместо светодиодов подключим пока один индикатор с общим катодом:
Для работы с ним запустим такую программу:
Результат работы должен быть как на гифке сверху.
Семисегментные индикаторы тоже можно подключать каскадом:
Здесь верхний сдвиговый регистр подключен к крайне правому сегменту, он является младшим регистром. Нижний сдвиговый регистр подключается к левому сегменту, он является старшим регистром. Текст программы при этом получается такой:
Кроме такого способа подключения семисегментнных индикаторов, который называют статическим, существует еще динамический способ, когда, допустим, один сдвиговый регистр подключается к сегментам индикаторов соединенных параллельно, а другой регистр с высокой скоростью неуловимой глазом, переключает общий анод или катод элементов. Такие штуки продают на Али уже в сборе со сдвиговыми регистрами 74hc595:
На скорую руку я набросал в Proteus схему такого индикатора:
Здесь индикатор с общим анодом, следовательно сегмент будет загораться при подаче логического нуля. Чтобы обеспечить совместимость с программой для управления индикаторами с общим катодом, я поставил на вход логические инверторы. Хотя, вместо этого можно было бы поменять значения в массиве seg[10], но здесь я хотел показать как делать логические инверторы без использования корпусных микросхем.
Чтобы обеспечить динамическую индикацию, нужно постоянно обновлять информацию на дисплее. Я не нашел ничего проще, чем использовать прерывание по таймеру:
Это программа только для Proteus. Для реального устройства должны быть изменены значения временных задержек. В главном цикле должно стоять 1000ms вместо десяти, и прерывание по таймеру можно запускать не так часто. Напомню, что прерывание в ATmega8 по таймеру TIMER0 рассматривалось здесь пару лет назад.
Результат работы программы должен выглядеть как-то так:
5) Подключение жидко-кристаллического дисплея HD44780 через сдвиговый регистр 74HC595
Широко известный в узких кругах дисплей с параллельной шиной, также можно подключать через сдвиговый регистр.
Для начала следует проверить работу симуляции дисплея в Proteus. Для этого составляется такая схема:
В качестве управляющей программы служит следующая программа:
Это модифицированная версия программы из примера двухлетней давности: «ATmega8: простая программа управления ЖК-дисплеем HD44780. В отличии от оригинала, здесь строб подается отдельно от данных, что наверно более корректно.
Теперь рисуем схему подключения дисплея через сдвиговый регистр:
Управляющую программу я сделал по принципу минимального изменения предыдущего кода, чтобы было понятно, как это делается:
В отличие от работы через параллельную шину, здесь нельзя прочитать порт, поэтому пришлось водить дополнительную переменную LCD, с которой и осуществляются все операции. Остальное думаю понятно.
В заключение хочу сказать, что кроме SPI, сдвиговый регистр возможно подключать через OneWire интерфейс по одному проводу через RC-цепочки. Изначально это задумывалось для микроконтроллеров в корпусах с малым количеством пинов, на вроде ATtiny13. Но это можно использовать также для SoC c малым количеством выводов, например: ESP8266 или RT5350F. Мне лично этот фокус показался бесполезным, но упомянуть о нем считаю нужным.
Что такое регистр?
Регистр. Регистр сдвига
Регистр это устройство, выполненное на триггерах для выполнения ряда действий с двоичными числами. Для тех, кто не знает, что такое триггер, рекомендуем познакомиться с простейшим RS-триггером.
Наиболее простая функция регистров — это запоминание числа и его длительное хранение. Эти устройства так и называются – регистры хранения. Вот простейший пример.
На входы D0 – D2 подаётся число, которое необходимо сохранить. Как только на входе С появляется импульс синхронизации, число записывается в триггер, изменяя их состояние. На рисунке показан трёхразрядный регистр хранения. При подаче на входы числа 1112 оно же появится на прямых выходах триггеров (Q0 — Q2). На инверсных выходах (Q0 — Q2) будет, естественно 0002. Сигналом R (Reset) или сброс, триггеры устанавливаются в нулевое состояние.
Обычно используются регистры, состоящие из 4, 8, или 16 триггеров. Изображение четырёхразрядного регистра на принципиальных схемах может быть таким.
На рисунке не показаны инверсные выхода триггеров и сигнал R. Регистры всегда обозначаются латинскими буквами RG. Если регистр сдвигающий, то под обозначением рисуется стрелка направленная влево, вправо или двойная.
Сдвигающие регистры или регистры сдвига.
Регистр сдвига это устройство, состоящее из нескольких последовательно соединённых триггеров, число которых определяет разрядность регистра. Регистры широко используются в вычислительной технике для преобразования кодов. Параллельного в последовательный и наоборот.
Кроме того сдвигающие регистры являются основой (АЛУ) арифметико-логического устройства, так как при сдвиге записанного в регистр двоичного числа на один разряд влево производится умножение числа на два, а при сдвиге числа на один разряд вправо число делится на два. Поэтому наибольшее распространение получили реверсивные или двунаправленные регистры.
Рассмотрим четырёхразрядный регистр сдвига, преобразующий последовательный двоичный код в параллельный. Применение последовательного кода оправдано тем, что по одной линии можно передавать огромные массивы информации. Таким примером может служить универсальная последовательная шина — USB порт любого устройства. Число триггеров в данном регистре может быть любым. Достаточно соединить прямой выход Q3 с D входом следующего триггера и так далее до достижения необходимой разрядности.
Регистр работает следующим образом. Первый информационный бит поступает на вход D0. Одновременно с этим битом приходит тактовый синхроимпульс на вход С. Входы С всех триггеров входящих в регистр, объединены между собой. С приходом первого тактового импульса уровень, находящийся на входе D0 записывается в первый триггер и с выхода Q0 приходит на вход следующего триггера, но записи во второй триггер не происходит, так как синхроимпульс уже закончился.
При поступлении следующего тактового импульса уровень, присутствующий на входе второго триггера запоминается в нём и поступает на вход третьего триггера. Одновременно следующий информационный бит запоминается в первом триггере. После прихода четвёртого тактового импульса в четырёх триггерах регистра будут записаны логические уровни, которые последовательно поступали на вход D0.
Допустим это уровни 01102. Тогда это двоичное число можно отобразить, подключив к выходам триггеров светодиоды. Так рассмотренный регистр изображается на принципиальной схеме.
Видно, что на условном изображении присутствует стрелка — указатель того, что это сдвиговый регистр.
Рассмотрим, как работает четырёх разрядный универсальный регистр сдвига К155ИР1 (аналог — SN7495N). Вот его внутреннее устройство.
Регистр содержит четыре D-триггера, которые соединены между собой с помощью дополнительных логических элементов И – ИЛИ, которые позволяют реализовать различные функции. На схеме:
V2 – вход управления. С его помощью выбирается режим работы регистра.
Q1 – Q4 выходы триггеров с которых снимается параллельный код.
V1 – вход для подачи последовательного кода.
C1, C2 – тактовые синхроимпульсы.
D1 – D4 – входы для записи параллельного кода.
Алгоритм работы регистра следующий. Если на вход V2 подать низкий потенциал, тактовые импульсы на C1, а на вход V1 подавать информационные биты, то регистр осуществляет сдвиг вправо. После приёма четырёх разрядов на выходах триггеров Q1 – Q4 мы получаем параллельный код. Таким образом осуществляется преобразование последовательного кода в параллельный.
Для обратного преобразования параллельный код записывается по входам D1 – D4, с подачей на вход V2 высокого потенциала и тактовых импульсов на вход С2. Затем подавая на вход V2 низкий потенциал, а тактовые импульсы на вход С1 мы сдвигаем записанный код, а с выхода последнего триггера снимается последовательный код.
По своей структуре это один из самых простых регистров сдвига.
Регистры сдвига в цифровой технике могут послужить основой, на которой собираются узлы с интересными свойствами. Это, например, кольцевые счётчики, которые называются счётчики Джонсона. Такой счётчик имеет количество состояний вдвое большее, чем число составляющих его триггеров. Например, если кольцевой счётчик состоит из трёх триггеров, то он будет иметь шесть устойчивых состояний. На вход счётчика ничего не подаётся кроме синхроимпульсов. В первоначальном состоянии все триггеры «сброшены», то есть на прямых выходах триггеров логические нули, а вот на входе D первого триггера с инверсного выхода третьего триггера находится логическая единица. Начнём подавать тактовые импульсы и процесс пошёл.
На таблице истинности хорошо видно, как изменяется двоичный код при поступлении шести тактовых импульсов.
Сдвиговый регистр 74HC595
Сдвиговый регистр — это набор последовательно соединённых триггеров (обычно их 8 штук). В отличии от стандартных регистров, сдвиговые поддерживают функцию сдвига вправо и влево. (т. е. переписывание данных с каждого предыдущего триггера на следующий по счёту).
Функционал и назначение у сдвиговых регистров довольно велик. Сегодня мы познакомим одного из них с Arduino (Отличный способ множить выходы у Arduino: занимаем 3, получаем 8).
Наверное самая популярная микросхема, представляющая собой такой регистр — это 74HC595.
— Работает на интерфейсе SPI: ноги DS, ST_CP, SH_CP — это шины управления. Соответственно: шина данных(MOSI), защёлка(SS) и тактовая линия(SCK). Подключаем на любые 3 контакта Arduino (библиотека SPI в коде не будет задействована). У меня это 12, 10, 13 выходы Arduino (стандарт).
— Ноги Q0, Q1, . Q7 — это выходы регистра (разряды). Для того, чтобы следить за состоянием каждого из них, повесим на каждый вывод по светодиоду (с последовательно соединённым резистором. Номинал от 150 до 330 Ом)
— VCC и GND — это питание. Подключаем к +5v и GND.
— выход Q7` не трогаем (предназначен для последовательного соединения таких регистров)
— MR — это сброс. Подключаем к +5v (сброс не активен).
— ну и OE притягиваем к земле (подключаем к контакту GND).
Получается вот, такая схема:
На BreadBoard можно разместить вот, так:
Теперь к коду:
— как говорилось ранее, библиотека SPI использоваться не будет. Есть удобная функция shiftOut().
для начала именуем наши пины (тактовая линия — clock, данные — data, защёлка — latch):
потом в void setup() обозначаем их как выходы и сразу ставим защёлке высокий уровень, чтобы регистр не принимал сигналов:
теперь давайте попробуем что-нибудь отправить на регистр:
— для начала ставим LOW на защёлку (начинаем передачу данных. Теперь регистр принимает сигналы с Arduino).
— потом отправляем данные (т. е. отправляем байт в цифровом или двоичном виде. В двоичном проще, т. к. каждый из 8 битов отвечает за свой разряд в регистре. Проще сориентироваться глазами):
Для начала отправим байт 0b10000000; (должен будет загореться первый светодиод):
— и в конце выставляем HIGH на защёлку (заканчиваем передавать данные).
В итоге весь наш код:
Теперь вгружаем в ардуину. Результат должен быть таким (зажёгся первый светодиод):
(если у вас зажёгся не первый, а последний светодиод, то в функции shiftOut поменяйте LSBFIRST на MSBFIRST и всё станет на свои места).
Итак, получилось! Предлагаю создать функцию для того, чтобы каждый раз не писать эти 3 СТРОЧКИ:
Я назову её: sendbyte;
Эта функция отправляет регистру состояние всех разрядов сразу. Это пригодится для управления семисегментом (например). Но, чтобы использовать регистр как расширитель портов, нужно управлять каждым разрядом по-отдельности (аналогично функции digitalWrite()):
— Мы можем отправлять регистру только полный байты (8 бит — 0b00000000). Если отправить не 8, а 5 бит (например: 0b00000000), то регистр будет ждать недостающие 3 бита. Значит, что когда мы хотим изменить состояние одного разряда регистра (включить его, или выключить) мы должны, по сути, послать ранее отправленный байт, с изменением на один бит.
(P. S.: Сейчас долгое и нудное объяснение (новичкам), кому не интересно, спуститесь чуть ниже :);
— Итак, сначала создаём, так называемую (мною), базу данных, в которой будет храниться состояние каждого разряда (включен(HIGH) или выключен(LOW)). тип: boolean:
Только что у нас появился массив переменных;
Каждая переменная в данном массиве обозначает свой разряд (в нулевой (по счёту) будет храниться состояние 1 разряда, второй — 3-го, и т. д.)
— Теперь напишем функцию (я назову её: sendpin). Она будет принимать 2 значения: номер разряда, и уровень, который нам надо этому разряду приписать: высокий(HIGH) или низкий(LOW).
— из-за того, что счёт начинается с нуля, нам придётся называть первый пин нулевым. Чтобы это исправить (мы будем писать как есть(первый, значит первый), а Arduino будет сама отбавлять один), Я написал:
— Затем отмечаем изменения в базе данных:
Теперь надо сформировать из 8 битов байт и отправить его на регистр.
— для начала создаём переменные:
value — тот байт, который будем отправлять. (по умолчанию его нужно сделать нулём):
add — это переменная, которая будет хранить в себе байт текущего разряда. для первого разряда это байт 1 (0b10000000);
теперь нам нужно прокрутить в базе данных все 8 переменных и сформировать байт (делать это будем с помощью цикла for():
Итак, каждый раз мы проверяем очередной разряд в базе данных. Если он должен иметь высокий уровень, то мы прибавляем к value add и переходим на следующий разряд в цепочке (как бы сдвигаемся на разряд выше (левее). Т. е., в двоичном коде всё просто: было так: 0b01000000; сдвинули единичку влево и получилось так: 0b10000000. А вот в цифровом виде всё по-другому. Сдвиг влево аналогичен умножению на 2 (а вправо, кстати, — делению на 2)). Получается примерно так:
Теперь остаётся только послать value на регистр:
В принципе, если понять, то всё очень просто.
Итак, давайте попробуем включить 2, 4, 6, и 8 разряды отдельно (4 раза напишем в цикле нашу функцию):
И кстати, в setup-e нужно очистить регистр (послать 0).
Записки программиста
Больше чипов 74xx: сдвиговые регистры и декодеры
Благодаря заметке Два способа мультиплексирования светодиодов на примере микроконтроллеров AVR мы с вами знаем, что можно управлять сотней светодиодов, используя всего лишь 11 пинов микроконтроллера. Но что делать, если нужно управлять двумястами или, скажем, тысячью светодиодами? Оказывается, что изученные способы мультиплексирования могут быть улучшены, да так, что используя всего лишь три пина микроконтроллера можно управлять абсолютно любым количеством светодиодов! И в этом нам помогут следующие микросхемы.
Примечание: Если вы пропустили предыдущий пост, посвященный микросхемам 74xx, вот он — Интегральные схемы: чипы стандартной логики 74xx. Впрочем, тот пост был посвящен логическим вентилям, и для понимания представленного далее материала читать его не требуется.
SIPO сдвиговый регистр 74HC595
Сдвиговые регистры — это микросхемы, позволяющие, очень грубо говоря, добавить пинов вашему микроконтроллеру 🙂 Для добавления пинов на запись, используются SIPO сдвиговые регистры. SIPO означает «последовательный вход, параллельный выход». Если же нужно больше пинов на чтение, используются сдвиговые регистры PISO, «параллельный вход, последовательный выход». В данном разделе мы познакомимся с типичным SIPO сдвиговым регистром, 74HC595.
Какой пин 74HC595 для чего предназначен, можно узнать из даташита [PDF]:
Если коротко, то:
- VCC, GND — это питание.
- OE — разрешение вывода. Чтобы вывод был всегда разрешен, можно подключить этот пин напрямую к минусу.
- SRCLR — сброс. Если не используется, то нужно подключить напрямую к плюсу.
- SER, SRCLK — используются для передачи данных. При подаче высокого напряжения на SRCLK происходит считывание одного бита данных с пина SER.
- RCLK — при подаче сюда высокого напряжения происходит одновременный вывод принятых данных на параллельные выходы.
- Qa-Qh — параллельные выходы. Сюда происходит вывод последних восьми полученных бит при подаче высокого напряжения на SRCLK.
- Qh’ — при получении очередного бита информации и смещении значений по параллельным выходам бит Qh на самом деле не отбрасывается, а поступает на этот пин. Подключив его к пину SER другого сдвигового регистра, а также соединив выходы RCLK и SRCLK обоих сдвиговых регистров, можно получить 16-разрядный сдвиговый регистр. Второй сдвиговый регистр в свою очередь можно соединить с третьим и так далее, получив сколь угодно разрядный регистр сдвига.
Надеюсь, идея ясна — мы последовательно передаем на сдвиговый регистр восемь бит информации по одному биту. Затем сдвиговый регистр параллельно выводит полученные биты на восемь пинов. Отсюда и «последовательный вход, параллельный выход».
const uint8_t hc595_data = 6 ; /* SER */
const uint8_t hc595_latch = 7 ; /* RCLK */
const uint8_t hc595_clock = 8 ; /* SRCLK */
void setup ( )
<
pinMode ( hc595_data, OUTPUT ) ;
pinMode ( hc595_latch, OUTPUT ) ;
pinMode ( hc595_clock, OUTPUT ) ;
void loop ( )
<
/* . */
digitalWrite ( hc595_latch, LOW ) ;
shiftOut ( hc595_data, hc595_clock, MSBFIRST, hc595_out ) ;
digitalWrite ( hc595_latch, HIGH ) ;
/* . */
delay ( 100 ) ;
>
Нам даже не нужно писать никаких циклов. В Arduino уже предусмотрена готовая процедура shiftOut , которая делает все за нас.
В итоге три пина микроконтроллера эффективно превратились в восемь пинов. Если соединить несколько сдвиговых регистров, как это было описано выше, то можно вместо восьми пинов получить сколько угодно. При этом в микроконтроллере все так же будет задействовано только три пина.
Существует чип 74HC164, который предоставляет аналогичную функциональность, и имеет при этом 14 пинов вместо 16-и. Его даташит можно полистать здесь [PDF].
PISO сдвиговый регистр 74HC165
Типичным представителем PISO сдвиговых регистров является 74HC165.
- VCC, GND — питание.
- A-H — входы сдвигового регистра.
- SH — когда на этом пине низкое напряжение, происходит считывание данных с пинов A-H.
- CLK INH — что-то делает только при высоком напряжении на SH. Низкое напряжение означает разрешить использование часов (пин CLK). На практике можно подключить напрямую к земле.
- CLK — когда на SH высокое напряжение и на CLK INH низкое, при подаче на CLK низкого напряжения происходит сдвиг данных.
- Qh — выход сдвигового регистра. Одноименный выход с чертой — это инвертированный выход.
- SER — при очередном сдвиге освободившийся бит принимает значение, поданное на этот пин. Пин может быть задействован при одновременном использовании нескольких сдвиговых регистров. Или можно просто подключить к земле.
Пример кода, считывающего состояние восьми кнопок, используя всего лишь три пина:
const uint8_t hc165_data = A5 ; /* QH */
const uint8_t hc165_latch = A4 ; /* SH */
const uint8_t hc165_clock = A3 ; /* CLK */
pinMode ( hc165_data, INPUT ) ;
pinMode ( hc165_clock, OUTPUT ) ;
pinMode ( hc165_latch, OUTPUT ) ;
>
uint8_t shiftIn165 ( uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder )
<
uint8_t value = 0 ;
uint8_t i ;
for ( i = 0 ; i shiftIn для работы с 74HC165, к сожалению, не годится, так в ней используется обратный порядок подачи сигналов LOW и HIGH на clockPin. Поэтому в приведенном коде используется собственная реализация с правильным порядком.
Декодер / демультиплексор 74HC138
В данном контексте было бы большим упущением не рассказать про демультиплексоры, так как они могут быть использованы для управления светодиодными матрицами, так же, как и сдвиговые регистры. Грубо говоря, демультиплексоры занимаются тем, что декодируют числа из бинарного представления в унарное. Типичным представителем демультиплексоров является 74HC138.
Вот иллюстрация из его даташита [PDF]:
- VCC, GND — питание.
- A, B, C — три бита входа.
- Y0-Y7 — выход. Если на вход подан ноль в бинарном представлении, на Y0 будет подано низкое напряжение, а на все остальные выходы высокое. Если подана единица в бинарном представлении, на Y1 будет низкое напряжение, а на всех остальных выходах высокое, и так далее.
- G1, G2A, G2B — разрешение вывода. Чтобы на выходах Y0-Y7 было что-то осмысленное, на G1 должно быть подано высокое напряжение, а на G2A и G2B — низкое. Иначе на всех выходах Y0-Y7 будет высокое напряжение независимо от входов A, B и C. Пины G2A и G2B можно просто подключить к земле.
const uint8_t hc138_a = 5 ;
const uint8_t hc138_b = 4 ;
const uint8_t hc138_c = 3 ;
const uint8_t hc138_enable = 9 ;
uint8_t hc138_out = 0 ;
pinMode ( hc138_a, OUTPUT ) ;
pinMode ( hc138_b, OUTPUT ) ;
pinMode ( hc138_c, OUTPUT ) ;
pinMode ( hc138_enable, OUTPUT ) ;
74HC138 может быть использован в бегущей строке. При использовании матричной схемы мультиплексирования светодиодов с его помощью можно выбирать строку светодиодной матрицы.
Существует также чип 74HC154. Он аналогичен по функциональности, но более громоздок и является четырехбитным. Его даташит можно полистать здесь [PDF].
Как несложно догадаться, если есть демультиплексоры, значит бывают и мультиплексоры. Они в каком-то смысле аналогичны PISO сдвиговым регистрам, так как позволяют увеличить количество читающих пинов микроконтроллера. В качестве примеров можно привести чипы 74HC151 и 74HC153. Их даташиты доступны, соответственно, здесь [PDF] и здесь [PDF].
Fun fact! При помощи мультиплексора можно реализовать произвольную логическую функцию, подключив его входы напрямую к питанию или земле в соответствии с таблицей истинности и используя управляющие сигналы, как входные данные.
Полная версия кода
Вы, конечно же, поняли, что приведенные выше отрывки кода являются частью одной программы. Вот ее полный исходный код:
const uint8_t hc595_data = 6 ; /* SER */
const uint8_t hc595_latch = 7 ; /* RCLK */
const uint8_t hc595_clock = 8 ; /* SRCLK */
const uint8_t hc138_a = 5 ;
const uint8_t hc138_b = 4 ;
const uint8_t hc138_c = 3 ;
const uint8_t hc138_enable = 9 ;
const uint8_t hc165_data = A5 ; /* QH */
const uint8_t hc165_latch = A4 ; /* SH */
const uint8_t hc165_clock = A3 ; /* CLK */
uint8_t hc595_out = 0 ;
uint8_t hc138_out = 0 ;
void setup ( )
<
pinMode ( hc595_data, OUTPUT ) ;
pinMode ( hc595_latch, OUTPUT ) ;
pinMode ( hc595_clock, OUTPUT ) ;
pinMode ( hc138_a, OUTPUT ) ;
pinMode ( hc138_b, OUTPUT ) ;
pinMode ( hc138_c, OUTPUT ) ;
pinMode ( hc138_enable, OUTPUT ) ;
pinMode ( hc165_data, INPUT ) ;
pinMode ( hc165_clock, OUTPUT ) ;
pinMode ( hc165_latch, OUTPUT ) ;
>
uint8_t shiftIn165 ( uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder )
<
uint8_t value = 0 ;
uint8_t i ;
for ( i = 0 ; i < 8 ; ++ i )
<
digitalWrite ( clockPin, LOW ) ;
if ( bitOrder == LSBFIRST )
value | = digitalRead ( dataPin ) << i ;
else
value | = digitalRead ( dataPin ) << ( 7 - i ) ;
digitalWrite ( clockPin, HIGH ) ;
>
void loop ( )
<
digitalWrite ( hc165_latch, LOW ) ;
delayMicroseconds ( 5 ) ;
digitalWrite ( hc165_latch, HIGH ) ;
delayMicroseconds ( 5 ) ;
hc595_out = shiftIn165 ( hc165_data, hc165_clock, MSBFIRST ) ;
digitalWrite ( hc595_latch, LOW ) ;
shiftOut ( hc595_data, hc595_clock, MSBFIRST, hc595_out ) ;
digitalWrite ( hc595_latch, HIGH ) ;
Фотография соответствующего прототипа на макетной плате:
Используемые чипы слева направо — микроконтроллер ATmega328P, SIPO сдвиговый регистр 74HC595, демультиплексор 74HC138, PISO сдвиговый регистр 74HC165. Состояние восьми кнопок считывается через 74HC165. Светодиоды слева, соответствующие нажатым кнопкам, не горят, а отпущенным — горят. Состояние этих светодиодов контролируется через 74HC595. На фото я зажал три правые кнопки карандашом и потому три соответствующих им светодиода не горят. Еще восемь светодиодов справа контролируются демультиплексором 74HC138. Их состояние зависит только от времени, по очереди гаснет один светодиод.
Заключение
Еще из интересных чипов стоит упомянуть шинный формирователь 74HC244. Это штука, которая может как бы отрезать одну часть цепи от другой. Если добавить в цепь 74HC04 (логическое НЕ), то при помощи 74HC244 можно будет использовать одни и те же пины для работы с SIPO и PISO сдвиговыми регистрами, плюс один пин для переключения между ними. Итого, если микроконтроллер имеет четыре пина, он может работать с любым количеством кнопок и светодиодов. У самого маленького известного мне микроконтроллера ATtiny13 целых пять свободных пинов, что позволяет обойтись и без 74HC04. Подробности о 74HC244 ищите в даташите [PDF], там все очень просто.
Также заслуживает внимания чип 74HC4051. Эта штука позволяет соединить аналоговый канал с любым из 8 других аналогвых каналов, или разъединить их все. Мне нравится думать о 74HC4051, как о переключателе, управляемом программного. Подробности — в даташите [PDF].
В контексте увеличения числа пинов микроконтроллера стоит также упомянуть чипы MCP23017 / MCP23S17 [PDF] и специализированные чипы для управления светодиодными матрицами вроде MAX7221 [PDF]. Интересны они тем, что предлагая функциональность, аналогичную функциональности сдвиговых регистров и декодеров, могут занимать меньше места на плате. Если же вы хотите увеличить числ ШИМ-пинов, обратите внимание на микросхему TLC5940 (видеообзор, библиотека). Однако обсуждение данных микросхем уже сильно выходит за рамки данного поста. Вы без труда сможете изучить их самостоятельно в качестве домашнего задания.
Итак, теперь вы знаете все необходимое, чтобы делать при помощи светодиодов потрясающие вещи, вроде таких или даже таких. Полную версию исходников к посту вы найдете в этом репозитории на GitHub. Как обычно, буду весьма рад вашим вопросам и дополнениям.
Сдвиговый регистр 74hc595 Arduino
В какой-то момент времени вы неизбежно столкнетесь с проблемой отсутствия достаточного количества контактов на вашем ардуино для удовлетворения потребностей вашего проекта или прототипа. Решение этой проблемы? Сдвиговый регистр, а точнее Arduino сдвиговый регистр 74hc595.
Каждый кто делал проекты на Ардуино, где использовал много светодиодов, понимал, что в значительной степени ограничен контактами Arduino и не может создавать огромные проекты, требующие большого количества контактов. В нашем конкретном проекте 16 светодиодов управляются всего лишь тремя контактами Arduino. Ключевым элементом является arduino сдвиговый регистр 74hc595. Каждый сдвиговый регистр 74HC595 может принимать до 8 светодиодов, а с помощью последовательных цепочек регистров можно увеличить контакты платы от условных 3-х до бесконечного числа.
Как работает регистр сдвига?
Прежде чем мы начнем подключать чип, давайте рассмотрим, как этот процесс работает.
Первое, что нужно прояснить, — это понятие «биты» для тех из вас, кто не знаком с двоичным кодом. Когда мы говорим о «битах», мы имеем в виду одно из чисел, составляющих двоичное значение. В отличие от обычных чисел, мы обычно считаем, что первый бит является самым большим. Итак, если мы берем двоичное значение 10100010, первый бит на самом деле равен 0, а восьмой бит равен 1. Следует также отметить, если это не подразумевалось, каждый бит может быть только 0 или 1.
Чип содержит восемь контактов, которые мы можем использовать для вывода, каждый из которых связан с битом в регистре. В случае сдвигового регистра 74HC595 мы рассматриваем их от QA до QH.
Чтобы записать эти выходы через Arduino, мы должны отправить двоичное значение в регистр сдвига, и из этого числа сдвиговый регистр может определить, какие выходы использовать. Например, если мы отправили двоичное значение 10100010, контакты, выделенные зеленым цветом на изображении выше, будут активными, а выделенные красным цветом будут неактивными.
Это означает, что самый правый бит сопоставляется как QH, а левый бит сопоставляется с QA. Выход считается активным, когда бит, сопоставленный с ним, установлен на 1. Важно помнить об этом, так как иначе вам будет очень сложно узнать, какие контакты вы используете.
Теперь, когда у нас есть основное понимание того, как мы используем смещение битов, чтобы указать, какие контакты использовать, мы можем начать подключать его к нашему Arduino.
Начинаем с 8 светодиодов
Для первой части урока нам понадобятся следующие комплектующие:
- Arduino Uno
- Макетная плата
- Ардуино сдвиговый регистр 74HC595
- 8 светодиодов
- 8 резисторов – 220 ом должно хватить
- Провода/перемычки
Начните с размещения сдвигового регистра на вашем макете, гарантируя, что каждая сторона находится на отдельной стороне макета, как показано ниже.
С надписью, направленной вверх, штифты 1-8 с левой стороны сверху вниз и 16 — 9 с правой стороны сверху вниз, как показано на рисунке ниже.
Собираем схему
Для начала подключим контакты 16 (VCC) и 10 (SRCLR) к выходу 5v на Arduino и соединяем выводы 8 (GND) и 13 (OE) с выводом Gnd на Arduino. Pin 13 (OE) используется для включения выходов, так как это активный низкий контакт, который мы можем подключить непосредственно к земле.
Затем нам нужно соединить три контакта, которыми мы будем управлять сдвиговым регистром:
- Pin 11 (SRCLK) сдвигового регистра 74HC595 на пин 11 на Arduino — это будет называться «синхронизирующим пином»,
- Pin 12 (RCLK) сдвигового регистра на пин 12 на Arduino — это будет обозначаться как «пин защелка»,
- Pin 14 (SER) сдвигового регистра на пин 13 на Arduino — это будет называться «пином данных»,
Все три этих контакта используются для выполнения сдвига битов, упомянутого ранее в этом руководстве. К счастью, ардуино предоставляет вспомогательную функцию специально для регистров сдвига, называемую shiftOut, которая будет обрабатывать почти все для нас, но мы вернемся к этому при просмотре кода.
Теперь нам просто нужно подключить все выходные выводы к нашим светодиодам, гарантируя, что резистор размещается перед светодиодами, чтобы уменьшить ток и что катоды светодиодов направлены на землю.
Чтобы уменьшить нагромождение проводов до минимума, мы поместили резисторы и светодиоды на отдельный макет, однако, вы можете воспользоваться одной макетной платой.
При размещении светодиодов убедитесь, что они подключены по порядку, так что QA подключен к первому светодиоду, а QH подключен к последнему светодиоду, так как иначе наш код не включит светодиоды в правильном порядке. Когда вы закончите, у вас должно получится что-то вроде этого:
Скетч для ардуино
Теперь мы готовы загрузить код. Подключите свой Arduino к компьютеру и загрузите на него следующий эскиз для 74hc595 Arduino:
Для начала определим в верхней части эскиза следующее:
- Расположение пинов: синхронизатора, защелки и данных
- Байт, который будет хранить биты, которые указывают сдвиговому регистру, какой вывод использовать
- Переменную, которая будет отслеживать, какой светодиод мы должны включить
В методе setup мы просто инициализируем режимы пинов и переменную светодиодов.
В методе loop (цикл) мы очищаем биты в переменной leds в начале каждой итерации, так что все биты устанавливаются в 0, так как мы хотим только включать один светодиод за раз. После этого мы увеличиваем или перезапускаем текущую переменную currentLED, чтобы затем опять включать правильный светодиод.
После этих двух операций мы переходим к более важной части — смещению бит. Сначала мы начинаем с вызова метода bitSet. Мы передаем методу bitSet байт, что хранит биты, и переменную currentLED.
Этот метод позволяет нам установить отдельные биты байта, указав их положение. Например, если мы хотим вручную установить байт в 10010, мы могли бы использовать следующие вызовы, поскольку биты, которые нам нужно установить в 1, являются вторыми справа (это позиция 1, когда мы начинаем в позиции 0) и пятый справа, который находится в положении 4:
Таким образом, каждый раз, когда мы увеличиваем текущую переменную currentLED и передаем ее методу bitSet, мы каждый раз устанавливаем бит слева от предыдущего до 1 и, таким образом сообщаем сдвиговому регистру активировать вывод слева от предыдущего.
После установки бит мы записываем на контакт защелки указание сдвиговому регистру, что собираемся отправить ему данные. Как только мы это сделаем, мы вызываем метод shiftOut, который есть Arduino. Этот метод разработан специально для использования сдвиговых регистров и позволяет просто сдвигать биты за один вызов. Для этого мы передаем данные и синхронизацию в качестве первых двух параметров, затем передаем константу LSBFIRST, которая сообщает методу, что первый бит должен быть наименее значимым, а затем мы проходим через байт, содержащий биты, которые мы действительно хотим перенести в регистр сдвига.
Как только мы закончим смещение битов, мы снова обращаемся на контакт защелки (используя HIGH в этот раз), чтобы указать, что мы отправили все данные. После того, как операция записи будет завершена, загорится соответствующий светодиодный индикатор, а затем задержится на 250 миллисекунд, прежде чем всё повторится.
16 светодиодов
Теперь перейдем к более сложной схеме используем 74hc595 Arduino для 16 светодиодов.
По большому счету в данном случае количество всех комплектующих увеличиваем вдвое, кроме, конечно, Ардуино Уно:
- Arduino UNO (x1)
- 74HC595 сдвиговый регистр (x2)
- Светодиоды (x16)
- 220 ом резисторы (x16)
- Провода/перемычки
- Две макетные платы (одна с 400 пинами, вторая с 830 пинами)
- Потенциометр для контроля яркости (по желанию)
Схема соединения
Схема соединения получилась уже больше, чем при 8 светодиодах и одном регистре сдвига 74HC595.
Соберите схему как на рисунке выше и подключите первый регистр сдвига следующим образом:
- GND (контакт 8) на землю
- Vcc (контакт 16) — 5В
- OE (контакт 13) на землю (GND)
- MR (контакт 10) — 5 В
- DS (контакт 14) — пин 11 Arduino
- SH_CP (контакт 11) на контакт Arduino 12
- ST_CP (контакт 12) к контакту 8 Arduino
Подключите второй регистр сдвига точно так же, но подключите DS (контакт 14) к первому выходу 9 регистра. После этого соедините контакты 1, 2, 3, 4, 5, 6, 7 и 15 из обоих регистров и светодиоды. Это соединение делает все контакты всегда активными и адресными, однако при включении Arduino некоторые из светодиодов могут быть включены. Решение для этого — подключить MR (контакт 10) и OE (контакт 13) к Arduino напрямую, но таким образом вы должны пожертвовать 2 выводами ардуины.
Чтобы добавить больше регистров сдвига, соедините их, как второй регистр. Всегда подключайте контакты MR и OE непосредственно к контакту Arduino и DS к предыдущему регистру. Если вы хотите отрегулировать яркость светодиодов, подключите потенциометр, как показано на рисунке выше, для управления сопротивлением для всех светодиодов. Однако это необязательно, и вы можете обойтись без него.
Скетч для ардуино
Варианты скетчей обычно предназначены для ограниченного числа регистров сдвига, т.к. для этого нет универсальной функции/метода. Данный код ниже переработан так, чтобы вы могли использовать неограниченное количество регистров сдвига:
В коде добавлено несколько эффектов для этих 16 светодиодов. Если вы хотите добавить больше светодиодов, подключите больше регистров сдвига по примеру выше и измените значение numOfRegisters в коде.
Вы также можете использовать этот код не только для светодиодов, если вам просто нужно больше контактов для вашего Arduino, используйте функцию regWrite (int pin, bool state) для записи состояния любого вывода. И нет предела, сколько сдвиговых регистров вы используете, просто измените значение numOfRegisters, а все остальное уже втоматизировано.