Ситуация, когда в микроконтроллере не хватает выходов, встречается довольно часто. Для решения подобной проблемы воспользуемся сдвиговым регистром 74HC595.
74HC595 — восьмиразрядный сдвиговый регистр с последовательным вводом, последовательным/параллельным выводом информации, с триггером-защелкой и тремя состояниями на выходах регистра.
Регистр контролирует 8 выходов, занимая всего 3 выхода микроконтроллера. Кроме этого можно собрать каскад из нескольких таких регистров.
Регистр использует принцип синхронизированной последовательной передачи сигнала. Значения сигнала (биты 1 или 0) передаются в регистр один за другим, при этом регистр получает синхронизирующий сигнал, который заставляет его считать сигнал с входа. Когда байт полностью вычитан, значения всех 8 бит распределяются по выходам регистра. То есть передаем в регистр сигналы последовательно, а на выходах регистра имеем 8-м параллельных сигналов.
Регистр может выдавать полученные сигналы параллельно или последовательно. Последовательная передача бит необходимо при каскадировании нескольких регистров. Первые 8 бит сигнала передаются на следующий регистр для дальнейшего параллельного вывода информации.
Выходы регистра могут быть в одном из трёх состояний:
- логический ноль;
- логическая единица;
- высокоомное (высокоимпедансное) состояние.
В высокоомном состоянии выходы отключены от схемы. Отключить можно только все выхода регистра вместе (по одному нельзя).
В исходном состоянии выводы регистра находятся в высокоомном состоянии. Это значит, что другие элементы могут изменять напряжение на них, не влияя на работоспособность и логику микросхемы. Это может быть полезно, если одними и теми же элементами планируется управлять при помощи разных регистров — когда активен один (сигнал LOW на входе OE), следует перевести второй в высокоомное состояние (сигнал HIGH на входе OE). Если регистр всего один, можно смело подключать OE к земле. Также к земле подключается выход GND. Для нормального функционирования регистра также следует подключить вход MR к рельсе питания. Туда же подключаем Vcc.
К минусам использования сдвигового регистра стоит отнести невозможность использования широтно-импульсной модуляции (ШИМ), потому что выходы регистра могут иметь только логические значения HIGH (1) и LOW (0).
Распиновка входов/выходов регистра
Регистр работает на интерфейсе SPI: выводы DS, ST_CP, SH_CP - это шины управления.
- Выводы 1-7, 15 ------------ Q0-Q7 ------------ Параллельные выходы (разряды);
- Вывод 8 ---------------------- GND -------------- земля;
- Вывод 9 ---------------------- Q7" ---------------- Выход для последовательного соединения регистров;
- Вывод 10 -------------------- MR ---------------- Сброс значений регистра. Сброс происходит при получение LOW. Если заведём питание +5В, то сброс будет неактивным;
- Вывод 11 -------------------- SH_CP ------------ Вход для тактовых импульсов - «тактовая линия (SCK)»;
- Вывод 12 -------------------- ST_CP ------------ Синхронизация выходов - «защёлка (SS)»;
- Вывод 13 -------------------- OE ------------ Вход для переключения состояния выходов из высокоомного в рабочее (подключаем на землю);
- Вывод 14 -------------------- DS ---------------- Вход для последовательных данных - «шина данных (MOSI)»;
- Вывод 16 -------------------- Vcc ---------------- Питание.
Соберём стенд с одним сдвиговым регистром.
Подключим:
- GND (пин 8) на землю;
- Vcc (пин 16) к питанию 5В;
- OE (пин 13) на землю;
- MR (пин 10) к питанию 5В;
Подадим питание на регистр и сделаем выходы активными. При таком подключении в момент подачи питания на схему на выходах будут случайные значения. Можно контролировать выводы MR и OE непосредственно с Arduino (обнуляя входы и/или подключая выходы в нужный момент). Но не стоит из-за этого нервничать, так как значения регистра и выводов будут перезаписаны, как только программа начнёт работать.
Схема подключения
Подключаем Arduino:
- DS (dataPin) 14-й вывод регистра с 11-ым выходом Arduino;
- SH_CP (clockPin) 11-й вывод регистра с 12-ым выходом Arduino;
- ST_CP (latchPin) 12-й вывод регистра c 8-ым выходом Arduino;
Конденсатор ёмкостью 0.1 микрофарада необходимо подключит на «защёлку» для минимизации шума в схеме при подаче "защелкивающего" импульса. Подключаем светодиоды к выходам регистра через токоограничивающие резисторы.
Для начала следует отметить, что библиотека SPI в данном примере использоваться не будет.
В место неё будет использовать функцию shiftOut() - выводит байт информации на порт вход/выхода последовательно (побитно).
У функции всего четыре параметра:
- Номер вывода, по которому передаются данные (подключенный к DS);
- Номер вывода, по которому передаются тактовые импульсы (подключенный к SH_CP).
- Параметр передачи битов в регистр: MSBFIRST — прямой порядок, начиная со старшего (первого) бита; LSBFIRST — обратный порядок, начиная с младшего (последнего бита).
- Значение, которое должно быть передано в регистр. В данном случае передаем значение от 0 до 255 (2 в степени 8, регистр 8-ми битный).
Объявим переменные и присвоим им соответствующие значения.
int latchPin = 8; int clockPin = 12; int dataPin = 11;
Конфигурируем выводы на выход и ставим «защёлку», чтобы сдвиговый регистр не принимал сигналов:
void setup(){ pinMode(clockPin, OUTPUT); pinMode(dataPin, OUTPUT); pinMode(latchPin, OUTPUT); digitalWrite(latchPin, HIGH); }
После этого отправим на регистр байт. Для этого снимем защёлку (ставим LOW) - начинаём передачу данных (регистр принимает сигналы с Arduino).
digitalWrite(latchPin, LOW);
Отправляем данные (отправляем байт в цифровом или двоичном виде) = 0b00000001.
shiftOut(dataPin, clockPin, MSBFIRST,0b00000001);
В конце ставим защёлку (ставим HIGH) - заканчиваем передачу.
digitalWrite(latchPin, HIGH);
В итоге весь наш код имеет следующий вид:
int latchPin = 8; int clockPin = 12; int dataPin = 11; void setup() { pinMode(clockPin, OUTPUT); pinMode(dataPin, OUTPUT); pinMode(latchPin, OUTPUT); digitalWrite(latchPin, HIGH); } void loop() { digitalWrite(latchPin, LOW); shiftOut(dataPin, clockPin, MSBFIRST, 0b00000001); digitalWrite(latchPin, HIGH); }
Заливаем прошивку в контроллер. Смотрим на результат.
Непосредственно управление регистром осуществляется с помощью входов DS, SH_CP и ST_CP. Когда происходит переключение SH_CP (clockPin) с LOW на HIGH, в регистр считывается значение с DS (1 бит). При переключении ST_CP (latchPin) с LOW на HIGH заканчивается прием информации и выводы переходят в назначенное состояние.
Напишем функцию (вместо 3-х строк) для оптимизации кода:
void sendBitsToShift (byte value){ digitalWrite(latchPin, LOW); shiftOut(dataPin, clockPin, MSBFIRST, value); digitalWrite(latchPin, HIGH); }
Чтобы использовать регистр, как расширитель портов, нужно управлять каждым разрядом по-отдельности.
Для удобства работы создадим массив типа «boolean» для хранения состояния разряда (HIGH или LOW).
boolean statesOfpin[8];
Напишем под него функцию, что будет принимать 2 параметра: номер разряда и уровень, который нужно этому разряду присвоить: HIGH или LOW.
void sendBitsToPin (int pin, boolean state){
Микроконтроллер начинает отсчёт с нуля. Чтобы не было путаницы будем отнимать единицу от номера текущего разряда. Другими словами - пользователь работает с 1 - 8 разрядами, а контроллер воспринимает это, как работу с 0 - 7.
pin--;
Перезаписываем изменения в массиве:
statesOfpin [pin] = state;
Формируем байт (из 8 битов) и отправляем его на регистр. Объявляем переменные: value - формируемый байт (по умолчанию с нулевым значением); add - хранить байт текущего разряда.
byte value = 0; byte add = 1;
Формируем байт.
for(int i=0; i<8; i++){
Проверяем очередной разряд в массиве. Если он должен иметь высокий уровень, то прибавляем к переменной value переменную add и переходим на следующий разряд.
if(statesOfpin [i]==HIGH) value+=add; add*=2; }
Посылаем значение переменной «value» в регистр:
digitalWrite(latchPin, LOW); shiftOut(data, clockPin, MSBFIRST, value); digitalWrite(latchPin, HIGH); }
Включаем 1, 4, 5 и 8 разряды по-отдельности.
sendBitsToPin (1, HIGH); sendBitsToPin (4, HIGH); sendBitsToPin (5, HIGH); sendBitsToPin (8, HIGH);
Для очистки регистра напишем функцию и вызовем её в setup (в программах представленных в статье - эта функция не использовалась):
void cleanreg(){ for(int i=0; i<8; i++) statesOfpin [i]=LOW; digitalWrite(latchPin, LOW); shiftOut(dataPin, clockPin, MSBFIRST, 0); digitalWrite(latchPin, HIGH); }
Другой вариант управления разрядами. Программа считывает значения введенные пользователем в «мониторе порта» от 0 до 7 и включает соответствующий светодиод. Введя «reset» мы сбрасываем значение на светодиодах.
Регистру можно отправлять только полный байт (8 бит - 0b00000000). Чтобы изменить состояние одного разряда регистра (включить или выключить) нужно послать ранее отправленный байт с изменением одного нужного бита.
Программа-счётчик выводит значения байта от 0 до 255 в двоичной системе счислений.
Продолжении следует..
sdvig_reg