Arduone kit
Урок №14 Сдвиговый Регистр
В этом опыте вы узнаете об использовании ИС Регистра Сдвига
Наконец мы дошли до Интегральных Схем (ICs). В этом опыте вы узнаете об использовании ИС Регистра Сдвига и об SPI (Serial Periphera Interface). Последовательный периферийный Интерфейс ISP служит для передачи данных. Один Регистр Сдвига добавит вашей Arduino дополнительные 8 выходов, заняв всего три. Схема текущего опыта позволяет управлять восемью светодиодами, используя лишь 3 порта Arduino
Схема подключения
Скетч
// Определения контактов:
// 74HC595 использует SPI (последовательный интерфейс),
// которому требуется всего три пина:
// data - данные
// clock - тактовые импульсы
// latch - защелка

int datapin = 2; 
int clockpin = 3;
int latchpin = 4;

// Для наглядности и понимания пины названы соответственно:
// Англ. - рус.: data - данные; clock - тактовые импульсы;
// latch - защелка.

// Мы также объявим глобальную переменную для данных, которые
// будем отправлять в регистр сдвига:

byte data = 0;


void setup()
{
  // Установим три SPI пина, которые будут выходными:

  pinMode(datapin, OUTPUT);
  pinMode(clockpin, OUTPUT);  
  pinMode(latchpin, OUTPUT);
}


void loop()
{
  // Мы собираемся использовать те же самые функции, которые
  // использовали в опыте №4 (про несколько светодиодов), мы
  // просто заменили DigitalWrite() новой функцией shiftWrite()
  // Про эту функцию поговорим чуть ниже.
  // Еще появилась новая функция, которая демонстрирует работу
  // двоичного счетчика.

  // Чтобы опробовать различные функции расположенные ниже, просто
  // раскомментируйте одну из них, которую хотите запустить, и
  // закомментируйте оставшиеся, которые не будут использоваться.
  
  one after another - один за другим
  //oneAfterAnother();      // один за другим
  
  //oneOnAtATime();       // прокрутить строку вниз
  
  //pingPong();           // прокрутить строку вниз и обратно

  //randomLED();          // мигание случайным светодиодом
  
  //marquee();            // бегущие огни

  //binaryCount();        // двоичный счет от 0 до 255
}


void shiftWrite(int desiredPin, boolean desiredState)

// Эта функция позволяет устанавливать на выходах регистра
// сдвига либо HIGH либо LOW, точно также, как при использовании
// функции digitalWrite().

// И также как digitalWrite(), эта функция принимает два параметра:

//    "desiredPin" желаемый pin сдвигового регистра от 0 до 7

//    "desiredState" желаемый потенциал на нем HIGH или LOW


// Внутри Arduino, цифры хранятся в виде "битовых" (bits) массивов,
// Каждый бит может содержать лишь одно значение: либо единицу,
// либо ноль (5 Вольт или 0, HIGH или LOW). Из за того что 8 бит
// называется "байтом" (byte) мы будем использовать переменную,
// которой мы дали название "data" в верхней части скетча, длинною
// в байт (byte=8bit), для передачи данных в регистр сдвига.
// Если бит в "data" при входе был единицей, на выходе будет 1.
// Если бит в "data" был "0", на выходе будет 0.

// Для изменения отдельных битов в переменной "data", мы будем
// использовать новую команду Arduino с названием bitWrite(),
// которая может изменять состояние указанного бита на 1 или 0.
{
  // Сначала мы изменим глобальную переменную "data", выборочно
  // поменяв выбранные биты на 1 или 0:

  bitWrite(data,desiredPin,desiredState);
  
  // Теперь мы отправим эти данные в регистра сдвига. Для этого
  // используем функцию shiftOut(), она делает всю тяжелую работу
  // управляет данными, тактовыми импульсами и т.д.:

  shiftOut(datapin, clockpin, MSBFIRST, data);

  // После того, как данные попали в регистр сдвига, нам надо чтобы
  // они появились на его выходах. Для этого их нужно "защелкнуть",
  // подав логическую единицу (HIGH) на 12 pin регистра сдвига.
  // Поэтому даем HIGH через переменную LatchPin, которая будет
  // сигнализировать сдвиговому регистру о том что данным пора
  // появиться на выходах.

  digitalWrite(latchpin, HIGH);
  digitalWrite(latchpin, LOW);
}


/*
oneAfterAnother()

Эта функция будет зажигать один светодиод, делать маленькую паузу,
включать следующий светодиод, опять пауза, затем следующий и так, пока
все светодиоды не загорятся. Затем начнет отключить их в обратном
порядке.
*/


void oneAfterAnother()
{
  int index;
  int delayTime = 1000; // Время (в миллисекундах) для пауз
                        // уменьшите или увиличте значение

  // Включить светодиоды:
 
  // Этот цикл for() увеличивает переменную на единицу от 0 до 7
  // Затем используется digitalWrite(), чтобы включить светодиод.
  // Затем пауза
  
  for(index = 0; index <= 7; index++)
  {
    shiftWrite(index, HIGH);
    delay(delayTime);                
  }

  // Выключить светодиоды:

  // Этот цикл for() уменьшает переменную на единицу от 0 до 7
  // Затем используется digitalWrite(), чтобы выключить светодиод.
  // Затем пауза
 
  for(index = 7; index >= 0; index--)
  {
    shiftWrite(index, LOW);
    delay(delayTime);
  }
}


/*
oneOnAtATime ()

Эта функция будет шаг за шагом, по очереди, по одному,
включать светодиоды - первый, второй, третий и т.д.
*/

void oneOnAtATime()
{
  int index;
  int delayTime = 1000; // Время (в миллисекундах) для пауз
                       // попробуйте уменьшить или увиличить
  
  // Этот цикл for() увеличивает переменную на единицу от 0 до 7
  // Т.е. "переменная", включили, пауза, выключили, прибавили
  // в переменную единицу, включили, пауза, выключили и так до 7,
  // затем все с начала
  
  for(index = 0; index <= 7; index++)
  {
    shiftWrite(index, HIGH);	// включить светодиод
    delay(delayTime);		// маленькая пауза, или большая
    shiftWrite(index, LOW);	// выключить светодиод
  }
}

 
/*
pingPong()

Эта функция будет шаг за шагом, по очереди, по одному,
включать светодиоды - первый, второй, третий и так до
восьмого, затем действие пойдет в обратном порядке 7, 6,
5, 4, 3, 2, 1 и все повторится, как в игре пинг-понг.
*/

void pingPong()
{
  int index;
  int delayTime = 100; // Время (в миллисекундах) для пауз
                       // попробуйте уменьшить или увеличить
  
  // Снова тот же цикл for() увеличивает переменную на единицу
  
  for(index = 0; index <= 7; index++)
  {
    shiftWrite(index, HIGH);	// включить светодиод
    delay(delayTime);		// маленькая пауза
    shiftWrite(index, LOW);	// выключить светодиод
  }

  // Снова цикл for() с уменьшением переменной
  
  for(index = 7; index >= 0; index--)
  {
    shiftWrite(index, HIGH);	// включить светодиод
    delay(delayTime);		// маленькая пауза
    shiftWrite(index, LOW);	// выключить светодиод
  }
}


/*
randomLED()

Функция включает по одному светодиоду в случайной
последовательности, также случайна длительность свечения
*/

void randomLED()
{
  int index;
  int delayTime = 1000; // Время (в миллисекундах) для пауз
                       // попробуйте уменьшить или увеличить
  
  // Далее используется функция random(), которая возвращает
  // случайное (точнее сказать псевдослучайное) число. Как
  // ее использовать. См https://arduino.ru/Reference/Random
  
  index = random(8); // Выбрать случайное число между 0 и 7
  
  shiftWrite(index, HIGH);	// включить светодиод
  delay(delayTime);		// маленькая пауза
  shiftWrite(index, LOW);	// выключить светодиод
}


/*
marquee()

Функция имитирует эффек бегущих огней
*/

void marquee()
{
  int index;
  int delayTime = 2000; // Время (в миллисекундах) для пауз
                       // попробуйте уменьшить или увеличить
  
  // Шаг - через три светодиода 1-ый и 5-ый, 2-ой и 6-ой...
  // То есть Мы будем включать каждый четвертый светодиод
  
  for(index = 0; index <= 3; index++)
  {
    shiftWrite(index, HIGH);    // включить светодиод
    shiftWrite(index+4, HIGH);  // увеличить на 4 и включить
    delay(delayTime); // Пауза, чтобы замедлить последовательность
    shiftWrite(index, LOW);	// выключить светодиод
    shiftWrite(index+4, LOW);  // увеличить на 4 и выключить
  }
}


/*
binaryCount()

Числа хранятся во внутренней памяти Arduino в виде массивов "бит".
Каждый бит может быть либо логической единицей (HIGH - высокий
потенциал, либо логическим нулем (LOW - низкий потенциал). Так же,
как десятичные числа, которые мы используем каждый день, положение
занимаемой позиции каждого бита влияет на общее число (сумму в байте).

Для примера: В двоичной системе положение бита в первой позиции
(первая позиция в данном случае "0" см. таблицу ниже, вторая "1",
третья "2" и т.д) будет соответствовать "1" в десятичной системе
исчисления, положение во 2 позиции будет соответствовать двойке
в десятичной, положение в третьей позиции буде соответствовать 4
в десятичной, следующая 8, 16, 32 и т.д )).

Таблица. Соответствие позиции битов десятичной системы к двоичной:

0              1
1              2
2              4
3              8
4              16
5              32
6              64
7              128

Пример 1:
Чтобы создать цифру пять нужно включить бит в первой позиции, т.е
записать в него единицу (HIGH), и бит в третьей позиции, записать
в него тоже единицу (HIGH). Складываем 1+4:

0=HIGH           1
1=LOW            2
2=HIGH           4
3=LOW            8
4=LOW            16
5=LOW            32
6=LOW            64
7=LOW            128

Пример 2:
Чтобы создать цифру 10 нужно включить бит во второй позиции, т.е
записать в него единицу, и бит в четвертой позиции, тоже записать
в него единицу. Складываем 2+8:

0=LOW            1
1=HIGH           2
2=LOW            4
3=HIGH           8
4=LOW            16
5=LOW            32
6=LOW            64
7=LOW            128

Пример 3:
Чтобы создать цифру 20 нужно включить бит в третьей позиции, т.е
установить его в HIGH, и бит в пятой позиции, тоже HIGH.
Складываем 4+16:

0=LOW            1
1=LOW            2
2=HIGH           4
3=LOW            8
4=HIGH           16
5=LOW            32
6=LOW            64
7=LOW            128

Если все биты LOW, это соответствует 0. Если все биты HIGH (включены),
чило равно 255.

Таким образом можно записать любое число от 0 до 255. Именно столько
помещается в 1 byte. 

Пример 4: число 200 (8+64+128):
11001000 

Пример 5: число 0:
00000000

Пример 6: число 255:
11111111


Эта функция будет увеличивать переменную "data" на 1 шаг за шагом
от 0 до 255. Достигнув 255 начнет все сначала и т.д. Из переменной,
данные передаются в регистр сдвига, после чего появляюются на
его выходах. Индикатором служат светодиоды. Если их выставить в
ряд, они покажут содержание переменной "data", т.е шаблон из
восьми бит, которые и составляют 1 байт.

См http://www.arduino.cc/playground/Code/BitMath для получения
дополнительной информации о двоичных чисел.
*/

void binaryCount()
{
  int delayTime = 1000; // Время (в миллисекундах) для пауз
                       // попробуйте уменьшить или увиличить
  
  // Отправить байт данных в регистр сдвига:

  shiftOut(datapin, clockpin, MSBFIRST, data);

  // Защелкиваем данные для того чтобы они появились на выходах:

  digitalWrite(latchpin, HIGH);
  digitalWrite(latchpin, LOW);
  
  // Увиличиваем данные на единицу и повторяем! 
  // Из за того что тип "byte" это 8-ми битное, беззнаковое,
  // целое число, в диапазоне от 0 до 255, мы не може добавить
  // более 255-и, в противном случае все "завалится" обратно
  // в 0, все начнется сначала.
  

  data++;

  // Задержка, для того чтобы вы что-то успели рассмотреть:

  delay(delayTime);
}
Что вы должны увидеть:
Вы должны увидеть различные световые эффекты на LED's светодиодах, аналогично опыту №4, но с использованием ИС Регистра Сдвига. Убедитесь в правильности сборки схемы. Проверьте загрузку кода в Arduino, или воспользуйтесь советами по устранению неполадок ниже.
Возможные трудности:
Индикатор питания Arduino гаснет Такое иногда случается, если вставить ИС ключом не в ту сторону. Если быстро поправить ничего не сломается.
Работает не совсем правильно Звучит как заезжанная пластинка, но возможно перепутаны местами провода.
Вам не понравилось
Пишите нам на e-mail, если схема показалась вам слишком сложной. Она одновременно и простая и сложная. Мы хотим узнать о ваших проблемах и пожеланиях: info@stemkit.kz
Применение в жизни:
Регистр сдвига обязательно используется в световом табло с бегущей строкой, которое состоит из огромного количества светодиодов.