Благодаря заметке Два способа мультиплексирования светодиодов на примере микроконтроллеров AVR мы с вами знаем, что можно управлять сотней светодиодов, используя всего лишь 11 пинов микроконтроллера. Но что делать, если нужно управлять двумястами или, скажем, тысячью светодиодами? Оказывается, что изученные способы мультиплексирования могут быть улучшены, да так, что используя всего лишь три пина микроконтроллера можно управлять абсолютно любым количеством светодиодов! И в этом нам помогут следующие микросхемы.

Примечание: Если вы пропустили предыдущий пост, посвященный микросхемам 74xx, вот он — Интегральные схемы: чипы стандартной логики 74xx . Впрочем, тот пост был посвящен логическим вентилям, и для понимания представленного далее материала читать его не требуется.

SIPO сдвиговый регистр 74HC595

Сдвиговые регистры — это микросхемы, позволяющие, очень грубо говоря, добавить пинов вашему микроконтроллеру. Для добавления пинов на запись, используются SIPO сдвиговые регистры. SIPO означает «последовательный вход, параллельный выход». Если же нужно больше пинов на чтение, используются сдвиговые регистры PISO, «параллельный вход, последовательный выход». В данном разделе мы познакомимся с типичным SIPO сдвиговым регистром, 74HC595.

Какой пин 74HC595 для чего предназначен, можно узнать из даташита [PDF] :

SIPO сдвиговый регистр 74HC595

Если коротко, то:

  • VCC, GND — это питание.
  • OE — разрешение вывода. Чтобы вывод был всегда разрешен, можно подключить этот пин напрямую к минусу.
  • SRCLR — сброс. Если не используется, то нужно подключить напрямую к плюсу.
  • SER, SRCLK — используются для передачи данных. При подаче высокого напряжения на SRCLK происходит считывание одного бита данных с пина SER.
  • RCLK — при подаче сюда высокого напряжения происходит одновременный вывод принятых данных на параллельные выходы.
  • Qa-Qh — параллельные выходы. Сюда происходит вывод последних восьми полученных бит при подаче высокого напряжения на SRCLK.
  • Qh’ — при получении очередного бита информации и смещении значений по параллельным выходам бит Qh на самом деле не отбрасывается, а поступает на этот пин. Подключив его к пину SER другого сдвигового регистра, а также соединив выходы RCLK и SRCLK обоих сдвиговых регистров, можно получить 16-разрядный сдвиговый регистр. Второй сдвиговый регистр в свою очередь можно соединить с третьим и так далее, получив сколь угодно разрядный регистр сдвига.

Надеюсь, идея ясна — мы последовательно передаем на сдвиговый регистр восемь бит информации по одному биту. Затем сдвиговый регистр параллельно выводит полученные биты на восемь пинов. Отсюда и «последовательный вход, параллельный выход».

Пример кода:

const uint8_t hc595_data = 6 ; /* SER */
const uint8_t hc595_latch = 7 ; /* RCLK */
const uint8_t hc595_clock = 8 ; /* SRCLK */

/* … */

void setup ( )
{
pinMode ( hc595_data, OUTPUT ) ;
pinMode ( hc595_latch, OUTPUT ) ;
pinMode ( hc595_clock, OUTPUT ) ;

/* … */
}

/* … */

void loop ( )
{
/* … */
digitalWrite ( hc595_latch, LOW ) ;
shiftOut ( hc595_data, hc595_clock, MSBFIRST, hc595_out ) ;
digitalWrite ( hc595_latch, HIGH ) ;
/* … */
delay ( 100 ) ;
}

Нам даже не нужно писать никаких циклов. В Arduino уже предусмотрена готовая процедура shiftOut , которая делает все за нас.

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

Существует похожий чип 74HC164, который имеет 14 пинов вместо 16-и. В нем отсутствует пин переноса (аналог Qh’). Даташит 74HC164 доступен здесь [PDF] .

PISO сдвиговый регистр 74HC165

Типичным представителем PISO сдвиговых регистров является 74HC165.

Картинка из даташита [PDF] :

PISO сдвиговый регистр 74HC165

Назначение пинов:

  • VCC, GND — питание.
  • A-H — входы сдвигового регистра.
  • SH — когда на этом пине низкое напряжение, происходит считывание данных с пинов A-H.
  • CLK INH — что-то делает только при высоком напряжении на SH. Низкое напряжение означает разрешить использование часов (пин CLK). На практике можно подключить напрямую к земле.
  • CLK — когда на SH высокое напряжение и на CLK INH низкое, при подаче на CLK низкого напряжения происходит сдвиг данных.
  • Qh — выход сдвигового регистра. Одноименный выход с чертой — это инвертированный выход.
  • SER — при очередном сдвиге освободившийся бит принимает значение, поданное на этот пин. Пин может быть задействован при одновременном использовании нескольких сдвиговых регистров. Или можно просто подключить к земле.

Пример кода, считывающего состояние восьми кнопок, используя всего лишь три пина:

const uint8_t hc165_data = A5 ; /* QH */
const uint8_t hc165_latch = A4 ; /* SH */
const uint8_t hc165_clock = A3 ; /* CLK */

/* … */

void setup ( )
{
/* … */

pinMode ( hc165_data, INPUT ) ;
pinMode ( hc165_clock, OUTPUT ) ;
pinMode ( hc165_latch, OUTPUT ) ;
}

uint8_t shiftIn165 ( uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder )
{
uint8_t value = 0 ;
uint8_t i ;

for ( i = 0 ; i < 8 ; ++ i )
{
digitalWrite ( clockPin, LOW ) ;
if ( bitOrder == LSBFIRST )
value | = digitalRead ( dataPin ) << i ;
else
value | = digitalRead ( dataPin ) << ( 7 i ) ;
digitalWrite ( clockPin, HIGH ) ;
}

return value ;
}

void loop ( )
{
digitalWrite ( hc165_latch, LOW ) ;
delayMicroseconds ( 5 ) ;
digitalWrite ( hc165_latch, HIGH ) ;
delayMicroseconds ( 5 ) ;

hc595_out = shiftIn165 ( hc165_data, hc165_clock, MSBFIRST ) ;

/* … */

delay ( 100 ) ;
}

Встроенная процедура shiftIn для работы с 74HC165, к сожалению, не годится, так в ней используется обратный порядок подачи сигналов LOW и HIGH на clockPin. Поэтому в приведенном коде используется собственная реализация с правильным порядком.

Декодер / демультиплексор 74HC138

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

Вот иллюстрация из его даташита [PDF] :

Декодер / демультиплексор 74HC138

Назначение пинов:

  • VCC, GND — питание.
  • A, B, C — три бита входа.
  • Y0-Y7 — выход. Если на вход подан ноль в бинарном представлении, на Y0 будет подано низкое напряжение, а на все остальные выходы высокое. Если подана единица в бинарном представлении, на Y1 будет низкое напряжение, а на всех остальных выходах высокое, и так далее.
  • G1, G2A, G2B — разрешение вывода. Чтобы на выходах Y0-Y7 было что-то осмысленное, на G1 должно быть подано высокое напряжение, а на G2A и G2B — низкое. Иначе на всех выходах Y0-Y7 будет высокое напряжение независимо от входов A, B и C. Пины G2A и G2B можно просто подключить к земле.

Пример кода:

const uint8_t hc138_a = 5 ;
const uint8_t hc138_b = 4 ;
const uint8_t hc138_c = 3 ;
const uint8_t hc138_enable = 9 ;

/* … */

uint8_t hc138_out = 0 ;

void setup ( )
{
/* … */

pinMode ( hc138_a, OUTPUT ) ;
pinMode ( hc138_b, OUTPUT ) ;
pinMode ( hc138_c, OUTPUT ) ;
pinMode ( hc138_enable, OUTPUT ) ;

/* … */
}

/* … */

void loop ( )
{
/* … */

digitalWrite ( hc138_enable, LOW ) ;
digitalWrite ( hc138_a, hc138_out & ( 1 << 0 ) ) ;
digitalWrite ( hc138_b, hc138_out & ( 1 << 1 ) ) ;
digitalWrite ( hc138_c, hc138_out & ( 1 << 2 ) ) ;
digitalWrite ( hc138_enable, HIGH ) ;
hc138_out = ( hc138_out + 1 ) & B00000111 ;

delay ( 100 ) ;
}

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

Существует также чип 74HC154. Он аналогичен по функциональности, но более громоздок и является четырехбитным. Его даташит можно полистать здесь [PDF] .

Как несложно догадаться, если есть демультиплексоры, значит бывают и мультиплексоры. Они в каком-то смысле аналогичны PISO сдвиговым регистрам, так как позволяют увеличить количество читающих пинов микроконтроллера. В качестве примеров можно привести чипы 74HC151 и 74HC153. Их даташиты доступны, соответственно, здесь [PDF] и здесь [PDF] .

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

Полная версия кода

Вы, конечно же, поняли, что приведенные выше отрывки кода являются частью одной программы. Вот ее полный исходный код:

#include <Arduino.h>

const uint8_t hc595_data = 6 ; /* SER */
const uint8_t hc595_latch = 7 ; /* RCLK */
const uint8_t hc595_clock = 8 ; /* SRCLK */

const uint8_t hc138_a = 5 ;
const uint8_t hc138_b = 4 ;
const uint8_t hc138_c = 3 ;
const uint8_t hc138_enable = 9 ;

const uint8_t hc165_data = A5 ; /* QH */
const uint8_t hc165_latch = A4 ; /* SH */
const uint8_t hc165_clock = A3 ; /* CLK */

uint8_t hc595_out = 0 ;
uint8_t hc138_out = 0 ;

void setup ( )
{
pinMode ( hc595_data, OUTPUT ) ;
pinMode ( hc595_latch, OUTPUT ) ;
pinMode ( hc595_clock, OUTPUT ) ;

pinMode ( hc138_a, OUTPUT ) ;
pinMode ( hc138_b, OUTPUT ) ;
pinMode ( hc138_c, OUTPUT ) ;
pinMode ( hc138_enable, OUTPUT ) ;

pinMode ( hc165_data, INPUT ) ;
pinMode ( hc165_clock, OUTPUT ) ;
pinMode ( hc165_latch, OUTPUT ) ;
}

uint8_t shiftIn165 ( uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder )
{
uint8_t value = 0 ;
uint8_t i ;

for ( i = 0 ; i < 8 ; ++ i )
{
digitalWrite ( clockPin, LOW ) ;
if ( bitOrder == LSBFIRST )
value | = digitalRead ( dataPin ) << i ;
else
value | = digitalRead ( dataPin ) << ( 7 i ) ;
digitalWrite ( clockPin, HIGH ) ;
}

return value ;
}

void loop ( )
{
digitalWrite ( hc165_latch, LOW ) ;
delayMicroseconds ( 5 ) ;
digitalWrite ( hc165_latch, HIGH ) ;
delayMicroseconds ( 5 ) ;

hc595_out = shiftIn165 ( hc165_data, hc165_clock, MSBFIRST ) ;

digitalWrite ( hc595_latch, LOW ) ;
shiftOut ( hc595_data, hc595_clock, MSBFIRST, hc595_out ) ;
digitalWrite ( hc595_latch, HIGH ) ;

digitalWrite ( hc138_enable, LOW ) ;
digitalWrite ( hc138_a, hc138_out & ( 1 << 0 ) ) ;
digitalWrite ( hc138_b, hc138_out & ( 1 << 1 ) ) ;
digitalWrite ( hc138_c, hc138_out & ( 1 << 2 ) ) ;
digitalWrite ( hc138_enable, HIGH ) ;
hc138_out = ( hc138_out + 1 ) & B00000111 ;

delay ( 100 ) ;
}

Фотография соответствующего прототипа на макетной плате:

Пример использования сдвиговых регистров и демультиплексоров

Используемые чипы слева направо — микроконтроллер ATmega328P, SIPO сдвиговый регистр 74HC595, демультиплексор 74HC138, PISO сдвиговый регистр 74HC165. Состояние восьми кнопок считывается через 74HC165. Светодиоды слева, соответствующие нажатым кнопкам, не горят, а отпущенным — горят. Состояние этих светодиодов контролируется через 74HC595. На фото я зажал три правые кнопки карандашом и потому три соответствующих им светодиода не горят. Еще восемь светодиодов справа контролируются демультиплексором 74HC138. Их состояние зависит только от времени, по очереди гаснет один светодиод.

Примечание: Вас могут заинтересовать статьи Как собрать Arduino прямо на макетной плате и Собираем USB-программатор для AVR из ATmega328P и FT232 .

Заключение

Еще из интересных чипов стоит упомянуть шинный формирователь 74HC244. Это штука, которая может как бы отрезать одну часть цепи от другой. Если добавить в цепь 74HC04 (логическое НЕ), то при помощи 74HC244 можно будет использовать одни и те же пины для работы с SIPO и PISO сдвиговыми регистрами, плюс один пин для переключения между ними. Итого, если микроконтроллер имеет четыре пина, он может работать с любым количеством кнопок и светодиодов. У самого маленького известного мне микроконтроллера ATtiny13 целых пять свободных пинов, что позволяет обойтись и без 74HC04. Подробности о 74HC244 ищите в даташите [PDF] , там все очень просто.

Также заслуживает внимания чип 74HC4051. Эта штука позволяет соединить аналоговый канал с любым из 8 других аналогвых каналов, или разъединить их все. Мне нравится думать о 74HC4051, как о переключателе, управляемом программного. Подробности — в даташите [PDF] .

В контексте увеличения числа пинов микроконтроллера стоит также упомянуть чипы MCP23017 / MCP23S17 [PDF] и специализированные чипы для управления светодиодными матрицами вроде MAX7221 [PDF] . Интересны они тем, что предлагая функциональность, аналогичную функциональности сдвиговых регистров и декодеров, могут занимать меньше места на плате. Если же вы хотите увеличить числ ШИМ-пинов, обратите внимание на микросхему TLC5940 ( видеообзор , библиотека ). Однако обсуждение данных микросхем уже сильно выходит за рамки данного поста. Вы без труда сможете изучить их самостоятельно в качестве домашнего задания.

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

Дополнение: Вас также могут заинтересовать посты Знакомство с компараторами на примере чипа LM339 и Изучаем работу операционного усилителя на примере NE5532 .

EnglishRussianUkrainian