Главная » Arduino
Призовой фонд
на май 2017 г.
1. Тестер компонентов MG328
Паяльник
2. Осциллограф DSO138
Паяльник
3. Регулируемый паяльник 60 Вт
Паяльник
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 Поиск в FivelВ блокнот
Сдвиговый регистр
SN74HC595
1 Поиск в FivelВ блокнот
R1-R8 Резистор150-330 Ом8 Поиск в FivelВ блокнот
Светодиод8 Поиск в FivelВ блокнот
Добавить все

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

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

Теги:

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

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

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

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

Комментарии (10) | Я собрал (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
Evgen #
- выход Q7` не трогаем (предназначен для последовательного соединения таких регистров), а сами туда светодиод вешают.
Ответить
0
Sergey Shalaev #
Неужели все собирают схему глядя на рисунок бредборда и не заглядывая в электрическую схему?
Ведь там ошибка!
не
11--10 и 12--13
а должно быть
11--13 и 12--10.
Ответить
0
unknown #
По моему в логических элементах входы слева, а выходы справа.
Ответить
Добавить комментарий
Имя:
E-mail:
не публикуется
Текст:
Защита от спама:
В чем измеряется напряжение?
Файлы:
 
Для выбора нескольких файлов использйте CTRL

Модуль измерения тока на ACS712 (30А)
Модуль измерения тока на ACS712 (30А)
Набор 4WD Kit Bluetooth Металлоискатель MD3010II
вверх