Опубликовано: 26.11.2016 18:31
Автор: jazon
В этой статье мы решили дать полную обзорную информацию по библиотеке LedControl.h и разобрать примеры использования её функций. Эта библиотека была написана для работы с микросхемами MAX7219 и MAX7221. Многим программистам - электронщикам которые занимаются с платформой Arduino всегда было интересно, как включаются массивы светодиодов заключенные в одну матрицу, как анимировать матрицы, как управлять семисегментными многоразрядными дисплеями. Используя библиотеку LedControl, мы получаем отличный инструмент для работы с упомянутыми устройствами. На нашем сайте уже было несколько интересных статей, в которых в той или иной мере мы работали с этой библиотекой, ниже в конце статьи будут ссылки на них. А здесь мы постараемся обобщить пройденный материал, и закрепить знания полученные в работе с этой библиотекой.
Пора начинать... А начнем мы с того, что создадим объект класса LedControl. Типичный код инициализации библиотеки будет выглядеть следующим образом:
/* Для начала подключим библиотеку */
#include "LedControl.h"
/* Создаём объект класса LedControl
* Используем пины 12, 11, 10 на плате Arduino в качестве SPI интерфейса
* для драйвера MAX7219
*
* Подключаем устройства согласно таблице:
* Arduino[Pin 12] <-> Display Module MAX7219 [DIN]
* Arduino[Pin 11] <-> Display Module MAX7219 [CLK]
* Arduino[Pin 10] <-> Display Module MAX7219 [LOAD/CS]
*
* Прототип создания объекта класса LedControl:
* LedControl(int dataPin, int clkPin, int csPin, int numDevices);
* где:
* int dataPin - пин 12 на плате Arduino
* int clkPin - пин 11 на плате Arduino
* int csPin - пин 10 на плате Arduino
* int numDevices - количество устройств на шине SPI
*/
/*В данном случае подключено одно устройство*/
LedControl LC = LedControl(12, 11, 10, 1);
Вообще, при подключении устройств с драйвером MAX72xx можно использовать любые пины на плате Arduino, но так как есть входы/выходы которые используются для последовательного соединения(пины 0 и 1), а также порты которые имеют в своей связке светодиодный индикатор(пин 13), то лучше избегать подключения к этим портам выбрав любые другие доступные. Также, порты указанные в объявлении объекта класса, не нужно инициализировать функцией pinMode() в разделе setup() программы, библиотека LedControl при создании объекта класса сама проинициализирует эти порты нужным образом.
Четвертый параметр - int numDevices, является количеством устройств с драйвером MAX72xx подключенных к одной шине каскадом. Одному объекту класса LedControl можно адресовать до 8 устройств, при этом, чем больше устройств на шине, тем соответственно ниже её производительность. Для параметра numDevices разрешены только значения от 1 до 8 включительно, поскольку одному объекту класса LedControl нельзя адресовать свыше 8-ми устройств.
Если необходимо управлять более восемью устройствами на базе драйвера MAX72xx, то можно создать еще несколько объектов класса LedControl. Для этого нужно использовать другую группу контактов подключения устройства, отличную от первого объекта класса LedControl. Например вот так:
/* Для начала подключим библиотеку */
#include "LedControl.h"
/* Создаём первый объект класса LedControl для 8-ми устройств */
LedControl LC1 = LedControl(12, 11, 10, 8);
/* Создаём второй объект класса LedControl для 8-ми устройств */
LedControl LC2 = LedControl(9, 8, 7, 8);
Как видно из примера, для подключения следующего каскада устройств(объект LC2), используется следующая группа контактов, отличная от тех, которыми проинициализирован объект LC1.
При инициализации устройства на базе драйвера MAX72xx(при условии подключения всего лишь одного устройства), можно использовать нижеследующую конструкцию кода в разделе программы setup():
void setup()
{
/*
* Отключение энергосберегающего режима
* Функция shutdown()
*/
LC1.shutdown(0, false);
/*
* Установка яркости свечения светодиодов в матрице
* либо сегментов в дисплее
*/
LC1.setIntensity(0, 8);
/*
* Очистка дисплея, либо матрицы
*/
LC1.clearDisplay(0);
}
Функция shutdown() - это функция отключения энергосберегающего режима, светодиоды потребляют много энергии, это может оказаться критичным, если полностью собранное устройство будет работать от батареек. Функция shutdown() может отключить дисплей или матрицу когда нужно будет перевести устройство в энергосберегающий режим, либо включить - когда нужно будет вывести устройство из энергосберегающего режима, либо отобразить какие-либо данные. Прототип вызова функции:
LC1.shutdown(int address, bool set);
где:
В данном примере при вызове функции shutdown() мы указываем, что объекту LC1 класса LedControl, адресовано всего одно устройство на базе драйвера MAX72xx, адрес которого равен 0, при этом второй параметр равен false, значит устройство должно быть выведено из энергосберегающего режима. Важно знать, что адресация устройств начинается с 0, а заканчивается адресом равным 7.
Следующая функция setIntensity() - устанавливает яркость свечения сегментов, либо светодиодов(смотря что подключено дисплей или матрица). Прототип вызова функции:
LC1.setIntensity(int address, int brightness);
где:
Функция clearDisplay - очищает дисплей(либо матрицу), с указанным адресом. Прототип вызова функции:
LC1.clearDisplay(int address);
где:
Здесь даётся указание очистить дисплей(либо матрицу) для устройства на базе драйвера MAX72xx, с адресом 0, адресованного объекту LC1 класса LedControl.
При инициализации устройств на базе драйвера MAX72xx(если они подключены каскадом), в разделе setup() имеет смысл использовать функцию getDeviceCount() для получения количества устройств на шине, это позволит инициализировать устройства динамически. Функция не принимает никаких параметров, но при этом возвращает целочисленное значение(тип int), которое хранит количество подключенных устройств на базе драйвера MAX72xx, адресованных объекту класса LedControl. Ниже приведен пример динамической инициализации в цикле for для 5-ти устройств, адресованных объекту LC класса LedControl.
/* Для начала подключим библиотеку */
#include "LedControl.h"
/* Создаём объект класса LedControl для 5-ти устройств */
LedControl LC = LedControl(12, 11, 10, 5);
void setup()
{
//Создаём целочисленную переменую devices
//и сохраняем в ней значение количества устройств
int devices = LC.getDeviceCount();
//Начинаем инициализацию устройств в цикле
//переменная devices = 5, поэтому цикл выполнится 5 раз
for(int address = 0; address < devices; address ++)
{
/*
* Выводим устройство с адресом равным address из
* энергосберегающего режима
*/
LC.shutdown(address, false);
/* Устанавливаем интесивность свечения
* для устройства с адресом равным address
* на средний уровень
*/
LC.setIntensity(address, 8);
/* и очищаем дисплей с адресом равным address*/
LC.clearDisplay(address);
}
}
В дополнение - ссылка на статью, в которой приведён пример каскадного подключения устройств на базе драйвера MAX72xx:
Управление LED матрицами 8х8 осуществляется, всего лишь тремя функциями. И начнем мы с функции, которая управляет каждым светодиодом на матрице индивидуально. Итак, функция setLed(), и прототип её вызова:
LC1.setLed(int address, int row, int column, boolean state);
где:
Что же представляют собой ряды и столбцы LED матрицы 8x8? На схеме ниже изображена LED матрица 8х8, с одним закрашенным кружочком, это и есть зажженный светодиод, на втором ряду и седьмом столбце(2,7).
Пример скетча в данном случае будет таким:
/* Создаём объект класса LedControl
* Используем пины 12, 11, 10 на плате Arduino в качестве SPI интерфейса
* для драйвера MAX7219
*
* Подключаем устройства согласно таблице:
* Arduino[Pin 12] <-> Display Module MAX7219 [DIN]
* Arduino[Pin 11] <-> Display Module MAX7219 [CLK]
* Arduino[Pin 10] <-> Display Module MAX7219 [LOAD/CS]
*
* Прототип создания объекта класса LedControl:
* LedControl(int dataPin, int clkPin, int csPin, int numDevices);
* где:
* int dataPin - пин 12 на плате Arduino
* int clkPin - пин 11 на плате Arduino
* int csPin - пин 10 на плате Arduino
* int numDevices - количество устройств на шине SPI
*/
/* Для начала подключим библиотеку */
#include "LedControl.h"
/* Создаём объект класса LedControl для 5-ти устройств */
LedControl LC = LedControl(12, 11, 10, 5);
void setup()
{
/*
* Выводим устройство с адресом равным 0 из
* энергосберегающего режима
*/
LC.shutdown(0, false);
/* Устанавливаем интесивность свечения
* для устройства с адресом равным 0
* на средний уровень
*/
LC.setIntensity(0, 8);
/* и очищаем дисплей с адресом равным 0*/
LC.clearDisplay(0);
}
void loop()
{
LC.setLed(0, 2, 7, true);
delay(500);
LC.setLed(0, 2, 7, false);
delay(500);
}
В примере видно, что вызов функции setLed() осуществляется в теле основной функции loop() программы. Светодиод на 2-ом ряду и 7-ом столбце матрицы включается и через полсекунды выключается, затем всё повторяется снова. Ну и в дополнение - ссылка на интересную статью, в которой эта функция используется более расширенно, реализация анимации "бегущего огонька" с примерами и обзорным видео:
Для включения ряда светодиодов на LED матрице 8x8 применяется функция setRow(). Функция позволяет использовать значение переменной с типом данных byte, для зажигания ряда светодиодов на матрице. Прототип вызова функции:
LC.setRow(int address, int row, byte value);
где:
Ниже приведена схема, показывающая LED матрицу 8х8, на которой во 2-м ряду включены 0-й, 2-й и 3-й светодиоды(они закрашены синим), остальные же выключены.
Пример скетча для включения ряда светодиодов:
/* Создаём объект класса LedControl
* Используем пины 12, 11, 10 на плате Arduino в качестве SPI интерфейса
* для драйвера MAX7219
*
* Подключаем устройства согласно таблице:
* Arduino[Pin 12] <-> Display Module MAX7219 [DIN]
* Arduino[Pin 11] <-> Display Module MAX7219 [CLK]
* Arduino[Pin 10] <-> Display Module MAX7219 [LOAD/CS]
*
* Прототип создания объекта класса LedControl:
* LedControl(int dataPin, int clkPin, int csPin, int numDevices);
* где:
* int dataPin - пин 12 на плате Arduino
* int clkPin - пин 11 на плате Arduino
* int csPin - пин 10 на плате Arduino
* int numDevices - количество устройств на шине SPI
*/
/* Для начала подключим библиотеку */
#include "LedControl.h"
/* Создаём объект класса LedControl для 5-ти устройств */
LedControl LC = LedControl(12, 11, 10, 5);
void setup()
{
/*
* Выводим устройство с адресом равным 0 из
* энергосберегающего режима
*/
LC.shutdown(0, false);
/* Устанавливаем интесивность свечения
* для устройства с адресом равным 0
* на средний уровень
*/
LC.setIntensity(0, 8);
/* и очищаем дисплей с адресом равным 0*/
LC.clearDisplay(0);
}
void loop()
{
//Здесь:
//0 - адрес устройства
//2 - ряд на матрице(возможные значения от 0 до 7)
//B10110000 - значение которым будет проинициализирован ряд
//на матрице, 1 - светодиоды включатся, 0 - останутся выключенными
LC.setRow(0, 2, B10110000);
}
Более интересный эффект даёт использование данной функции в теле цикла for. Это позволяет динамически отрисовывать различные пользовательские шрифты, пиктограммы и другие анимации. Пример использования функции setRow() в теле цикла for раскрывает следующая статья:
и инструментарий который можно использовать для создания шрифтов и пиктограмм:
Почти что идентичная предыдущей, функция setColumn(), которая позволяет зажечь столбец светодиодов на LED матрице 8x8. Прототип вызова функции:
LC.setColumn(int address, int column, byte value);
где:
Ниже приведена схема, показывающая LED матрицу 8х8, на которой в 0-м столбце включены 5-й, 6-й и 7-й светодиоды(они закрашены синим), остальные же выключены.
Пример скетча для включения ряда светодиодов:
/* Создаём объект класса LedControl
* Используем пины 12, 11, 10 на плате Arduino в качестве SPI интерфейса
* для драйвера MAX7219
*
* Подключаем устройства согласно таблице:
* Arduino[Pin 12] <-> Display Module MAX7219 [DIN]
* Arduino[Pin 11] <-> Display Module MAX7219 [CLK]
* Arduino[Pin 10] <-> Display Module MAX7219 [LOAD/CS]
*
* Прототип создания объекта класса LedControl:
* LedControl(int dataPin, int clkPin, int csPin, int numDevices);
* где:
* int dataPin - пин 12 на плате Arduino
* int clkPin - пин 11 на плате Arduino
* int csPin - пин 10 на плате Arduino
* int numDevices - количество устройств на шине SPI
*/
/* Для начала подключим библиотеку */
#include "LedControl.h"
/* Создаём объект класса LedControl для 5-ти устройств */
LedControl LC = LedControl(12, 11, 10, 5);
void setup()
{
/*
* Выводим устройство с адресом равным 0 из
* энергосберегающего режима
*/
LC.shutdown(0, false);
/* Устанавливаем интесивность свечения
* для устройства с адресом равным 0
* на средний уровень
*/
LC.setIntensity(0, 8);
/* и очищаем дисплей с адресом равным 0*/
LC.clearDisplay(0);
}
void loop()
{
//Здесь:
//0 - адрес устройства
//0 - столбец на матрице(возможные значения от 0 до 7)
//B00000111 - значение которым будет проинициализирован столбец
//на матрице, 1 - светодиоды включатся, 0 - останутся выключенными
LC.setColumn(0, 0, B00000111);
}
Важно!!! О производительности...
Есть одно различие в работе функций setRow() и setColumn(), а именно в том как обновляется включение светодиодов в матрице при использовании этих функций. Функция setRow(int address, int row, byte value) в качестве параметра которым адресуется ряд, принимает одно целочисленное значение и по нему включает ряд светодиодов. Функция setColumn() использует функцию setLed() так сказать внутри своего тела, чтобы каждый раз включить/выключить светодиод в столбце.То есть, при обработке значения, которым будет проинициализирован столбец, внутри функции setColumn() будет восемь раз вызвана функция setLed(), которая в свою очередь включит/выключит каждый светодиод в столбце индивидуально. При каскадном подключении одного или двух устройств, это не будет заметно визуально. Но если включать каскадно длинные светодиодные табло, либо экраны(в таком случае количество подключенных устройств может быть от 6-и до 8-ми), то уже будет заметна визуальная задержка отрисовки пользовательских анимаций.
Здесь мы рассмотрим две стандартные функции для отрисовки символов и цифр на 7-ми сегментных дисплеях, а также рассмотрим нестандартное применение функции setRow() в качестве визуализации для пользовательских символов. Итак, по БЕЛАЗам...!!!
В основном, 7-ми сегментные дисплеи применяются для отображения каких - либо цифровых данных. Первая рассматриваемая нами функция будет заниматься именно отображением числовых символов. Функция setDigit() применяется именно при использовании 7-ми сегментных дисплеев, и прототип её вызова выглядит так:
LC.setDigit(int address, int digit, byte value, boolean dp);
где:
В целом, один драйвер MAX72xx может управлять максимум восемью разрядами на дисплее. Пример программного кода, для отображения цифры 6 в пятом разряде 7-ми сегментного дисплея:
/* Создаём объект класса LedControl
* Используем пины 12, 11, 10 на плате Arduino в качестве SPI интерфейса
* для драйвера MAX7219
*
* Подключаем устройства согласно таблице:
* Arduino[Pin 12] <-> Display Module MAX7219 [DIN]
* Arduino[Pin 11] <-> Display Module MAX7219 [CLK]
* Arduino[Pin 10] <-> Display Module MAX7219 [LOAD/CS]
*
* Прототип создания объекта класса LedControl:
* LedControl(int dataPin, int clkPin, int csPin, int numDevices);
* где:
* int dataPin - пин 12 на плате Arduino
* int clkPin - пин 11 на плате Arduino
* int csPin - пин 10 на плате Arduino
* int numDevices - количество устройств на шине SPI
*/
/* Для начала подключим библиотеку */
#include "LedControl.h"
/* Создаём объект класса LedControl для 5-ти устройств */
LedControl LC = LedControl(12, 11, 10, 5);
void setup()
{
/*
* Выводим устройство с адресом равным 0 из
* энергосберегающего режима
*/
LC.shutdown(0, false);
/* Устанавливаем интесивность свечения
* для устройства с адресом равным 0
* на средний уровень
*/
LC.setIntensity(0, 8);
/* и очищаем дисплей с адресом равным 0*/
LC.clearDisplay(0);
}
void loop()
{
//Здесь:
//0 - адрес устройства на базе драйвера MAX72xx
//5 - порядковый номер разряда на дисплее
//6 - это и есть отображаемая цифра
//false - управление включением десятичной точки разряда
//с порядковым номером 5
LC.setDigit(0, 5, 6, false);
}
А также полезная статья на эту тему:
Отображением символов управляет функция setChar(), но к сожалению она может отобразить лишь определенный набор символов. таких как:
Прототип вызова функции setChar() выглядит так:
LC.setChar(int addr, int digit, char value, boolean dp);
где:
Итак мы видим, что скорее всего, тот набор символов что даётся по умолчанию к этой функции, будет недостаточно полным, ведь на самом деле можно придумать еще!!! Вот здесь и начинается нестандартное применение функции setRow(), а применять мы её будет в связке с генератором символов для 7-ми сегментных дисплеев. Для примера нужно перейти по ссылке, на странице видна интерактивная форма с сегментами, кликая по которым можно отрисовать нужный символ. В окне результата справа, появится двоичный(бинарный) код отрисованного символа, его можно скопировать в буфер обмена. Кстати, можно также воспользоваться кликабельными примерами символов, которые находятся в форме ниже. Далее, нужно лишь вызвать функцию setRow() передав ей в качестве параметра byte value содержимое буфера обмена. И всё же неплохо уточнить прототип вызова функции setRow() именно для отрисовки символов для 7-ми сегментных дисплеев:
LC.setRow(int address, int digit, byte value);
где:
Ну что же, в завершение можно дать ссылку на еще одну статью, а именно по теме нестандартного использования функции setRow(), и вообще началу работы с 7-ми сегментными дисплеями на базе драйвера MAX72xx:
Библиотеку LedControl.h можно скачать здесь.
Если вам понравилась эта статья - комментируйте, оставляйте свои пожелания и критику, задавайте вопросы и предлагайте свои темы.
Если у Вас есть опыт в работе с Arduino и собственно есть время для творчества, мы приглашаем всех желающих стать авторами статей публикуемых на нашем портале. Это могут быть как уроки, так и рассказы о ваших экспериментах с Arduino. Описание различных датчиков и модулей. Советы и наставления начинающим. Пишите и размещайте свои статьи в соответсвующей ветке форума.