Программирование Arduino урок 13 — сдвиговый регистр 74HC595

Доброго времени суток! Ситуация, когда в микроконтроллере не хватает выходов, встречается довольно часто. Для решения подобной проблемы воспользуемся сдвиговым регистром 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

 

ПОДЕЛИТЕСЬ С ДРУЗЬЯМИ!


About alexlevchenko

Ценю в людях честность и открытость. Люблю мастерить разные самоделки. Нравится переводить статьи, ведь кроме того, что узнаешь что-то новое - ещё и даришь другим возможность окунуться в мир самоделок.

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

Ваш e-mail не будет опубликован. Обязательные поля помечены *

* Copy This Password *

* Type Or Paste Password Here *