Управление драйвером семисегментных индикаторов MAX7219
В этой статье хочу показать как программно управлять модулем с драйвером MAX7219 и восемью семисегментными индикаторами. Довелось пообщаться с этим модулем и надо сказать, мне он очень понравился. Понравилось и то, как легко им управлять и то, что он освобождает микроконтроллер от обслуживания динамической индикации. С ним можно вообще данные переписывать только при их изменении, как с LCD дисплеем. Привожу здесь код программы (демо) для микроконтроллера на языке Си.
В общем то управление драйвером простое, как сдвиговым регистром по трехпроводной схеме (3-Wire). Вернее он и имеет как раз в своем составе сдвиговый регистр. Алгоритм управления такой. Низким уровнем на входе CS разрешаем принимать данные. Данные отсылаются по 16 бит, старшим битом вперед. Биты с 15 по 8 это или адрес знакоместа (значения от 1 до 8), или служебная команда (значения от 9 до 15). Биты с 7 по 0 это данные, либо для инструкции, либо образ (маска) символа. Каждый выставленный бит на входе DIN записывается в регистр по фронту тактового импульса на входе CLK. После того как все биты переданы, "защелкиваем" их, выставив единичку на входе CS.
Управляет драйвер восемью светодиодными семисегментными индикаторами с общим катодом. Это означает, что чтобы погасить все сегменты индикатора, надо прописать в него 0, а что бы зажечь, нужно прописать 255. Каждый из разрядов индикатора имеет независимую адресацию и его содержимое может быть обновлено без необходимости перезаписи всего индикатора.
Внешний вид модуля 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 << y)) // проверка бита /********************** конфигурация **************************/ __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[]. Но если возникнет надобность закодировать какой-то иной символ, то можно воспользоваться онлайн-генератором здесь на сайте. В нем можно задать любую последовательность сегментов.