Управление драйвером семисегментных индикаторов MAX7219

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

В общем то управление драйвером простое, как сдвиговым регистром по трехпроводной схеме (3-Wire). Вернее он и имеет как раз в своем составе сдвиговый регистр. Алгоритм управления такой. Низким уровнем на входе CS разрешаем принимать данные. Данные отсылаются по 16 бит, старшим битом вперед. Биты с 15 по 8 это или адрес знакоместа (значения от 1 до 8), или служебная команда (значения от 9 до 15). Биты с 7 по 0 это данные, либо для инструкции, либо образ (маска) символа. Каждый выставленный бит на входе DIN записывается в регистр по фронту тактового импульса на входе CLK. После того как все биты переданы, “защелкиваем” их, выставив единичку на входе CS.

Управляет драйвер восемью светодиодными семисегментными индикаторами с общим катодом. Это означает, что чтобы погасить все сегменты индикатора, надо прописать в него 0, а что бы зажечь, нужно прописать 255. Каждый из разрядов индикатора имеет независимую адресацию и его содержимое может быть обновлено без необходимости перезаписи всего индикатора.

Внешний вид модуля MAX7219.

внешний вид модуля MAX7219

Сама плата выполнена качественно, а вот индикаторы на ней припаяны кривовато. Подключение индикаторов странное. Ожидалось, что под номером 1 будет индикатор расположенный слева, но как видим слева идут 8, 7, 6 и т. д.. Почему-то распаяны они именно так, хоть это и не критично, и легко корректируется в коде программы.

знакоместа идут справа налево

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

вид модуля через светофильтр

вид модуля через светофильтр

А так индикаторы смотрятся через светофильтр. Яркость свечения не уменьшилась, а вот незасвеченные сегменты уже не видно. Код “демки” на языке Си.

/**************************************************************/
/*** Управление драйвером семисегментных индикаторов MAX7219 **/
/************** нагруженным на восемь индикаторов. ************/
/************ Микроконтроллер: PIC16F628A *********************/
/************ Среда разработки MPLAB IDE v8.89 - язык C *******/
#include pic.h               // нужен для HI-TECH C компилятора
#include htc.h               // для работы с функцией задержки
#define _XTAL_FREQ 4000000   // прописываем частоту генератора
/************* прописали выводы микроконтроллера **************/
#define knopkaup RA0         // кнопка больше
#define knopkadown RA1       // кнопка меньше
#define	DIN RB0              // определение ввод данных
#define	CLK RB1              // определение тактирующего сигнала
#define	CS RB2               // определение выбор устройства
#define DIN_OFF() DIN = 0;   // данные в ноль
#define DIN_ON() DIN = 1;    // данные в еденичку
#define STR_OFF() CLK = 0;   // Строб в ноль
#define STR_ON() CLK = 1;    // Строб в еденичку
#define WR_OFF() CS = 0;     // начало передачи
#define WR_ON() CS = 1;      // завершение передачи
/******************* логические операции **********************/
#define TestBit(x,y) (x & (1 // проверка бита
/********************** конфигурация **************************/
__CONFIG                   // Биты конфигурации
(INTIO                     // Внутренний генератор 4 мГц
& UNPROTECT                // off защиту памяти
& BOREN                    // on контроль питания
& MCLRDIS                  // off вывод начальной установки
& PWRTEN                   // on таймер задержки запуска
& WDTDIS                   // off сторожевой таймер
& LVPDIS );                // off низковольтное программирование
/************************ переменные **************************/
unsigned char const cifra[11] = {0b01111110, 0b00110000,
 0b01101101, 0b01111001, 0b00110011, 0b01011011, 0b01011111,
 0b01110000, 0b01111111, 0b01111011, 0b00000000};
unsigned char const segment[6] = {0b01000000, 0b00100000,
 0b00010000, 0b00001000, 0b00000100, 0b00000010};
unsigned char i, c, bright_indik, hg1, hg2, hhg1, hhg2;
/************************* функции ****************************/
void podgot(void)
{
  TRISA = 0b00000011; // направление работы ножек порта А
  TRISB = 0b00000000; // направление работы ножек порта В
  CMCON = 0x07;       // отключение компараторов
  PORTB = 0xff;       // очищаем порт B
  RBPU  = 0x01;       // подтягивающие R (0-вкл, 1-выкл)
}
void w3_write(unsigned char adres, unsigned char data)
{
  char i;
  WR_OFF();                  // начало передачи
  for(i = 8; i > 0;i --)
  {
    if(TestBit(adres, i - 1))
    {
      DIN_ON();              // выставили единичку
    }
    else
    {
      DIN_OFF();             // выставили нолик
    }
    STR_ON();                // такт в единичку
    __delay_us(5);           // длительность строба
    STR_OFF();               // такт в ноль
  }
  for(i = 8; i > 0; i --)
  {
    if(TestBit(data, i - 1))
    {
      DIN_ON();              // выставили единичку
    }
    else
    {
      DIN_OFF();             // выставили нолик
    }
    STR_ON();                // такт в единичку
    __delay_us(5);
    STR_OFF();               // такт в ноль
  }
  WR_ON();                   // завершение передачи
}
void clear(void)
{
  char i;
  for(i = 8; i > 0; i --)
  {
    w3_write(i, cifra[10]);  // гасим все индикаторы
  }
}
void inic7219(void)
{
  w3_write(0x0F, 0x00);         // тест выключен
  w3_write(0x0C, 0x01);         // нормальный режим
  w3_write(0x0B, 0x07);         // кол-во знаков 8
  w3_write(0x09, 0x00);         // дешифраторы отключены
  w3_write(0x0A, bright_indik); // яркость свечения
  clear();
}
void klava(void)
{
  if(knopkaup == 0 && bright_indik != 15)
  {
    bright_indik ++; clear();
    w3_write(0x0A, bright_indik); // яркость свечения
    hg1 = bright_indik / 10; // значение первой цифры
    hg2 = bright_indik % 10; // значение второй цифры
    hhg1 = cifra[hg1];       // маска первой цифры
    hhg2 = cifra[hg2];       // маска второй цифры
    w3_write(5, hhg1);       // прописали первую цифру
    w3_write(4, hhg2);       // прописали вторую цифру
    __delay_ms(1500); clear();
    return;
  }
  if(knopkadown == 0 && bright_indik != 0)
  {
    bright_indik --; clear();
    w3_write(0x0A, bright_indik);
    hg1 = bright_indik / 10;
    hg2 = bright_indik % 10;
    hhg1 = cifra[hg1];
    hhg2 = cifra[hg2];
    w3_write(5, hhg1);
    w3_write(4, hhg2);
    __delay_ms(1500); clear();
  }
}
/******************* основная программа ***********************/
void main(void)
{
  podgot();
  bright_indik = 8;          // яркость по умолчанию
  inic7219();
   __delay_ms(500);
  while(1)
  {
    for(c = 0; c  3; c ++)
    {
      for(i = 0; i  6; i ++)
      {
        w3_write(8, segment[i]);
        w3_write(7, segment[i]);
        w3_write(6, segment[i]);
        w3_write(5, segment[i]);
        w3_write(4, segment[i]);
        w3_write(3, segment[i]);
        w3_write(2, segment[i]);
        w3_write(1, segment[i]);
        __delay_ms(80);
      }
    }
    __delay_ms(500);
    clear(); klava();
    for(i = 8; i > 0; i --)
    {
      w3_write(i, cifra[i]);
      __delay_ms(500);
    }
    __delay_ms(500);
    clear(); klava();
  }
}

Теперь о коде. Главная здесь функция w3_write(), на ней все построено. При вызове функция получает два аргумента, adres и data и засылает их в регистр. Сначала восемь бит адреса или инструкции, затем восемь бит данных. Как уже было сказано, старшим битом вперед. После подачи питания и конфигурирования микроконтроллера вызывается подпрограмма inic7219(), которая прописывает в микросхему некоторую последовательность команд, после которой микросхема начинает нормально работать. Без инициализации микросхема ничего высвечивать не будет.

Еще в коде программы производится опрос двух кнопок. Это регулировка яркости свечения индикаторов. Если подключить модуль к отладочной плате, то можно увидеть, как действует регулировка. В Протеусе к сожалению этого не видно. Значения яркости от трех до пятнадцати яркость одинаковая. От ноля до двух индикаторы вообще не светятся.

О соответствии битов data и сегментов индикаторов. Старший, седьмой бит управляет точкой (DP), биты с шестого по нулевой сегменты A,B,C,D,E,F и G соответственно. В принципе образы всех цифр уже прописаны в массиве cifra[]. Но если возникнет надобность закодировать какой-то иной символ, то можно воспользоваться онлайн-генератором здесь на сайте. В нем можно задать любую последовательность сегментов.

В заключении ссылка на проект Протеуса с hex файлом.