Сколькими светодиодами можно управлять с помощью одного 8-ми битного порта микроконтроллера/ПЛИС без применения каких-либо микросхем? 16-ю, скажете вы? Пятьюдесятью шестью, скажу я
Если между любыми двумя (из N) портами МК/ПЛИС подключить 2 светодиода встречно-параллельно, то всего получится N·(N-1) = 8·7 = 56 светодиодов. Получится вот такая матрица:
Индикация, естественно, динамическая. Коэффициент мультиплексирования 1/8. Изображение может выводится как построчно по схеме с «общим катодом» (ОК), так и по столбцам по схеме с «общим анодом» (ОА).
Для поджига одного светодиода необходимо установить порт, к которому он подключен катодом (строку) на вывод лог. «0», анодом (столбец) — на вывод лог. «1», остальные порты перевести в третье состояние (ввод).
Кстати, нумерация светодиодов на картинке не очень информативна: С1-1 подключен между СА1 и СА2, а светодиод С1-2 между СА1 и СА3. Применительно к МК я бы обозначил светодиоды так:
И нумерация от 0 до 7, и видно какой светик куда подключен (первая цифра показывает к какому порту подключен катод, вторая — анод). Коты постарше заметят, что это похоже на индексы элементов квадратной матрицы 8×8, у которой «удалили» главную диагональ и «сдвинули» две половины.
Допустим, мы хотим вывести изображение. Для его хранения хватит 7 байт (хранить по столбцам), однако проще отвести 8 байт и хранить по строкам, дополнив 7 бит не несущим информации, например, старшим «нулём». Итак, у нас есть 8 байт, содержащие 56 бит изображения. Пусть это будет вот такая «рожица»:
Соответственно, в памяти хранится:
0b00001000 (№1)
0b00110110 (№2)
0b00100010 (№3)
0b01010101 (№4)
0b01000001 (№5)
0b00101010 (№6)
0b00110110 (№7)
0b00001000 (№8)
Изображение (кадр) выводится за 8 шагов, на каждом i-том шаге только один i-тый порт (i-тая строка) устанавливается на вывод лог. «0», остальные 7 — лог. «1» или третье состояние. Поэтому перед непосредственным выводом изображения в порт его необходимо преобразовать, либо хранить уже готовым для вывода. Второй вариант плох тем, что пропадает возможность «двигать» изображение и хранимая информация «не наглядна». Суть преобразования — вставка «0» (не замена, а именно вставка, т.е. со сдвигом) в i-тый бит информационного байта на i-том шаге.
Гениально (на мой взгляд) компактный код предложил Kavka:
Код: Выделить всё
ldi mask, 0b11111111; загружаем маску
shift:; цикл
ld data, X; загружаем откуда-то (флэш/ОЗУ) инф. байт
mov tmp, data; копируем
and tmp, mask; делаем лог. «И» копии и маски
add data, tmp; складываем инф. байт с его маскированной копией
st X+, data; результат сохраняем
lsl mask; сдвигаем максу влево
brne shift; условие выхода из цикла — обнуление маски!В результате получим:
0b00010000 (№1)
0b01101100 (№2)
0b01000010 (№3)
0b10100101 (№4)
0b10000001 (№5)
0b01001010 (№6)
0b00110110 (№7)
0b00001000 (№8)
Всё. Это можно выбрасывать в порт (PORTX) и направление порта (DDRX), не забывая устанавливать в «1» соответствующий битик DDR:
На выходе должно получиться так:
По даташитам AVRки выдерживают суммарный ток 200 мА при максимальном токе на пин 40 мА. 200 мА на 7 одновременно горящих светодиодов будет 28.5 мА, а с учётом мультиплексирования максимальное время горения будет 1/8, т.е. максимальный средний ток через светодиод будет 3.5 мА.
Однако можно умощнить вывод с сохранением третьего состояния. Например, вот такой схемой на четырёх транзисторах и двух диодах, предложенной Goldsmith:
Для ограничения тока через светодиод можно использовать параллельно включённые резистор и диод: резистор будет ограничивать вытекающий ток (когда порт будет анодом), а диод будет шунтировать его для втекающего тока (когда порт — общий катод).
