Главная » Arduino
Призовой фонд
на сентябрь 2017 г.
1. 1000 руб
PCBWay
2. Осциллограф DSO138
Паяльник
3. Тестер компонентов MG328
Паяльник
4. 100 руб.
От пользователей

Сдвиговый регистр 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):

#define clock 13
#define data 12
#define latch 10

потом в void setup() обозначаем их как выходы и сразу ставим защёлке высокий уровень, чтобы регистр не принимал сигналов:

void setup(){
  pinMode(clock, OUTPUT);
  pinMode(data, OUTPUT);
  pinMode(latch, OUTPUT);
  digitalWrite(latch, HIGH);
}

теперь давайте попробуем что-нибудь отправить на регистр:

- для начала ставим LOW на защёлку (начинаем передачу данных. Теперь регистр принимает сигналы с Arduino).

digitalWrite(latch, LOW);

- потом отправляем данные (т. е. отправляем байт в цифровом или двоичном виде. В двоичном проще, т. к. каждый из 8 битов отвечает за свой разряд в регистре. Проще сориентироваться глазами):

Для начала отправим байт 0b10000000; (должен будет загореться первый светодиод):

shiftOut(data, clock, LSBFIRST,0b10000000);

- и в конце выставляем HIGH на защёлку (заканчиваем передавать данные).

digitalWrite(latch, HIGH);

В итоге весь наш код:

#define clock 13
#define data 12
#define latch 10

void setup() {
  pinMode(clock, OUTPUT);
  pinMode(data, OUTPUT);
  pinMode(latch, OUTPUT);
  digitalWrite(latch, HIGH);
}

void loop() {
  digitalWrite(latch, LOW);
  shiftOut(data, clock, LSBFIRST, 0b10000000);
  digitalWrite(latch, HIGH);
}

Теперь вгружаем в ардуину. Результат должен быть таким (зажёгся первый светодиод):

(если у вас зажёгся не первый, а последний светодиод, то в функции shiftOut поменяйте LSBFIRST на MSBFIRST и всё станет на свои места).

Итак, получилось! Предлагаю создать функцию для того, чтобы каждый раз не писать эти 3 СТРОЧКИ:

Я назову её: sendbyte;

void sendbyte(byte value){
  digitalWrite(latch, LOW);
  shiftOut(data, clock, LSBFIRST, value);
  digitalWrite(latch, HIGH);
}

Эта функция отправляет регистру состояние всех разрядов сразу. Это пригодится для управления семисегментом (например). Но, чтобы использовать регистр как расширитель портов, нужно управлять каждым разрядом по-отдельности (аналогично функции digitalWrite()):

- Мы можем отправлять регистру только полный байты (8 бит - 0b00000000). Если отправить не 8, а 5 бит (например: 0b00000000), то регистр будет ждать недостающие 3 бита. Значит, что когда мы хотим изменить состояние одного разряда регистра (включить его, или выключить) мы должны, по сути, послать ранее отправленный байт, с изменением на один бит.

(P. S.: Сейчас долгое и нудное объяснение (новичкам), кому не интересно, спуститесь чуть ниже :);

- Итак, сначала создаём, так называемую (мною), базу данных, в которой будет храниться состояние каждого разряда (включен(HIGH) или выключен(LOW)). тип: boolean:

boolean states[8];

Только что у нас появился массив переменных;

Каждая переменная в данном массиве обозначает свой разряд (в нулевой (по счёту) будет храниться состояние 1 разряда, второй - 3-го, и т. д.)

- Теперь напишем функцию (я назову её: sendpin). Она будет принимать 2 значения: номер разряда, и уровень, который нам надо этому разряду приписать: высокий(HIGH) или низкий(LOW).

void sendpin(int pin, boolean state){
  pin--;
  states[pin]=state;
  
  byte value = 0;
  byte add = 1;
  for(int i=0; i<8; i++){
    if(states[i]==HIGH) value+=add;
    add*=2;
  }
  digitalWrite(latch, LOW);
  shiftOut(data, clock, LSBFIRST, value);
  digitalWrite(latch, HIGH);
}

- из-за того, что счёт начинается с нуля, нам придётся называть первый пин нулевым. Чтобы это исправить (мы будем писать как есть(первый, значит первый), а Arduino будет сама отбавлять один), Я написал:

pin--;

- Затем отмечаем изменения в базе данных:

 states[pin]=state;

Теперь надо сформировать из 8 битов байт и отправить его на регистр.

- для начала создаём переменные: 

value - тот байт, который будем отправлять. (по умолчанию его нужно сделать нулём):

byte value = 0;

add - это переменная, которая будет хранить в себе байт текущего разряда. для первого разряда это байт 1 (0b10000000);

byte add = 1;

теперь нам нужно прокрутить в базе данных все 8 переменных и сформировать байт (делать это будем с помощью цикла for():

for(int i=0; i<8; i++){
    
}

Итак, каждый раз мы проверяем очередной разряд в базе данных. Если он должен иметь высокий уровень, то мы прибавляем к value add и переходим на следующий разряд в цепочке (как бы сдвигаемся на разряд выше (левее). Т. е., в двоичном коде всё просто: было так: 0b01000000; сдвинули единичку влево и получилось так: 0b10000000. А вот в цифровом виде всё по-другому. Сдвиг влево аналогичен умножению на 2 (а вправо, кстати, - делению на 2)). Получается примерно так:

if(states[i]==HIGH) value+=add;
add*=2;

Теперь остаётся только послать value на регистр:

digitalWrite(latch, LOW);
shiftOut(data, clock, LSBFIRST, value);
digitalWrite(latch, HIGH);

В принципе, если понять, то всё очень просто.

Итак, давайте попробуем включить 2, 4, 6, и 8 разряды отдельно (4 раза напишем в цикле нашу функцию):

sendpin(2, HIGH);
sendpin(4, HIGH);
sendpin(6, HIGH);
sendpin(8, HIGH);

И кстати, в setup-e нужно очистить регистр (послать 0).

Можно даже такую функцию создать:

void cleanreg(){
  for(int i=0; i<8; i++) states[i]=LOW;
  digitalWrite(latch, LOW);
  shiftOut(data, clock, LSBFIRST, 0);
  digitalWrite(latch, HIGH);
}

В общем результат таков:

Список радиоэлементов

Обозначение Тип Номинал Количество ПримечаниеМагазинМой блокнот
Плата Arduino
Arduino Uno
1 Поиск в LCSCВ блокнот
Сдвиговый регистр
SN74HC595
1 Поиск в LCSCВ блокнот
R1-R8 Резистор150-330 Ом8 Поиск в LCSCВ блокнот
Светодиод8 Поиск в LCSCВ блокнот
Добавить все

Скачать список элементов (PDF)

Прикрепленные файлы:

Теги:

Опубликована: 0 0
Я собрал 0 1
x

Оценить статью

  • Техническая грамотность
  • Актуальность материала
  • Изложение материала
  • Полезность устройства
  • Повторяемость устройства
  • Орфография
0

Средний балл статьи: 4.8 Проголосовало: 1 чел.

Комментарии (14) | Я собрал (0) | Подписаться

0
Andrej #
Отлично, спасибо за статью! Вот если бы еще такую статью по программированию эффектов светодиодов WS2812 на ардуино. Ещё раз спасибо!
Ответить
+3
diogen_b #
Мы можем отправлять регистру только полный байты (8 бит - 0b00000000). Если отправить не 8, а 5 бит (например: 0b00000000), то регистр будет ждать недостающие 3 бита.
Ничего регистр "ждать" не будет - это всего лишь сдвиговый регистр. Просто на остальных трех выводах будут сдвинутые предыдущие значения с первых трех разрядов (разумеется, после записи в защелку). А по Вашему получается, что регистр типа "зависнет" и будет "ждать". Начинающих такие утверждения могут ввести в заблуждение. А так, наверное, кому-то статья будет полезна.
Ответить
0
Евгений #
Я так понял, ардуина дорисовывает недостающие разряды. То есть 0b101 будет отправлен как 0b00000101.
Ответить
0
si4karuk #
Та да, в свое время изломал голову с отправкой нескольких бит. А потом прочел даташит
Ответить
+1
Andrey #
В момент включения содержимое регистров будет неопределенным. Необходимо подключить MR через кондер к земле.
Ответить
0
DBWolf #
У меня почему-то горят все диоды одновременно
Ответить
0
kaj62 #
Спасибо за статью! А как данной схеме изменять яркость светодиодов?
Ответить
0
zeconir #
Можно на вход разрешения подавать ШИМ. А если нужно менять каждого светодиода отдельно, то это уже не так просто.
Ответить
0
Evgen #
- выход Q7` не трогаем (предназначен для последовательного соединения таких регистров), а сами туда светодиод вешают.
Ответить
0
nikita #
Q7' и Q7 это разные пины
Ответить
0
Sergey Shalaev #
Неужели все собирают схему глядя на рисунок бредборда и не заглядывая в электрическую схему?
Ведь там ошибка!
не
11--10 и 12--13
а должно быть
11--13 и 12--10.
Ответить
0
unknown #
По моему в логических элементах входы слева, а выходы справа.
Ответить
0
nikita #
Вот бы библиотеку с кодом в конце, я пытался написать, но не получилось...
Ответить
0
Влад #
Подскажите как отправлять сигнал на конкретную ножку в каскаде из 4-х выходных регистров? С одним регистром всё в норме, но есть необходимость работы с четырьмя.
Ответить
Добавить комментарий
Имя:
E-mail:
не публикуется
Текст:
Защита от спама:
В чем измеряется сила тока?
Файлы:
 
Для выбора нескольких файлов использйте CTRL

Модуль измерения тока на ACS712 (30А)
Модуль измерения тока на ACS712 (30А)
USB осциллограф DSO-2090 UNI-T UT-61A
вверх