Ардуино: всё о сдвиговом регистре

Сдвиговый регистр — очень распространенное устройство, которое часто применяется для упрощения работы с сегментными индикаторами, с линейками и с матрицами светодиодов. Все эти устройства состоят из множества светодиодов, и если управлять ими напрямую, потребуется занять много выводов контроллера. К примеру, для подключения обычного сегментного индикатора необходимо задействовать восемь выводов. Два таких индикатора займут уже 16 ног Ардуино.

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

DSC01321_В электронике регистром называют устройство, которое может хранить небольшой объем данных для быстрого доступа к ним. Они есть внутри каждого контроллера и микропроцессора, включая и микроконтроллер Atmega328 — сердце Ардуино Уно. Как правило регистры представляют собой сборку из D-триггеров — элементарных ячеек памяти, с которыми мы уже встречались в отдельном уроке. Записывать данные в регистр можно либо последовательно, либо параллельно. Регистры первого типа называются сдвиговыми, второго типа — параллельными.

Считывать данные из регистра можно одновременно из всех ячеек. Именно это его свойство помогает нам работать с кучей светодиодов.

1. Принцип работы сдвигового регистра

Регистр называется сдвиговым, потому что при добавлении каждого нового бита в него, мы как бы сдвигаем все остальные в сторону. Вспомним, что один бит позволяет нам хранить ноль или единицу, истину или ложь. Посмотрим на диаграмме, как это происходит.

Пусть в начальном состоянии регистр уже заполнен какими-то восемью битами. Попробуем «задвинуть» в него восемь новых бит: 11011010.

reg_shift_1

Как видно, после двух итераций, в начале регистра оказалось два новых бита, а два бита в последних ячейках «вывалились» через край в небытие. На 8-м шаге весь регистр оказался заполнен новыми битами.

Регистры можно соединять в цепочку. В таком случае, вытесненный бит не будет пропадать без следа, а отправится в начало следующего регистра.

reg_shift_2

2. Сдвиговый регистр 74HC595

На этом уроке мы разберем работу сдвигового регистра 74HC595, который может хранить 8 бит данных. Схема выводов микросхемы представлена на картинке. Кстати, у этого регистра есть и отечественный аналог КР1564ИР52.

shift_register_09_lrg

  • Q0-Q7 — выходы каждой из 8 ячеек;
  • VCC — питание микросхемы, 5В;
  • GND — земля;
  • DS — линия данных;
  • ST_CP — линия синхроимпульса для передачи данных из внутренних ячеек, во внешние;
  • SH_CP — линия синхроимпульса для передачи данных из DS во внутренние ячейки;
  • OE — инверсный, разрешение на вывод данных с внешних ячеек;
  • Out3, Out4 — выводы для подключения второго двигателя;
  • Q7′ — выход регистра, который необходимо соединить с Q0 следующего регистра для создания цепочки.

У регистра есть один вход данных и два входа синхронизации. Синхроимпульс SH_CP запоминает текущее состояние входа данных DS. Другими словами, если на DS в момент синхронизации был высокий уровень HIGH, то в первой ячейке регистра сохранится 1. В противном случае, сохранится 0.

Но надо отметить, что на самом деле сдвиговый регистр 74HC595 содержит не 8, а целых 16 ячеек памяти! Первые 8 ячеек заполняются последовательно, как мы и выяснили из предыдущей диаграммы, а  вот другие 8 носят особую функцию. Второй слой ячеек соединяется непосредственно с выходами Q0-Q7, и чтобы переместить бит из первого слоя во второй, нам потребуется второй синхроимпульс ST_CP. Это может немного путать, но зато такой двухслойный регистр дает нам очень полезную возможность. Мы можем неторопливо заполнять ячейки первого слоя памяти, при этом на выходе регистра всё еще будут старые значения. После того, как мы заполним весь регистр, просто отправим на ST_CP импульс, и выходы регистра одновременно обновятся.

Двухслойная структура регистра пригодится нам в следующем уроке, где нужно будет избавиться от паразитной засветки индикаторов.

Теперь подробнее про алгоритм работы с синхроимпульсами. Вот так выглядит временная диаграмма регистра 74HC595:

shift_register_10_lrg

Необходимо отметить, что порядок следования импульсов очень важен. Сначала мы устанавливаем на выводе DS нужный уровень сигнала, и только потом делаем импульс на SH_CP.

3. Управление восемью светодиодами

Итак, начнем с самого простого. Будем управлять восемью светодиодами, подключенными к Ардуино Уно посредством сдвигового регистра 74HC595. Не будем забывать, что каждому светодиоду необходим токозадающий резистор. Наличие регистра не освобождает нас от этого важного компонента.

Принципиальная схемаardu-595-led_схема

Внешний вид макетаardu-595-led_bb

Программа

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

const int data_pin = 2;
const int sh_pin = 4;
const int st_pin = 3;

int bt = 0;

void shift(byte v){
    for(int i=0; i<8; i++){
        digitalWrite(sh_pin, LOW);
        digitalWrite(data_pin, v & (1 << i ));
        digitalWrite(sh_pin, HIGH);
    }
    digitalWrite(st_pin, HIGH); 
    digitalWrite(st_pin, LOW);
}

void setup() {
    pinMode(data_pin, OUTPUT);
    pinMode(sh_pin, OUTPUT);
    pinMode(st_pin, OUTPUT);
}

void loop() {
    shift(1<<bt);
    bt++;
    if( bt==8 )
        bt = 0;
    delay(200);
}

Для заполнения регистра мы добавили специальную функцию shift. Функция в цикле опускает уровень на SH_CP, затем устанавливает нужный бит на выводе DS, и в конце поднимает SH_CP. Наконец, после завершения цикла, мы делаем импульс на ST_CP для передачи битов на выходы регистра. Всё как во временной диаграмме, которую мы разобрали ранее.

В цикле мы должны перебрать все биты числа v. Сначала взять первый бит, передать его в регистр. Потом второй, потом третий, и т.д. Как это сделать? Разберем вот такую конструкцию:

 v & (1 << i)

переменная v — это восемь бит, которые мы хотим записать в регистр. Операция 1<<i сдвигает единицу на i позиций влево. К примеру, 1<<3 соответствует числу 0000 1000 в бинарном виде. 1<<4 даст уже  0001 0000, и так далее. Назовем результат этой операции трафаретом.

Операция & — это бинарная операция «И». С помощью неё мы как бы накладываем трафарет на число v. Допустим, число v = 0111 0110. На третьем шаге цикла трафарет будет равен 0000 0100. Теперь наложим трафарет и получим что? Получим 1!

0111 0110 & 0000 0100 = 1

На следующей итерации трафарет уже будет равен 0000 1000, наложим теперь его на v:

0111 0110 & 0000 1000 = 0

В общем, мы двигаем единичку в трафарете, и каждый раз накладываем полученный трафарет на число.

Теперь посмотрим на основной цикл:

void loop() {
    shift(1<<bt);
    bt++;
    if( bt==8 )
        bt = 0;
    delay(200);
}

У нас есть итератор bt, который мы меняем вручную, без for. Просто прибавляем каждый раз по единичке, и обнуляем, когда bt увеличится до 8. Самое главное здесь — вызов функции shift. В качестве аргумента функции мы передаем единицу, сдвинутую влево на bt позиций. Этим мы задаем номер зажигаемого светодиода.

Вот как будет выглядеть полученное устройство, в случае использования не отдельных светодиодов, а шкального индикатора из 10 светодиодов. Поскольку сдвиговый регистр 74HC595 позволяет хранить только 8 бит, мы не будем использовать крайние два светодиода.

register595

4. Управление сегментным индикатором

Теперь подключим к Ардуино Уно самый обычный сегментный индикатор. По сути, такой индикатор представляет собой набор светодиодов, выставленных в цифры восемь.

Принципиальная схема

ardu-595_схема

Внешний вид макета

ardu-595_bb

Программа

const int data_pin = 2;
const int sh_pin = 4;
const int st_pin = 3;

int bt = 0;

byte digits[10] = {
    0b00111111, // 0
    0b00000110, // 1
    0b01011011, // 2
    0b01001111, // 3
    0b01100110, // 4
    0b01101101, // 5
    0b01111101, // 6
    0b00000111, // 7
    0b01111111, // 8
    0b01101111, // 9
};

void shift(byte v){
    for(int i=0; i<8; i++){
        digitalWrite(sh_pin, LOW);
        digitalWrite(data_pin, v & (1 << i ));
        digitalWrite(sh_pin, HIGH);
    }
    digitalWrite(st_pin, HIGH); 
    digitalWrite(st_pin, LOW);
}

void setup() {
    pinMode(data_pin, OUTPUT);
    pinMode(sh_pin, OUTPUT);
    pinMode(st_pin, OUTPUT);
}

void loop() {
    shift( digits[bt] );
    bt++;
    if( bt==10 )
        bt = 0;
    delay(500);
}

Каждая цифра на нашем индикаторе — это комбинация сегментов. Например, чтобы зажечь цифру 7 потребуется передать в регистр число  00000111. То есть всего три сегмента: два справа и один сверху. В программе мы создали массив digits, в котором будем хранить комбинации для всех цифр от 0 до 9.

В основном цикле мы будем передавать в функцию shift комбинацию с индексом bt. Как и в предыдущей программе, bt на каждой итерации увеличивается на единицу, пока не достигнет числа 10.

Сдвиговый регистр и сегментный индикатор на Ардуино

Задания

  1. Написать программу для Ардуино, которая будет отображать на линейке светодиодов уровень напряжения на аналоговом входе, к которому подключен переменный резистор. При уровне 0 индикатор не светится. На уровне 512 светится 4 из 8 светодиодов. Все светодиоды светятся при уровне равном 1023.
  2. Соединить два регистра в цепочку, и подключить к ним два сегментных индикатора. Написать программу для Ардуино, которая будет вести обратный отсчет от 99 до 0, с периодом 1 секунда.
  3. Игра «перетягивание каната». В схеме игры присутствуют две кнопки, и линейка светодиодов. В игре участвует два человека. Задач игрока — как можно чаще нажимать на свою кнопку. Чем чаще игрок нажимает кнопку, тем больше в его сторону перетягивается канат. Центр каната отображается горящим светодиодом на линейке. Чем больше его превосходство одного игрока над другим, тем ближе активный светодиод к соответствующему краю линейки. Игра заканчивается, когда активный светодиод достигает края линейки.

Заключение

На этом уроке мы научились работать с регистром 74HC595, который при умелом использовании сильно упрощает работу со светодиодными индикаторами. Согласно изложенной логике, для каждых 8 светодиодов требуется ставить один сдвиговый регистр. Получается, для матрицы, состоящей из 8×8=64 светодиодов нам нужно 8 регистров? Вовсе нет! На следующем уроке мы познакомимся с динамической индикацией. Именно этот метод обычно используется для управления огромными массивами светодиодов. С помощью динамической индикации мы научимся работать с матрицей светодиодов, используя всего два регистра.


Изменено:

Ардуино: всё о сдвиговом регистре: 4 комментария

  1. Очень хотелось бы увидеть на сайте урок с динамической индикацией к примеру 3 семи сегментов и 74HC595

  2. Написать программу для Ардуино, которая будет отображать на линейке светодиодов уровень напряжения на аналоговом входе, к которому подключен переменный резистор. При уровне 0 индикатор не светится. На уровне 512 светится 4 из 8 светодиодов. Все светодиоды светятся при уровне равном 1023. — ПОЖАЛУЙСТА, опубликуйте ответ на это задание (схема, скетч), очень нужно! Спасибо!

  3. Здравствуйте!
    Скажите, а можно ли как-нибудь использовать эту микросхему для размножения вводов? Если да, то как? Если нет, то есть ли микросхемы позволяющие это сделать?

    • Регистр в данном случае не подойдет. Для увеличения количества вводов можно использовать мультиплексор.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *