Сдвиговый регистр 74hc595 Arduino
Рано или поздно каждый сталкивается с нехваткой контактов на ардуино для реализации своего проекта или прототипа. Как решить эту проблему? С помощью сдвигового регистра, а именно Arduino сдвигового регистра 74hc595.
Все, кто работал над проектами на Ардуино с большим количеством светодиодов, осознавали, что возможности существенно ограничены числом доступных контактов Arduino, и создание масштабных проектов, требующих множества выводов, затруднено. В нашем конкретном случае 16 светодиодов управляются всего тремя контактами Arduino. Ключевой компонент здесь — arduino сдвиговый регистр 74hc595. Один сдвиговый регистр 74HC595 способен управлять до 8 светодиодами, а при последовательном соединении нескольких регистров количество доступных выводов можно увеличить от условных 3-х практически до любого числа.
Как работает регистр сдвига?
Прежде чем приступить к подключению микросхемы, разберёмся в принципе её работы.
Для начала поясним понятие «биты» для тех, кто не знаком с двоичным счислением. Говоря о «битах», мы подразумеваем одно из чисел, образующих двоичное значение. В отличие от обычных чисел, принято считать, что первый бит — самый старший. Таким образом, если взять двоичное значение 10100010, то первый бит равен 0, а восьмой — 1. Также стоит отметить, что каждый бит может принимать только значение 0 или 1.
В микросхеме имеется восемь выходных контактов, каждый из которых соответствует определённому биту в регистре. Для сдвигового регистра 74HC595 они обозначаются от QA до QH.
Для управления этими выходами через Arduino необходимо передать двоичное значение в сдвиговый регистр, на основании которого он определит, какие выходы активировать. К примеру, при отправке двоичного значения 10100010 контакты, выделенные зелёным на изображении выше, окажутся активными, а выделенные красным — неактивными.
Таким образом, самый правый бит соответствует QH, а самый левый — QA. Выход считается активным при значении соответствующего ему бита, равном 1. Это важно учитывать, поскольку иначе будет сложно определить, какие контакты задействованы.
Теперь, когда мы разобрались с основами использования сдвига битов для указания нужных контактов, можно переходить к подключению к Arduino.
Начинаем с 8 светодиодов
Для первой части урока потребуются следующие компоненты:
Arduino Uno
Макетная плата
Ардуино сдвиговый регистр 74HC595
8 светодиодов
8 резисторов – 220 ом должно хватить
Провода/перемычки
Разместите сдвиговый регистр на макетной плате таким образом, чтобы каждая сторона микросхемы располагалась на отдельной половине платы, как показано ниже.
При расположении надписью вверх контакты 1-8 находятся на левой стороне сверху вниз, а 16-9 — на правой стороне сверху вниз, как изображено на рисунке ниже.
Собираем схему
Начнём с подключения контактов 16 (VCC) и 10 (SRCLR) к выходу 5v Arduino, а контактов 8 (GND) и 13 (OE) — к выводу Gnd Arduino. Pin 13 (OE) отвечает за активацию выходов, и поскольку он работает по логике активного низкого уровня, его можно подсоединить напрямую к земле.
Далее необходимо подключить три контакта, через которые будет осуществляться управление сдвиговым регистром:
Pin 11 (SRCLK) сдвигового регистра 74HC595 на пин 11 на Arduino - это будет называться «синхронизирующим пином»,
Pin 12 (RCLK) сдвигового регистра на пин 12 на Arduino - это будет обозначаться как «пин защелка»,
Pin 14 (SER) сдвигового регистра на пин 13 на Arduino - это будет называться «пином данных»,
Все три контакта задействованы для выполнения операции сдвига битов, описанной ранее. К счастью, в ардуино есть встроенная вспомогательная функция shiftOut, предназначенная специально для работы со сдвиговыми регистрами, которая берёт на себя практически всю работу, но об этом подробнее при разборе кода.
Остаётся подключить все выходные контакты к светодиодам, убедившись, что перед каждым светодиодом установлен резистор для ограничения тока, а катоды светодиодов направлены к земле.
Для уменьшения количества проводов резисторы и светодиоды вынесены на отдельную макетную плату, хотя при желании можно разместить всё на одной.
Подключая светодиоды, следите за правильным порядком: QA должен быть соединён с первым светодиодом, а QH — с последним, иначе код не будет включать светодиоды в нужной последовательности. По завершении у вас должна получиться примерно такая конфигурация:
Скетч для ардуино
Теперь всё готово к загрузке кода. Подсоедините Arduino к компьютеру и загрузите следующий скетч для 74hc595 Arduino:
int latchPin = 12;
int clockPin = 11;
int dataPin = 13;
byte leds = 0;
int currentLED = 0;
void setup()
{
pinMode(latchPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(clockPin, OUTPUT);
leds = 0;
}
void loop()
{
leds = 0;
if (currentLED == 7)
{
currentLED = 0;
}
else
{
currentLED++;
}
bitSet(leds, currentLED);
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, LSBFIRST, leds);
digitalWrite(latchPin, HIGH);
delay(250);
}
В начале скетча объявляются следующие элементы:
Номера пинов: синхронизатора, защелки и данных
Байт для хранения битов, определяющих, какой вывод сдвигового регистра активировать
Переменная для отслеживания текущего светодиода, который необходимо включить
В методе setup происходит инициализация режимов пинов и переменной светодиодов.
В методе loop (цикл) в начале каждой итерации переменная leds сбрасывается — все биты устанавливаются в 0, поскольку в каждый момент времени должен гореть только один светодиод. Затем переменная currentLED увеличивается или сбрасывается в начало, чтобы далее активировать нужный светодиод.
После этих двух действий переходим к ключевой части — операции сдвига битов. Сначала вызывается метод bitSet. В него передаётся байт, хранящий биты, и переменная currentLED.
Данный метод позволяет устанавливать отдельные биты байта, указывая их позицию. К примеру, для ручной установки байта в значение 10010 потребуется два вызова, так как необходимо установить в 1 второй бит справа (позиция 1, отсчёт с нуля) и пятый справа (позиция 4):
bitSet(leds, 1);
bitSet(leds, 4);
Соответственно, при каждом увеличении переменной currentLED и её передаче в метод bitSet, устанавливается бит левее предыдущего, тем самым указывая сдвиговому регистру активировать следующий вывод.
После установки нужных битов на контакт защелки отправляется сигнал LOW, сообщающий сдвиговому регистру о готовности к приёму данных. Затем вызывается встроенный в Arduino метод shiftOut. Этот метод создан специально для сдвиговых регистров и выполняет передачу битов за один вызов. Ему передаются контакты данных и синхронизации в качестве первых двух параметров, константа LSBFIRST, указывающая, что первым передаётся младший бит, и наконец, байт с битами для записи в регистр сдвига.
По завершении сдвига битов на контакт защелки снова подаётся сигнал (на этот раз HIGH), означающий, что передача данных окончена. После этого загорается соответствующий светодиод, и программа ожидает 250 миллисекунд перед началом следующего цикла.
16 светодиодов
Перейдём к более сложной схеме с использованием 74hc595 Arduino для управления 16 светодиодами.
Детали
По сути, количество всех комплектующих удваивается, за исключением, разумеется, Arduino Uno:
Arduino UNO (x1)
74HC595 сдвиговый регистр (x2)
Светодиоды (x16)
220 ом резисторы (x16)
Провода/перемычки
Две макетные платы (одна с 400 пинами, вторая с 830 пинами)
Потенциометр для контроля яркости (по желанию)
Схема соединения
Схема подключения оказалась заметно сложнее по сравнению с вариантом на 8 светодиодов и один сдвиговый регистр 74HC595.
Соберите схему согласно рисунку выше и выполните подключение первого регистра сдвига:
GND (контакт 8) на землю
Vcc (контакт 16) - 5В
OE (контакт 13) на землю (GND)
MR (контакт 10) - 5 В
DS (контакт 14) - пин 11 Arduino
SH_CP (контакт 11) на контакт Arduino 12
ST_CP (контакт 12) к контакту 8 Arduino
Второй регистр сдвига подключается аналогичным образом, за исключением того, что DS (контакт 14) подсоединяется к выходу 9 первого регистра. Далее соедините контакты 1, 2, 3, 4, 5, 6, 7 и 15 обоих регистров со светодиодами. Такое подключение обеспечивает постоянную активность и адресуемость всех контактов, однако при включении Arduino некоторые светодиоды могут загореться самопроизвольно. Устранить это можно, подключив MR (контакт 10) и OE (контакт 13) напрямую к Arduino, но при этом придётся задействовать 2 дополнительных вывода платы.
Для добавления дополнительных регистров сдвига подключайте их по аналогии со вторым. Контакты MR и OE всегда подсоединяйте непосредственно к Arduino, а DS — к предыдущему регистру. Для регулировки яркости светодиодов установите потенциометр по схеме, показанной на рисунке выше. Впрочем, это необязательно, и можно обойтись без него.
Скетч для ардуино
Обычно скетчи рассчитаны на фиксированное число регистров сдвига, поскольку универсальной функции для произвольного количества не существует. Приведённый ниже код переработан таким образом, чтобы поддерживать неограниченное число регистров сдвига:
int latchPin = 8;
int clockPin = 12;
int dataPin = 11;
int numOfRegisters = 2;
byte* registerState;
long effectId = 0;
long prevEffect = 0;
long effectRepeat = 0;
long effectSpeed = 30;
void setup() {
//Initialize array
registerState = new byte[numOfRegisters];
for (size_t i = 0; i < numOfRegisters; i++) {
registerState[i] = 0;
}
//set pins to output so you can control the shift register
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
}
void loop() {
do{
effectId = random(6);
} while (effectId == prevEffect);
prevEffect = effectId;
switch (effectId)
{
case 0:
effectRepeat = random(1, 2);
break;
case 1:
effectRepeat = random(1, 2);
break;
case 3:
effectRepeat = random(1, 5);
break;
case 4:
effectRepeat = random(1, 2);
break;
case 5:
effectRepeat = random(1, 2);
break;
}
for (int i = 0; i < effectRepeat; i++) {
effectSpeed = random(10, 90);
switch (effectId)
{
case 0:
effectA(effectSpeed);
break;
case 1:
effectB(effectSpeed);
break;
case 3:
effectC(effectSpeed);
break;
case 4:
effectD(effectSpeed);
break;
case 6:
effectE(effectSpeed);
break;
}
}
}
void effectA(int speed){
for (int i = 0; i < 16; i++){
for (int k = i; k < 16; k++){
regWrite(k, HIGH);
delay(speed);
regWrite(k, LOW);
}
regWrite(i, HIGH);
}
}
void effectB(int speed){
for (int i = 15; i >= 0; i--){
for (int k = 0; k < i; k++){
regWrite(k, HIGH);
delay(speed);
regWrite(k, LOW);
}
regWrite(i, HIGH);
}
}
void effectC(int speed){
int prevI = 0;
for (int i = 0; i < 16; i++){
regWrite(prevI, LOW);
regWrite(i, HIGH);
prevI = i;
delay(speed);
}
for (int i = 15; i >= 0; i--){
regWrite(prevI, LOW);
regWrite(i, HIGH);
prevI = i;
delay(speed);
}
}
void effectD(int speed){
for (int i = 0; i < 8; i++){
for (int k = i; k < 8; k++)
{
regWrite(k, HIGH);
regWrite(15 - k, HIGH);
delay(speed);
regWrite(k, LOW);
regWrite(15 - k, LOW);
}
regWrite(i, HIGH);
regWrite(15 - i, HIGH);
}
}
void effectE(int speed){
for (int i = 7; i >= 0; i--){
for (int k = 0; k <= i; k++)
{
regWrite(k, HIGH);
regWrite(15 - k, HIGH);
delay(speed);
regWrite(k, LOW);
regWrite(15 - k, LOW);
}
regWrite(i, HIGH);
regWrite(15 - i, HIGH);
}
}
void regWrite(int pin, bool state){
//Determines register
int reg = pin / 8;
//Determines pin for actual register
int actualPin = pin - (8 * reg);
//Begin session
digitalWrite(latchPin, LOW);
for (int i = 0; i < numOfRegisters; i++){
//Get actual states for register
byte* states = ®isterState[i];
//Update state
if (i == reg){
bitWrite(*states, actualPin, state);
}
//Write
shiftOut(dataPin, clockPin, MSBFIRST, *states);
}
//End session
digitalWrite(latchPin, HIGH);
}
В код включено несколько световых эффектов для 16 светодиодов. Если вы планируете подключить больше светодиодов, добавьте дополнительные регистры сдвига по приведённой схеме и измените значение numOfRegisters в коде.
Этот код применим не только для светодиодов — если вам просто требуются дополнительные контакты для Arduino, воспользуйтесь функцией regWrite (int pin, bool state) для управления состоянием любого вывода. Ограничений на количество сдвиговых регистров нет — достаточно изменить значение numOfRegisters, а всё остальное уже автоматизировано.