В первой части мы рассмотрели подключение многоразрядного семисегментного индикатора при динамической развертке по разрядам, т.е. в один момент времени отображается один разряд индикатора целиком. Недостатком такого включения является относительно большое число дополнительных элементов на принципиальной схеме: транзисторные ключи, резисторы в цепи каждого сегмента.
Рассмотрим вариант динамической индикации с по сегментной разверткой.
Посегментная динамическая индикация.
При таком способе в каждый момент времени светятся одинаковые сегменты во всех разрядах индикатора. Т.е. подаем сигнал включения на сегмент, а разряды «поджигаем» только те, где данный сегмент должен светиться. При такой развертке имеем фиксированное число «поджиганий» в цикле развертки: 7 (сегменты) + 1 (точка). Время свечения каждого сегмента не должно превышать 5 мс (цикл полной развертки, при этом, составит 40 мс — предел!). Т.к. для двухразрядного индикатора при токе каждого сегмента 10 мА общий ток через порт контроллера будет составлять максимум 20 мА, следовательно можно обойтись без транзисторных ключей. И токоограничивающих резисторов нужно меньше — не по числу сегментов, а по числу разрядов. Пример принципиальной схемы для двух разрядов ниже:
Двухразрядный индикатор подключен к Arduino Pro mini. Размеры элементов таковы, что выводы индикатора непосредственно можно запаять в контактные площадки модуля (см фото в начале статьи). Катоды сегментов разрядов подключены к выводам платы напрямую без токоограничивающих резисторов. При небольшом числе разрядов (до четырех) это допустимо, т.к. при посегментной развертке, через вывод протекает суммарный ток одного сегмента всех разрядов (при четырех разрядах и 5 мА на сегмент, общий ток 5 мА * 4 = 20 мА, что допустимо). Аноды разрядов индикатора подключаются к выводам платы через токоограничивающий резистор — в каждый момент времени ток определяется только одним сегментом.
Простой скетч, демонстрирующий работу динамической посегментной индикации, приведен ниже. Ничего полезного программа не делает, но позволяет легко в себе разобраться. Основными процедурами являются DisplayShow() — реализующая один цикл развертки (3 мс на свечение одного сегмента, всего восемь); ShowSeg() — включение нужных разрядов для выбранного сегмента и DigToSegmRaz() — кодирование цифры в ее 7-сегментное изображение по разрядам. Программа индицирует на индикаторе число «3.4».
/* индикация числа "34" на 2х разрядном 7-сегм.индикаторе программная динамическая развертка по сегментам 3мс на сегмент 8 сегментов - 2 разряда (резисторы) Общий Анод */ #define DIG1 9 #define DIG2 A0 #define s_A 6 #define s_B 5 #define s_C 13 #define s_D 10 #define s_E 12 #define s_F 7 #define s_G 8 #define s_H 11 #define Takt 3 //мс на каждый сегмент int dig1 = 0; //левый int dig2 = 0; //правый byte pnt = 0; //точка меж разрядами //посегментная развертка 0 в разряде - погашено! byte segA = 0; //развертка по сегментная, А byte segB = 0; //развертка по сегментная, B byte segC = 0; //развертка по сегментная, C byte segD = 0; //развертка по сегментная, D byte segE = 0; //развертка по сегментная, E byte segF = 0; //развертка по сегментная, F byte segG = 0; //развертка по сегментная, G byte segH = 0; //развертка по сегментная, H void setup() { pinMode(s_A, OUTPUT); pinMode(s_B, OUTPUT); pinMode(s_C, OUTPUT); pinMode(s_D, OUTPUT); pinMode(s_E, OUTPUT); pinMode(s_F, OUTPUT); pinMode(s_G, OUTPUT); pinMode(s_H, OUTPUT); pinMode(DIG1, OUTPUT); pinMode(DIG2, OUTPUT); Clean(); digitalWrite(DIG1,HIGH); digitalWrite(DIG2,HIGH); } void loop() { DisplayMath(34); DigToSegmRaz(); //раскидать цифры по сегментам развертки DisplayShow(); } void DisplayMath(int data) { pnt = 0; //изначально точка погашена dig1 = dig2 = 0; if (data < 100) { while (data >= 10) { data -= 10; dig1++; } dig2 = data; pnt = 1; //вкл точку меж разрядами } else { data = data / 10; while (data >= 10) { data -= 10; dig1++; } dig2 = data; } } void DisplayShow() { digitalWrite(s_A,LOW); //включаем линию сегментов А ShowSeg(segA); delay(Takt); digitalWrite(s_A,HIGH); //выключаем линию сегментов А digitalWrite(s_B,LOW); //вкл В ShowSeg(segB); delay(Takt); digitalWrite(s_B,HIGH); //выключаем линию сегментов В digitalWrite(s_C,LOW); //вкл C ShowSeg(segC); delay(Takt); digitalWrite(s_C,HIGH); //выключаем линию сегментов C digitalWrite(s_D,LOW); //вкл D ShowSeg(segD); delay(Takt); digitalWrite(s_D,HIGH); //выключаем линию сегментов D digitalWrite(s_E,LOW); //вкл E ShowSeg(segE); delay(Takt); digitalWrite(s_E,HIGH); //выключаем линию сегментов E digitalWrite(s_F,LOW); //вкл F ShowSeg(segF); delay(Takt); digitalWrite(s_F,HIGH); //выключаем линию сегментов F digitalWrite(s_G,LOW); //вкл G ShowSeg(segG); delay(Takt); digitalWrite(s_G,HIGH); //выключаем линию сегментов G digitalWrite(s_H,LOW); //вкл H ShowSeg(segH); delay(Takt); digitalWrite(s_H,HIGH); //выключаем линию сегментов H } //включение разрядов индикатора void ShowSeg(byte digit) { switch(digit) { case 1: { digitalWrite(DIG1,LOW); //правый разряд включить digitalWrite(DIG2,HIGH); } break; case 2: { digitalWrite(DIG1,HIGH); //левый разряд включить digitalWrite(DIG2,LOW); } break; case 3: { digitalWrite(DIG1,HIGH); //оба разряда включить digitalWrite(DIG2,HIGH); } break; default: { //case 0: digitalWrite(DIG1,LOW); //оба разряда гасим digitalWrite(DIG2,LOW); } break; } } //раскидать цифры по сегментам развертки void DigToSegmRaz() { //для левого разряда switch(dig1) { case 0: { segA = B10; segB = B10; segC = B10; segD = B10; segE = B10; segF = B10; segG = B00; } break; case 1: { segA = B00; segB = B10; segC = B10; segD = B00; segE = B00; segF = B00; segG = B00; } break; case 2: { segA = B10; segB = B10; segC = B00; segD = B10; segE = B10; segF = B00; segG = B10; } break; case 3: { segA = B10; segB = B10; segC = B10; segD = B10; segE = B00; segF = B00; segG = B10; } break; case 4: { segA = B00; segB = B10; segC = B10; segD = B00; segE = B00; segF = B10; segG = B10; } break; case 5: { segA = B10; segB = B00; segC = B10; segD = B10; segE = B00; segF = B10; segG = B10; } break; case 6: { segA = B10; segB = B00; segC = B10; segD = B10; segE = B10; segF = B10; segG = B10; } break; case 7: { segA = B10; segB = B10; segC = B10; segD = B00; segE = B00; segF = B00; segG = B00; } break; case 8: { segA = B10; segB = B10; segC = B10; segD = B10; segE = B10; segF = B10; segG = B10; } break; case 9: { segA = B10; segB = B10; segC = B10; segD = B10; segE = B00; segF = B10; segG = B10; } break; } //для правого разряда с помощью ИЛИ включаем единицей нужный сегмент switch(dig2) { case 0: { //для "0" надо включить все, кроме G segA = segA | 1; segB = segB | 1; segC = segC | 1; segD = segD | 1; segE = segE | 1; segF = segF | 1; } break; case 1: { //для "1" включим сегменты B и С segB = segB | 1; segC = segC | 1; } break; case 2: { segA = segA | 1; segB = segB | 1; segD = segD | 1; segE = segE | 1; segG = segG | 1; } break; case 3: { segA = segA | 1; segB = segB | 1; segC = segC | 1; segD = segD | 1; segG = segG | 1; } break; case 4: { segB = segB | 1; segC = segC | 1; segF = segF | 1; segG = segG | 1; } break; case 5: { segA = segA | 1; segC = segC | 1; segD = segD | 1; segF = segF | 1; segG = segG | 1; } break; case 6: { segA = segA | 1; segC = segC | 1; segD = segD | 1; segE = segE | 1; segF = segF | 1; segG = segG | 1; } break; case 7: { segA = segA | 1; segB = segB | 1; segC = segC | 1; } break; case 8: { segA = segA | 1; segB = segB | 1; segC = segC | 1; segD = segD | 1; segE = segE | 1; segF = segF | 1; segG = segG | 1; } break; case 9: { segA = segA | 1; segB = segB | 1; segC = segC | 1; segD = segD | 1; segF = segF | 1; segG = segG | 1; } break; } if (pnt == 1) segH = B10; //управляем точкой else segH = B00; } void Clean() { //все гасим (очистка) digitalWrite(s_A,HIGH); digitalWrite(s_B,HIGH); //катоды + digitalWrite(s_C,HIGH); digitalWrite(s_D,HIGH); digitalWrite(s_E,HIGH); digitalWrite(s_F,HIGH); digitalWrite(s_G,HIGH); digitalWrite(s_H,HIGH); digitalWrite(DIG1,HIGH); digitalWrite(DIG2,HIGH); //аноды + }
Надо отметить, что программа так же написана в ХУДШИХ традициях программирования. При ее работе контролер тоже только разверткой изображения и занимается, сделать что-то полезное ему «некогда», разве что — в прерываниях… Тем не менее, такой подход к написанию программы позволил «быстренько» создать вполне работоспособный велоспидометр (статья в журнале «Радио»).

Для увеличения числа разрядов индикатора в схеме надо аноды новых разрядов подключить через резисторы к портам Arduino. В ShowSeg() надо добавить отработку комбинаций включения для новых разрядов индикатора. В процедуре DigToSegmRaz() также необходимо дописать логическое ИЛИ для включения сегментов новых разрядов.
Для индикаторов с общим катодом схема изменится: аноды сегментов подключаются к выходам микроконтроллера без резисторов, а катоды разрядов через резисторы. В процедурах DisplayShow() и Show() надо поменять местами HIGH и LOW.
В первой части, посвященной методике работы с драйвером светодиодных индикаторов MAX7221, было знакомство с этим драйвером. В частности был описан режим прямого управления сегментами. Осталось научится работать во втором режиме, при котором используется встроенный в микросхему декодер символов