Семисегментный индикатор. Большие цифровые индикаторы из светодиодов Микросхема для управления семисегментным индикатором

В сегодняшней статье поговорим о 7-сегментных индикаторах и о том, как их «подружить» с Ардуино. Есть несколько вариантов. Самый простой, безусловно, это зайти на и купить готовый индикатор с интегрированным шилдом (это платка согласования так называется), но мы не ищем лёгких путей, поэтому пойдем путем чуть более сложным. Новички – не пугайтесь, эта статья, как и предыдущие мои статьи ( и ) именно для вас. Пусть гуру пишут для таких же умудренных опытом гуру, а я новичок – пишу для новичков.

Почему именно 7-сегментный индикатор? Ведь существует столько всяких экранов, с большим количеством символов, строк, разнообразных диагоналей и разрешений, черно-белых и цветных, самые доступные из которых стоят пару долларов… А тут: «старенький», до безобразия простой, но требующий огромного количества пинов 7-сегментный индикатор, но все-таки преимущество есть и у этого «старичка». Дело в том, что пользуясь приведенными здесь скетчами можно оживить не только индикатор с высотой цифр 14 мм, но и более серьезные (правда уже самодельные) проекты, и метровые цифры в данном случае далеко не предел. Жителям столиц это может быть не так интересно, а вот население Новокацапетовки или Нижней Кедровки очень порадуется, если на клубе или сельсовете появятся часы, которые еще могут и дату отображать, и температуру, а о создателе этих часов будут говорить очень долго. Но, подобные часы тема отдельной статьи: будет желание у посетителей – напишу. Всё выше написанное можно считать вступлением. Как и прошлая моя статья эта будет состоять из частей, на этот раз из двух. В первой части мы просто «по управляем» индикатором, а во второй – попробуем приспособить его для чего-то хоть немного полезного. Итак, продолжим:

Часть первая. Экспериментально – познавательная

За основу данного проекта взят нам уже хорошо знакомый по предыдущим статьям ARDUINO UNO. Напомню, что приобрести его легче всего можно здесь: или здесь: , кроме этого понадобится 4-разрядный, 7-сегментный индикатор. У меня, в частности GNQ-5641BG-11. Почему именно этот? Да просто потому, что лет 5 назад купил его по ошибке, идти менять было лень, вот он и валялся все это время, ожидая своего часа. Думаю, что подойдет любой с общим анодом (и с общим катодом можно, но придется данные массива и остальные значения портов инвертировать – т.е. менять на обратные), лишь бы не был слишком мощным, чтобы не сжечь Ардуинку. Кроме этого – 4 токоограничивающих резистора, примерно 100 Ом каждый и кусок шлейфа (мне хватило 10 см) на 12 пин (жил) можно «оторвать» от более широкого, что я и сделал. А можно вообще отдельными проводочками подпаяться, проблем не будет. Еще понадобятся штыри на плату (11 шт.) хотя, если аккуратно можно и без них. Эскиз индикатора можно увидеть на рисунке 1, а его схему на рисунке 2. Также отмечу, что на каждый сегментик этого индикатора лучше подавать не более 2.1В (ограничивается 100-Омными резисторами), и в этом случае он будет потреблять не более 20 мА. В случае, если загорится цифра «8» потребление не превысит 7х20=140 мА, что вполне допустимо для выходов Ардуино. Любознательный читатель задаст вопрос: «Но ведь 4 разряда по 140 мА это уже 4х140=560 мА, а это уже многовато!» Отвечу – останется 140. Каким образом? Читайте дальше! Расположение пинов на индикаторе видно на рисунке 3. А подключение делаем согласно таблице 1.


Рис. 1 - Эскиз индикатора


Рис. 2 - Схема индикатора


Рис. 3 - Расположение пинов

Таблица 1

Пин Ардуино Уно

Пин индикатора

Примечание

Сегмент G

Сегмент F

Сегмент E

Сегмент D

Сегмент C

Сегмент B

Сегмент A

Общий анод сегмента № 1, подключать через резистор 100 Ом.

Общий анод сегмента № 2, подключать через резистор 100 Ом.

Общий анод сегмента № 3, подключать через резистор 100 Ом.

Общий анод сегмента № 6, подключать через резистор 100 Ом.



Заливаем простенький скетч, который представляет собой простенькую «считалочку» от 0 до 9:


А теперь немного пояснений. DDRD это регистр порта D (DDRB – соответственно порта В) за «страшным» словом «регистр» всего лишь «спряталась» функция, которая указывает, будет порт своим пином читать что-то (принимать информацию), либо наоборот туда можно будет что-то писать (отдавать информацию). В данном случае строчка DDRD=B11111111; указывает, что все пины порта D выходные, т.е. информация из них будет выходить. Буквочка «В» обозначает, что в регистр записано двоичное (бинарное) число. Нетерпеливый читатель тут же спросит: «А десятичное можно!?!». Спешу успокоить – можно, но об этом чуть позже. Если бы мы хотели половину порта задействовать на вход, а половину на выход можно было бы указать так: DDRD=B11110000; единицы показывают те пины, которые будут отдавать информацию, а нули – те, которые будут эту самую информацию принимать. Основное удобство регистра заключено еще и в том, что не надо прописывать 8 раз все пины, т.е. мы экономим в программе 7 строк. А теперь разберем следующую строку:

PORTB=B001000; // устанавливаем высокий уровень 11 пина порта В

PORTB это регистр данных порта В, т.е. записав в него какое-либо число мы указываем на каком пине порта будет единица, а на каком – ноль. В добавление к комментарию скажу, если взять Ардуино Уно таким образом, чтобы видеть контроллер и цифровые пины были сверху - будет понятна запись в регистр, т.е. какой «ноль» (или «единица»)отвечает за какой пин, т.е. крайний правый ноль порта В отвечает за 8-й пин, а крайний левый – за 13-й (у которого встроенные светодиод). Для порта D соответственно правый за пин 0, левый за пин 7.
Надеюсь после таких развёрнутых пояснений все понятно, а раз понятно предлагаю вернуться к известной нам и горячо любимой с детства десятичной системе счисления. И еще – скетч в 25 строк вроде и небольшой, но для новичка все-таки несколько громоздок. Будем уменьшать.

Заливаем еще более простой скетч, та же самая «считалочка»:


Видео 1 .
Всего 11 строчек! Вот это по-нашему, «по-новичковски»! Прошу обратить внимание вместо двоичных чисел в регистры записаны десятичные. Естественно, для десятичных чисел никаких букв впереди не нужно. Думаю, не лишним будет свести все числа в таблицы.

Таблица 2. Соответствие отображаемого знака данным порта

Общий анод

Общий катод

Двоичная система

Десятичная система

Двоичная система

Десятичная система

Таблица 3. Соответствие отображаемого разряда данным порта

Общий анод

Общий катод

Двоичная система

Десятичная система

Двоичная система

Десятичная система



Внимание! Данные таблиц 2 и 3 справедливы только при распайке согласно таблице 1.
А теперь зальем скетч со «считалочкой» от 0 до 9999:




Рис. 4 - Считалочка

Работу скетча можно посмотреть на Видео 2 .

В этом скетче комментариев больше, чем самого кода. Вопросов возникнуть не должно…. Кроме одного, что это за «цикл мерцания» такой, что, собственно говоря, там мерцает и для чего? А еще переменная для этого какая-то…
А все дело в том, что одноименные сегменты всех четырех разрядов у нас соединены в одной точке. А1, А2, А3 и А4 имеют общий катод; А1, В1,…..G1 общий анод. Так, что подав одновременно на 4 разрядный индикатор «1234» мы получим «8888» и очень удивимся по этому поводу. Чтобы этого не произошло нужно сначала зажечь «1» в своем разряде, потом отключить её, зажечь «2» в своем и т.д. Если делать это очень быстро, то мерцание цифр сольётся, как кадры на киноплёнке и глаз его практически не будет замечать. А максимальное значение переменной мерцания в данном случае управляет скоростью смены цифр на индикаторе. Кстати, именно благодаря этому «мерцанию» и максимальное потребление тока всего 140 мА, вместо 560. А теперь предлагаю перейти к чему-то более полезному.

Часть вторая. Хоть немного полезная

В этой части мы выведем символы с персонального компьютера на 7-сегментный индикатор при помощи ARDUINO MEGA. Почему вдруг возникла идея «поменять лошадей на переправе»? Причин две: первая – до этого в своих статьях я ни разу не рассматривал ARDUINO MEGA; и вторая – в ARDUINO UNO я так и не разобрался, как мне динамически менять местами СОМ порт и порт D. Но я новичок – мне простительно. Приобрести данный контроллер, естественно можно здесь: . Для реализации задуманного пришлось взять паяльник и перепаять шлейф со стороны Ардуино, а также написать новый скетч. Как перепаян шлейф можно посмотреть на Рисунке 5. Все дело в том, что ARDUINO MEGA и ARDUINO UNO имеют разную распиновку портов, да и в Меге портов гораздо больше. Соответствие использованных пинов видно из Таблицы 4.



Рис. 5 - Новая распайка шлейфа

Таблица 4

Порт Мега


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

Также следует обратить внимание, что порт С у Ардуино Мега «начинается» с 37 пина и далее по убывающей, а порт А – с 22 пина и далее по возрастающей.



Рис. 6 - Общий вид



Небольшие особенности реализации: выводить будем 4 символа. Символы должны быть цифрами. Если ввели «1234» и увидим «1234», если ввели «123456» все равно увидим «1234», если ввели «йцук», «фыва1234», «отиог485909оапоьм» - не увидим ничего. Если ввели «рр2345мм» увидим « 23» т.е. небольшая, встроенная «защита от дурака».

Собственно скетч:



А как работает данная программа можно посмотреть на Видео 3 .



Обзор подготовил Павел Сергеев

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

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

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

Семисегментный индикатор состоит из семи светодиодов (отсюда и его название), расположенных прямоугольником, как показано на рисунке. Каждый из семи светодиодов называется сегментом, поскольку при свечении сегмент образует часть цифры (десятичной или 12-ричной Иногда в пределах одного пакета используется 8-й дополнительной светодиод. Он служит для отображения десятичной точки (DP), позволяя, таким образом, отображать если два или более 7-сегментных индикаторов соединены вместе для представления чисел больше десяти.

Каждый из семи светодиодных сегментов дисплея соединен с соответствующей площадкой контактного ряда, расположенного прямо на прямоугольном пластиковом корпусе индикатора. Светодиодные контакты промаркированы метками от a до g, представляющими каждый отдельный сегмент. Другие контакты светодиодных сегментов соединены между собой и образуют общий вывод.

Итак, прямое смещение, поданное на соответствующие контакты светодиодных сегментов в определенном порядке, заставит некоторые сегменты светиться, а остальные останутся затемненными, что позволяет высветить нужный символ шаблона числа, которое будет отображено на дисплее. Это и позволяет нам представлять каждую из десяти десятичных цифр от 0 до 9 на 7-сегментном индикаторе.

Общий вывод, как правило, используется для определения типа 7-сегментного дисплея. Каждый светодиод дисплея имеет два соединительных вывода, один их которых называется "анод", а другой, соответственно, носит название "катод". Поэтому светодиодный семисегментный индикатор может иметь два типа схемотехнического исполнения - с общий катодом (ОК) и с общим анодом (ОА).

Разница между этими двумя типами дисплеев заключается в том, что в конструкции с ОК катоды всех 7 сегментов непосредственно соединены друг с другом, а в схеме с общим (ОА) анодом между собой соединены аноды всех 7 сегментов. Обе схемы работают следующим образом.

  • Общий катод (ОК) - соединенные между собой катоды всех светодиодных сегментов имеет уровень логического "0" или подключен к общему проводу. Отдельные сегменты высвечиваются подачей на их анодный вывод сигнала "высокого" логического уровня или логической "1" через ограничительный резистор для создания прямого смещения отдельных светодиодов.
  • Общий анод (ОА) - аноды всех светодиодных сегментов объединены и имеют уровень логической "1". Отдельные сегменты индикатора светятся при соединении каждого конкретного катода с землей, логическим "0" или низкопотенциальным сигналом через соответствующий ограничительный резистор.

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

Хотя 7-сегментный индикатор можно рассматривать как единый дисплей, он все-таки состоит из семи отдельных светодиодов в рамках одного пакета, и как таковые эти светодиоды нуждаются в защите от перегрузки по току. Светодиоды излучают свет только тогда, когда они смещены в прямом направлении, а количество излучаемого ими света пропорционально прямому току. Это означает только то, что интенсивность свечения светодиода возрастает примерно линейно с увеличением тока. Так что, во избежание повреждения светодиода, этот прямой ток должен контролироваться и ограничиваться до безопасного значения внешним ограничительным резистором.

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

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


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

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

В качестве примера рассмотрим два индикатора: SA39-11xxx (xxx - три-четыре буквы, кодирующие цвет, в моём случае GWA) и BC56-12xxx (у меня xxx = SRWA). Приведу ниже список цветов:

  • HWA - ярко-красный на фосфиде галлия GaP, 700 нм
  • EWA - высокопроизводительный красный на фосфиде-арсениде и фосфиде галлия GaAsP/GaP, 625 нм (не знаю, как по-другому можно перевести "HIGH EFFICIENCY RED")
  • GWA - зеленый на фосфиде галлия GaP, 565 нм
  • YWA - желтый на фосфиде-арсениде и фосфиде галлия GaAsP/GaP, 590 нм
  • SRWA - супер ярко-красный на арсениде галлия-алюминия GaAlAs, 660 нм

В названии индикаторов вторая буква обознаяет тип соединения светодиодов: С - общий катод, А - общий анод. Ниже приведена электрическая схема и чертеж SA39 и SC39. Обратите внимание на буквы, которыми обозначили каждый сегмент (a-g) и обозначение точки (DP). Эти названия мы будем использовать в коде программы для объявления макросов. Это позволит как можно сильнее абстагировать программу от электрической схемы, от способа соединения индикатора и МК.

Значит, "ножки" 3 и 8 нужно подключить к шине +5 В (или, в крайнем случае, подать на них +5 В от МК, но так делать не рекомендуется), а остальные - к какому-либо порту МК. При этом не очень-то важно, в каком порядке, т. к. в случае ошибки Вы просто увидите на индикаторе не цифру, а какую-нибудь букву "зю". Тогда придется либо подключить по-другому, либо внести небольшие изменения в программу. В общем, символ, отображемый на индикаторе, зависит от того, какое число отправить в порт. Всего существует 255 комбинаций, и все они возможны независимо от способа подключения. Я использовал порт D для подключения индикатора.

Остается только лишь написать простенькую программу:

#include "iom16.h" #define a 1 // Эти макросы содержат числа, соответствующие двойке, #define b 2 // возведенной в степень, равной номеру "ножки" того #define c 4 // порта, к которому подключен сегмент индикатора с #define d 128 // одноименным макросу названием. Для того, чтобы вывести #define e 64 // какую-либо цифру на индикатор, нужно отправить в порт #define f 32 // число 255 минус сумму соответствующих сегментам макросов. #define g 16 // Эти числа позволяют сделать программу независимой от подключения. #define DP 8 // Измените эти числа, если индикатор выводит букву "зю" short unsigned int i = 1; unsigned char DigNumber = 0; unsigned char Dig; // Массив, в котором хранятся числа, которые нужно // вывести через порт на индикатор, чтобы он показал цифру, равную номеру // элемента массива. Числа зависят только от макросов. void io_init() { DDRD = 0xFF; // К порту D подключен индикатор PORTD = 0xFF; } void timer0_init() { OCR0 = 15; // Таймер срабатывает каждые 1024 такта. Прерывание каждые // 1024*16 тактов. TCCR0 |= (1 void Dig_init() { Dig = 255 - (a+b+c+d+e+f); // Если индикатор с общим анодом, Dig = 255 - (b+c); // нужно сумму макросов отнять от Dig = 255 - (a+b+g+e+d); // 255. Если с общим катодом, то Dig = 255 - (a+b+g+c+d); // отнимать не нужно. Dig = 255 - (f+g+b+c); // Имена макросов соответствуют Dig = 255 - (a+f+g+c+d); // именам сегментов индикатора Dig = 255 - (a+f+g+c+d+e); Dig = 255 - (a+b+c); Dig = 255 - (a+b+c+d+e+f+g); Dig = 255 - (a+b+c+d+f+g); } void main() { io_init(); timer0_init(); Dig_init(); SREG |= (1 //Выводим на индикатор цифру "0" while (1) {} } #pragma vector = TIMER0_COMP_vect __interrupt void Indic_change() { if (i // 675*16*1024 = 11,0592 МГц { // Каждую секунду меняется цифра на индикаторе i++; } else { i = 1; if (DigNumber else DigNumber = 0; PORTD = Dig; } }

Как это работает, думаю, ясно из комментариев к коду. Макросы после #define позволяют сделать код почти независящим от способа подключения индикатора. Если, например, Вы подключили 5-й вывод индикатора (d-сегмент) к выводу PD3 МК, то для того, чтобы все правильно работало, нужно сопоставить макросу d число 2 3 =8, написав

#define d 8

Откомпилировав программу и прошив ее в МК, если все правильно подключено и соответствующе описано в #define, получаем цифровые электронные часы, которые умеют считать до 10. Если у Вас установлен резонатор на 11,0592 МГц, то эти часы будут тикать раз в секунду и с, казалось бы, поразительной точностью: за час они не собьются ни на секунду! Но удивительного тут ничего нет: вся точность упирается в качество резонатора и отсутствие ошибок в программе. Кстати, в электронных часах стоят такие же резонаторы, только меньших размеров и частот (обычно 3 КГц). Но собирать часы на МК несколько нерационально, потому что существуют специализированные микросхемы для этого, умеющие отсчитывать время, дату, месяц, день недели, год и т.д. Связав с такой микросхемой МК, можно научить его "чувствовать" время.

Но мы несколько отвлеклись от темы нашей статьи. Теперь пора рассмотреть работу с трехзначным индикатором, коим является BC56-12xxx. По логике у него должно быть 8*3+1=25 выводов. Но у него их только лишь 12. Давайте посмотрим его документацию.

Оказывается, внутри находятся три семисегментных индикатора, соединенные параллельно, и от каждого из них выходит один общий электрод (катод или анод). Чтобы было понятнее, покажу электрическую схему:

Итак, подавая напряжение на выводы 1, 2, 3, 4, 5, 7, 10, 11, формируют цифру (символ), мы их назовем информационными или шиной данных, а управляя выводами 8, 9, 12, определяют позицию этой цифры. Выводы 8, 9, 12 назовем выводами выбора устройства или шиной адреса. Понятно, что нельзя одновременно зажечь две или три разные цифры. Придется использовать стробирование, т. е. зажигать цифры по очереди с высокой скоростью. Они будут мерцать, но глаз этого не успеет заметить.

Значит, с выводами 1, 2, 3, 4, 5, 7, 10, 11 работа совершенно аналогична. А выводы 8, 9, 12 нужно замыкать на землю по очереди. Казалось бы, чего проще - присоединить их к МК и все. Но, как я уже говорил, не следует цеплять к МК общий электрод - это слишком большая нагрузка для него, и его порт ввода-вывода может сгореть. Следует использовать полевые транзисторы, как это было описано в предыдущей статье.

Мне кажется, настало время рассказать о шифраторах и дешифраторах. Дешифраторами называются комбинационные устройства, преобразующие n-разрядный двоичный код на их входе в логический сигнал, появляющийся на том выходе, десятичный номер которого соответствует двоичному коду. Дешифраторы имеют как правило 3 или 4 входа и 8 или 16 выходов соответственно. Как работает дешифратор? Подадим на вход число в двоичном коде, например, 5, установив лог. 1 на первом и третьем выводах на входе. Тогда появится лог. 1 на пятом выходе. Шифраторы выполняют обратную операцию - если подать лог. 1 на один из входов, на выходе появится двоичный код номера этого входа.

Дешифраторы позволяют решить проблему нехватки выходов. Например, у МК есть 3 свободных выхода для выбора устройства, а мы хотим подключить семь устройств. Но ведь у этих трех выходов могут быть 8 различных состояний! Подключив дешифратор, из трех выходов сделаем восемь работающих по очереди и решим т. о. проблему.

В школах и особенно вузах часто на уроках информатики рисуют логическую схему работы памяти, где есть груда логических элементов "И" и/или "ИЛИ" для выборки ячейки памяти, какая-то шина данных, шина адреса, ячейки памяти... Короче, обычно преподаватель сам не может понять, что он нарисовал, как это все работает и не загибается. Оказывается, там стоит дешифратор и все работает очень просто. По шине адреса приходит адрес ячейки памяти в двоичном коде, в которую надо записать информацию (или прочитать) и поступает в дешифратор. Дешифратор подключает требуемую ячейку к цепи питания, ячейка начинает работать и сохраняет тот двоичный код, который установлен на шине данных (или выдает туда свое содержимое). После этого исчезает адрес на шине адреса и дешифратор отключает эту ячейку до следующего использования. При запуске компьютера в программе Setup можно установить напряжение на ЦПУ (там можно выбрать из нескольких значений). А как это происходит? Есть специальная шина, по которой двоичный код поступает в дешифратор. Дешифратор открывает один из нескольких транзисторов и через этот транзистор идет питание требуемого напряжения на ЦПУ.

При программировании МК может возникнуть ситуация, когда потребуется подключить к нему очень много устройств. Вот тогда и придется вспомнить о дешифраторах, организовать одну шину данных для всех устройств и одну шину адреса, идущую к дешифратору. А к дешифратору уже через транзисторы , чтобы не нагружать МК или дешифратор (это важно, но об этом часто забывают) подключать устройства. Я не думаю, что у нас будет такая ситуация в этих учебных статьях, но на будущее хорошо бы это запомнить.

Вернемся к нашей конструкции. Схема очень проста. Я прицепил к порту А половинку панельки для широких микросхем, так чтобы подключенными оказались выводы 1, 2, 3, 4, 5, 7, 10, 11 вставленного в нее семисегментного индикатора BC56-12xxx. Другие три вывода подключены через уже знакомые нам транзисторы IRF7311 к выводам порта С (вывод 12 к РС5, 9 - к РС6, 8 - к РС7). Один из транзисторов (корпуса два, а их четыре) остался про запас.

Код программы приведен ниже. Поскольку в будущем может возникнуть необходимость некоторое трехзначное число, хранящееся в переменной, вывести на индикатор, неплохо было бы написать для этого какую-нибудь специальную функцию. Назовем ее Display(). Казалось бы, реализовать ее очень просто, нужно число поделить на 100, найти целое от деления и остаток и потом также поделить на 10. Но... Но МК не знает функций mod и div. Это во-первых. А во-вторых, у него нет математического сопроцессора для деления, и одна операция деления может занимать сотни и даже тысячи тактов процессора, в отличие от сложения/вычитания (1 такт для char) и умножения на целое (2 такта для char). Поэтому всегда старайтесь заменить деление чем-либо другим, если возможно. Иногда бывает даже рациональнее отправить некоторые данные через COM-порт в компьютер, там произвести вычисления и вернуть обратно результат. Как это реализовать, в следующей статье. А сейчас рассмотрим наглядный пример.

Предположим, Вы решили поставить у себя в ванной электронный регулятор температуры воды на МК, который постоянно измеряет температуру воды в душе специальным датчиком и с помощью мотора крутит кран так, чтобы температура стремилась к заданному значению. И Вы используете некий алгоритм, позволяющий с очень большой точностью управлять этим процессом. Но алгоритм содержит операции деления, извлечения корня, вычисления логарифма, косинуса и, несомненно, интеграла. И когда Вы пойдете мыться, после поворота ручки регулировки температуры, МК "зависнет" и будет на Вас несколько секунд будет лить воду температурой 70-80 °С, а потом, когда он все вычислит, с большой точностью выставит нужные Вам 28,32204°С. :)

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

#include "iom16.h" #define a 1 #define b 4 #define c 16 #define d 64 //Меняем эти числа для другого индикатора #define e 128 #define f 2 #define g 8 #define DP 32 short unsigned int i = 1; short unsigned int Number = 0; unsigned char Dig; // В этих переменных хранятся цифры, которые нужно отобразить char Disp5, Disp6, Disp7; // Функция выделяет цифры из трехзначного числа Number void Display (short unsigned int Number) { unsigned char Num1, Num2, Num3; Num1=Num2=0; while (Number >= 100) { Number -= 100; Num1++; } while (Number >= 10) { Number -= 10; Num2++; } Num3 = Number; Disp5 = Dig; Disp6 = Dig; Disp7 = Dig; } void io_init() //Инициализация портов ввода/вывода { DDRA = 0xFF; PORTA = 0; DDRC |= (1 void timer0_init() { OCR0 = 15; TCCR0 |= (1 void Dig_init() { Dig = (a+b+c+d+e+f); // Сейчас у нас схема с общим катодом Dig = (b+c); Dig = (a+b+g+e+d); Dig = (a+b+g+c+d); Dig = (f+g+b+c); Dig = (a+f+g+c+d); Dig = (a+f+g+c+d+e); Dig = (a+b+c); Dig = (a+b+c+d+e+f+g); Dig = (a+b+c+d+f+g); } void main() { unsigned char j, k = 0; Dig_init(); Display(0); io_init(); timer0_init(); SREG |= (1 while(1) { for (j = 0; j // Задержка для отображения цифры (k == 3) ? k = 0: k++; PORTC &= 31; //Очистка PC7, PC6, PC5 for (j = 0; j// Задержка для выключения транзистора switch (k) { case 0: PORTC |= (1 // Единицы PORTA = Disp7; break ; case 1: PORTC |= (1 // Десятки PORTA = Disp6; break ; case 2: PORTC |= (1 // Сотни PORTA = Disp5; } } } #pragma vector = TIMER0_COMP_vect __interrupt void Indic_change() { if (i else { i = 1; if (Number else Number = 0; PORTB++; Display(Number); // Увеличение отображаемого числа. } }

Функция Display(Number) берет число Number и отнимает от него по сотне, пока Number не станет меньше 100. Количество отнятых сотен сохраняется в Num1. Аналогично потом отнимают десятки. Количество десятков - в переменной Num2. Остаток (единицы) сохраняется в Num3. Глобальным переменным Disp5, Disp6, Disp7 присваиваются значения, которые нужно отправить в порт A, чтобы отобразить исходное число Number. Как это выглядит в действии, увидите, когда прошьёте программу в МК.

© Киселев Роман
Июнь 2007

Доброго времени суток! После моего затяжного и вынужденного перерыва, продолжим освоение курса «Программирование Ардуино». В одном из наших предыдущих уроков, мы уже работали с последовательностью светодиодов, теперь пора переходить к следующему этапу обучения. Темой сегодняшней статьи будет – 7-сегментный индикатор.

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

Прошлый раз мы работали с последовательностью из 8 светодиодов, сегодня их также будет 8 (7 – светодиодных полосок и 1 точка). В отличии от предыдущей последовательности, элементы этого набора не выстроенные в ряд (друг за дружкой), а расположены в определённом порядке. Благодаря чему используя лишь один компонент можно вывести 10 цифр (от 0 до 9).

Еще одно существенное отличие, что выделяет данный индикатор на фоне простых светодиодов. У него общий катод (вернее две равноценные ножки 3 и 8, на который заведен катод). Достаточно всего лишь соединить один из катодов с землей (GND ). Аноды у всех элементов индикатора индивидуальные.

Небольшое отступление. Все выше сказанное относится к 7-сегментным индикаторам с общим катодом. Однако существуют индикаторы с общим анодом. Подключение таких индикаторов имеет существенные отличия, поэтому прошу не путать «грешное с праведным». Необходимо четко понимать, какой именно тип семисегментника у вас в руках!

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

Надеюсь, вы не забыли об необходимости использования токоограничивающих резисторов при подключении светодиодов. Это же относится и к индикаторам: на каждый элемент индикатора должен быть подключен свой резистор. 8 элементов (7 + 1) – 8 резисторов.

У меня под рукой оказался семисегментник с маркировкой 5161AS (общий катод). Распиновка контактов:



Принципиальная схема

Как говорил ранее, для того, чтобы включить сегмент «А» подключим к любому общему контакту (3 или 8) «землю», а на вывод 7 подадим 5В питания. Если индикатор с общим анодом, то на анод подаём 5В, а на вывод сегмента «землю»!

Соберём тестовый стенд. Соединяем провода по порядку, начиная с первой ножки, которая идёт на 2-й вывод платы Ардуино. Землю подключим к 8 выводу индикатора.

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

Для проверки индикатора запустим написанную программу. Выберем элемент «А» и помигаем им.


Теперь помигаем цифрой 2. Для этого включим еще несколько элементов.

Чтобы вывести одну цифру, нужно написать n-число строчек кода. Затруднительно, не находите.

Есть другой путь. Для того, чтобы вывести любую цифру на индикаторе, сначала её нужно представить в виде определенной последовательности бит.

Таблица соответствия.

Если у дисплея общий анод, то 1 нужно заменить на 0, а 0 – на 1!

Столбец hex – представление цифры в байтовом виде (более детально поговорим об этом во второй части).

Число в двоичной системе счисления записывается следующим образом: 0b00000000. 0b – двоичная система. Нули означают, что все светодиоды выключены.

При подключении мы задействовали выводы с 2 по 9. Чтобы включить 2 вывод записываем в него единицу = 0b00000001. За точку отвечает четвёртый бит справа. За чёрточку посередине индикатора отвечает самый последний бит.

Давайте напишем пример вывода цифры 0.

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

Примечание: функция bitRead() считывает состояние указанного бита и возвращает значение состояния (0 или 1). bitRead(x, n) где, x — число, бит которого необходимо считать; n — номер бита, состояние которого необходимо считать. Нумерация начинается с младшего значащего бита (крайнего правого) с номером 0.

И в завершении первой части напишем небольшой счетчик.