Главная » Arduino
Призовой фонд
на февраль 2021 г.
1. 1500 руб
Сайт Паяльник
2. Мультиметр ANENG M118A
Сайт Паяльник
3. 350 руб.
От пользователей


RGB катодные светодиоды

Сдвиговый регистр 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 Поиск в магазине ОтронВ блокнот
Сдвиговый регистр
SN74HC595
1 Поиск в магазине ОтронВ блокнот
R1-R8 Резистор150-330 Ом8 Поиск в магазине ОтронВ блокнот
Светодиод8 Поиск в магазине ОтронВ блокнот
Добавить все

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

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

Теги:

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

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

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

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

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

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

Модуль измерения тока на ACS712 (30А)
Модуль измерения тока на ACS712 (30А)
Металлоискатель MD3010II USB-реле (2 канала)
вверх