Иногда из множества устройств нужно выбрать единственное, тогда нам на помощь приходят электронные схемы, преобразующие двоичное число на входе в сигнал на выходе с нужным номером – линейные дешифраторы. Помимо линейных дешифраторов встречаются и другие их виды, например, для зажигания семисегментных индикаторов. В статье же будут рассмотрены только линейные двоичные на примере подключения к Ардуино.
Недавно мне понадобилось сделать жесткое переключение 30 напряжений в блоке питания, кому-то может понадобиться в определенной последовательности включать насосы для полива, а кому-то сделать бегущий «огонек» для визуального оформления витрины. На помощь в таких ситуациях приходят именно линейные дешифраторы. Конечно, функцию выбора можно реализовать напрямую с помощью выходов микроконтроллера, но не будем забывать, что их не так и много, а у Digispark, например, их вообще пообкусывали еще на этапе проектирования, оставив всего 6. Для управления нагрузками через дешифратор выходов МК понадобится значительно меньше: всего log2(количество нагрузок), т.е. два для четырех, три – для восьми, четыре – для 16, пять для 32 и т.д. Плюс еще желательно использовать вход разрешения / стробирования дешифрации, чтобы во время выбора нагрузки не было ложных срабатываний, пока Вы еще не подали нужные сигналы на все входы. В закромах Алиэкспресса готового модуля мне найти не удалось. Хорошо, что самостоятельно такой модуль можно сделать элементарно: достаточно небольшой монтажной платы, «гребенки» разъемов, нескольких коротких проводов и самой микросхемы, паяльные принадлежности и руки. Причем, последние необязательно прямые, и даже расти они могут из центра тяжести. Голова же тут может и вовсе не участвовать – настолько все просто.
Среди моих радиодеталей завалялся 4-х-битный дешифратор К155ИД3 – ТТЛ-ИМС, как раз подходит для подключения напрямую к выводам Ардуино, и питается то же от пяти вольт. У него имеется копеечный зарубежный аналог 74154 (в пределах пары вечно зеленых с учетом доставки).
Кратко разберем работу этой микросхемы. Выходы у нее инверсные, поэтому нагрузку или ключ надо подключать между выходом дешифратора и плюсом питания. Входов всего шесть – два входа при логическом нуле разрешают микросхеме работать, а по четырем в двоичном виде передается номер выбираемого выхода.
Адресные входы имеют номера 23, 22, 21 и 20. (четыре штуки – двоичное число от нуля до 15)
Входы разрешения – 18 и 19 (если логический ноль, то разрешена дешифровка)
Выходы – 1-11 и 13-17 (16 штук)
Итак, подавая на входы 23-20 номер выхода в двоичном виде, а на входы 18 и 19 - низкий логический уровень, получаем на выходе, номер которого передали, низкий логический уровень. Считаются выходы 1-11, 13-17 по порядку нулевой – первая ножка микросхемы, первый – вторая, … 10 – 11, 11 – 13, … 15 – 17.
Для удобства использования я взял монтажную плату 4х6 см2 и развел на ней микросхему на китайскую гребенку. Вывел питание, адресные входы, один разрешающий вход и выходы. Для тестов подключил линейку из 16 светодиодов – анодами к +5В, а катодами через резисторы на 100 Ом к выходам 1-11, 13-17 ИД3. Питание у микросхемы 12 ножка – земля Ардуины, 24-я ножка – +5В Ардуины. Один из разрешающих выводов (19) также подключен к земле. Выводы адресов 23-20 подключил к выводам D2-D5, а второй разрешающий вход (18) – к D6. Проверил правильность пайки, мигая светодиодами. Поскольку в один момент времени мы можем включить только 1 светодиод, то для создания картинки из нескольких светодиодов я использовал принцип динамической индикации: включал все нужные светодиоды последовательно, без задержек и так повторял в течение 10-200мс. Потом менял картинку. Получался обман зрения, как на телевизоре при быстрой смене статических кадров.
Вот код:
//Класс для работы с дешифратором
class XOutput
{
private:
byte D0, D1, D2, D3, E;
public:
//Передаем номера адресных пинов и пина разрешения
XOutput(byte d0, byte d1, byte d2, byte d3, byte e){ D0 = d0; D1 = d1; D2 = d2; D3 = d3; E = e; }
XOutput(){ }
//Устанавливаем пины на вывод, запрещаем микросхеме работать
void begin(){ pinMode(D0, OUTPUT); pinMode(D1, OUTPUT); pinMode(D2, OUTPUT); pinMode(D3, OUTPUT); }
//Передаем номера адресных пинов и пина разрешения, устанавливаем их на вывод, запрещаем микросхеме работать
void begin(byte d0, byte d1, byte d2, byte d3, byte e){ E = e; D0 = d0; D1 = d1; D2 = d2; D3 = d3; pinMode(E, OUTPUT); digitalWrite(E, HIGH); pinMode(D0, OUTPUT); pinMode(D1, OUTPUT); pinMode(D2, OUTPUT); pinMode(D3, OUTPUT); }
//Запрещаем микросхеме работать (чтобы в процессе установки не было ложных срабатываний), устанавливаем номер выхода, разрешаем дешифрацию
void set(byte x){ digitalWrite(E, HIGH); if(x < 16) { digitalWrite(D0, (x & 1) ? HIGH : LOW); digitalWrite(D1, (x & 2) ? HIGH : LOW); digitalWrite(D2, (x & 4) ? HIGH : LOW); digitalWrite(D3, (x & 8) ? HIGH : LOW); digitalWrite(E, LOW); } }
//Последовательно устанавливаем все выходы по значениям битовой маски х
void setMany(unsigned int x){ if( x == 0) { digitalWrite(E, HIGH); return; } unsigned int j = 1; for(byte i = 0; i < 16; i++, j <<= 1) if(x & j) set(i); }
};
XOutput XO;
void setup(void)
{
//Инициализируем дешифратор: адресные входы D2-D5, сигнал разрешения работы - D6
XO.begin(2, 3, 4, 5, 6);
}
//Массив данных для мигания светодиодами (если 1 - светодиод горит)
unsigned int U[] =
{
0b1000000000000001, 0b1100000000000011, 0b1100000000000011,
0b1110000000000111, 0b1110000000000111, 0b1111000000001111,
0b1111100000011111, 0b1111110000111111, 0b1111111001111111,
0b1111111111111111, 0b1111111001111111, 0b1111110000111111,
0b1111100000011111, 0b1111000000001111, 0b1110000000000111,
0b1110000000000111, 0b1100000000000011, 0b1000000000000001,
0b1100000000000011, 0b0011000000001100, 0b0000110000110000,
0b0000001111000000, 0b0000001111000000, 0b0000110000110000,
0b0011000000001100, 0b1100000000000011, 0b1010101010101010,
0b1010101010101010, 0b0010010010010010, 0b0010010010010010,
0b0001000100010001, 0b0000100001000010, 0b0000100001000010,
0b1000000000000000, 0b0100000000000000, 0b0010000000000000,
0b0001000000000000, 0b0000100000000000, 0b0000010000000000,
0b0000001000000000, 0b0000000100000000, 0b0000000010000000,
0b0000000001000000, 0b0000000000100000, 0b0000000000010000,
0b0000000000001000, 0b0000000000000100, 0b0000000000000010,
0b0000000000000001, 0b0000000000000001, 0b0000000000000010,
0b0000000000000100, 0b0000000000001000, 0b0000000000010000,
0b0000000000100000, 0b0000000001000000, 0b0000000010000000,
0b0000000100000000, 0b0000001000000000, 0b0000010000000000,
0b0000100000000000, 0b0001000000000000, 0b0010000000000000,
0b0100000000000000, 0b1000000000000000, //Всего 65
};
byte i = 0;
bool k = 0;
void loop()
{
//Без задержек включаем последовательно по битовой маске все светодиоды, которые должны гореть
XO.setMany(U[i]);
unsigned long t = millis();
//Если подошло время - меняем картинку из включенных светодиодов (здесь примерно каждые 100мс)
if(t % 100 < 30)
{
if(!k)
{
if(++i >= 65) i = 0;
k = true;
}
}else k = false;
}
Ф
Фотографии платы сразу после пайки еще с флюсом:
Вот видео работы дешифратора:
P.s. Используя два таких модуля, и инвертировав выходы на одном из них, можно управлять светодиодной матрицей 16х16. Увеличив число модулей до четырех – уже матрицей 32х32 и т.д.
Если статья заинтересовала, то пишите в комментариях. Расскажу, как соединять дешифраторы блоками для управления еще большим количеством нагрузок или как управлять мощной нагрузкой. Могу объяснить подробнее непонятный участок. Задавайте вопросы!