Софтуерна реализация на динамична индикация върху микроконтролер. Динамичен дисплей

10.09.2021


Схема на свързване на едноцифрен седемсегментен индикатор
Схема на свързване на многоразряден седемсегментен индикатор

Устройство за показване на цифрова информация. Това е най-простата реализация на индикатор, който може да показва арабски цифри. За изобразяване на букви се използват по-сложни многосегментни и матрични индикатори.

Както казва името му, той се състои от седем елемента на дисплея (сегменти), които се включват и изключват отделно. Чрез включването им в различни комбинации те могат да се използват за създаване на опростени изображения на арабски цифри.
Сегментите са обозначени с букви A до G; осми сегмент - десетична точка (десетична точка, DP), предназначена за показване на дробни числа.
Понякога на седемсегментния индикатор се показват букви.

Предлагат се в различни цветове, обикновено бели, червени, зелени, жълти и сини. Освен това те могат да бъдат с различни размери.

Също така светодиодният индикатор може да бъде едноцифрен (както на фигурата по-горе) или многоцифрен. Основно в практиката се използват едно-, дву-, три- и четирицифрени LED индикатори:

В допълнение към десетте цифри, седемсегментните индикатори могат да показват букви. Но малко букви имат интуитивно представяне от седем сегмента.
На латиница: главно A, B, C, E, F, G, H, I, J, L, N, O, P, S, U, Y, Z, малки a, b, c, d, e, g , h, i, n, o, q, r, t, u.
На кирилица: A, B, V, G, g, E, i, N, O, o, P, p, R, S, s, U, Ch, Y (две цифри), b, E/Z.
Следователно седемсегментните индикатори се използват само за показване на прости съобщения.

Общо седемсегментният LED индикатор може да показва 128 знака:

Типичният светодиоден индикатор има девет проводника: единият отива към катодите на всички сегменти, а останалите осем отиват към анода на всеки сегмент. Тази схема се нарича "обща катодна верига", има и схеми с общ анод(тогава е обратното). Често не един, а два общи терминала се правят в различни краища на основата - това опростява окабеляването, без да увеличава размерите. Има и така наречените „универсални“, но аз лично не съм срещал такива. Освен това има индикатори с вграден шифтинг регистър, който значително намалява броя на участващите изводи на порта на микроконтролера, но те са много по-скъпи и рядко се използват на практика. И тъй като необятността не може да се обхване, засега няма да разглеждаме такива индикатори (но има и индикатори с много по-голям брой сегменти, матрични).

Многоцифрени LED индикаторичесто работят на динамичен принцип: изходите на едноименните сегменти на всички цифри са свързани заедно. За да се покаже информация на такъв индикатор, управляващата микросхема трябва циклично да подава ток към общите клеми на всички цифри, докато токът се подава към клемите на сегмента в зависимост от това дали даден сегмент свети в дадена цифра.

Свързване на едноцифрен седемсегментен индикатор към микроконтролер

Диаграмата по-долу показва как е свързан едноцифрен седемсегментен индикаторкъм микроконтролера.
Трябва да се има предвид, че ако индикаторът с ОБЩ КАТОД, тогава то общо заключениесе свързва с "земя", а сегментите се запалват чрез захранване логическа единицакъм изхода на порта.
Ако индикаторът е ОБЩ АНОД, тогава се подава към общия му проводник "плюс"напрежение, а сегментите се запалват чрез превключване на изхода на порта в състояние логическа нула.

Индикацията в едноцифрен светодиоден индикатор се осъществява чрез прилагане на двоичен код към щифтовете на порта на микроконтролера на съответната цифра на съответното логическо ниво (за индикатори с OK - логически единици, за индикатори с OA - логически нули).

Токоограничаващи резисториможе да присъства или да не присъства в диаграмата. Всичко зависи от захранващото напрежение, което се подава към индикатора и технически характеристикипоказатели. Ако например напрежението, подадено към сегментите, е 5 волта и те са проектирани за работно напрежение от 2 волта, тогава трябва да се монтират токоограничаващи резистори (за ограничаване на тока през тях за повишено захранващо напрежение и да не изгарят не само индикатора, но и порта на микроконтролера).
Много е лесно да се изчисли стойността на резисторите за ограничаване на тока, като се използва формулата на дядото Ом.
Например, характеристиките на индикатора са както следва (взети от листа с данни):
— работно напрежение — 2 волта
— работен ток — 10 mA (=0,01 A)
— захранващо напрежение 5 волта
Формула за изчисление:
R= U/I (всички стойности в тази формула трябва да са в ома, волтове и ампери)
R= (захранващо напрежение - работно напрежение)/работен ток
R= (5-2)/0,01 = 300 ома

Схема на свързване за многоразрядни седемсегментни LED индикатор По принцип същото като при свързване на едноцифрен индикатор. Единственото нещо е, че в катодите (анодите) на индикаторите се добавят управляващи транзистори:

Не е показано на диаграмата, но между основите на транзисторите и щифтовете на порта на микроконтролера е необходимо да се включат резистори, чието съпротивление зависи от вида на транзистора (стойностите на резисторите се изчисляват, но можете също да опитате да използвате резистори с номинална стойност 5-10 kOhm).

Индикацията чрез изхвърляния се извършва динамично:
— двоичният код на съответната цифра се задава на изходите на PB порта за 1-ва цифра, след което логическото ниво се прилага към контролния транзистор на първата цифра
— двоичният код на съответната цифра се задава на изходите на PB порта за 2-ра цифра, след което логическото ниво се прилага към контролния транзистор на втората цифра
— двоичният код на съответната цифра се задава на изходите на PB порта за 3-та цифра, след което логическото ниво се прилага към контролния транзистор на третата цифра
- така в кръг
В този случай е необходимо да се вземе предвид:
— за индикатори с добреизползва се управляваща транзисторна структура NPN(контролиран от логическа единица)
- за индикатор с ОА- структурен транзистор PNP(контролиран от логическа нула)

Динамичният дисплей е един от проблемите, пред които са изправени начинаещите програмисти на микроконтролери. Много е казано за него, но реших да подкрепя това, което е известно, със снимки и примери за изходен код в C, за да улесня овладяването на този метод на показване.

1 Основи, или въведение

Първо, нека дефинираме терминологията, която ще използваме в цялата статия.

Ако трябва да управлявате дисплей, състоящ се от едно седемсегментно познато, това не създава никакви проблеми - може да се мисли като 8 независими светодиода. Ако трябва да покажете повече информация от един знак, проблемите започват: 2 познати места съставляват 16 светодиода, три - 24 и т.н., тоест за трицифрен дисплей може просто да няма достатъчно пинове на микроконтролера, а не да споменете 6 или повече цифрени дисплеи и по-специално матрични индикатори.

За простота нека се съгласим, че всички наши индикатори имат общ катод. Решението на проблема е съвсем просто: свържете клемите на сегментите на всички индикатори един към друг. Сега, ако искате да покажете информация на първото познато място, трябва да приложите необходимите нива към сегментните линии и да свържете общия изход на първия индикатор към общ проводниксхеми. Разбира се, трябва да има високи нива на общите катоди на всички останали индикатори. Очевидно необходимите сегменти на първия индикатор ще светнат. За изход към втори, трети и т.н. индикаторите трябва да правят същото, т.е. Чрез прилагане на логическа нула към един от общите катоди, ние избираме текущата показана цифра и състоянието на сегментните линии определя видимия символ.

За да се възприема целият дисплей като непрекъснато светещ, цифрите трябва да се сменят бързо - повече от 25 пъти в секунда. Както можете да видите, нивата на всички изходи (които, между другото, са станали значително по-малки, отколкото при обичайния подход) непрекъснато се променят, т.е. имат не статични нива, а динамични, откъдето идва и името на метода за индикация - динамичен.

Динамично изображение на дисплея

2 Видове хардуерна реализация

2.1 Плоски матрици

Ако се абстрахираме от седемсегментните индикатори, нашият дисплей може да бъде представен като матрица от отделни светодиоди, чиито аноди са комбинирани в редове на матрицата, а катодите в колони. Всъщност е точно така.

Очевидно, като предоставим необходимите нива на редовете и колоните на нашата матрица, можем да осветим всеки елементарен LED сегмент (известен още като пиксел - това е по-традиционен термин във връзка с матричните дисплеи). В зависимост от това как точно променяме нивата на редове и колони, можем да получим няколко типа динамичен дисплей:

  • по линии;
  • по колони;
  • сегмент по сегмент (на пиксел);
  • по смесен начин.

Разгледахме опцията за колона в предишната глава. Опцията за ред се различава от нея само по това, че редовете и колоните на нашата матрица са разменени. Методът сегмент по сегмент означава, че във всеки даден момент само един ред и една колона съдържат нивото, необходимо за светване на светодиода. Тоест във всеки един момент може да светне само един светодиод от цялата матрица (за разлика от предишните опции, когато целият ред или цялата колона могат да светят едновременно). Този метод напомня на сканиране на телевизор, когато лъчът се движи около целия екран, осветявайки фосфора на правилните места. Смесената опция, както подсказва името, е, че едновременно „активни“ нива могат да присъстват на няколко реда и колони едновременно.

Първите два варианта са много лесни за изпълнение и затова са широко използвани. Третият вариант се използва по-рядко, т.к изисква повече високи скоростиактуализиране на информация за редове и колони и среден токпрез сегмента (т.е. яркостта на сегмента) в този случай е значително по-ниска, отколкото в други. Последният смесен метод е най-малко разпространен, въпреки че има редица положителни качества. На първо място, този метод изисква използването на стабилни източници на ток в редовите и колонните вериги, в противен случай яркостта на светещите сегменти неизбежно ще зависи от техния общ брой. И изчисляването на комбинации от сигнали на редове и колони не е много лесно.

2.2 Многомерни матрици

Примерите, които разгледахме, предполагат изпълнението на монохромен дисплей, т.е. състоящ се от едноцветни светодиоди. Какво да направите, ако искате да получите многоцветен дисплей, например от RGB светодиоди? Има две възможни решения.

Първият е просто да увеличим броя на редовете (или колоните) на нашата матрица, третирайки всеки RGB светодиод като 3 независими отделни светодиода. Големият недостатък на този подход е 3 пъти увеличението на броя на редовете (или колоните). включено прост примерЛесно е да се види какво означава това на практика: използвайки два осем-битови микроконтролера на микроконтролера, можем да имаме монохромна 8x8 матрица от сегменти или цветна 4x4 матрица. Съгласете се, че във втория случай е практически невъзможно да се покаже нещо разбираемо...

Вторият начин е да преминете от „плоска“ матрица от сегменти към „многоизмерна“. Ако сигналът на всяка линия преминава през мултиплексор 1x3, тогава можем да си представим системата за показване на RGB светодиоди като 3 независими матрици с оригинално измерение: всяка матрица се състои от светодиоди с един и същи цвят и ние избираме желаната матрица с помощта на мултиплексор управляващи сигнали. Картината обяснява казаното.

Очевидно е, че в случай на многомерна матрица е необходим и допълнителен брой контролни линии, но този брой не е толкова голям: на същите два порта на контролера можем да получим цветен дисплей 7x7!!!

2.3 Начини за намаляване на размерността на матриците

Ако броят на изводите на микроконтролера е много ограничен, ще трябва да потърсим начини да намалим броя на редовете и колоните на нашата матрица. Разбира се, чудеса не се случват и в този случай ще трябва да платим, като използваме допълнителни микросхеми в допълнение към микроконтролера. Както може би се досещате, тук можете да използвате разгледания по-рано метод на „многоизмерни“ матрици - в края на краищата никой няма да ни забрани просто да използваме утроен брой едноцветни светодиоди вместо RGB светодиоди? Основното нещо е да ги подредите по подходящ начин...

И така, можем да намалим размерността на матрицата, като използваме:

  • Декодери или мултиплексори;
  • регистри за смяна.

Вече срещнахме мултиплексори по-рано, декодер, както се досещате, не се различава принципно от мултиплексора. Трябва само да се добави, че чрез използване на декодери/мултиплексори както за редове, така и за колони е възможно да се намали измерението на матрицата по двете измерения наведнъж, но в този случай може да се наложи да се използва само динамична индикация сегмент по сегмент, с всичките му недостатъци.

Shift регистрите могат да помогнат много по-добре от дешифраторите. Разгледайте диаграмата на фигурата по-долу.

Лесно е да се види, че произволен брой редове и колони ще изискват само увеличаване на броя на регистрите, а броят на включените контролни линии на микроконтролера ще остане същият! Малък минус този подходе, че с увеличаването на броя на регистрите във веригата, скоростта на последователно извеждане на информация в тях ще трябва да се увеличи, което не винаги е лесно постижимо. Например обикновените микроконтролери от семейството AVR, практически не ви позволяват да надвишите скоростта на серийния изход от 10 мегабита/сек. От друга страна, ако използвате други контролери, които могат да извеждат сигнали по-бързо, могат да възникнат проблеми от различен ред: разпространението на високочестотен тактов сигнал по дълга линия (и с голям брой регистри той неизбежно ще бъде един ) се случва напълно различно от нискочестотния, така че ще са необходими специални мерки по време на окабеляването печатна платкаи други неща, които няма да разгледаме в рамките на тази статия.

3 Методи за внедряване на софтуер

Няма да разглеждаме софтуерната реализация на всички споменати опции за динамично показване - това би раздуло неоснователно статията. Ще се ограничим само до три от най-популярните примери: плоска матрица с директно управление на редове и колони, същото с помощта на декодер и, накрая, вариант, използващ регистри за смяна. Във всички случаи ще се обърне специално внимание на всички нюанси софтуерна реализация, тоест C кодът ще бъде придружен от обяснения само в случаите, когато това съвпада с намерението на автора, а не изобщо с вашето ниво на обучение. С това намеквам, че трябва да знаете основите на C без мен.

За всички примери се съгласяваме, че нашият дисплей е изграден върху седемсегментни индикаторис общ катод.

3.1 Най-простият начин

Очевидно би било най-удобно в програмата да има определен масив, чието съдържание недвусмислено да определя кои сегменти в кои познати области на дисплея светят - един вид аналог на екранната RAM.

Нека въведем определението на следните константи:

#define SCR_SZ 6 /* брой запознавания на дисплея */ #define ROWS PORTB /* показване на порт „редове“, т.е. управление на сегмент */ #define COLS PORTD /* порт за управление на „колона“, т.е. общи катоди */

Сега нека декларираме екранния масив:

Unsigned char SCR;

Като начало ще приемем, че всеки елемент от масива съответства на познатостта на дисплея и всеки бит от този елемент съответства на определен сегмент от индикатора. Кой бит на кой сегмент отговаря - в този случай няма значение, както няма значение как са зададени тези битове в байтовете на нашия масив, просто ще приемем, че те вече са там. За простота ще приемем също, че общи катодисвързан към щифтовете на порта COLSпоследователно: най-малкият бит е най-десният индикатор, след това вторият, след това третият и т.н.

Как да накарам този масив да се "показва" на дисплея? Нека напишем следния код:

< SCR_SZ; pos++){ ROWS = SCR; COLS = ~(1 << pos); }

Ще изпълнява ли необходимата функция? да Но не е добре.

Първо, имайте предвид, че нямаме контрол върху това колко бързо се актуализира съдържанието на редовете и колоните. Второ, имайте предвид, че до момента, в който се отпечата новият елемент на масива РЕДОВЕна линиите COLSСтарото значение е все още там! До какво ще доведе това? Да, освен това за части от секундата зоната за познатост ще покаже сегменти от съседната зона за познатост, т.е. някои сегменти ще бъдат фалшиво осветени.

Можете да избегнете този ефект, като направите следното: преди да актуализирате съдържанието РЕДОВЕ, винаги гасете познатото място, което е било предишното. За да не се занимавате с определянето на предишното познаване, можете да загасите всичко наведнъж. Така нашият код приема следната форма:

Unsigned char pos; докато (1) за (поз = 0; поз< SCR_SZ; pos++){ COLS = 0xFF; ROWS = SCR; COLS = ~(1 << pos); delay(); }

Добавихме заглушаване на целия дисплей, преди да актуализираме състоянието на сегментните линии (като изпратим общите катоди високо, ние ще изключим индикатора, независимо от това, което присъства на анодите) и въведохме забавяне в края на цикъла. Сега дисплеят ще работи много по-добре. Но дали сме написали добра програма? Уви, не.

Факт е, че безкрайният цикъл на показване докатопросто няма да ни позволи да правим нищо друго. Каква програма ще имаме, която само да показва нещо на индикатора?! Разбира се, не всичко е 100% лошо, тъй като може да се направи нещо полезно с помощта на прекъсвания... и вместо забавяне забавяне ()можете да извършвате някои действия... Но всичко това е много, много криво: не е препоръчително да се извършва нещо сложно и тромаво в обработчиците на прекъсвания; от друга страна, ако направите нещо сложно и тромаво вместо забавяне, тогава е трудно да осигурите същото време за изчисление, в противен случай ще се окаже, че познатите места светят за различни периоди от време, което визуално ще изглежда като техните блясък или трептене с различна яркост.

По принцип тази опция може да бъде разрешена само по изключение, само като учебен пример или в случай (но отново, само по изключение!), когато основният решаван проблем е много прост (това може да бъде напр. , проблемът с измерването с помощта ADCнапрежение и го покажете на дисплея).

Какво трябва да направите? Отговорът, както винаги, е прост: всички процеси, които трябва да се извършват незабелязано от решението на основната задача (и индикацията, разбира се, е такъв процес), трябва да се извършват с помощта на прекъсвания на таймера.
Прекъсванията ще пристигат на строго определени интервали, което ще осигури равномерно осветяване на познатите табели. Индикацията за фон ще ни позволи просто да напишем нещо в масива в точното време в главния цикъл SCR- и веднага ще се появи на дисплея! И всички модификации на кода ще се сведат до факта, че вместо цикли използваме функция за обработка на прекъсвания:

ISR(TIMER0_OVF_vect)( статичен неподписан char pos = 0; COLS = 0xFF; ROWS = SCR; COLS = ~(1<< pos); if(++pos == SCR_SZ) pos = 0; }

Няколко коментара.

Променлива поз, указващ номера на текущия светещ знак, ние го правим локална статична променлива, така че да запазва стойността си от прекъсване до прекъсване. В края на функцията ние независимо (в края на краищата вече нямаме цикъл) увеличаваме броя на познатото място, докато достигнем лимита - в този случай отиваме отново в началото.

В основната програма ще трябва само да инициализираме портовете и таймера (в този случай - Таймер 0), така че да се препълва на интервалите, от които се нуждаем, и да позволява прекъсвания. След това не е нужно да мислите за индикацията - тя ще работи тихо и спокойно сама. Но как да определите желания интервал на препълване на таймера? Много просто. Човешкото око възприема трептенето с честота над 25 Hz като непрекъснато сияние. Имаме 6 индикатора, всеки от тях трябва да мига с тази честота, което означава, че информацията на дисплея трябва да се актуализира с честота 25 x 6 = 150 Hz или повече. Сега нека изчислим стойността на прескалера на таймера: разделете тактовата честота на MK на 256 ( Таймер 0всеки има AVRосем бита, което означава, че препълва след преброяване до 256) - това ще бъде желаната стойност на предразпределителя на таймера. Разбира се, малко вероятно е резултатът да съвпадне с една от стандартните стойности на прескалера - това не е проблем, можете да вземете най-близката по-малка подходяща стойност. Дисплеят ще работи на по-висока честота, но това няма да влоши качеството му! Страничен ефект ще бъде голямо натоварване на MK ядрото за дисплея. Ако това силно пречи на основната програма, ще трябва да превключите дисплея на друг таймер, например 16-битов Таймер 1, или въведете брояч за пропуснати препълвания на таймера:

#define SKIP 15 /* брой прекъсвания на таймера за пропускане */ ISR(TIMER0_OVF_vect)( static unsigned char pos = 0; static unsigned char skip = SKIP; if (--skip) return; skip = SKIP; COLS = 0xFF; ROWS = SCR; COLS = ~(1<< pos); if(++pos == SCR_SZ) pos = 0; }

В тези опростени примери приемаме, че към порта COLS, освен общите катоди на индикаторите, нищо друго не е свързано. В реалния живот обаче такъв късмет не се случва често и нещо друго най-вероятно е свързано с останалите линии на този порт. Следователно, когато организирате динамичен дисплей, винаги трябва да гарантирате, че състоянието на всички портови линии, които не са пряко включени в дисплея, остава непроменено. Това се прави просто: вместо просто да пишете нова стойност в порта, трябва да използвате маскиране на ненужни битове:

COLS |= 0x3F; // така че загасяваме всички познати места COLS &= ~(1<

И двата оператора не променят стойността на най-значимите битове на порта COLS.

3.2 Метод с декодер

Декодерът може да се използва за конвертиране HEXили BCDкодирайте в седемсегментни символи или за да изберете една от колоните на матрицата. И двете опции ще се различават от най-простия метод, обсъден по-рано, само по това как ще бъде организиран изходът към портовете РЕДОВЕи/или COLS, към който ще бъдат свързани входовете на декодера.
Възможност за използване на декодер за получаване на седемсегментен символ:

ISR(TIMER0_OVF_vect)( статичен неподписан char pos = 0; COLS |= 0x3F; ROWS = (ROWS & 0xF0) | (SCR & 0x0F); COLS &= ~(1<< pos); if(++pos == SCR_SZ) pos = 0; }

Както можете да видите, промените са минимални - преди показване РЕДОВЕсимволен код от масива SCR, най-значимите битове се маскират, след което най-малко значимите битове се задават в съответствие с кода на символа. Тоест считаме, че декодерът е свързан към 4-те най-малко значими бита на порта РЕДОВЕ.

Надявам се, че няма смисъл да давам пример за декодиране на колони - всичко вече е ясно.

3.3 Метод на регистриране

Въпреки че динамичната индикация с помощта на регистри за смяна не се различава фундаментално от описаните по-рано методи, има няколко варианта за нейното прилагане. Ще разгледаме най-простия - извеждане на битове чисто софтуерно. И при изпълнението на други (използвайки USI/USART/SPI/TWI) можете да опитате сами.

За варианта на предварително избрания дисплей от 6 и седемсегментни познати места използваме 2 регистъра за смяна от типа 74HC595. Този регистър се управлява от три сигнала: тактови импулси за въвеждане на серийни данни CLK, самите данни ДАННИи импулс на едновременно паралелно извеждане на информация, записана в регистъра НАБОР. Нека декларираме съответните макроси (за простота ще изпратим всички сигнали към един порт):

#define CLK _BV(PB0) #define DATA _BV(PB1) #define SET _BV(PB2) #define REG_PORT PORTB

За да пишете в регистъра, е удобно да напишете отделна функция:

Static void shift(unsigned char d)( unsigned char i; for (i=0; i< 8; i++){ // устанавливаем нужный уровень DATA if(d & 1) REG_PORT |= DATA; else REG_PORT &= ~DATA; REG_PORT |= CLK; // даем импульс CLK REG_PORT &= ~CLK; d >>= 1; } }

Силно препоръчително е да направите тази функция статична, т.к ще се използва в манипулатора на прекъсвания. Компилаторът най-вероятно ще направи статични функции във формата вграден-вмъквания в манипулатора на прекъсвания, т.е. няма да има ненужно използване на стека, което не е гарантирано за нестатични функции.

Сега нашият манипулатор на прекъсвания ще изглежда така:

ISR(TIMER0_OVF_vect)( статичен неподписан char pos = 0; shift(SCR); shift(~(1<< pos)); REG_PORT |= SET; // выдаем импульс SET REG_PORT &= ~SET; if(++pos == SCR_SZ) pos = 0; }

Тъй като данните, записани в регистрите, се появяват на неговите изходи едновременно, не е необходимо първо да се гасят индикаторите. Трябва да се помни, че софтуерният последователен изход е доста дълъг процес, особено за матрици с големи размери, така че трябва да бъде оптимизиран за скорост възможно най-много. Това може да се направи най-добре с помощта на хардуера за сериен изход, намиращ се в MCU.

4 За тези, които никога нямат достатъчно

И така, вие се запознахте с основите на внедряването на динамичен дисплей. Но, както обикновено, въпросите не намаляват, а се увеличават. Предусещайки някои от тях, ще се опитам веднага да дам необходимите отговори.

4.1 Аноди, катоди - какво да избера?

Всичко, което разгледахме по-рано, се отнася до индикатори с общи катоди. Ами ако искате да го използвате с обикновени аноди? Като цяло всичко остава същото, с изключение на това, че преди извеждане ще е необходимо да се обърнат данните - изчистването на познанието се извършва чрез извеждане на нули в COLS, запалване - съответно единици и сегменти в РЕДОВЕще бъдат включени с нули вместо единици. Така че манипулаторът на прекъсванията ще изглежда така:

ISR(TIMER0_OVF_vect)( статичен неподписан char pos = 0; COLS &= 0xC0; ROWS = ~SCR; COLS |= (1<< pos); if(++pos == SCR_SZ) pos = 0; }

Това е просто. Освен ако, разбира се, не се опитате да напишете универсален код, подходящ както за обикновени аноди, така и за обикновени катоди. Има два начина да направите това: или с помощта на директиви за условно компилиране, или с помощта на функция за преобразуване. Ще демонстрирам първия вариант и ще ви предложа да помислите сами за втория.

#define COMMON_ANODE 1 ISR(TIMER0_OVF_vect)( static unsigned char pos = 0; #if COMMON_ANODE != 1 COLS &= 0xC0; ROWS = ~SCR; COLS |= (1<< pos); #else COLS |= 0x3F; ROWS = SCR; COLS &= ~(1 << pos); #endif if(++pos == SCR_SZ) pos = 0; }

Въпреки че това е малко тромаво, след като го напишете веднъж, можете да го използвате във всички проекти без практически никакви промени.

4.2 Трептене

В много случаи дисплеят се използва не само като средство за показване на информация, идваща от вътрешността на устройството, но и за показване на въведени от потребителя данни. И в този случай е необходимо да можете по някакъв начин да отделите непроменливото от променливото на дисплея. Най-лесният начин да направите това е да накарате съответното познато място (или няколко познати места) да трепти.

Много лесно се прави. Нека въведем глобална променлива, всеки единичен бит от която ще обозначава мигащ символ:

unsigned char мига = 0;

Сега нека леко модифицираме манипулатора на прекъсванията:

ISR(TIMER0_OVF_vect)( статичен неподписан char pos = 0; статичен неподписан char запис = 0; COLS |= 0x3F; if(!(мига & (1)<

Както можете да видите, добавена е само една статична променлива - броячът на входовете към манипулатора на прекъсванията влизанеи оператор за тестване на условие. Логиката е проста: изходът на следващото запознаване се извършва само ако или в съответния бит мигамнула или най-значимият бит на брояча влизанее равно на 1. Ако предположим, мигамсъдържа всички нули, тогава това условие винаги е изпълнено - показват се всички познати места. Ако мигамсъдържа 1 в един от своите битове, тогава съответният знак ще бъде показан само в момента, когато най-важният бит на брояча е равен на 1. Тъй като броячът се увеличава всеки път, когато се въведе манипулаторът на прекъсване, съответният знак ще трептене с честота 128 пъти по-малка от честотата на прекъсване.

4.3 Регулиране на яркостта на сегментите

Писах за регулирането на яркостта в отделна статия, която се наричаше по този начин.

4.4 Произволно разпределение на кеглите

По-рано беше казано, че щастието да посветиш цял MK порт за дисплей е доста рядко. Но още по-рядко се получава удобна следа от печатна платка, ако единият порт се използва изцяло за редове, а другият порт се използва за колони от матрицата на дисплея. Много по-често оптимално проследяване се получава само когато редове и колони са смесени между два или дори повече микроконтролерни порта. Няма да се налага да жертвате красотата на печатната платка, ако организирате софтуерно пренареждане на битове по време на показване.

Нека да разгледаме един абстрактен пример. Нека най-доброто проследяване се осигури със следното разпределение на сигналите по линиите на MK портовете:

Сегмент А

Сегмент Б

Сегмент H

Сегмент C

Сегмент D

Сегмент G

Сегмент E

Сегмент F

Както можете да видите, линиите на матрицата са смесени между трите порта и всички неизползвани линии на тези портове не трябва естествено да променят нивата си по време на процеса на показване.

Най-добре е да започнете да разработвате функция за динамична индикация за този случай чрез разпределяне на сегменти в символни битове. Преди това вярвахме, че в масива SCRНие съхраняваме битови маски на знаци, т.е. Тези в байта показват светещи сегменти. Не сме мислили кой бит на кой сегмент отговаря. Така че сега е моментът да помислим за това.

Удобно е да рисувате предназначението на портовите линии под формата на три плочи:

1

А

0

4

з

3

2

б

Е

д

5

Ж

г

В

Трябва да съберем всички сегменти в един байт. Това ще трябва да се направи със сменни операции, така че трябва да се опитате да ги разпределите така, че да направите минимум смени. нека поговорим

Ако сегментът бита FEGDCоставете в символа, така че да попаднат в PORTDбез смени, след това сегмента зможе също да остане в 6-ия бит на символа и също така не трябва да се измества преди изхода PORTC, но за сегменти Аи INбитове 7 и 3 ще останат, тоест най-вероятно сегментът INще трябва да се измести с 3 позиции преди изхода и сегментът А- до 6. Ще се спра на този вариант, а вие можете да продължите да търсите минималните смени (смените на няколко позиции не са толкова бърза операция, затова е препоръчително да намалите броя им до минимум).

И така, в нашия случай разпределението на битовете върху символния байт беше както следва:

А

з

Е

д

б

Ж

г

В

Нека маркираме битовите маски за изход към съответните портове:

г

0

0

1

1

0

1

1

1

0x37

б

1

0

0

0

0

0

0

0

0x80

В

0

1

0

0

1

0

0

0

0x48

Използвайки тези маски, използваме операцията „побитово И“, за да изберем необходимите битове за изход към порта.

Нека декларираме константите на маската:

#define MASKD 0x37 #define MASKB 0x80 #define MASKC 0x48

Преди това извеждахме символа към един порт РЕДОВЕ, сега тази процедура ще бъде разделена на три части:

PORTD = (PORTD & ~MASKD) | (SCR & MASKD); PORTB = (PORTB & ~MASKB) | ((SCR & MASKB) >> 6); PORTC = (PORTC & ~MASKC) |

((SCR & _BV(6)) | (((SCR & _BV(3)) >> 3); PORTCМоля, имайте предвид, че за теглене до един бит трябва да бъде изведен без смяна, а вторият - с смяна, така че вместо MASKC Трябваше да използвам отделни макроси.

_BV()

Сега остава да решите как да гасите и запалвате съответните познати места. Нека декларираме константи, съответстващи на контролните битове за познаване:

#define COM0 _BV(0) #define COM1 _BV(3) #define COM2 _BV(4) #define COM3 _BV(5) #define COM4 _BV(7) #define COM5 _BV(3) #define COM_D (COM5) #define COM_C (COM2 | COM3 | COM4) #define COM_B (COM0 | COM1) За да загасите всички познати, трябва да изведете съответните константи към портовете:

COM_x

Но за да включите познатостта, ще трябва да сте хитри (няма смисъл да извеждате към трите порта, защото само един бит ще бъде активен в конкретен порт, в зависимост от стойността поз), например с помощта на оператора превключвател:

Switch(pos)( case 0: PORTB &= ~COM0; break; case 1: PORTB &= ~COM1; break; case 2: PORTC &= ~COM2; break; case 3: PORTC &= ~COM3; break; case 4: PORTC &= ~COM4 случай 5: PORTD &= ~COM5;

Не е най-красивият начин, но работи.

Така нашият манипулатор на прекъсвания приема следната форма:

ISR(TIMER0_OVF_vect)( статичен неподписан char pos = 0; статичен неподписан char запис = 0; // потискане на PORTD |= COM_D; PORTC |= COM_C; PORTB |= COM_B; // показване на PORTD = (PORTD & ~MASKD) | ( SCR & MASKD); (PORTB & ~MASKB) |. ((SCR & MASKB) >> 6); / blink if(!(blink & (1<< pos)) || (++entry & 0x80)) { switch(pos){ case 0: PORTB &= ~COM0; break; case 1: PORTB &= ~COM1; break; case 2: PORTC &= ~COM2; break; case 3: PORTC &= ~COM3; break; case 4: PORTC &= ~COM4; break; case 5: PORTD &= ~COM5; break; } } if(++pos == SCR_SZ) pos = 0; }

Сега остава да разберем как по-удобно да опишем символите за изход ... Предлагам да направите следното: дефинирайте константи, съответстващи на битовете на сегментите, и след това "конструирайте" необходимите символи от тези константи:

// елементарни сегменти #define _A _BV(7) #define _B _BV(3) #define _C _BV(0) #define _D _BV(1) #define _E _BV(4) #define _F _BV(5) #define _G _BV (2) #define _H _BV(6) // цифрови символи #define d_0 (_A | _B | _C | _D | _E | _F) #define d_1 (_B | _C) #define d_2 (_A | _B | _G | _D | _E) // и така нататък

По този начин, ако трябва да покажете нула в най-дясната позиция на дисплея, просто трябва да напишете на правилното място:

SCR = d_0;

Ако в друг проект трябва да разпределите битовете по различен начин, ще промените само числата в макросите Трябваше да използвам отделни макросиза елементарни сегменти и всички символи ще бъдат „преработени“ автоматично. За най-простите случаи, описани в началото, няма да ви се налага да правите нищо друго, но за опцията „пренареждане на битове“ ще трябва, разбира се, да се бърникате.

4.5 Поддръжка на бутони

При традиционния недостиг на MK щифтове, проблемът с големия брой бутони, без които рядко всяко устройство може да мине, е много остър. Използват се различни матрични включвания и др. трикове, обаче, като леко усложните функцията на динамичния дисплей, е лесно да имате толкова бутони на ваше разположение, колкото са познатите на дисплея, и в този случай допълнително ще трябва да използвате само един порт за микроконтролер. Вярно е, че все още трябва да инсталирате диод на всеки бутон.

Това е показано схематично на фигурата.

А програмата изглежда така:

#define keypin() (!(PIND & _BV(KEY))) ISR(TIMER0_OVF_vect)( static unsigned char pos = 0; static unsigned char entry = 0; static unsigned char tmp_key = 0; ROWS = 0; if(keypin( )) tmp_key |= 1<< pos; COLS |= 0x3F; if(!(blink & (1<< pos)) || (++entry &0x80)){ ROWS = (ROWS & 0xF0) | (SCR & 0x0F); COLS &= ~(1 << pos); } if(++pos == SCR_SZ){ pos = 0; key = tmp_key; tmp_key = 0; } }

тук КЛЮЧ- това е макрос, който задава бита на избрания порт, на който са „свързани“ всички бутони, макрос щифт()връща логическата стойност TRUE, ако избраният пин е с ниско логическо ниво. В примера бутоните са свързани към PORTD.

При всяко прекъсване на таймера, всички сегменти първо се гасят - това е необходимо, за да не може токът през светодиодите да доведе до погрешно неразпознаване на натиснатия бутон. След това се запитва входът на бутона - ако нивото е ниско, това означава, че е натиснат бутонът, свързан към съответния пози катод. В променлива tmp_keyсъстоянията на бутоните се натрупват и пренаписват в глобална променлива ключслед завършване на цикъла на показване. Всичко, което трябва да направите, е да анализирате смисъла от време на време ключи обработване на открити кликвания:

Статичен неподписан char get_key())( unsigned char tmp = 0; tmp = ключ; _delay_ms(10); if(key == tmp) return tmp; else return 0; )

Тази проста функция гарантира, че бутоните няма да отскачат, въпреки факта, че поради „динамичния“ характер на търсенето на бутони, вероятността от отскачане вече е ниска.

5 Какво друго?

И така, вие сте усвоили доста типични техники за внедряване на динамичен дисплей. Мисля, че това ще ти е достатъчно за първия път, а може би дори и за целия ти живот. В крайна сметка основното е да разберете техниките и алгоритмите и винаги можете сами да добавите тънкости и нюанси. Но какво друго може да очаква „близо“ до динамичния дисплей?

Както казах по-рано, можете да добавяте, дори до независимо регулиране на всеки сегмент.

Можете да помислите за оптималността на манипулатора на прекъсвания - за образователни цели написах доста груб код, например, използвах навсякъде SCR, въпреки че би било по-оптимално да прочетете стойността в локална променлива веднъж и след това да оперирате с нейната стойност. Въпреки че оптимизаторът със сигурност ще помогне с моя подход, за практически цели си струва да опитате и да оптимизирате себе си, наблюдавайки се по отношение на размера на получения код и/или скоростта на програмата.

Можете да помислите за интересната идея за автоматично регулиране на яркостта на дисплея в зависимост от нивото на околната светлина. Както знаете, LED индикаторите са по-малко видими, колкото по-тъмно е - те просто се размазват. Следователно, на тъмно е разумно да се намали яркостта на индикаторите, като се увеличи през дневните часове. Най-простото нещо е да използвате отделен фоторезистор или светодиод като светлинен сензор, но можете да го направите по различен начин: известно е, че светодиодът може да работи и като фотодиод, следователно, ако използвате порта, свързан към входа за индикация ADC, след това, ако желаете, можете да измерите фото-едс на несветещия сегмент на индикатора и да използвате тази стойност, за да регулирате яркостта...

Можете да помислите за използване на хардуер за сериен изход, за който вече намекнах.

Интересен вариант на напълно универсален подход към динамичния дисплей, с който също препоръчвам да се запознаете, беше предложен от МОЛЧЕЦ. Накратко, същността: разпределението на сегментите по символни битове, присвояването на портове за управление на индикатора и дори вида на индикатора - накратко, всички, всички, всички параметри - са посочени под формата на конфигурационна таблица в EEPROM. Въз основа на тази таблица всичко е организирано програмно: от инверсия в зависимост от вида на индикатора до пренареждане на битове на различни портове. В този случай изходният код на програмата за динамичен дисплей винаги остава непроменен, а конфигурационната таблица се съставя от крайния потребител в зависимост от неговите предпочитания. Методът е наистина универсален и гъвкав, но е свързан с повишена консумация на програмна памет.


3 Публикувано от АРВ, в 06:48 на 25.08.2010г
Миша, на твое място не бих давал такива категорични изказвания „ти не можеш“, „никой не го е написал“ или „авторско право“, защото първо не е учтиво и второ:
1. Направих пълзяща линия на матрица 10x16 преди много време (това беше) - можете да намерите видео на работата й в тази бележка http://site/content/view/160/38/
2. Написах статия (ще я намерите в новините - последната за днес) как се прави тикер на LCD. Ако напрегнете малко мозъка си, тогава преработването на алгоритъма за изход към матрица е дреболия.
3. на моя уебсайт няма нито една статия, копирана от някъде (copy-paste не е авторско право, направихте печатна грешка), всички материали са напълно оригинални. Много сайтове имат копия на тези материали с мое разрешение (или разрешението на авторите на материалите, които имат пълното право да публикуват своите материали на много места едновременно).

Само регистрирани потребители могат да оставят коментари.
Моля, регистрирайте се или влезте във вашия акаунт.

Актуализиран на 03.04.15 г. здравейте всички В последната статия разгледахме алгоритъма за комуникация с LCD дисплея, както и извеждане на информация към него и го тествахме в симулатор. В тази публикация ще говоря накратко за „евтин“ метод за показване на информация - това е седем сегментен индикатор

, който е най-простият от индикаторите, за показване на арабски цифри, както и някои символи, които могат да бъдат показани на него. Ще разгледаме и C програма за AVR и връзка в хардуер и симулатор. За показване на букви се използват по-сложни многосегментни и матрични индикатори. Но тук ще говорим за седем сегмента... Ще разгледаме и какво е динамичен дисплей
, като начин за незабавно показване на измерената стойност. За да направим това, ще разгледаме използването на прекъсвания в програмата.

Така че трябва да знаете, че индикаторите идват с общ анод и катод, както е на фигурата по-долу. Имах под ръка индикатор с общ катод (долната част на фигурата), чийто контролен изход е свързан към минуса. С това ще работим. Ако има няколко индикатора, тогава катодите се управляват от няколко MK крака. !!! Но винаги използвайте транзистори, защото... I/O портовете може да изгорят поради относително висок ток.Използвах обикновени 315 транзистори. На фигурата по-долу съм показал приблизителна връзка, чрез тях, на управляващия изход на индикатора и контролера. За монтаж се нуждаем от 11 крака на микроконтролера, т.е. за показване на информация за сегменти има 8 крака (7 + точка) и един крак за всеки индикатор, за да го контролирам, имам три от тях, така че има и три контролни крака. По-долу съм дал и описал програмата. За да контролираме сегменти, ще използваме щифтове от един порт, за да не се объркаме. Написа за микроконтролер ATmega8

. Ако искате да се отървете от „камъка“, тогава това не е проблем, например, където можете лесно да промените настройките за друг „камък“, главно това са номерата на ПИН и портове. Общите правила за универсалност и трансфер също са описани там.

Чертеж на свързване на транзистор към MK и индикатор. програма. В тази малка програма (на Si ) Дадох пример за включване на три индикаторни елемента и извеждане на число със запетая. Използване на таймер и прекъсване за изход към индикатора. Докато пишем програмата, трябва да решим кой щифт на порта да отговаря на сегмента на индикатора. Самият индикаторен елемент е показан на фигурата по-долу. Отстрани има описание на свързването на щифтовете към сегментите на индикаторния елемент (щифт на порта – номер на крака на елемента (фиг. по-горе) – буква на сегмента – номер в масива, отговорен за включването сегментите на елемента).

PB0 - 12 - управление на първия елемент

PB6 - 9 - управление на втория елемент
PB7 - 8 - управление на третия елемент
PD7 – 11 – (A) – 128
PD6 – 10 – (F) – 64
PD5 – 7 – (B) – 32
PD4 – 5 – (G) – 16
PD3 – 4 – – 8
PD2 – 3 – (DP) – 4
PD1 – 2 – (D) – 2
PD0 – 1 – (E) – 1

#включи
#включи
#включи
/*Нека дефинираме седемсегментен елемент за всеки щифт на порта (фигурата по-горе)*/
#дефинирайте 128
#define b 32
#дефинирай от 8
#define d 2
#define e 1
#define f 64
#define g 16
#define dp 4
/*Тези макроси съдържат числа, съответстващи на две, повдигнати на степен,равен на номера на „крака“ на порта, към който е свързан сегментът на индикаторасъщото име като макроса.*/
кратко неподписано int j, k = 0; /*променливите се използват в макроса за прекъсване*/
float i = 0;
/*Променлива за изход към индикатора*/ кратко неподписано
int w = 0;
/*Променлив индикатор за включване на точката*/
unsigned char слот;
/*Масив, който съхранява числата, от които се нуждаете изход през порта към индикатора, така че да показва цифра, равна на числото
{
елемент от масив. Числата зависят само от макросите.*/
void Slot_init()
/*Функция за инициализация на индикатора*/
Слот = (a+b+c+d+e+f);
Слот = (b+c);
Слот = (a+b+g+e+d);
Слот = (a+b+g+c+d); .
Слот = (f+g+b+c);
/*Имената на макроси съответстват на имената на индексните сегменти*/
Слот = (a+f+g+c+d);
Слот = (a+f+g+c+d+e);
}
Слот = (a+b+c);
Слот = (a+b+c+d+e+f+g);
Слот = (a+b+c+d+f+g);
Слот = dp; /*Точка*/
{
/*Тези променливи съхраняват числата, които трябва да бъдат показани*/
char Elem1, Elem2, Elem3;/* Функцията извлича цифри от трицифрено число Number */
void Display (float Number)
{
поплавък N1, N2;/*Променливи за функцията modf*/
N1 = modf(число, &N2);
}
short unsigned int Num1, Num2, Num3;
Num1=Num2=0;
докато (Число >= 100) /*Стотици*/
{
Число -= 100;
Num1++;
}
докато (число >= 10) /*десетки*/
{
Число -= 10;
Num2++;
}
Num3 = Число; /*Единици*/
Elem1 = Слот;
if (w == 1) /*Условие за включване на точка във втория елемент*/
{
Elem2 = (Slot|0×04);
/*логическо събиране с щифт, съответстващ на точка*/ w = 0;
}
/*Изключете точката*/
друго
Elem2 = Слот;
}
Elem3 = Слот;
{
int main (void) /*началото на основната програма*/ DDRB = 0Xff;
/*конфигурира всички пинове на порт B като изходи*/
DDRD = 0xff;
/*конфигурира всички пинове на порт D като изходи*/
PORTD = 0×00;
/*Задайте 0*/
PORTB |= _BV(PB6);
PORTB |= _BV(PB0);
PORTB |= _BV(PB7);
slot_init();<sei();
/*Активиране на общо прекъсване*/</*Инициализиране на таймера T0*/
TIMSK = (1 /*Флаг за разрешаване на препълване на таймера на брояча T0*/
{
TCCR0 = (0
/* 1000000/8 = 125000= 125000/256 = 488.28 Hz */
докато (1)
/*Безкраен цикъл, показване на променливата на индикатора*/
_закъснение_ms(1000);
} i=i+0.1;
} ако (i == 99,9)

i = 0,0;дисплей(i); /*Скоба за затваряне на безкраен цикъл*/, /*Затваряща скоба на главната програма*/

Следващата стъпка е да добавите функция за прекъсване, която ще бъде задействана от специален вектор TIMER0_OVF_vect, който отговаря за прекъсванията при препълване на T0. За това използваме хардуерен таймер/брояч T0. По-горе в програмата записахме настройките на таймера и също изчислихме честотата, с която ще се появи динамичният дисплей.
{
Тези. Кога регистърът за броене в брояча е препълнен
Общата програма спира и се изпълнява функцията по-долу, след излизане от нея продължава изпълнението на основната програма.<=30; j++) { } ISR (TIMER0_OVF_vect)
PORTB &= 0x3e; //Почистване на PB7, PB6, PB0_за (j = 0; j
// Забавяне за изключване на транзистора
{
(k == 3) ? k = 0: k++;<< PINB7); /*Променлива, която е отговорна за пожарната последователност
триелементен индикатор, 0,1 и 2. При определено число, 1 се задава на определен крак, след което транзисторът се отваря и индикаторните сегменти, съответстващи на променливата Elemn, светват */
превключвател (k)
случай 0: PORTB |= (1<< PINB6); // Единици
PORTD = Elem3;
превключвател (k)
прекъсване;<< PINB0); случай 1: PORTB |= (1
// Десетки
}
}

PORTD = Елем2;случай 2: PORTB |= (1 // Стотици. Нямаме нужда от транзистори в симулатора (Proteus). Има и една съществена разлика в програмата, а именно в прекъсването, къдеточзакъснение за изключване на транзистора - въведете 50 такта в симулатора. Всичко трябва да работи.

Докато публикувахме публикации, програмата ни за индикатора се промени малко, а именно добавихме четвърти елемент, показващ знак минус върху него, символите „H“ и „C“, формата на изхода на времето и комбинацията от всички режими. Така че четете, анализирайте и експериментирайте.

По-долу са източниците и проектът, базиран на горния материал.

(Изтегляния: 795 души)

това е всичко В следващата статия ще опиша свързването на температурни сензори и ще покажа информацията на индикатора. До скоро!

В този урок ще научим за схемите за свързване на седемсегментни LED индикатори към микроконтролери и как да управляваме индикаторите.

Светодиодните седемсегментни индикатори остават един от най-популярните елементи за изобразяване на цифрова информация.

За това допринасят следните им качества.

  • Ниска цена. По отношение на дисплея, няма нищо по-евтино от LED цифрови индикатори.
  • Разнообразие от размери. Най-малкият и най-големият индикатор са LED. Знам за LED индикатори с височина на цифрите от 2,5 мм до 32 см.
  • Свети в тъмното. В някои приложения това свойство е почти решаващо.
  • Имат различни цветове на светене. Има дори двуцветни.
  • Доста ниски управляващи токове. Съвременните LED индикатори могат да бъдат свързани към щифтовете на микроконтролерите без допълнителни ключове.
  • Подходящ за тежки условия на работа (температурен диапазон, висока влажност, вибрации, агресивна среда и др.). За това качество светодиодните индикатори нямат равни сред другите видове дисплейни елементи.
  • Неограничен експлоатационен живот.

Видове LED индикатори.

Седемсегментният LED индикатор показва знак, използвайки седем светодиода - цифрови сегменти. Осмият светодиод осветява десетичната точка. Така че има 8 сегмента в седемсегментен индикатор.

Сегментите са обозначени с латински букви от "A" до "H".

Анодите или катодите на всеки светодиод са комбинирани в индикатора и образуват общ проводник. Следователно има индикатори с общ анод и общ катод.

LED индикатор с общ анод.

LED индикатор с общ катод.

Статично LED управление.

Светодиодните индикатори трябва да бъдат свързани към микроконтролера чрез токоограничаващи резистори.

Изчисляването на резисторите е същото като за отделните светодиоди.

R = (U захранване - U сегмент) / I сегмент

За тази верига: I сегмент = (5 – 1,5) / 1000 = 3,5 mA

Съвременните LED индикатори светят доста ярко дори при ток от 1 mA. За схема с общ анод ще светят сегментите, на чиито контролни изводи микроконтролерът ще генерира ниско ниво.

В схемата на свързване на индикатор с общ катод се променя полярността на захранващите и управляващите сигнали.

Сегментът ще светне, на чийто контролен щифт ще се генерира високо ниво (5 V).

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

Необходими са осем пина за свързване на всеки седемсегментен индикатор към микроконтролера. Ако има 3-4 индикатора (цифри), тогава задачата става практически невъзможна. Просто няма достатъчно пинове на микроконтролера. В този случай индикаторите могат да бъдат свързани в мултиплексиран режим, в режим на динамична индикация.

Резултатите от едноименните сегменти на всеки индикатор се комбинират. Това води до матрица от светодиоди, свързани между сегментните щифтове и общите индикаторни щифтове. Ето схема за мултиплексно управление на триразряден индикатор с общ анод.

За свързване на три индикатора са необходими 11 пина, а не 24, както в режим на статичен контрол.

При динамичен дисплей само една цифра свети по всяко време. Сигнал с високо ниво (5 V) се подава към общия щифт на един от битовете, а сигнали с ниско ниво се изпращат към сегментните щифтове за онези сегменти, които трябва да светят в този бит. След определено време светва следващият разряд. Високо ниво се прилага към неговия общ щифт и сигналите за състояние за този бит се изпращат към сегментните щифтове. И така нататък за всички цифри в безкраен цикъл. Времето на цикъла се нарича време за регенериране на индикатора. Ако времето за регенерация е достатъчно кратко, човешкото око няма да забележи превключването на изхвърлянията. Ще изглежда, че всички изхвърляния постоянно светят. За да се избегне мигането на индикаторите, се смята, че честотата на цикъла на регенерация трябва да бъде най-малко 70 Hz. Опитвам се да използвам поне 100 Hz.

Схемата за динамична индикация за светодиоди с общ катод изглежда така.

Полярността на всички сигнали се променя. Сега към общия проводник на активния разряд се прилага ниско ниво, а към сегментите, които трябва да светят, се прилага високо ниво.

Изчисляване на динамични елементи на дисплея на светодиодни (LED) индикатори.

Изчислението е малко по-сложно, отколкото за статичен режим. По време на изчислението е необходимо да се определи:

  • среден ток на сегменти;
  • импулсен ток на сегменти;
  • съпротивление на сегментния резистор;
  • импулсен ток на общите клеми на разрядите.

защото Цифрите на индикатора светват на свой ред, яркостта на сиянието определя средния ток. Трябва да го изберем въз основа на параметрите на индикатора и необходимата яркост. Средният ток ще определи яркостта на индикатора на ниво, съответстващо на статично управление със същия постоянен ток.

Нека изберем среден сегментен ток от 1 mA.

Сега нека изчислим импулсния ток на сегмента. За да се осигури необходимия среден ток, импулсният ток трябва да бъде N пъти по-голям. Където N е броят на индикаторните цифри.

I сегмент имп. = I сегмент. ср. *Н

За нашата схема I сегмент. имп. = 1 * 3 = 3 mA.

Изчисляваме съпротивлението на резисторите, които ограничават тока.

R = (U захранване - U сегмент) / I сегмент. имп.

R = (5 – 1,5) / 0,003 = 1166 Ohm

Определяме импулсните токове на общите клеми на разрядите. 8 сегмента могат да светят едновременно, което означава, че трябва да умножите импулсния ток на един сегмент по 8.

I категория имп. = I сегмент. имп. * 8

За нашата верига I категория имп. = 3 * 8 = 24 mA.

  • Съпротивлението на резистора е избрано да бъде 1,1 kOhm;
  • щифтовете на микроконтролера за управление на сегмента трябва да осигуряват ток най-малко 3 mA;
  • щифтовете на микроконтролера за избор на индикаторната цифра трябва да осигуряват ток най-малко 24 mA.

При такива стойности на тока индикаторът може да се свърже директно към щифтовете на платката Arduino, без да се използват допълнителни ключове. За ярки индикатори такива токове са напълно достатъчни.

Схеми с допълнителни ключове.

Ако индикаторите изискват повече ток, тогава е необходимо да се използват допълнителни клавиши, особено за сигнали за избор на цифри. Общият ток на разреждане е 8 пъти тока на един сегмент.

Схема на свързване на LED индикатор с общ анод в мултиплексиран режим с транзисторни ключове за избор на разряди.

За да изберете малко в тази схема, е необходимо да генерирате сигнал с ниско ниво. Съответният ключ ще се отвори и ще подаде захранване към разряда на индикатора.

Схема на свързване на LED индикатор с общ катод в мултиплексиран режим с транзисторни ключове за избор на разряди.

За да изберете бит в тази схема, е необходимо да генерирате сигнал с високо ниво. Съответният ключ ще отвори и затвори общия разряден терминал към земята.

Може да има схеми, в които е необходимо да се използват транзисторни превключватели както за сегменти, така и за общи битови изводи. Такива схеми лесно се синтезират от предишните две. Всички показани схеми се използват, когато индикаторът се захранва с напрежение, равно на захранването на микроконтролера.

Ключове за индикатори с повишено захранващо напрежение.

Има големи индикатори, в които всеки сегмент се състои от няколко светодиода, свързани последователно. За захранване на такива индикатори е необходим източник с напрежение по-голямо от 5 V, което трябва да осигурява превключване на повишено напрежение, контролирано от сигнали на микроконтролера (обикновено 5 V).

Веригата на ключовете, които свързват индикаторните сигнали към земята, остава непроменена. И превключвателите на захранването трябва да бъдат изградени по различна схема, например по този начин.

В тази схема активният бит се избира от високото ниво на управляващия сигнал.

Между превключването на цифрите на индикатора всички сегменти трябва да бъдат изключени за кратко време (1-5 μs). Това време е необходимо за завършване на преходните процеси на превключване на клавишите.

Структурно разрядните щифтове могат да бъдат комбинирани в един корпус на многоцифрен индикатор или многоцифрен индикатор може да бъде сглобен от отделни едноцифрени индикатори. Освен това можете да сглобите индикатор от отделни светодиоди, комбинирани в сегменти. Това обикновено се прави, когато е необходимо да се събере много голям индикатор. Всички горепосочени схеми ще бъдат валидни за такива опции.

В следващия урок ще свържем седемсегментен LED индикатор към платката Arduino и ще напишем библиотека, за да го управляваме.

Категория: . Можете да го маркирате.