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

Программа
Программа будет последовательно зажигать каждый из светодиодов. Для хранения номера горящего светодиода используем переменную bt типа byte.
const int data_pin = 2;
const int sh_pin = 4;
const int st_pin = 3;
b bt = 0;
// функция, которая выводит байт в регистр побитно
void shift(byte v){
// перебираем все биты байта
// для каждого бита опускаем уровень на SH_CP
// выставляем нужный уровень на DS
// и обратно поднимаем SH_CP
// всё строго с диаграммой
for(int i=0; i<8; i++){
digitalWrite(sh_pin, LOW);
digitalWrite(data_pin, v & (1 << i ));
digitalWrite(sh_pin, HIGH);
}
// отправляем финальный импульс на контакт ST_CP
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, передавая в неё очередной байт
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. Теперь наложим трафарет и получим:
0111 0110 & 0000 0100 = 0000 0100 = истина
Тут следует уточнить, что в языке C++, как и во многих других языках, любое отличное от нуля число интерпретируется как «истина» или логическая единица. digitalWrite интерпретирует эту логическую единицу как высокий уровень сигнала, что нам и требуется!
На следующей итерации трафарет уже будет равен 0000 1000, наложим теперь его на v:
0111 0110 & 0000 1000 = 0000 0000 = ложь
В общем, мы двигаем единичку в трафарете, и каждый раз накладываем полученный трафарет на число.
Теперь посмотрим на основной цикл:
void loop() {
shift(1<<bt);
bt++;
if( bt==8 )
bt = 0;
delay(200);
}
У нас есть итератор bt, который мы меняем вручную, без for. Просто прибавляем каждый раз по единичке, и обнуляем, когда bt увеличится до 8. Самое главное здесь — вызов функции shift. В качестве аргумента функции мы передаем единицу, сдвинутую влево на bt позиций. Этим мы задаем номер зажигаемого светодиода.
Вот как будет выглядеть полученное устройство, в случае использования не отдельных светодиодов, а шкального индикатора из 10 светодиодов. Поскольку сдвиговый регистр 74HC595 позволяет хранить только 8 бит, мы не будем использовать крайние два светодиода.
Очень хотелось бы увидеть на сайте урок с динамической индикацией к примеру 3 семи сегментов и 74HC595
Написать программу для Ардуино, которая будет отображать на линейке светодиодов уровень напряжения на аналоговом входе, к которому подключен переменный резистор. При уровне 0 индикатор не светится. На уровне 512 светится 4 из 8 светодиодов. Все светодиоды светятся при уровне равном 1023. — ПОЖАЛУЙСТА, опубликуйте ответ на это задание (схема, скетч), очень нужно! Спасибо!
int sh_cp = 10; //назначаем выводы сдвигового регистра
int st_cp = 9; //назначаем выводы сдвигового регистра
int ds = 8; //назначаем выводы сдвигового регистра
int potvalue = 0; //переменная для значения потенциометра
void setup() {
pinMode(sh_cp, OUTPUT); //задаем выходы ардуины для сдвигового регистра
pinMode(st_cp, OUTPUT); //задаем выходы ардуины для сдвигового регистра
pinMode(ds, OUTPUT); //задаем выходы ардуины для сдвигового регистра
pinMode(A0, INPUT); //задаем вход ардуины для потенциометра
}
void loop() {
potvalue = analogRead(A0); //читаем значение потенциометра
potvalue = map(potvalue, 0, 1023, 0, 8); //масштабируем значение на 8 светодиодов, т.е. получаем количество горящих светодиодов
potvalue = (1<<potvalue)-1; // переводим количесвто светодиодов в степень числа 2 минус 1. Используем сдвиг, т.к. функция pow работает не корректно
digitalWrite(st_cp, LOW); // установка синхронизации "защелки" на LOW
shiftOut(ds, sh_cp, MSBFIRST, potvalue); // передаем последовательно на вход данных сдвигового регистра
digitalWrite(st_cp, HIGH); //"защелкиваем" регистр, устанавливаем значения на выходах
delay(500);//
}
схема типовая, выводы подключения регистра и потенциометра видны из скетча
Здравствуйте!
Скажите, а можно ли как-нибудь использовать эту микросхему для размножения вводов? Если да, то как? Если нет, то есть ли микросхемы позволяющие это сделать?
Регистр в данном случае не подойдет. Для увеличения количества вводов можно использовать мультиплексор.
Есть ещё регистр 74HC165, как раз для этого предназначенный:
http://amperka.ru/product/74hc165-shift-in-register
Да, действительно, входной регистр может помочь!
Немного запутанная функция передачи бит в регистр, может можно использовать стандартную функцию shiftOut() без цикла for ?
digitalWrite(st_pin,LOW);
shiftOut(data_pin,sh_pin,MSBFIRST,v);
digitalWrite(st_pin,HIGH);
Можно и так. Также можно использовать аппаратный SPI, будет еще быстрее. Можно использовать готовые функции для регистра. Но в данном уроке хотело раскрыть суть побитового заполнения регистра, для этого и цикл.
Вот такой код работает правильно:
digitalWrite(st_pin,LOW);
shiftOut(data_pin,sh_pin,LSBFIRST,v);
digitalWrite(st_pin,HIGH)
не работает ваш скетч выводит какие то кракозябры
data_pin, v & (1 << i ) вот в этой строчке результат не будет только 0 или один. Он может быть 0, 1, 2, …. и так далее. Но, я так понял, что любой результат, больший 0 приравнивается к сигналу HIGH.
Спасибо, полезная информация. Единственная придирка в том ,что двоичную арифметику стоило объяснить без лишних упрощений, более корректно. Из вашего объяснения можно подумать, что A & (1 << B) всегда равно либо 1, либо 0. Однако правильный ответ — степени двойки (в том числе и 0 и 1). Другое дело, что для digitalWrite все что не равно нулю это HIGH, что делает ваше объяснение верным с точки зрения этой функции, но с точки зрения битовой арифметики оно все равно не очень корректно и может запутать. Повторюсь, это лишь придирка.
Вы пишите:
————————————
Теперь наложим трафарет и получим что? Получим 1!
0111 0110 & 0000 0100 = 1
————————————
Но ведь:
0111 0110 & 0000 0100 = 0000 0100
Другое дело, что в результате важно логическое значение: 0 или не 0.
Двусмыслие устранили, спасибо за комментарий!
Можно и без всяких уточнений написать такой код:
digitalWrite (data_pin, (v>>i) & 1);
Добрый день, спасибо за статью, потихоньку осваиваю ардуино, но с кодом так и не разберусь, так как если подключить по Вашей схеме, и залить данный скетч на поочередное включение диодов, то результат каша, диоды мигают как хотят, но вот если поменять входы 3 и 4 на ардуино местами, то все работает как надо. Долго смотрел где неверно собрал, ничего, может тут ошибка?
Хочу с помощью сдвигового регистра собрать шаговый искатель на карусельный станок. Переключение по одной скорости получилось прекрасно, но набор скорости по ступеням по возрастанию или убыванию пока не получается. Чувствую что нужно применить метод типа устранения дребезга контактов, но опыта не хватает. Может быть кто-нибудь подскажет програмку для осуществления моей идеи, буду благодарен.
Народ. Подскажите, как через сдвиговый регистр 74HC595 принимать данные?
Я знаю что нужно использовать другой сдвиговый регистр, но можно ли этот перенаправить
Этот нельзя, нужен 74HC165
https://shop.robotclass.ru/index.php?route=product/product&product_id=1169
Я знаю что нужен этот регистр. Я посмотрел много сайтов, но нигде нормально не объясняется как его запрограммировать. Если можешь подскажи как на ардуино запрограммировать, без библиотеки episode.
Библиотека spi
Большое спасибо!
Где на схеме 74РС595 вот это:
Out3, Out4 — выводы для подключения второго двигателя?
И почему нет описания 10-й ноги MR?
про » Out3, Out4 — выводы для подключения второго двигателя» — это опечатка, я так понял — не отредактировали ранее выбранное описание блока
Поправили, спасибо!
Для последовательного соединения ногу №9 (Q7′) разве с Q0 надо соединять?
А не с ногой ввода данных DS?
да…. так и есть
я весь мозг себе сломал, знакомясь по вашей статье с регистрами: «почему же у меня каскад не работает???»
будьте любезны: исправьте, что Q7′ соединяется с DS а не с Q0
и неплохо бы было дописать что в каскаде регистров надо паралелить ноги ST_CP и SH_CP — не для всех это очевидно…. ну и дописать как работают ноги MR и OE — это всё пришлось узнавать из других статей
Спасибо, исправили! Про ST_CP и SH_CP тоже полезное замечание. Расширим урок примером каскада.
Может не так понял, Но пункт 3 «Необходимо отметить, что порядок следования импульсов очень важен. Сначала мы устанавливаем на выводе DS нужный уровень сигнала, и только потом делаем импульс на SH_CP. » то есть после того как установили нужные данные на DS и потом для «сохранения» подаем импульс.. тут разве SH_PD ?? просто абзацем выше написано «После того, как мы заполним весь регистр, просто отправим на ST_CP импульс, и выходы регистра одновременно обновятся. «
Что за переменная bt?
Пожалуйста, пишите в программе комментарии.
Ниже есть описание кода, в том числе и переменной bt.
Комментарии тоже добавили!