Arduino: LED матрица
Пакет поддержки Arduino: цифровые выходы - светодиодная матрица
Продолжаем работать с цифровыми выходами Arduino - в этот раз задействуем уже 16 пинов Arduino MEGA, подключая их к LED матрице 1088BS для вывода бинарных изображений.
Введение
В предыдущих примерах мы уже рассмотрели работу с цифровыми выводами - в примере Blink и примере с семисегментным индикатором. При помощи LED матриц в этом примере мы идём по пути повышения мерности отображаемых дискретных данных.
Мы используем тот же микроконтроллер Arduino MEGA и светодиодную матрицу 8x8 1088BS. Также понадобятся 2 макетные платы, 8 резисторов 330 Ом и соединительные провода.
Аппаратная часть
Устройство для этого примера соберём согласно представленной ниже схеме соединений:

Для удобства сборки можно опираться на таблицу подключений:
|
№ контакта 1088BS |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
|
Обозначение контакта |
R5 |
R7 |
C2 |
C3 |
R8 |
C5 |
R6 |
R3 |
R1 |
C4 |
C6 |
R4 |
C1 |
R2 |
C7 |
C8 |
|
№ пина Arduino |
34 |
36 |
41 |
42 |
37 |
44 |
35 |
32 |
30 |
43 |
45 |
33 |
40 |
31 |
46 |
47 |
Контакты с приставкой R (rows) отвечают за подачу в строку светодиодов с заданным номером высокого уровня напряжения. Напряжение на них подаётся через токоограничивающие резисторы
Контакты с приставкой C (columns) отвечают за подачу в колонку светодиодов с заданным номером низкого уровня напряжения.
Особенности управления
Чтобы по одному измерению матрицы гарантированно загорались все необходимые светодиоды из заданного изображения, необходимо реализовать динамическую индикацию. В случае LED матрицы это означает, что в один момент времени будет возможно зажечь требующиеся светодиоды только в одном столбце.
Статичность изображения таким образом достигается за счёт высокой частоты переключения между столбцами - такие переключения (мерцания) перестают быть видимы невооружённым взглядом.
Кроме того, чтобы при переключении не создавалось размытого изображения, необходимо между включениями столбцов сделать паузу, когда светодиоды не зажигаются. Это позволит выдержать необходимое время для гашения светодиодов на предыдущем шаге.
Также, для удобства кодирования изображения удобнее всего использовать заданные номера строк и колонок матрицы. Это позволит нам задавать только координаты точек, а их интерпретацию в набор битов выполнит наша модель.
Модель примера
Так, в модели примера:

кодирование координат выполняется следующим образом:
- На блоки дискретных выходов, соответствующих колонкам C1 - C8 передаётся вектор битов
columns_code(начиная со старшего бита). - Этот вектор инвертирован при помощи блоков
BiasиUnary minus, так как в колонках матрицы за зажигание светодиода отвечает низкий уровень напряжения. - Вектор битов вычисляется блоком
Integer to Bit Convertor, при этом входное целое число - это десятичное представление числа, которое побитно разделяется в итоговый вектор. - Это число определяется в интерполяционной таблице согласно следующему вектору значений:
Y = 2 .^ (7:-1:0)
также в интерполяционной таблице нулевому значению входа соответствует нулевое выходное значение.
- Для динамической индикации (последовательного переключения столбцов) используется блок
on_column. В нём задаётся значение включаемого столбца на текущем шаге и шаг дискретизации для определения скорости переключения между столбцами. - Дополнительно, для того, чтоб изображение не было смазанным, в последовательности включаемых столбцов между этими значениями передаются нули - для гашения всех столбцов.
- Также, блок
on_columnпередаёт свои значения на управляющий вход блокаmultipirtswitchдля передачи последовательности, которая определяет строки с загорающимися светодиодами для текущего столбца. - Далее, выбранная последовательность аналогично проходит через интерполяционную таблицу, на выходе которой все значения выходной последовательности суммируются. Затем определяется последовательность битов, которая зажжёт или погасит светодиоды в текущем столбце.
- Эта последовательность побитово передаётся на цифровые выходы Arduino, блоки R1 - R8.
Кодируемое изображение
Строки, в которых должны быть зажжены светодиоды, определены в блоках Constant на входах данных блока multiportswitch. Номера строк мы зададим согласно кодируемому изображению. Для матрицы 8×8, например, логотип платформы Engee можно представить в следующем упрощённом виде:

Отсюда, данные последовательностей в строках для блоков Constant можно определить таким образом:
Col1 = zeros(8)
Col2 = vcat(zeros(5), [3,4,6])
Col3 = vcat(zeros(4), [2,3,6,7])
Col4 = vcat(zeros(6), [2,7])
Col5 = vcat(zeros(7), [7])
Col6 = vcat(zeros(4), [2,3,6,7])
Col7 = vcat(zeros(4), [3,4,5,6])
Col8 = zeros(8);
Здесь, вектора дополняются нулями для сохранения размерности выходного значения. Дополняемые нулями вектора содержат номера строк, в которых для заданного столбца должен зажигаться светодиод.
Подготовка
При помощи этого блока кода автоматизируем запуск серверной программы Engee.Интеграции:
import .engee.package as epkg
const PKGNAME = "Engee-Device-Manager"
function epkg_start(pkg::String)
if !epkg.isinstalled(pkg)
@info "Package not installed. Installing and Starting..."
epkg.install(pkg)
@info "Package is up to date. Starting..."
println("Ссылка для подключения к серверу:\n"*epkg.start(pkg))
else
updates = epkg.checkupdates(pkg)
if isnothing(updates)
@info "Package is up to date. Starting..."
println("Ссылка для подключения к серверу:\n"*epkg.start(pkg))
else
@info "Updates available. Reinstalling and Starting..."
epkg.update(pkg)
@info "Package is up to date. Starting..."
println("Ссылка для подключения к серверу:\n"*epkg.start(pkg))
end
end
end
epkg_start(PKGNAME)
Также за кадром, как обычно, запустим клиентскую программу Engee.Интеграции и подключим наше устройство.
Выполнение модели
Теперь перейдём к выполнению модели. Запустим её в независимом режиме, так как Arduino в пакете поддержке имеется физическое ограничение в частоте дискретизации выполняемой модели из-за особенностей платформы. Ограничение периода дискретизации установлено на уровне 20 мс, тогда как для полноценной динамической индикации в этой модели требуется 100 мкс.
Как влияет частота дискретизации модели на статичность изображения при динамической индикации, хорошо видно на записи ниже.
Также, итоговый результат работы в виде статического изображения:

Ещё одна особенность текущей модели в сравнении с предыдущими из начальных примеров - порты блоков периферии Arduino, а также константы и преобразования в модели оптимизированы с точки зрения достаточных для работы типов данных - по максимуму используется тип UInt8, в том числе, в блоках CFunction периферии Arduino.
Заключение
В этом примере мы смогли задействовать ещё больше цифровых выходов Arduino MEGA. Так мы смогли из модели Engee управлять динамической индикацией на LED матрице 1088BS с выводом бинарного изображения.