Андрей Смирнов
Время чтения: ~22 мин.
Просмотров: 14

7 сегментный индикатор на MAX7219 — подключение и модернизация

Smart-Electronics-MAX7219-dot-matrix-module-microcontroller-module-DIY-KIT.jpg

  • Цена: $1.01 x 8

Микросхема MAX7219 — готовый драйвер для семисегментных и матричных светодиодных индикаторов. Как подключать маленькие и большие цифровые индикаторы я уже писал. Теперь решил попробовать собрать матричный дисплей. Много DIY, печатных плат и программирования микроконтроллера под катом. Заказал 8 матричных модулей 8×8 с ценой чуть больше доллара за штуку. Так как при количестве больше 1 шт получалась платная доставка, не поленился, сделал 8 заказов. Сейчас товар не доступен, но легко можно найти такой же, может чуть дороже.24cf0e.jpg Ехало все это богатство больше двух месяцев. В комплекте платка с микросхемой, сам индикатор, разъемы для индикатора и для соединения каждой платы.d0d7c0.jpg Размеры индикатора 3.2 см Х 3.2 см. Подключение к микроконтроллеру по SPI «в один конец» по трем проводам. Модули подключаются каскадно — DIN->DOUT. Все остальные выводы запаралелены. Подключив один модуль к ардуинке (фоток не осталось) решил сразу собирать дисплей. Из двух конфигураций 8×64 и 16×32 выбрал вторую, так как решил в конечном итоге делать часы. Первая же это классическая «бегущая строка». Чтобы меньше возиться с проводами, развел плату под дисплей (и чего бы на нее сразу контроллер не установить было?)

Готовый собранный экран подключил к ESP8266. Для таких модулей обычно используется ардуиновская библиотека LedControl . Но мне больше приглянулся драйвер для модулей MAX7219 к графической библиотеке AdafruitGFX. В отличие от LedControl, где с каждому модулю обращаются по номеру, Max72xxPanel позволяет работать со всеми модулями, как с едиными пиксельным дисплеем. К ESP8266 подключение такое:

  • DIN -> GPIO13 (MOSI)
  • SCK -> GPIO14 (SCK)
  • CS -> GPIO16 (к любому свободному)

В конструкторе объекта матрицы определяем PinCS, а также количество модулей по вертикали и по горизонтали В секции SETUP программы нужно сконфигурировать наш дисплей, то есть задать последовательность подключения модулей и орентацию каждого модуля.У меня получилось так: Микросхема MAX7219 поддерживает 16 градаций яркости светодиодов. Ставим максимальную: Дисплей превращается в яркий красный фонарь мощностью более 12Вт К тому же довольно ощутимо нагревающийся Собственно удивляться нечему — все написано в даташите на MAX7219, Максимальный ток на всех сегментах одного модуля — 330мА, что при умножении на 8 и дает 2.6А. Минимальный ток — 1/16 от этой цифры. В нашем случае около 160мА. При установке интенсивности ток будем меняться с шагом 1/16 от максимального. При такой яркости дисплея не вижу смысла устанавливать значение интенсивности больше 7. С током разобрались, перейдем к выводу информации на наш дисплей. В примерах к библиотеке Max72xxPanel есть простенькая программа — вывод бегущей строки. По умолчанию, строка выдается стандартным шрифтом библиотеки GFX 5×7. Русификация данной библиотеки подробно рассмотрена здесь. Суть сводится к тому, что нужно скачать по ссылке архив, взять оттуда русский фонт и положить его в папку AdafruitGFX-master. Остальные файлы, это примеры, как перекодировать константы, введенные в среде Arduino в UTF-8 в кодировку фонта 1251. Там есть для этого функция utf8rus Небольшое отступление про кодировку русских букв в среде АрдуиноТут должно быть много русского мата. Про всех родственников этого итальянца. Сперва я долго возился с выводом русских слов, введенных в редакторе Arduino IDE на дисплей. Выяснил, что в функции utf8rus нужно смещать на 1 меньше. Как я радовался получив «Привет» на экран. Но в какой то момент времени вместо внятных слов опять получалась белиберда. Смещение в кодировки было то на 1, то на 2 символа. Причем, во вновь созданном скетче все было нормально. До поры, до времени. Я уже было решил хранить русские константы в отдельном файле либо кодировать в виде ‘234’. Пока не стал открывать программу в редакторе NotePad++. Тот определял кодировку UTF8, то UTF8 без BOM. Путем натурального эксперимента было определено, что если брать файл, и преобразовывать его в UTF без BOM, то следующая сборка проходит нормально и русские константы нормально отображаются. Документированный «баг» стал «фичей». С отображением текста теперь все ясно. Но дисплей у на ГРАФИЧЕСКИЙ. Значит без отображения графики, хотя бы статической, никуда. Чтобы подсунуть графику библиотеке GFX, нужно запихнуть ее в байтовый массив. Для этого можно воспользоваться онлайн-сервисом Рисуем картинку или иконку в любом редакторе, подсовываем ее этому сервису. Шаманим с параметрами, если нужно и получаем готовый массив Теперь если скормить этот массив функции drawBitmap, то получаем ее на дисплее Интересно смотреть в тепловизор, как нагреваются отдельные пикселы С дисплеем все понятно. Теперь можно сделать из него что-нибудь полезное. В интернете ходит шутка, что бы вы не делали с ESP8266 — получается метеостанция. ))) Вот ее то мы и будем делать, только без датчиков. Погоду пусть контроллер берет из интернета, с бесплатного сервиса openweathermap.org и отображает попеременно со временем, которое получает по NTP. Погода получается в формате jSON. Пытался договориться с Яндексом на получение погоды, но служба поддержки меня послала объяснила, что бесплатный доступ к API погоды они дают только СМИ. Под цифры полной высоты шрифт не подобрал, поэтому нарисовал 10 картинок

Значок подключения к WiFi Полный скетч который запрашивает время и погоду и выводит на экран выложил на GITHUB Осталось подобрать подходящий корпус Вытравливаю плату с контроллером (и что бы ее с платой дисплея не совместить?) Прошиваю ESP8266 на программаторе. Паяю плату контроллера Монтирую в корпусе
Закрываю прозрачным стеклом с красным светофильтром (хорошо подходят цветные файлы для бумаг ) Для крепление с ходу не придумалось ничего лучше стяжек Питание — старый зарядник от телефона. При яркости 50% и не полном заполнении экрана ток потребления получается порядка 0.5А, так что зарядника вполне хватит. И часы в черновом варианте готовы.
Смотреть работу часов лучше на видео Восторг кота слышен на заднем плане ))) Пора подводить итог. Модули вполне годные, но работать мне с ними не понравилось. Слишком много возьни, избыточное количество микросхем, хотя лучше, чем на WS2812, где микросхема в каждом диоде. Все же лучше применять готовые дисплеи. Например,P6 RGB гораздо большего размера обойдется в $11 В целом проект удачный, часы после небольшой доработки корпуса пойдут в подарок. Доделаю выдачу даты, снижение яркости дисплея после захода солнца (сервис openweathermap.org lдает эту информацию) и прогноз погоды, а также отображения температуры в корпусе часов в комнате. Разъем для DS18B20 предусмотрен. Всем хорошего дня и солнечных выходных. А то пока делал часы, больше 21С они не вещали. И это в июле!Кот заставку одобрил
ГлавнаяSPIAVR Урок 28. SPI. Драйвер LED MAX7219

&nbsp

&nbsp

&nbsp

    Урок 28

Продолжем работать с шиной SPI.

Сегодня мне в руки попался драйвер 8-разрядных светодиодных индикаторов. Данный драйвер оснащем декодером символов, умеет управлять динамической индикацией и много чего ещё. Ну, и, самое главное, управляется данная микросхема по шине SPI, что не дало мне права обойти его стороной.

Сегодня мы его и попробуем подключить и поуправлять им. Работать мы будем с ней также только на передачу, работа на приём ждёт нас впереди в более поздних занятиях.

Ну и как всегда, обратимся к технической документации, чтобы, так сказать немного с ним ознакомиться для начала.

Вот типовая схема подключения микросхемы MAX7219

Мы видим, что у данного драйвера есть 8 параллельных выходов для сегментов и также восем параллельных выходов для разрядов. Также есть контакт для последовательного входа данных, выхода на схеме нет, хотя вообще он у драйвера есть, то есть разработчики сами прекрасно понимают, что мониторить здесь нечего. Также есть вход для выбора микросхемы Chip Select и вход для синхроимупульсов. На 18 ножку Iset мы подтягиваем резистор с шины питания, который рекомендуется впаивать с номиналом 9,53 килоома, тем самым мы устанавливаем пиковый ток для сегментов. Ну и, соответственно, мы подключаем на 19 ножку питание, а на 9 и 4 — общий провод.

Так как данная микросхема не совсем простая, у неё также существует немалая структурная схема

Здесь мы видим внизу 16-битный регистр, 8 младших битов которого являются данными, а следующие 4 бита — адресом для регистров. Также мы видим несколько регистров различного назначения, драйвер сегментов и драйвер разрядов. Видим мы ещё широтно-импульсный модулятор, управляющий интенсивностью свечения и управляемый особым регистром. Существует также интересный регистр — SCAN-LIMIT, который управляет количеством задействованных разрядов.

Интересным является также декодер сегментов, который может сам формировать свечение определённых сегментов в разряде в зависимости от поступившего значения. Раньше, я помню, это называлось дешифратором. Данный декодер можно также отключать, причём его можно для каких-то разрядов включить, а для каких-то — выключить. Возникает вопрос — для чего вообще выключать декодирование? Ответ здесь многогранный. Во-первых, для того, чтобы вывести какие-то особенные замысловатые символы, которых нет в списке кодов. А самое главное то, что при использовании декодера символов мы можем управлять индикатором только с общим катодом, индикатором с общим анодом мы уже управлять не можем, а если декодирование отключить, то уже можно что-то придумать для управления и общими анодами. Ну мы этим заниматься не будем, будем пользоваться декодером.

Дальше в технической документации рассматриваются все регистры подробно, сейчас мы не будем это рассматривать, а будем только по мере необходимости при написании кода.

Ну и тогда не будем медлить, а перейдём непосредственно к проекту. Проект создан был с именем LED7219, код нём находится весь с проекта предыдущего занятия. Единственная разница — мы не будем подключать библиотеку файлов led.c и led.h, так как у нас есть драйвер и он данными вещами, описанных в данных библиотеках, займётся на аппаратном уровне.

Уберём поэтому инициализацию таймера и прерываний из функции main()

timer_ini();

sei();

Также удалим всё полностью из бесконечного цикла.

Так как микросхема не простая, она нуждается уже в инициализации. Отдельную функцию инициализации мы писать на будем, так как кода будет не так много.

А создадим мы функцию, которая будет передавать команды в данный драйвер. Добавим мы её до функции main(). Параметром будет передаваемый байт, а в теле функции мы запишем данный байт в регистр SPDR и затем стандартным способом данный байт в шину SPI передадим

voidSPI_SendByte(charbyte)

{

  SPDR=byte;

  while(!(SPSR&(1<<SPIF)));

}

Затем будет ещё одна функция, которую мы напишем ниже. Данная функция будет передавать байт не просто в шину, а в определённый регистр микросхемы. Судя по рисунку со структурной схемой и глядя в нём на регистр данных мы видим, куда именно и что там расположить. Входными параметрами будут адрес регистра и байт данных

voidSend_7219(charrg,chardt)

{

  PORTB&=~(1<<PORTB2);

  SPI_SendByte(rg);

  SPI_SendByte(dt);

  PORTB|=(1<<PORTB2);

}

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

Посмотрим схему в проетусе. За основу также взята была схема с прошлого знанятия и, соответственно, переработана под новую микросхему. Дело в том. что у меня отдельной микросхемы нет, а есть модуль, в котором уже установлен восьмиразрядный индикатор, поэтому такой же индикатор мы подключим и в протеусе (нажмите на картинку для увеличения изображения)

Мы видим, что на вход DIN идёт выход MISO контроллера, а также мы подвели к нему синхронизацию и выбор. Ну а индикатор соответствующими разрядами и сегментами мы подключили к соответствующим параллельным выходам драйвера. Вообщем, схема получилась проще паренной репы.

А вот так вот у нас всё выглядит в модуле

А вот вид сзади

Мы видим здесь нашу микросхему MAX3219 и все соединения. Выполнено очень даже чинно. Также мы подвели к микросхеме 4 провода, воспользовавшить обычными контактными разъёмами. Здесь у нас шина питания и общий провод, а также 3 провода SPI. Вот и всё

Ну а вот так выглядит всё это вместе с отладочной платой

Также здесь мы видим, что вместо восьмиразрядного индикатора в модуле установлены два четырёхразрядных индикатора, что, собственно, не очень тяготит, так как раздряды все находятся друг от друга на одинаковом расстоянии, так сказать, без разрывов.

Вернёмся в наш проект.

Так как мы никуда не торопимся, давайте всё-таки включим предделитель на тактирование шины SPI в функции SPI_init()

SPCR|=(1<<SPE)|(1<<MSTR)|(1<<SPR0);//включим шину, объ¤вим ведущим, делитель 16

Так как теперь мы можем подавать команды регистрам, то можем уже заняться инициализацией.

Прочистим себе дорогу в main(), убрав вот это всё

SPDR=0b00000000;

while(!(SPSR&(1<<SPIF)));//подождем пока данные передадутся

SPDR=0b00000000;

while(!(SPSR&(1<<SPIF)));//подождем пока данные передадутся

//сгенерируем отрицательный фронт для записи в STORAGE REGISTER

PORTB|=(1<<PORTB2);//высокий уровень

PORTB&=~(1<<PORTB2);//низкий уровень

Задержку оставим.

Давайте сначала посмотрим в даташите таблицу адресов регистров

Сначала дадим следующую команду

SPI_init();

Send_7219(0x09,0xFF);//включим режим декодирования

По комментарию ясно, что мы включили режим декодирования.

С девяткой ясно. Разбираемся с 0xFF.

Для этого есть другая таблица с примерами настройки декодирования

То есть мы видим, что каждому биту в аргументе команды соответствует один разряд, то есть значением 0xFF мы включили декодирование на все разряды нашего индикатора. А, например, если бы передали только 0x0F, то мы бы включили только 4 младших разряда.

Вообщем, с командой ясно, можно также поглядеть саму таблицу кодов для декодирования

Здесь мы видим, какие символы мы можем передать с помощью декодера. Вообщем-то основные все есть. Обидно только, что нет буквы «C». Ну да ничего. Также мы видим, что код символа передаётся только в четырёх младших разрядах байта данных, следующие три бита вообще не используются, а последний старший бит отвечает за точку.

Следующим шагом нашей инициализации будет настройка количества задействованных разрядов. Для этого у нас есть регистр с адресом 0x0B.

Вот его таблица

Здесь схема простая. Значение данному регистру мы передаём, равное количествузадейстовванных разрядов, уменьшенное на 1.

Поэтому давайте добавим глобальную переменную для количества разрядов и сразу её и инициализируем

#include «main.h»

chardg=8;

То есть мы будем использовать все 8 разрядов

Теперь передадим значение в регистр

Send_7219(0x09,0xFF);//включим режим декодирования

Send_7219(0x0B,dg1);//сколько разрядов используем

Теперь займёмся яркостью свечения. Для этого у нас существует отдельный регистр с адресом 0x0A

Так как у нас MAX7219, то для нас первая колонка. Здесь я думаю всё просто. Для начала зададим среднюю интенсивность свечения индикатора

Send_7219(0x0B,dg1);//сколько разрядов используем

Send_7219(0x0A,0x07);//яркость

Ну и последняя настройка — это включение индикатора, также существует отдельный регистр, думаю, показывать его нет смысла, так как у него всего два значения: 0 — отключено, 1 — включено

Send_7219(0x0A,0x07);//яркость

Send_7219(0x0C,1);//включим индикатор

После всех данных настроек желательно весь мусор, который наберётся в буфере данных, очистить. Для этого напишем функцию очистки дисплея, опять же над функцией main()

voidClear_7219(void)

{

  chari=dg;

  do{

    Send_7219(i,0xF);//символ пустоты

  }while(—i);

}

Ну здесь для нас, как всегда всё просто. Мы поочерёдно во все задействованные разряды установим пустые символы. В качестве адреса регистра у нес уже здесь выступает адрес информационного регистра, соответствующий заданному разряду. А байт 0xF — это у нас код символа пустоты (в таблице выше он выглядит как «blank»).

Вызовем вышенаписанную функцию в main()

Send_7219(0x0C,1);//включим индикатор

Clear_7219();

Ну и наконец-то давайте теперь что-то попробуем вывести на дисплей, например, какой-нибудь символ, а лучше всего во все восемь разрядов символы номеров разрядов

Clear_7219();

Send_7219(0x01,1);

Send_7219(0x02,2);

Send_7219(0x03,3);

Send_7219(0x04,4);

Send_7219(0x05,5);

Send_7219(0x06,6);

Send_7219(0x07,7);

Send_7219(0x08, 8);

Соберём код и посмотрим сначала работу кода в протеусе

В протеусе всё хорошо. Прошьём контроллер и проверим работу нашего индикатора на живом индикаторе

Всё у нас работает.

И мы видим, где именно и какой разряд.

Казалось бы, на этом можно и закончить. Но что толку в посылании в разряд символа? Не интересно. Давайте что-то повеселее напишем.

Сначала попробуем поиграть с яркостью. Попробуем её убавить

Send_7219(0x0A,0x02);//яркость

Посмотрим результат

Да, отличается, стало темнее.

Теперь давайте напишем функцию для вывода какой-то числовой величины, чтобы посылать не поразрядно цифры, а как и в прежних проектах, целыми цифрами.

Создадим такую функцию опять же над функцией main()

voidNumber_7219(volatilelongn)

{

}

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

Начнём с переменной знака, вдруг, мы захотим вывести отрицательную величину

voidNumber_7219(volatilelongn)

{

  charng=0;//переменная для минуса

Дальше условие, при котором мы включим данный флаг и соответственно входное значение умножим на -1, чтобы сделать его положительным и в дальнейшем уже работать как с неотрицательной величиной

charng=0;//переменная для минуса

if(n<0)

{

  ng=1;

  n*=-1;

}

Очистим дисплей

  n*=-1;

}

Clear_7219();

Дальше ещё условие равенства величины нулю, тогда мы ноль отправим только в младший разряд и выйдем из функции

Clear_7219();

if(n==0){

  Send_7219(0x01,0);//в первый разряд напишем 0

  return;

}

Затем добавим ещё одну переменную для счётчика

  return;

}

chari=0;

Дальше цикл, в котором мы заполним разряды цифрами из нашей величины

chari=0;

do{

  Send_7219(++i,n%10);

  n/=10;

}while(n);

Здесь также у нас всё несложно, мы уменьшаем с каждым разрядом в 10 раз нашу величину и извлекаем из неё последний разряд с помощью деления по модулю на 10, и отправляем в текущий разряд.

Ну и по окончанию тела функции отобразим в следующий разряд символ минуса

  }while(n);

  if(ng){

  Send_7219(i+1,0xA);//символ —

  }

}

Ну, давайте проверим данную функцию. После отображения наших символов от 1 до 8 в функции main() добавим небольшую задержку, а затем отобразим какую-нибудь величину

Send_7219(0x08,8);

_delay_ms(1000);

Number_7219(-2016);

Соберём код, прошьём контроллер и посмотрим результат, так как в протеусе почему-то не заработало

Отлично!

Ну теперь, чтобы выглядело всё поживее, напишем какой-нибудь счётчик, тем более у нас переменная уже есть. Добавим код в беспонечный цикл, перед этим также вставим задержку

Number_7219(-2016);

_delay_ms(1000);

while(1)

{

  NumberFull_7219(i);

  i++;

  _delay_ms(200);

}

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

Соберём код, прошьём контроллер и проверим

Ну вот мы с вами и познакомились с новым устройством, тем самым потренировались лишний раз с шиной SPI.

Только мы опять с шиной SPI не заканчиваем. На следующем занятии мы попробуем подключить по данной шине внешний АЦП.

    Исходный код

    Техническая документация на микросхемы MAX7219-MAX7221

Программатор и индикатор с драйвером можно приобрести здесь:

Программатор (продавец надёжный) USBASP USBISP 2.0

Индикатор светодиодный семиразрядный с драйвером MAX7219

    Смотреть ВИДЕОУРОК

Сегодня мы поговорим об очень удобных и полезных микрухах — драйверах MAX7219 и MAX7221. Эти драйвера позволяют управлять семисегментными индикаторами (с общим катодом), светодиодными линейками или просто отдельными светодиодами. Максимум к ним можно подключить по 64 светодиода (ну или, соответственно, по восемь семисегментных индикаторов). Сами драйвера управляются по интерфейсу SPI (режим 0), поддерживая частоту работы интерфейса до 10 МГц. Надо сказать, что драйвер MAX7219 не полностью соответствует нормам SPI (в отличии от MAX7221), но тем не менее его прекрасно можно по SPI программировать, главное — чётко помнить в чём же всё таки заключается несоответствие (позднее расскажу об этом и ещё некоторых отличиях этих микросхем).

Распиновка и назначение ног.

1 — DIN. Последовательный ввод данных. Данные загружаются в 16-ти разрядный сдвиговый регистр по переднему фронту тактового сигнала.

2,3,5-8,10,11 — DIG0-DIG7. Выводы для подключения общих катодов индикаторов. В MAX7219 эти линии при отключении подтягиваются к плюсу, а в MAX7221 переходят в высокоомное состояние (в Z-состояние).

4,9 — GND. Сюда подключается «ноль» питания. Для правильной работы микрухи — к «нулю» должны быть подключены оба вывода.

12 — LOAD у MAX7219 и

CS

у MAX7221. У MAX7219 данные загружаются в сдвиговый регистр независимо от состояния сигнала LOAD. Запоминаются и поступают к дальнейшей обработке последние 16 принятых бит. Происходит это по переднему фронту сигнала LOAD (то есть только в момент переключения сигнала LOAD из 0 в 1). У MAX7221 данные загружаются в приёмный сдвиговый регистр только когда сигнал

CS

находится в состоянии низкого уровня (то есть только когда микросхема «выбрана», если говорить в терминах интерфейса SPI). Запоминаются и поступают к обработке также последние 16 принятых бит, происходит это также по переднему фронту сигнала

CS

.

13 — CLK. Вход тактирования. Как я уже сказал, микросхемы совместимы с SPI Mode 0, т.е. в отсутствии передачи на линии тактирования низкий уровень, по переднему фронту сигнала CLK происходит считывание данных со входа, по заднему — сдвиг (подробнее о том, как это работает — почитайте теорию SPI по ссылке в начале статьи).

14-17, 20-23 — SEG A-SEG G, DP. Выводы для подключения сегментов семисегментных индикаторов. В MAX7219 эти линии при отключении подтягиваются к GND, а в MAX7221 переходят в высокоомное состояние (в Z-состояние).

18 — ISET. К этому выводу подключается резистор (вторая нога резистора — к плюсу), позволяющий задавать пиковый ток сегмента и таким образом устанавливать яркость свечения сегментов. Минимальное сопротивление этого резистора должно быть 9,53 кОм, что примерно соответствует току сегмента 40мА. Ток, текущий через ISET номинально в 100 раз меньше пикового тока сегмента. Из даташита совершенно непонятно, одинаково ли падение напряжения на этом резисторе, но если считать, что оно одинаково, то это даст такую формулу для расчёта резистора: R=9,53*40/Ipk, где Ipk — требуемый пиковый ток сегмента. Подключив к этой ноге переменный резистор — можно регулировать яркость свечения сегментов.

19 — V+. Сюда подключается «+» питания.

24 — DOUT. Последовательный вывод данных. На этом выводе появляются принятые на входе DIN данные c задержкой в 16 с половиной тактов. Почему именно 16.5, а не 16 или 17? Потому что в SPI первая половина такта (после переднего фронта для MODE 0) — чтение, вторая половина такта (задний фронт для режима MODE 0) — сдвиг, а данные появятся на выходе только после сдвига. С помощью DOUT можно каскадно соединить несколько драйверов, при этом выход (DOUT) первого драйвера подключается ко входу (DIN) второго драйвера, выход второго — ко входу третьего и т.д.

Управляется MAX7219/MAX7221 через специальные регистры. Данные, как я уже говорил, загружаются в микросхему по SPI, в виде 16-ти битных пакетов (помните, на входе 16-ти битный сдвиговый регистр), старшим битом вперёд. В пакетах содержится адрес регистра, к которому обращаются, и данные, которые в него нужно загрузить.

Формат пакета:

Карта регистров:

Имя регистра Адрес регистра
bin hex
D15-D12 D11 D10 D9 D8
No-op XXXX X0h
Digit 0 XXXX 1 X1h
Digit 1 XXXX 1 X2h
Digit 2 XXXX 1 1 X3h
Digit 3 XXXX 1 X4h
Digit 4 XXXX 1 1 X5h
Digit 5 XXXX 1 1 X6h
Digit 6 XXXX 1 1 1 X7h
Digit 7 XXXX 1 X8h
Decode Mode XXXX 1 1 X9h
Intensity XXXX 1 1 XAh
Scan Limit XXXX 1 1 1 XBh
Shutdown XXXX 1 1 XCh
Display Test XXXX 1 1 1 1 XFh

После подачи питания все регистры сброшены и MAX7219 / MAX7221 находится в остановленном состоянии. Прежде чем использовать драйвер — сначала нужно его настроить (записать в нужные регистры нужные данные).

Данные, записанные в регистрах «Digit0»-«Digit7» определяют состояния сегментов соответствующих семисегментных индикаторов. В зависимости от выбранного режима («No decode», «BCD code B»), эти данные могут интерпретироваться двумя способами.

В режиме «No decode» каждый бит данных в соответствующем регистре «Digit X» определяет состояние одного из сегментов семисегментного индикатора «X» (0 — сегмент погашен, 1 — сегмент горит). Карта сегментов и соответствующие им биты указаны на рисунке справа.

В режиме «BCD code B» 7 младших бит данных, записанных в регистре «Digit X», кодируют отображаемый на семисегментном индикаторе символ, в соответствии с таблицей ниже, а старший бит данных кодирует состояние сегмента DP (0 — сегмент погашен, 1 — сегмент горит).

Таблица кодировки режима «BCD code B»:

Символ Данные в регистре Digit X Состояние сегментов индикатора
D6-D4 D3 D2 D1 D0 A B C D E F G
XXX 1 1 1 1 1 1
1 XXX 1 1 1
2 XXX 1 1 1 1 1 1
3 XXX 1 1 1 1 1 1 1
4 XXX 1 1 1 1 1
5 XXX 1 1 1 1 1 1 1
6 XXX 1 1 1 1 1 1 1 1
7 XXX 1 1 1 1 1 1
8 XXX 1 1 1 1 1 1 1 1
9 XXX 1 1 1 1 1 1 1 1
XXX 1 1 1
E XXX 1 1 1 1 1 1 1 1
H XXX 1 1 1 1 1 1 1
L XXX 1 1 1 1 1 1
P XXX 1 1 1 1 1 1 1 1
пусто XXX 1 1 1 1

Режим выбирается индивидуально для каждого из регистров «Digit 0» — «Digit 7», установкой в 0 («No decode») или 1 («BCD code B») соответствующего бита регистра «Decode Mode».

Данные в регистре «Intensity» определяют средний ток сегмента (в долях от пикового тока, заданного резистором на ноге «ISET») в соответствии с таблицей ниже:

Доля от Ipk D4 — D7 D3 D2 D1 D0 HEX код
MAX7219 MAX7221
1/32 1/16 XXXX X0h
3/32 2/16 XXXX 1 X1h
5/32 3/16 XXXX 1 X2h
7/32 4/16 XXXX 1 1 X3h
9/32 5/16 XXXX 1 X4h
11/32 6/16 XXXX 1 1 X5h
13/32 7/16 XXXX 1 1 X6h
15/32 8/16 XXXX 1 1 1 X7h
17/32 9/16 XXXX 1 X8h
19/32 10/16 XXXX 1 1 X9h
21/32 11/16 XXXX 1 1 XAh
23/32 12/16 XXXX 1 1 1 XBh
25/32 13/16 XXXX 1 1 XCh
27/32 14/16 XXXX 1 1 1 XDh
29/32 15/16 XXXX 1 1 1 XEh
31/32 15/16 XXXX 1 1 1 1 XFh

В регистре «Scan Limit» можно выбрать обслуживаемые драйвером семисегментные индикаторы. Они определяются четырьмя младшими битами загруженного в этот регистр байта. Количество обслуживаемых драйвером индикаторов связано с их частотой обновления. Если задействованы все 8 семисегментных индикаторов, то частота обновления составляет 800 Гц, если меньше, то 8*800/N (N — количество задействованных индикаторов). Поскольку количество обслуживаемых индикаторов влияет на яркость, то не рекомендуется показывать пустые старшие символы простым отключением их от обслуживания в регистре «Scan Limit».

Таблица (обслуживаемые индикаторы, в зависимости от значения в регистре «Scan Limit»):

Номера обслуживаемых индикаторов Данные в регистре «Scan Limit»
D3 — D7 D2 D1 D0 HEX
X0h>
XXXXX 1 X1h
XXXXX 1 1 X3h
XXXXX 1 X4h
XXXXX 1 1 X5h
XXXXX 1 1 X6h
XXXXX 1 1 1 X7h

Регтр «Display test» позволяет провести тестирование исправности сегментов всех подключенных семисегментных индикаторов. При установки младшего бита этого регистра в 1 — драйвер включает все сегменты всех подключенных индикаторов. Чтобы прекратить тест и вернуться в нормальное состояние — нужно записать в младший бит регистра «Display test» ноль.

Регистр «No-op» используется при каскадном подключении драйверов. Для того, чтобы обратиться, например, к третьему драйверу в цепочке, не влияя на работу первых двух, — нужно для первых двух обратиться к регистру «No-op». Поскольку адрес этого регистра равен нулю, то сделать это очень просто: сначала за 16 тактов отправляем данные для третьего регистра, потом устанавливаем линию данных в ноль и отщёлкиваем ещё 2 раза по 16 тактов. В результате первый отправленный пакет будет загружен в третий регистр, а следующие два пакета (загруженные в первый и второй регистры) будут иметь адрес ноль, то есть будут обращаться к регистру «No-op».

А теперь небольшой пример того, как к этим драйверам подключать семисегментные индикаторы. Вместо семисегментных индикаторов могут быть просто диоды (собственно, семисегментный индикатор с общим катодом — это и есть всего лишь восемь светодиодов, у которых объединены катоды). Схема подключения семисегментных индикаторов к драйверу:

Пример готовой платы (лицевая панель контроллера ICPCon) с пятью семисегментными индикаторами и драйвером MAX7219:

max7219_7221_5.jpg

Вот и всё. Реализацию SPI на микроконтроллере можно посмотреть по ссылке ниже.

— Программа для контроллера SPI-шлюза.

Используемые источники:

  • https://mysku.ru/blog/aliexpress/53513.html
  • http://narodstream.ru/avr-urok-28-spi-drajver-led-max7219/
  • https://radiohlam.ru/max7219_7221/

Рейтинг автора
5
Подборку подготовил
Максим Уваров
Наш эксперт
Написано статей
171
Ссылка на основную публикацию
Похожие публикации