Знакомство с микросхемой регистра сдвига 74hc595 — управление 16 светодиодами

Содержание

Анимация светодиодов

Другой скетч.

В path[] мы указываем последовательность включённых и выключенных светодиодов. Между этими последовательностями будет происходит анимация.

Для анимации бегущих огней можно реализовать задачу через функцию bitWrite().

Код попроще, чтобы лучше понять происходящее.

В методе setup() мы просто инициализируем режимы выводов и переменную светодиодов.

В методе loop() очищаем биты в переменной leds в начале каждой итерации, так что все биты устанавливаются в 0, так как мы хотим только включать один светодиод за раз. После этого мы увеличиваем или перезапускаем текущую переменную currentLed, чтобы затем опять включать правильный светодиод.

После этих двух операций мы переходим к смещению бит. Начинаем с вызова метода bitSet(), которому передаём байт, что хранит биты, и переменную currentLed.

Этот метод позволяет нам установить отдельные биты байта, указав их положение. Например, если мы хотим вручную установить байт в 10010, мы могли бы использовать следующие вызовы, поскольку биты, которые нам нужно установить в 1, являются вторыми справа (это позиция 1, когда мы начинаем в позиции 0) и пятый справа, который находится в положении 4:

Таким образом, каждый раз, когда мы увеличиваем текущую переменную currentLed и передаем ее методу bitSet(), мы каждый раз устанавливаем бит слева от предыдущего до 1 и, таким образом сообщаем сдвиговому регистру активировать вывод слева от предыдущего.

После установки бит мы записываем на контакт защёлки указание сдвиговому регистру, что собираемся отправить ему данные. Как только мы это сделаем, мы вызываем метод shiftOut(). Метод позволяет сдвигать биты за один вызов. Для этого мы передаём данные и синхронизацию в качестве первых двух параметров, затем передаём константу LSBFIRST, которая сообщает методу, что первый бит должен быть наименее значимым, а затем мы проходим через байт, содержащий биты, которые мы действительно хотим перенести в регистр сдвига.

Как только мы закончим смещение битов, мы снова обращаемся на контакт защёлки (используя HIGH в этот раз), чтобы указать, что мы отправили все данные. После того, как операция записи будет завершена, загорится соответствующий светодиодный индикатор, а затем задержится на 250 миллисекунд, прежде чем всё повторится.

7Каскадное подключение регистров сдвига к Arduino

Давайте подключим три регистра сдвига 74HC595 к Arduino и попробуем управлять ими по SPI.

В разделе 3 этой статьи была дана схема подключения одного регистра 74HC595 к Arduino. Схема, когда к Arduino подключены несколько ведомых устройств в каскадном режиме, отличается не сильно. Основное отличие в том, что используется один пин выбора ведомого, который активирует одновременно все подключённые устройства (пин SS Arduino подключён ко всем входам STCP), а также данные из ведущего (выход MOSI Arduino) передаются первому в цепочке ведомому 74HC595 на вход последовательных данных DS, тот в свою очередь из последовательного порта Q7′ передаёт данные следующему ведомому на последовательный вход DS, и так далее. Последний ведомый из своего порта Q7′ передаёт данные ведущему в линию MISO, но в нашем случае это не обязательно. Остальные выводы сдвиговых регистров подключены так же, как на предыдущей схеме. У Arduino же используются те же 4 стандартных пина SPI, что и при подключении к единственному регистру сдвига.

Соберём в соответствии с этим нашу схему. У меня получилось как-то так:

Каскадное подключение трёх сдвиговых регистров к Arduino – вид со стороны параллельных выходов 74HC595 Каскадное подключение трёх сдвиговых регистров к Arduino – вид со стороны пинов управления 74HC595

Теперь напишем скетч для «бегущей волны», но теперь она будет немного длиннее. В моём случае – из 19-ти светодиодов, каждый из которых будет представлять один из разрядов параллельных выходов (на все 24 не хватило места на монтажке).

Скетч «бегущей волны» со сдвиговым регистром (разворачивается)

#include <SPI.h>

void setup() {
  pinMode(PIN_SPI_SS, OUTPUT);
  SPI.begin();
  Serial.begin(9600);
}

void loop() {
  for (int i=0; i<20; i++) { //вообще, тут нужно писать i<25, т.к. всего параллельных выходов у трёх регистров 24

    unsigned long num = (long)1<<i; // "гоним" горящий огонёк по разрядам, сдвигая единицу на 1 разряд влево каждую итерацию 
    /* 
    * 19 (или 24) разрядов числа поместятся только в беззнаковый long 
    * unsigned long может хранить до 32-х разрядов. 
    * Т.к. у нас три сдвиговых регистра или 3*8=24 бит, то используем этот тип данных 
    */

    /* 
    * Реализация SPI в Arduino такова, что можно передавать числа либо байтами, либо словами по 2 байта.
    * Поэтому делим наше число на байты, их получается 3, как и регистров сдвига:
    */
    byte a = (byte)num; //младшие 8 бит числа
    byte b = (byte)(num>>8);//средние 8 бит числа
    byte c = (byte)(num>>16); //старшие 8 бит числа

    digitalWrite(PIN_SPI_SS, LOW); // начинаем передачу по SPI
    SPI.transfer(c); //передаём старший байт числа
    SPI.transfer(b); //передаём средний байт числа
    SPI.transfer(a); //передаём младший байт числа
    digitalWrite(PIN_SPI_SS, HIGH); // завершаем передачу по SPI

    // Контрольный вывод в COM-порт:
    Serial.print((String)i + ": ");
    Serial.print(num, HEX);
    Serial.print("=");
    Serial.print(c, HEX);
    Serial.print(",");
    Serial.print(b, HEX);
    Serial.print(",");
    Serial.println(a, HEX);

    delay(100); // задержимся немного
  }
}

Обратите внимание, мы обращались к параллельным выходам 3-х сдвиговых регистров как к большому 24-разрядному числу. Но что делать, если вы подключили к Arduino большее количество 74HC595? Такими большими числами Arduino, конечно же, оперировать не умеет

В таком случае придётся работать с байтами. То есть передавать в каждый регистр своё 8-разрядное значение.

А вот так это выглядит в действии:

Каскадное подключение трёх сдвиговых регистров к Arduino в действии

На видео в конце статьи результат наглядно показан в динамике. К каждому из трёх сдвиговых регистров подключены светодиоды своего цвета – красные, зелёные и синие, и видно, как наше число «перескакивает» с регистра в регистр.

Таким образом, мы детально изучили вопрос информационного обмена между ведущим устройством, в роли которого выступил Arduino, и сдвиговым регистром 74HC595. Научились подключать сдвиговый регистр, записывать в него данные и считывать из него данные.

1Описание и назначение сдвигового регистра 74HC595

Сдвиговый регистр 74HC595 и ему подобные используются в качестве устройств преобразования последовательных данных в параллельные, а также может использоваться как «защёлка» для данных, удерживая заданное состояние.

Схема выводов («распиновка») приведена на рисунке слева.

Назначение выводов сдвигового регистра 74HC595 и внешний вид в выводном корпусе DIP-16

Назначение выводов микросхемы 74HC595 такое.

Обозначение вывода Назначение
Q0…Q7 выходы параллельных данных;
GND земля (0 В);
Q7′ выход последовательных данных;
MR сброс ведущего устройства (активный низкий);
SHCP вход тактовых импульсов сдвигового регистра;
STCP вход тактовых импульсов «защёлки»;
OE разрешение вывода (активный низкий);
DS вход последовательных данных;
VCC питание +5 В.

Конструктивно микросхема выполняется в нескольких типах корпусов; я буду использовать микросхему в выводном корпусе DIP-16, т.к. его проще использовать с макетной платой (бредбордом).

Скетч для arduino, который считывает данные с регистра 74HC165

В завершение прикладываю код, для считывания сигналов с регистра. Скетч с подробными комментариями, описывать что-то еще нет смысла, поэтому приведу просто листинг:

#define NUMBER_OF_SHIFT_CHIPS   1 // количество регистров
#define DATA_WIDTH   NUMBER_OF_SHIFT_CHIPS * 8 // количество входов
#define PULSE_WIDTH_USEC   5 // задержка при считывании данных 

// для хранения считаных байт
// если регистров больше двух, то int меняется на long
#define BYTES_VAL_T unsigned int 

// пины для подключения регистра
int ploadPin = 8;
int clockEnablePin = 9;
int dataPin = 11;
int clockPin = 12;

BYTES_VAL_T pinValues; // текущее значение пинов 
BYTES_VAL_T oldPinValues; // предыдущее значение пинов

// функция для считывания пинов
BYTES_VAL_T read_shift_regs() {
    long bitVal;
    BYTES_VAL_T bytesVal = 0;

	// опрашиваем регистр о состоянии пинов
    digitalWrite(clockEnablePin, HIGH);
    digitalWrite(ploadPin, LOW);
    delayMicroseconds(PULSE_WIDTH_USEC);
    digitalWrite(ploadPin, HIGH);
    digitalWrite(clockEnablePin, LOW);

	// считываем полученные данные о пинах
    for(int i = 0; i < DATA_WIDTH; i++){
        bitVal = digitalRead(dataPin);
        bytesVal |= (bitVal << ((DATA_WIDTH-1) - i));
        digitalWrite(clockPin, HIGH);
        delayMicroseconds(PULSE_WIDTH_USEC);
        digitalWrite(clockPin, LOW);
    }
	
	// возвращяем результат опроса регистра
    return(bytesVal);
}

// функция для вывода состояния пинов
void display_pin_values(){
	// перебор всех пинов 
	for(int i = 0; i < DATA_WIDTH; i++){
		Serial.print("  Button-");
		Serial.print(i);
		Serial.print(": ");
		if((pinValues >> i) & 1){
		  Serial.print("ON");
		}else{
		  Serial.print("OFF"); 
		}   
		Serial.println();
	}
	Serial.println();
}

void setup(){
	// для вывода данных в монитор порта
	Serial.begin(9600);

	// установка режима работа пинов
	pinMode(ploadPin, OUTPUT);
	pinMode(clockEnablePin, OUTPUT);
	pinMode(clockPin, OUTPUT);
	pinMode(dataPin, INPUT);
	digitalWrite(clockPin, LOW);
	digitalWrite(ploadPin, HIGH);

	// считываем значения с пинов
	pinValues = read_shift_regs();
	// выводим результат
	display_pin_values();
	// сохраняем текущее значение
	oldPinValues = pinValues;
}

void loop(){
	// считываем значения с пинов
    pinValues = read_shift_regs();
	// если значения изменились, то выводим их
    if(pinValues != oldPinValues){
		// выводим результат в монитор порта
        display_pin_values();
		// сохраняем текущее значение
        oldPinValues = pinValues;
    }
    delay(50);
}

Программная часть:

Основой управления сдвиговым регистром в Arduino является команда shiftOut(), которая выводит на заданный пин байт информации побитно. Использует 2 пина: Пин данных – dataPin и тактовый пин синхронизации clockPin. Для того, чтобы сдвиговый регистр принял данные, на его вывод STcp (Latch) на время передачи должен быть подан сигнал «0».Синтаксис команды ShiftOut() следующий:shiftOut(dataPin, clockPin, bitOrder, value), где:dataPin, clockPin – выводы Arduino, к которым подключены 14(data) и 11(latch) выводы сдвигового регистра 74HC595. Как видно из таблицы, которая была приведена ранее, это 9 и 10 выводы Arduino.bitOtder – может принимать 2 значения и указывает направление вывода бит: слева (MSBFIRST) или справа (LSBFIRST).value – однобайтовое число (0-255) которое нужно вывести на индикатор побитно.Например, нужно вывести на дисплей цифру 3. Для этого сегменты a,b,c,d,g – нужно засветить (подать на них «1»), а сегменты f, e -погасить (подать на них «0»). Схематически это выглядит так :

Другими словами, в сдвиговый регистр нужно записать число 0b11110010 (0b обозначает, что число в двоичной системе исчисления). Делается это так:digitalWrite(8, LOW); // Устанавливаем Latch в «0»shiftOut(9, 10, LSBFIRST, 0b11110010); // Записываем побитно число 11110010 в двоичной системеdigitalWrite(8, HIGH); // Устанавливаем Latch в «1»Все! На дисплее должна засветиться цифра 3. Если нужно засветить единицу в первом разряде (он подключен вместо точки «DP») – тогда к коду цифры нужно добавить 1:0b11110010 + 1 = 0b111100110b11110010 – это «3»0b11110011 – это «13»И напоследок в качестве примера привожу тестовый скетч, который высвечивает на дисплее числа от 0 до 19 с задержкой в 1 секунду:

int latchPin = 8; //STcp
int clockPin = 10; // SHcp
int dataPin = 9; //Ds
// Массив в котором указано, какие сегменты должны зажигаться
// например, в "0" должны светиться сегменты abcdef (0b11111100)
int num = { b11111100, //цифра 0
                b01100000, //цифра 1
                b11011010, //цифра 2
                b11110010, //цифра 3
                b01100110, //цифра 4
                b10110110, //цифра 5
                b10111110, //цифра 6
                b11100000, //цифра 7
                b11111110, //цифра 8
                b11110110, //цифра 9
                b00001101, //знак ||
              };
void setup() {
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
}

void loop() {
 
   for (int i=; i<=19; i++){
    digitalWrite(latchPin, LOW);  // установка синхронизации "защелки" на LOW
 if (i<10)  shiftOut(dataPin, clockPin, LSBFIRST, num);   // передаем последовательно на вход данных
      else shiftOut(dataPin, clockPin, LSBFIRST, num+1);
   digitalWrite(latchPin, HIGH);  //"защелкиваем" регистр, устанавливаем значения на выходах
    delay(1000);}
  
}

Скачать его можно здесь. 

Добавление пинов arduino

Чтобы увеличить количество пинов есть несколько способов. Самый простой, это подключить кнопки или датчики к одному аналоговому пину через резисторы разного сопротивления, тогда в коде можно добавить условия для каждого уровня сигнала. Второй способ – использовать сдвиговый регистр, который позволяет принимать до восьми цифровых сигналов. А так же регистры можно выстраивать каскадами, один за другим, каждый раз добавляя 8 новых пинов.
Ниже будет рассмотрен второй вариант с использованием сдвигового регистра 74HC165. Я уже как-то описывал работу со сдвиговым регистром 74HC595, который может передавать данные. Сегодняшний регистр работает наоборот – принимает сигналы.

7Каскадное подключение регистров сдвига к Arduino

Давайте подключим три регистра сдвига 74HC595 к Arduino и попробуем управлять ими по SPI.

В разделе 3 этой статьи была дана схема подключения одного регистра 74HC595 к Arduino. Схема, когда к Arduino подключены несколько ведомых устройств в каскадном режиме, отличается не сильно. Основное отличие в том, что используется один пин выбора ведомого, который активирует одновременно все подключённые устройства (пин SS Arduino подключён ко всем входам STCP), а также данные из ведущего (выход MOSI Arduino) передаются первому в цепочке ведомому 74HC595 на вход последовательных данных DS, тот в свою очередь из последовательного порта Q7′ передаёт данные следующему ведомому на последовательный вход DS, и так далее. Последний ведомый из своего порта Q7′ передаёт данные ведущему в линию MISO, но в нашем случае это не обязательно. Остальные выводы сдвиговых регистров подключены так же, как на предыдущей схеме. У Arduino же используются те же 4 стандартных пина SPI, что и при подключении к единственному регистру сдвига.

Соберём в соответствии с этим нашу схему. У меня получилось как-то так:

Каскадное подключение трёх сдвиговых регистров к Arduino – вид со стороны параллельных выходов 74HC595 Каскадное подключение трёх сдвиговых регистров к Arduino – вид со стороны пинов управления 74HC595

Теперь напишем скетч для «бегущей волны», но теперь она будет немного длиннее. В моём случае – из 19-ти светодиодов, каждый из которых будет представлять один из разрядов параллельных выходов (на все 24 не хватило места на монтажке).

Скетч «бегущей волны» со сдвиговым регистром (разворачивается)

#include <SPI.h>

void setup() {
  pinMode(PIN_SPI_SS, OUTPUT);
  SPI.begin();
  Serial.begin(9600);
}

void loop() {
  for (int i=0; i<20; i++) { //вообще, тут нужно писать i<25, т.к. всего параллельных выходов у трёх регистров 24

    unsigned long num = (long)1<<i; // "гоним" горящий огонёк по разрядам, сдвигая единицу на 1 разряд влево каждую итерацию 
    /* 
    * 19 (или 24) разрядов числа поместятся только в беззнаковый long 
    * unsigned long может хранить до 32-х разрядов. 
    * Т.к. у нас три сдвиговых регистра или 3*8=24 бит, то используем этот тип данных 
    */

    /* 
    * Реализация SPI в Arduino такова, что можно передавать числа либо байтами, либо словами по 2 байта.
    * Поэтому делим наше число на байты, их получается 3, как и регистров сдвига:
    */
    byte a = (byte)num; //младшие 8 бит числа
    byte b = (byte)(num>>8);//средние 8 бит числа
    byte c = (byte)(num>>16); //старшие 8 бит числа

    digitalWrite(PIN_SPI_SS, LOW); // начинаем передачу по SPI
    SPI.transfer(c); //передаём старший байт числа
    SPI.transfer(b); //передаём средний байт числа
    SPI.transfer(a); //передаём младший байт числа
    digitalWrite(PIN_SPI_SS, HIGH); // завершаем передачу по SPI

    // Контрольный вывод в COM-порт:
    Serial.print((String)i + ": ");
    Serial.print(num, HEX);
    Serial.print("=");
    Serial.print(c, HEX);
    Serial.print(",");
    Serial.print(b, HEX);
    Serial.print(",");
    Serial.println(a, HEX);

    delay(100); // задержимся немного
  }
}

Обратите внимание, мы обращались к параллельным выходам 3-х сдвиговых регистров как к большому 24-разрядному числу. Но что делать, если вы подключили к Arduino большее количество 74HC595? Такими большими числами Arduino, конечно же, оперировать не умеет

В таком случае придётся работать с байтами. То есть передавать в каждый регистр своё 8-разрядное значение.

А вот так это выглядит в действии:

Каскадное подключение трёх сдвиговых регистров к Arduino в действии

На видео в конце статьи результат наглядно показан в динамике. К каждому из трёх сдвиговых регистров подключены светодиоды своего цвета – красные, зелёные и синие, и видно, как наше число «перескакивает» с регистра в регистр.

Таким образом, мы детально изучили вопрос информационного обмена между ведущим устройством, в роли которого выступил Arduino, и сдвиговым регистром 74HC595. Научились подключать сдвиговый регистр, записывать в него данные и считывать из него данные.

2Краткое описание интерфейса SPI

Коротко напомню о последовательном интерфейсе SPI, который мы будем использовать для передачи данных в сдвиговый регистр.
SPI – это четырёхпроводный двунаправленный последовательный интерфейс, в котором принимают участие ведущее и ведомое устройства. Ведущим в нашем случае будет являться Arduino, ведомым – регистр 74HC595.

Среда разработки для Arduino имеет встроенную библиотеку работы по интерфейсу SPI. При её применении используются цифровые выводы с 10 по 13 на платах Arduino Uno и Arduino Nano; также они продублированы и выведены на отдельный разъём ICSP:

Выводы Arduino, отведённые под SPI

Обозначение вывода Назначение
SCLK вывод тактовых импульсов SPI;
MOSI данные от ведущего – к ведомому;
MISO данные от ведомого к ведущему;
SS выбор ведомого.

2Краткое описание интерфейса SPI

Коротко напомню о последовательном интерфейсе SPI, который мы будем использовать для передачи данных в сдвиговый регистр.
SPI – это четырёхпроводный двунаправленный последовательный интерфейс, в котором принимают участие ведущее и ведомое устройства. Ведущим в нашем случае будет являться Arduino, ведомым – регистр 74HC595.

Среда разработки для Arduino имеет встроенную библиотеку работы по интерфейсу SPI. При её применении используются цифровые выводы с 10 по 13 на платах Arduino Uno и Arduino Nano; также они продублированы и выведены на отдельный разъём ICSP:

Выводы Arduino, отведённые под SPI

Обозначение вывода Назначение
SCLK вывод тактовых импульсов SPI;
MOSI данные от ведущего – к ведомому;
MISO данные от ведомого к ведущему;
SS выбор ведомого.

Объяснение программы для Raspberry Pi

Полный код программы приведен в конце статьи, здесь же мы кратко рассмотрим его основные фрагменты.

После того, как все необходимые соединения в схеме сделаны, мы можем подать питание на Raspberry Pi и после загрузки ее операционной системы можно начать писать программу в ней на Python. Подробнее о том, как это можно сделать, можно прочитать в статье про мигание светодиода с помощью Raspberry Pi.

В программе нам первым делом необходимо подключить (импортировать) библиотеку для работы с контактами ввода/вывода. Также мы импортируем эту библиотеку RPi.GPIO под именем “IO” (то есть переименовываем ее для использования в программе), то есть далее в программе всегда, когда мы захотим обратиться к контактам ввода/вывода, мы будем использовать слово ‘IO’.

Python

import RPi.GPIO as IO

1 importRPi.GPIO asIO

Иногда контакты ввода/вывода (GPIO pins), которые мы собираемся использовать в программе, могут выполнять другие функции. В этом случае во время исполнения программы мы будем получать предупреждения (warnings). Следующей командой мы укажем плате Raspberry Pi на то, чтобы она игнорировала эти предупреждения и продолжала исполнение программы.

Python

IO.setwarnings(False)

1 IO.setwarnings(False)

Мы можем обращаться к контактам ввода/вывода (GPIO pins) платы Raspberry Pi используя либо номер контакта на плате, либо его функциональный номер. В представленной выше распиновке контактов ввода/вывода можно увидеть, к примеру, что обозначение GPIO5 соответствует контакту PIN 29. То есть в зависимости от того, какой способ обращения к контактам мы выбрали, мы можем обращаться к рассмотренному контакту либо по номеру ‘29’, либо по номеру ‘5’. В данном проекте мы выберем способ обращения к контактам по их функциональным номерам, поэтому используем следующую команду:

Python

IO.setmode (IO.BCM)

1 IO.setmode(IO.BCM)

Далее мы сконфигурируем контакты GPIO4, GPIO5 и GPIO6 в качестве цифровых выходов – с них будет осуществляться управление регистром сдвига.

Python

IO.setup(4,IO.OUT)
IO.setup(5,IO.OUT)
IO.setup(6,IO.OUT)

1
2
3

IO.setup(4,IO.OUT)

IO.setup(5,IO.OUT)

IO.setup(6,IO.OUT)

Далее запишем команду цикла, который будет исполняться 8 раз.

Python

for y in range(8):

1 foryinrange(8)

Также в программе мы будем использовать команду «While 1:» – она будет формировать бесконечный цикл. Внутри этого цикла все команды будут исполняться непрерывно.

Начинаем с 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:

Для начала определим в верхней части эскиза следующее:

  • Расположение пинов: синхронизатора, защелки и данных
  • Байт, который будет хранить биты, которые указывают сдвиговому регистру, какой вывод использовать
  • Переменную, которая будет отслеживать, какой светодиод мы должны включить

В методе setup мы просто инициализируем режимы пинов и переменную светодиодов.

В методе loop (цикл) мы очищаем биты в переменной leds в начале каждой итерации, так что все биты устанавливаются в 0, так как мы хотим только включать один светодиод за раз. После этого мы увеличиваем или перезапускаем текущую переменную currentLED, чтобы затем опять включать правильный светодиод.

После этих двух операций мы переходим к более важной части — смещению бит. Сначала мы начинаем с вызова метода bitSet

Мы передаем методу bitSet байт, что хранит биты, и переменную currentLED.

Этот метод позволяет нам установить отдельные биты байта, указав их положение. Например, если мы хотим вручную установить байт в 10010, мы могли бы использовать следующие вызовы, поскольку биты, которые нам нужно установить в 1, являются вторыми справа (это позиция 1, когда мы начинаем в позиции 0) и пятый справа, который находится в положении 4:

Таким образом, каждый раз, когда мы увеличиваем текущую переменную currentLED и передаем ее методу bitSet, мы каждый раз устанавливаем бит слева от предыдущего до 1 и, таким образом сообщаем сдвиговому регистру активировать вывод слева от предыдущего.

После установки бит мы записываем на контакт защелки указание сдвиговому регистру, что собираемся отправить ему данные. Как только мы это сделаем, мы вызываем метод shiftOut, который есть Arduino. Этот метод разработан специально для использования сдвиговых регистров и позволяет просто сдвигать биты за один вызов. Для этого мы передаем данные и синхронизацию в качестве первых двух параметров, затем передаем константу LSBFIRST, которая сообщает методу, что первый бит должен быть наименее значимым, а затем мы проходим через байт, содержащий биты, которые мы действительно хотим перенести в регистр сдвига.

Как только мы закончим смещение битов, мы снова обращаемся на контакт защелки (используя HIGH в этот раз), чтобы указать, что мы отправили все данные. После того, как операция записи будет завершена, загорится соответствующий светодиодный индикатор, а затем задержится на 250 миллисекунд, прежде чем всё повторится.

Входы 74HC595

OE

Вход переводящий выходы из высокоимпедансного состояние в рабочее состояние. При логической единице на этом входе выходы 74HC595 будут отключены от остальной части схемы. Это нужно например для того чтобы другая микросхема могла управлять этими сигналами.

Если нужно включить в рабочее состояние микросхеме подайте логический ноль на этот вход. А если в принципе не нужно переводить выходы в высокоимпедансное состояние – смело заземляйте этот вывод.

MR — сброс регистра

Переводить все выходы в состояние логического нуля. Чтобы сбросить регистр нужно подать логический ноль на этот вход и подать положительный импульс на вход STCP.

Подключаем этот выход через резистор к питанию микросхемы и при необходимости замыкаем на землю.

DS – вход данных

Последовательно подаваемые сюда данные будут появляются на 8-ми выходах регистра в параллельной форме.

SHCP – вход для тактовых импульсов

Когда на тактовом входе SHCP появляется логическая единица, бит находящийся на входе данных DS считывается и записывается в самый младший разряд сдвигового регистра. При поступлении на тактовый вход следующего импульса высокого уровня, в сдвиговый регистр записывается следующий бит со входа данных. Тот бит который был записан ранее сдвигается на один разряд (из Q0 в Q1) , а его место занимает вновь пришедший бит. И так далее по цепочке.

STCP – вход «защёлкивающий» данные

Что бы данные появились на выходах Q0…Q7 нужно подать логическую единицу на вход STCP. Данные поступают в параллельный регистр который сохряняет их до следующего импульса STCP.

4Тестовый скетч для изучения работы регистра сдвига

Напишем вот такой скетч и загрузим в память Arduino. Здесь мы по циклу будем записывать два числа – 210 и 0 – в сдвиговый регистр с небольшими временными интервалами между ними. Да, только и всего.

Скетч записи данных в сдвиговый регистр (разворачивается)

#include <SPI.h> // подключаем библиотеку SPI

void setup() {
  SPI.begin();  // инициализируем SPI
  pinMode(PIN_SPI_SS, OUTPUT); 
}

void loop() {
    digitalWrite(PIN_SPI_SS, LOW); // выбор регистра сдвига
    SPI.transfer(210); // передаём число "210" в сдвиговый регистр
    digitalWrite(PIN_SPI_SS, HIGH); // конец передачи
    delay(10); // задержка 10 мсек

    digitalWrite(PIN_SPI_SS, LOW);  
    SPI.transfer(0);                
    digitalWrite(PIN_SPI_SS, HIGH); 
    delay(90);
}

PIN_SPI_SS – это внутренняя стандартная константа, которая соответствует выводу «10» Ардуино в режиме SPI. Данная константа определена в файле pins_arduino.h, который находится по пути %programfiles%\arduino-(версия)\hardware\arduino\avr\variants\ Также там определены константы PIN_SPI_MOSI (пин 11), PIN_SPI_MISO (пин 12), PIN_SPI_SCK (пин 13). В ранних версиях Arduino IDE (например, 1.6.хх) этих констант не было.

В принципе, мы могли бы с таким же успехом использовать любой другой цифровой вывод Arduino; тогда пришлось бы в программе объявить его и не забыть задать режим работы – OUTPUT.

Подавая на этот вывод LOW, мы активируем наш сдвиговый регистр на приём/передачу. После передачи мы снова поднимаем напряжение в HIGH, и обмен заканчивается. Включим схему в работу и посмотрим, что покажет логический анализатор.