Сдвиговые регистры – очень нужная и популярная вещь во многих проектах. Они позволяют размножить выходы вашего контроллера, что очень полезно, когда в реальном проекте вы нагрузите mega328 экраном, клавиатурой и другой периферией. Немного изучим теорию работы этого элемента, соберём простой скетч, а потом по графикам будет понятен алгоритм работы. Взглянем на выводы нашей микросхемы.
Микросхема работает по интерфейсу SPI, и разобраться в логике её работы совсем не сложно. Внутри есть три основных блока. Первый – это сдвиговый регистр. Данные приходят сюда через DS пин, и также могут уходить далее через Q7′ (последовательный выход данных). DS – это последовательный вход данных, данные мы можем посылать бесконечно, и они будут идти паровозиком до самого последнего регистра в цепочке (если их много). Правда есть один нюанс, подавая данные, на входе DS, мы должны обязательно обеспечивать наличие синхроимпульсов на входе (SH_CP – shift register clock input). Далее на схеме мы видим регистр хранения, вот он то как-раз и представляет наибольшую ценность, ведь он связан с параллельным 8-разрядным выходом. Как не трудно догадаться, заставляет эти данные появится на выходе пин ST_CP (storage register clock input) – вход для синхроимпульсов регистра хранения. Именно подавая сюда логическую 1, мы заставим данные отправиться на выходы Q0-Q7. Нужно уточнить, что предыдущие данные хранятся, пока не поступит очередная команда на ST_CP.
Естественно микросхему нужно запитать, для этого используются два пина VCC – напряжение питания и GND – земля. Осталось два странных вывода, это OE (Output Enable) – сигнал разрешения выхода, для нас логично его включить, а для этого подадим на него отрицательное значение. Выход MR (master reset) используется для перезагрузки. Для нашей задачи перезагрузка не нужна, поэтому подтянем его к питанию.
На основе полученных данных, соберём простую схему из двух регистров 74HC595.
Можно воспользоваться стандартными средствами библиотеки Arduino, но мы напишем более простой код, который даст понимание работы. Нам потребуется три вывода с микроконтроллера (из которых получим целых 16!), обозначим их:
#define sh_cp 4
#define st_cp 5
#define ds 6
И назначим их на выход:
void setup() {
pinMode(sh_cp, OUTPUT);
pinMode(st_cp, OUTPUT);
pinMode(ds, OUTPUT);
}
Теперь нужно выполнить команды, которые отправят данные на вход, и затем выведут их в параллельный 8 разрядный выход . Нужно проверить пин ST_CP, что он находится в 0, потому что при 1, мы получим вывод данных, что нам пока ни к чему. 0 будем удерживать до тех пор, пока не запишем все данные в регистр
void loop() {
digitalWrite(st_cp, LOW);
Следующим этапом, нужно загрузить данные в сдвиговый регистр. Для этого нам нужно подать данные на DS (data pin) и подать синхроимпульс SH_CP (clock pin). Можно просто чередовать “0” и “1”.
digitalWrite(ds, HIGH); // Подаём данные (1)
digitalWrite(sh_cp, LOW); // Вывод синхроимпульса в 0
digitalWrite(sh_cp, HIGH); // Вывод синхроимпульса в 1
Логическая 1 загружена! Предлагаю попробовать последовательность 11001100. Остальные 7 бит загрузить не составит труда
digitalWrite(ds, HIGH); // 1
digitalWrite(sh_cp, LOW);
digitalWrite(sh_cp, HIGH);
digitalWrite(ds, LOW); // 0
digitalWrite(sh_cp, LOW);
digitalWrite(sh_cp, HIGH);
digitalWrite(ds, LOW); // 0
digitalWrite(sh_cp, LOW);
digitalWrite(sh_cp, HIGH);
digitalWrite(ds, HIGH); // 1
digitalWrite(sh_cp, LOW);
digitalWrite(sh_cp, HIGH);
digitalWrite(ds, HIGH); // 1
digitalWrite(sh_cp, LOW);
digitalWrite(sh_cp, HIGH);
digitalWrite(ds, LOW); // 0
digitalWrite(sh_cp, LOW);
digitalWrite(sh_cp, HIGH);
digitalWrite(ds, LOW); // 0
digitalWrite(sh_cp, LOW);
digitalWrite(sh_cp, HIGH);
Теперь насколько вы помните из теории, нам нужно переместить загруженные данные на 8 разрядный выходной каскад. Для этого мы подадим логическую единицу на ST_CP и сделаем небольшую задержку.
digitalWrite(st_cp, HIGH);
delay(500);
Проверим в симуляторе, что у нас получилось. На светодиодах должна отобразиться последовательность 11001100. Получилось грубо говоря 00110011, т.е. наоборот, но это и логично, ведь начало последовательности по мере загрузки в регистр оказалась в конце, поэтому с этим нужно быть внимательным.
Если посмотреть на осциллограмму, то принцип работы становится очень понятным. Каждый бит данных DS, подтверждается синхроимпульсом SH, а в конце загрузки последовательности, мы выводим данным на выводы Q0-Q7, с помощью подачи логической 1 на вывод ST.
Чтобы не страдать с таким длинным кодом в arduino есть простая команда ShiftOut(). В этой команде помимо последовательного вывода данных на пин DS (data pin) , производится подача синхроимпульса на вывод SH_CP (clock Pin). Сам синтаксис команды выглядит так:
shiftOut(dataPin, clockPin, bitOrder, value)
Ещё есть порядок вывода данных – bitOrder: MSBFIRST или LSBFIRST. (Старший значащий бит будет загружен первым или наоборот – наименее значимый бит первым). Сначала рассмотрим MSBFIRST, как наиболее часто применимый. Выполняя данную команду два раза подряд (так как у нас два регистра) без подтверждения вывода на ST_CP, оба регистра заполняются полностью. Делаем мы это, для того, чтобы проверить как работают последовательно соединённые регистры.
digitalWrite(st_cp, LOW);
shiftOut(ds, sh_cp, MSBFIRST, 0b01100110);
shiftOut(ds, sh_cp, MSBFIRST, 0b01100101);
А вот после заполнения данных можно сделать и вывод данных, переведя вывод ST_CP в высокий уровень, и в этот момент данные отправятся на выходы Q0-Q7 обеих регистров.
digitalWrite(st_cp, HIGH);
В это легко убедиться в программе PROTEUS, посмотрев диаграмму и результат свечения светодиодов. Выше мы отправили последовательность двоичных символов 0b01100110 и 0b01100101.
Точно также наглядно видно работу сдвиговых регистров, соединённых уже последовательно. Данные через Q7″ после первых 8 бит, просто пошли на следующий сдвиговый регистр, а ST соединён параллельно, и активировал выход данных на обеих регистрах сразу.
Также можно попробовать другой порядок выводы данных – LSBFIRST (наименее значимый бит первым).
digitalWrite(st_cp, LOW);
shiftOut(ds, sh_cp, LSBFIRST, 0b01100110);
shiftOut(ds, sh_cp, LSBFIRST, 0b01100101);
digitalWrite(st_cp, HIGH);
Всё тоже самое, но в каждом регистре диоды горят наоборот. В зависимости от задачи, можно пользоваться и тем, и тем методом.
Осциллограмма.
Сдвиговые регистры, а в частности распространённый 74HC595 – отличный способ недорого увеличить количество выходов микроконтроллера. Конечно у него есть ограничения, например суммарный ток, и ток на каждый отдельно взятый вывод, что не позволяет управлять с помощью него относительно мощной нагрузкой. Но эти проблемы можно обойти транзисторными ключами, реле или применением сдвиговых регистров с парой Дарлингтона на выходном каскаде.