Еще раз о динамической индикации на led-индикаторах

Урок 19. Семисегментные светодиодные индикаторы (LED). Режимы управления, подключение к микроконтроллеру

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

Предыдущий урок     Список уроков     Следующий урок

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

Этому способствуют следующие их качества.

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

Типы светодиодных индикаторов.

Семисегментный светодиодный индикатор отображает символ с помощью семи светодиодов – сегментов цифры. Восьмой светодиод засвечивает децимальную точку. Так что в семисегментном индикаторе 8 сегментов.

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

Аноды или катоды каждого светодиода объединяются в индикаторе и образуют общий провод. Поэтому существуют индикаторы с общим анодом и общим катодом.

Светодиодный индикатор с общим анодом.

Светодиодный индикатор с общим катодом.

Статическое управление светодиодным индикатором.

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

Расчет резисторов такой же, как для отдельных светодиодов.

R = ( U питания  –  U сегмента ) / I сегмента

Для этой схемы:  I сегмента = ( 5 – 1,5 ) / 1000 = 3,5 мА

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

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

Засветится сегмент, на управляющем выводе которого будет сформирован высокий уровень (5 В).

Мультиплексированный режим управления светодиодными (LED) индикаторами.

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

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

Для подключения трех индикаторов потребовалось 11 выводов, а не 24, как при статическом режиме управления.

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

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

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

Я стараюсь использовать не менее 100 Гц.

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

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

Расчет элементов динамической индикации светодиодных (LED) индикаторов.

Расчет несколько сложнее, чем для статического режима. В ходе расчета необходимо определить:

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

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

Выберем средний ток сегмента 1 мА.

Теперь рассчитаем импульсный ток сегмента. Чтобы обеспечить требуемый средний ток, импульсный ток должен быть в N раз больше. Где N число разрядов индикатора.

I сегм. имп. = I сегм. средн. * N

Для нашей схемы I сегм. имп. = 1 * 3 = 3 мА.

Рассчитываем сопротивление резисторов, ограничивающих ток.

R = ( U питания  –  U сегмента ) / I сегм. имп.

R = ( 5 – 1,5 ) / 0.003 = 1166 Ом

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

I разряда имп. =  I сегм. имп. * 8

Для нашей схемы  I разряда имп. = 3 * 8 = 24 мА.

В итоге:

  • сопротивление резисторов выбираем 1,1 кОм;
  • выводы микроконтроллера управления сегментами должны обеспечивать ток не менее 3 мА;
  • выводы микроконтроллера выбора разряда индикатора должны обеспечивать ток не менее 24 мА.

При таких значениях токов индикатор может быть подключен непосредственно к выводам платы Ардуино, без использования дополнительных ключей. Для ярких индикаторов, таких токов вполне достаточно.

Схемы с дополнительными ключами.

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

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

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

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

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

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

Ключи для индикаторов с повышенным напряжением питания.

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

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

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

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

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

Более того, можете собрать индикатор из отдельных светодиодов, объединенных в сегменты. Так обычно поступают, когда необходимо собрать индикатор очень больших размеров.

Все приведенные выше схемы будут справедливы и для таких вариантов.

В следующем уроке подключим семисегментный светодиодный индикатор к плате Ардуино, напишем библиотеку для управления им.

Предыдущий урок     Список уроков     Следующий урок

Источник: http://mypractic.ru/urok-19-semi-segmentnye-svetodiodnye-indikatory-led-rezhimy-upravleniya-podklyuchenie-k-mikrokontrolleru.html

Многоразрядный семисегментный индикатор

Доброго дня уважаемые друзья!
Приветствую Вас на сайте «Мир микроконтроллеров»

Подключение многоразрядного семисегментного индикатора
Организация динамической индикации
Алгоритм работы программы
Программа индикации на многоразрядном семисегментном индикаторе

Подключение многоразрядного семисегментного индикатора

Давайте еще раз посмотрим схему подключения многоразрядного семисегментного индикатора к микроконтроллеру:

На этой схеме выводы порта РВ (РВ0 — РВ7) микроконтроллера через токоограничительные резисторы подключены к соответствующим сегментам (a-g) многоразрядного семисегментного индикатора. Соответствующие сегменты всех разрядов индикатора соединены параллельно. Катоды (аноды) каждого разряда индикатора подключены через транзисторы к выводам порта PD.

 Организация динамической индикации

Работа многоразрядного индикатора осуществляется следующим образом:

1. На управляющий транзистор первого разряда индикатора (7Seg1), с вывода порта микроконтроллера PD0 подается логическая единица, которая открывает транзистор, в результате чего подается напряжение питания на данный разряд индикатора.

На базах остальных транзисторов — логический ноль, транзисторы закрыты.
2. На выводах порта РВ0-РВ7 выставляется двоичный код соответствующей десятичной цифры — высвечивается нужная цифра в первом разряде.
3.

На управляющий транзистор второго разряда (7Seg2) с вывода порта PD1 подается логическая единица (на остальные транзисторы — логический ноль) — подается питание на второй разряд индикатора.
4.

На выводах порта РВ0-РВ7 выставляется двоичный код следующей (второй) десятичной цифры — высвечивается нужная цифра во втором разряде.
5.

На управляющий транзистор третьего разряда (7Seg3) с вывода порта PD2 подается логическая единица (на остальные транзисторы — логический ноль) — подается питание на третий разряд индикатора.
6. На выводах порта РВ0-РВ7 выставляется двоичный код следующей (третьей) десятичной цифры — высвечивается нужная цифра во втором разряде.
7. И так, по кругу

Такая работа многоразрядного семисегментного индикатора называется —динамическая индикация.
Частота переключения разрядов должна быть в пределах 100 герц, тогда не будет заметно мерцание разрядов.

Для переключения разрядов можно задействовать (на примере микроконтроллера ATtiny2313) таймер «TIMER 0«. Настройка таймера производится следующим образом (при тактовой частоте 1 мГц — заводская установка): — предделитель таймера устанавливаем в СК/8

— вызов прерывания по переполнению счетчика таймера

Вот так настройка таймера выглядит в программе:
Где:
— SP — настройка стека
— Timer 0 — настройка параметров таймера
— TIMSK — настройка прерывания

Алгоритм работы программы

Рассмотрим алгоритм программы для осуществления динамической индикации и вывода данных в многоразрядный семисегментный индикатор:

Этот алгоритм, в принципе, иллюстрирует организацию динамической индикации данных на многоразрядном индикаторе.

При этом надо учитывать, что при первом прерывании выполняется первый «прямоугольник», а затем происходит выход из подпрограммы, при втором прерывании выполняется второй «прямоугольник» и тоже выход из подпрограммы и при третьем прерывании — нижний «прямоугольник» с выходом из подпрограммы, и далее по кругу.

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

Программа индикации на многоразрядном семисегментном индикаторе

Как я уже писал в другой статье — АЛГОРИТМ — предшественник программы, и чем продуманнее он будет написан, тем легче будет писать программу.

Назначение переменных:

Давайте посмотрим какие переменные для работы подпрограммы вывода данных на индикатор назначил я:

Data0, Data1 и  Data2 — переменные, в которые основная программа записывает вычисленное значение (трехзначное)
Data — переменная, в которой записан адрес первой переменной данных — Data0
@Data — эта запись означает, что в переменной Data будет храниться адрес первой переменной данных — Data0
DataIndex — эта переменная хранит текущий номер переменной данных, которая выводилась на индикацию последней (0, 1 или 2, соответственно для Data0, Data1 или Data2)
PortDigits — эта переменная хранит данные о том, какой разряд индикатора зажигался последним

Настройка стека:

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

Настройка восьмиразрядного таймера Taimer0:

Taimer0 в подпрограмме используется как средство обеспечивающее динамическую индикацию разрядов индикатора

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

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

Тактовая частота микроконтроллера — 1 мГц, или 1 000 000 Гц
Устанавливаем внутренний делитель частоты таймера в СК/8 — рабочая частота таймера будет в 8 раз меньше тактовой частоты микроконтроллера
Получаем: 1000 000/8 = 125 000 Гц, или 125 кГц — тактовая частота таймера
Настраиваем вызов прерывания по переполнению счетчика таймера (счетчик таймера восьмиразрядный и считает до 255, после этого сбрасывается в ноль и вызывается прерывание)
Получаем: 125 000/255 = 490 Гц (что соответствует времени приблизительно в 2 миллисекунды)
Мы поочередно зажигаем три разряда:
Получаем: 490/3 = 163 Гц — разряды индикатора будут переключаться с частотой 163 Гц. Настройка таймера производится соответствующей настройкой соответствующих регистров таймера.

Давайте посмотрим как это происходит в Algorithm Builder:

Инициализация индикатора

Инициализация индикатора — эта фраза подразумевает настройку разрядов портов, к которым подключены выводы индикатора на вывод, а также обнуление переменных данных Data0…2 и запись первоначальных данных в остальные переменные. Процесс инициализации индикатора прописывается в начале основной программы. Назовем подпрограмму инициализации Ini_Indikator2/

Давайте посмотрим этот процесс на примере:

В первой строке разряды порта РВ с 0 по 6 (к которым подключены семь сегментов индикатора) настраиваются на вывод информации (десятичную точку индикатора не используем).
Во второй строке разряды порта PD с 0 по 2 (к которым подключены управляющие транзисторы) также настраиваются на вывод.

Третьей строкой на выходах порта РВ устанавливается логический ноль — сегменты индикатора погашены для индикаторов с общим катодом).

Четвертая строка — обнуляем переменную DataIndex
Пятая строка — в переменную PortDigits записываем единицу
Следующие три строки — обнуляем переменные данных

Теперь нам необходимо куда-то записать двоичные коды цифр которые будут подаваться на разряды порта PB для высвечивания соответствующей цифры на индикаторе. В статье по программированию работы одноразрядного семисегментного индикатора, мы эти коды записывали программным путем в ОЗУ микроконтроллера. Сейчас мы сделаем по-другому — запишем двоичные коды в теле самой программы.

Для этого создадим таблицу двоичных кодов и присвоим ей имя, к примеру D0_9:

В этой таблице размещены двоичные коды (хотя и записаны в шестнадцатиричной системе) цифр от 0 до 9.

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

Подпрограмма вывода данных на многоразрядный семисегментный индикатор

Присвоим подпрограмме имя, к примеру Indikator2, посмотрим на нее и разберем построчно:

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

В переменной DataIndex храниться номер ячейки памяти (0, 1 или 2) с данными (Data0, Data1 или Data2) которые необходимо вывести на разряд индикатора в текущий момент. Первоначально мы записали в нее ноль.
Первой строкой мы записываем содержимое DataIndex в регистр R20, теперь в нем соответственно то-же ноль.

Во второй строчке мы увеличиваем содержимое регистра R20 на единицу (r20++), теперь в R20 записана единица, означающая, что данные мы будем брать из переменной Data1. При втором прерывании R20 увеличится еще на единицу, станет равным 2, и соответственно следующие данные мы будем брать из переменной Data2.

При следующем прерывании R20 станет равным 3.
Следующей строчкой (r20 Y записываем адрес переменной Data0 в двойной регистр Y (R28, R29).
Затем складываем содержимое двойного регистра Y с содержимым R20 (0,1 или 2).

Командой [Y] -> r21 записываем содержимое переменной данных (или Data0, или Data1, или Data2 — в зависимости от значения r20) в рабочий регистр R21. Теперь в регистре R21 записана цифра из соответствующей переменной данных (к примеру цифра 5).

Следующей командой @D0_9*2 -> Z мы загружаем начальный адрес таблицы с двоичными кодами в двойной регистр Z (R30, R31). По начальному адресу у нас находится двоичный код для цифры 0.
Теперь мы складываем содержимое Z с R21 (с пятеркой) и получаем в регистре Z адрес в таблице двоичного кода с цифрой 5.

Следующей командой LPM[Z] -> R21 мы записываем двоичный код цифры 5 в рабочий регистр R21.
Команду NOP — холостой ход, можно и не прописывать — она вставлена для разделения отдельных кусков программы для наглядности.

Следующей командой PortDidgit -> R20 мы загружаем в рабочий регистр R20 содержимое переменной PortDidgit, а в нее мы предварительно записали единицу. Теперь в R20 записана единица (#b 0000 0001).
Следующей командой PortB мы выводим двоичный код соответствующей цифры на подключенный разряд индикатора.
Командой R20 -> PortDigits — мы сохраняем текущее значение в переменной (последний зажженный разряд индикатора).

Вот так полностью выглядит подпрограмма вывода данных на семисегментный индикатор с динамической индикацией и первоначальными настройками:

Вот, в принципе, и все. Если что-то не очень понятно, или совсем непонятно, пишите, отвечу на все вопросы.

Предыдущие статьи:
Часть 1: Семисегментный светодиодный индикатор: описание, подключение к микроконтроллеру
Часть 2: Перевод двоичного кода десятичного числа в код семисегментного индикатора. Программа вывода цифры на одноразрядный светодиодный индикатор.

Источник: https://microkontroller.ru/praktikum-mikrokontrollershhika/mnogorazryadnyiy-semisegmentnyiy-indikator/

Ардуино: динамическая индикация

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

Но один семисегментный индикатор почти бесполезен. Он ведь отображает всего одну цифру. А что если мы хотим вывести большое число, скажем, от 0 до 500? Нам потребуется целых три цифры, а значит и три индикатора.

Как будем подключать их к контроллеру? Можем напрямую, но тогда мы займем 7*3 = 21 вывод! Это очень расточительно. К тому же, нужна будет уже другая плата, так как у Ардуино Уно просто не хватит цифровых выводов.

Попробуем использовать сдвиговый регистр? Уже лучше. Теперь нам понадобится три регистра, объединенных в цепочку, а также три вывода Ардуино для управления ими. В общем то на этом можно бы было и остановить оптимизацию нашей схемы, но мы пойдем дальше. Обойдемся всего одним сдвиговым регистром!

Динамическая индикация

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

Таким образом, чтобы человек видел на индикаторе трехзначное число, вовсе необязательно зажигать все цифры разом. Достаточно в один момент времени включать только один отдельный индикатор.

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

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

Подключение к Ардуино

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

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

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

Внешний вид макета

В качестве электронных ключей рекомендуем использовать транзисторы в корпусе TO92, например 2N7000. Для подключения каждого транзистора понадобится два резистора: на 100-150 Ом и на 2.2-10 кОм.

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

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

На каждой линии от регистра к индикатору необходим токозадающий резистор 200-300 Ом, чтобы светодиоды в индикаторе не перегорели. Этот нюанс работы со светодиодами мы рассмотрели на одном из самых первых уроков про светодиоды.

Тщательно собираем схему и переходим к программе.

Программа для динамической индикации

const byte digit_pins[3] = {5,6,7}; const byte data_pin = 2; const byte sh_pin = 4; const byte st_pin = 3; unsigned long tm, next_flick; const unsigned int to_flick = 1; byte digit = 0; unsigned int counter = 125; const byte digits[10] = { B11101110, B10000010, B11011100, B11010110, B10110010, B01110110, B01111110, B11000010, B11111110, B11110110 }; void fill( byte d ){ for(char i=0; i

Источник: http://robotclass.ru/tutorials/arduino-dynamic-led-indication/

Arduino. Динамическая индикация

Динамическая индикация — это метод отображения целостной картины путем последовательного отображения отдельных элементов этой картины.
Эта статья научит вас выводить на дисплее сегментного индикатора одновременно несколько цифр. Достигается это за счет «инерционности» человеческого зрения.

Подготовка к работе

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

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

Так, чтобы это стало не заметно для глаза.
Для этого на индикаторе должны быть объединены аноды разрядов и катоды сегментов.

Индикатор с динамической индикацией

Все примеры выполнены с использованием EduBoard и TutorShield. На нашем шилде именно такой индикатор. Для его использования установите перемычки, выделенные на рисунке:

Перемычки для включения индикатора

Принципиальная схема подключения индикатора:

Принципиальная схема подключения индикатора

Первый пример

Для начала выведите два разных числа на индикаторе, используя следующий код:

#define DIG1 4 #define DIG2 5 #define A 6 #define B 7 #define C 8 #define D 9 #define E 10 #define FF 11 #define G 12 #define TAKT 1000 void setup() { pinMode(A, OUTPUT); pinMode(B, OUTPUT); pinMode(C, OUTPUT); pinMode(D, OUTPUT); pinMode(E, OUTPUT); pinMode(FF, OUTPUT); pinMode(G, OUTPUT); pinMode(DIG1, OUTPUT); pinMode(DIG2, OUTPUT); digitalWrite(A,HIGH); digitalWrite(B,HIGH); digitalWrite(C,HIGH); digitalWrite(D,HIGH); digitalWrite(E,HIGH); digitalWrite(FF,HIGH); digitalWrite(G,HIGH); digitalWrite(DIG1,HIGH); digitalWrite(DIG2,HIGH); } void loop() { digitalWrite(DIG1,LOW); Show(3); delay(TAKT); Clean(); digitalWrite(DIG1,HIGH); digitalWrite(DIG2,LOW); Show(4); delay(TAKT); Clean(); digitalWrite(DIG2,HIGH); } void Show(int digit) { switch(digit) { case 0: { digitalWrite(A,LOW); digitalWrite(B,LOW); digitalWrite(C,LOW); digitalWrite(D,LOW); digitalWrite(E,LOW); digitalWrite(FF,LOW); } break; case 1: { digitalWrite(B,LOW); digitalWrite(C,LOW); } break; case 2: { digitalWrite(A,LOW); digitalWrite(B,LOW); digitalWrite(D,LOW); digitalWrite(E,LOW); digitalWrite(G,LOW); } break; case 3: { digitalWrite(A,LOW); digitalWrite(B,LOW); digitalWrite(C,LOW); digitalWrite(D,LOW); digitalWrite(G,LOW); } break; case 4: { digitalWrite(B,LOW); digitalWrite(C,LOW); digitalWrite(FF,LOW); digitalWrite(G,LOW); } break; case 5: { digitalWrite(A,LOW); digitalWrite(C,LOW); digitalWrite(D,LOW); digitalWrite(FF,LOW); digitalWrite(G,LOW); } break; case 6: { digitalWrite(A,LOW); digitalWrite(C,LOW); digitalWrite(D,LOW); digitalWrite(E,LOW); digitalWrite(FF,LOW); digitalWrite(G,LOW); } break; case 7: { digitalWrite(A,LOW); digitalWrite(B,LOW); digitalWrite(C,LOW); } break; case 8: { digitalWrite(A,LOW); digitalWrite(B,LOW); digitalWrite(C,LOW); digitalWrite(D,LOW); digitalWrite(E,LOW); digitalWrite(FF,LOW); digitalWrite(G,LOW); } break; case 9: { digitalWrite(A,LOW); digitalWrite(B,LOW); digitalWrite(C,LOW); digitalWrite(D,LOW); digitalWrite(FF,LOW); digitalWrite(G,LOW); } break; } } void Clean() { digitalWrite(A,HIGH); digitalWrite(B,HIGH); digitalWrite(C,HIGH); digitalWrite(D,HIGH); digitalWrite(E,HIGH); digitalWrite(FF,HIGH); digitalWrite(G,HIGH); }

Основной цикл этого примера линеен и прост. Сначала в первом разряде на одну секунду выводится цифра 3, затем во втором 4.
Если уменьшить интервал TAKT, то можно добиться того, чтобы за счет инерционности зрения казалось, что цифра 34 горит непрерывно.

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

Эмпирическим путем установлено, что обновления изображения с частотой 50 раз в секунду вполне достаточно для приемлемого восприятия. Это значит, что идентификатор TAKT должен иметь значение меньше 10мс.

Попробуйте запустить программу с этим числом, а затем попробуйте увеличить его до 20мс и понаблюдайте за разницей.
Не забудьте после оставить значение TAKT 10.

Управление яркостью

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

#define BRIGHT 2 void loop() { digitalWrite(DIG1,LOW); Show(3); delay(BRIGHT); Clean(); digitalWrite(DIG1,HIGH); delay(TAKT-BRIGHT); digitalWrite(DIG2,LOW); Show(4); delay(BRIGHT); Clean(); digitalWrite(DIG2,HIGH); delay(TAKT-BRIGHT); }

Переопределение идентификатора BRIGHT от 0 до 10 будет приводить к изменению яркости. На время BRIGHT индикатор будет включен, а на время TAKT-BRIGHT выключен. Надо понимать, что эта константа будет справедлива только для ситуаций, когда TAKT равен 10мс.

Упрощение использования

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

В нем блок АЦП микроконтроллера периодически делает замер и сохраняет результат в память. Это результат можно из памяти вытащить и показать на индикаторе. То есть желательно иметь функцию, которая будет разделять двухразрядные числа две цифры.

Назовем эту функцию DisplayMath():

void DisplayMath(int data) { dig1 = dig2 = 0; if (data = 10) { data -= 10; dig1++; } dig2 = data; } }

В эту функцию будет передаваться число, которое нужно разобрать по разрядам. Результат обработки функция записывает в глобальные переменные dig1 и dig2.
Для начала происходит проверка входных данных.

Если переданное значение больше 100, то функция не будет делать ничего и переменные dig1 и dig2 обнулятся. Если меньше 100, то запускается пересчет.
Далее локальная переменная data декрементируется с шагом 10 и подсчитывается количество итераций.

Например, если функции передано значение 48 цикл while будет выполнен 4 раза и концу его выполнения переменные будут иметь состояние dig1=4, data=8. Далее остается только записать остаток data в переменную dig2.

В итоге после запуска этой функции в переменных dig1 и dig2 окажутся значения разрядов.
Сам вывод цифр на дисплей тоже лучше вынести в отдельную функцию. Назовем ее DisplayShow():

void DisplayShow() { digitalWrite(DIG1,LOW); Show(dig1); delay(BRIGHT); Clean(); digitalWrite(DIG1,HIGH); delay(TAKT-BRIGHT); digitalWrite(DIG2,LOW); Show(dig2); delay(BRIGHT); Clean(); digitalWrite(DIG2,HIGH); delay(TAKT-BRIGHT); }

Окончательный код с использованием этих функций:

#define DIG1 4 #define DIG2 5 #define A 6 #define B 7 #define C 8 #define D 9 #define E 10 #define FF 11 #define G 12 #define TAKT 10 #define BRIGHT 2 int dig1 = 0; int dig2 = 0; void setup() { pinMode(A, OUTPUT); pinMode(B, OUTPUT); pinMode(C, OUTPUT); pinMode(D, OUTPUT); pinMode(E, OUTPUT); pinMode(FF, OUTPUT); pinMode(G, OUTPUT); pinMode(DIG1, OUTPUT); pinMode(DIG2, OUTPUT); digitalWrite(A,HIGH); digitalWrite(B,HIGH); digitalWrite(C,HIGH); digitalWrite(D,HIGH); digitalWrite(E,HIGH); digitalWrite(FF,HIGH); digitalWrite(G,HIGH); digitalWrite(DIG1,HIGH); digitalWrite(DIG2,HIGH); } void loop() { DisplayMath(34); DisplayShow(); } void DisplayMath(int data) { dig1 = dig2 = 0; if (data = 10) { data -= 10; dig1++; } dig2 = data; } } void DisplayShow() { digitalWrite(DIG1,LOW); Show(dig1); delay(BRIGHT); Clean(); digitalWrite(DIG1,HIGH); delay(TAKT-BRIGHT); digitalWrite(DIG2,LOW); Show(dig2); delay(BRIGHT); Clean(); digitalWrite(DIG2,HIGH); delay(TAKT-BRIGHT); } void Show(int digit) { switch(digit) { case 0: { digitalWrite(A,LOW); digitalWrite(B,LOW); digitalWrite(C,LOW); digitalWrite(D,LOW); digitalWrite(E,LOW); digitalWrite(FF,LOW); } break; case 1: { digitalWrite(B,LOW); digitalWrite(C,LOW); } break; case 2: { digitalWrite(A,LOW); digitalWrite(B,LOW); digitalWrite(D,LOW); digitalWrite(E,LOW); digitalWrite(G,LOW); } break; case 3: { digitalWrite(A,LOW); digitalWrite(B,LOW); digitalWrite(C,LOW); digitalWrite(D,LOW); digitalWrite(G,LOW); } break; case 4: { digitalWrite(B,LOW); digitalWrite(C,LOW); digitalWrite(FF,LOW); digitalWrite(G,LOW); } break; case 5: { digitalWrite(A,LOW); digitalWrite(C,LOW); digitalWrite(D,LOW); digitalWrite(FF,LOW); digitalWrite(G,LOW); } break; case 6: { digitalWrite(A,LOW); digitalWrite(C,LOW); digitalWrite(D,LOW); digitalWrite(E,LOW); digitalWrite(FF,LOW); digitalWrite(G,LOW); } break; case 7: { digitalWrite(A,LOW); digitalWrite(B,LOW); digitalWrite(C,LOW); } break; case 8: { digitalWrite(A,LOW); digitalWrite(B,LOW); digitalWrite(C,LOW); digitalWrite(D,LOW); digitalWrite(E,LOW); digitalWrite(FF,LOW); digitalWrite(G,LOW); } break; case 9: { digitalWrite(A,LOW); digitalWrite(B,LOW); digitalWrite(C,LOW); digitalWrite(D,LOW); digitalWrite(FF,LOW); digitalWrite(G,LOW); } break; } } void Clean() { digitalWrite(A,HIGH); digitalWrite(B,HIGH); digitalWrite(C,HIGH); digitalWrite(D,HIGH); digitalWrite(E,HIGH); digitalWrite(FF,HIGH); digitalWrite(G,HIGH); }

Обратите внимание насколько прост основной цикл loop(). В нем всего две строки. Если вы измените значение 34 на любое другое, то оно будет отображено на индикаторе.
Для демонстрации работы индикатора запустим счетчик с произвольной скоростью и будем выводить его состояние. Замените основной цикл и добавьте две переменных:

int value = 0; int i = 0; void loop() { i++; if (i == 7) { i = 0; value ++; if (value == 100) value = 0; } DisplayMath(value); DisplayShow(); }

Вы увидите как на экране побегут цифры от 0 до 99.

Заключение

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

Индивидуальные задания

  1. Увеличьте модуль счета. Подключите четыре дополнительных светодиода на выводах A0-A5 и допишите программу так, чтобы счетчик считал от 0 до 699.
  2. Если в старшем разряде 0, то его нет смысла показывать.

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

  3. Сделайте так, чтобы если функции DisplayMath() передано число больше 99 на дисплее отображалось -0 (overflow, переполнение)

Остальные статьи цикла можно найти здесь.

Мы будем очень рады, если вы поддержите наш ресурс и посетите магазин наших товаров shop.customelectronics.ru.

Источник: http://www.customelectronics.ru/arduino-dinamicheskaya-indikatsiya/

Alex_EXE

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

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

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

https://www.youtube.com/watch?v=uaYBXeAYSN4

Семисегментный индикатор

На примере обновлённого вольтметра сделанном на микроконтроллере PIC16F676 в этой статье расскажу о динамической индикации семисегментных индикаторов.

Для динамической индикации понадобиться таймер, в котором будет постоянно крутиться функция вывода значения на дисплей. Обычно микроконтроллеры содержат несколько таймеров, под динамическую индикацию подойдёт самый простой из них. В примере использован первый 8 битный таймер TMR0.

Для начала таймер нужно сконфигурировать:

OPTION=0b00000000; // Настройка TMR0 INTCON=0b10100000; // Прерывания разрешены и только от TMR0

Для работы понадобятся следующие глобальные переменные:

unsigned char v1,v2,v3, vn;

Первые три отвечают за значения соответствующих сегментов, а последняя за номер горящего сегмента в данный момент (динамическая индикация).

Обработчик прерываний занят обработкой таймера, который постоянно по очереди сменяет сегменты.

void interrupt isr(void) { if(T0IF) // при переполнение TMR0 { vn++; // переключение сегмента switch(vn) // выбор сегмента { case 1:seg7(v1,1);break; case 2:seg7(v2,2);break; case 3:{seg7(v3,3);vn=0;}break; } TMR0=100; // установка таймера не на начало T0IF=0; // сбрасываем флаг } }

Для вывода значения символа семисегментного индикатора с общим анодом используется следующая функция:

void seg7(unsigned char c, unsigned char s) { unsigned char t=0; // g сегмент PORTA=0b00000000; // сброс порта A switch(s) // выбор анода { case 1 :{t=1;}break; case 2 :{t=2;}break; case 3 :{t=32;}break; } switch(c%10) // выбор сегментов (катодов) { // 00bfaed g case 0 : {PORTC=0b00000000;PORTA=t+4;}break; case 1 : {PORTC=0b00011110;PORTA=t+4;}break; case 2 : {PORTC=0b00010001;PORTA=t;}break; case 3 : {PORTC=0b00010100;PORTA=t;}break; case 4 : {PORTC=0b00001110;PORTA=t;}break; case 5 : {PORTC=0b00100100;PORTA=t;}break; case 6 : {PORTC=0b00100000;PORTA=t;}break; case 7 : {PORTC=0b00010110;PORTA=t+4;}break; case 8 : {PORTC=0b00000000;PORTA=t;}break; case 9 : {PORTC=0b00000100;PORTA=t;}break; } }

У PIC16F676 неполный порты вывода, поэтому все сегменты на порт C не влезли, сегмент g пришлось разместить на порте A, а точку приходиться подключать схематически к одному из общих анодов через инвертор. Схема такого подключения выглядит следующим образом:

Схема вольтметра

Если использовать другой микроконтроллер, у которого есть хотя бы один полноценный порт, например PIC16F628A

Схема цифрового термометра

функция примет следующий вид:

void seg7(unsigned char c, unsigned char s) { unsigned char t=0; switch(c%10) // выбор сегментов (катодов) { // gcPdeafb case 0 : {t=0b10100000;}break; case 1 : {t=0b10111110;}break; case 2 : {t=0b01100010;}break; case 3 : {t=0b00101010;}break; case 4 : {t=0b00111100;}break; case 5 : {t=0b00101001;}break; case 6 : {t=0b00100001;}break; case 7 : {t=0b10111010;}break; case 8 : {t=0b00100000;}break; case 9 : {t=0b00101000;}break; } PORTA=0b00000000; // сброс порта A switch(s) // выбор анода { case 1 :{ PORTA =4;}break; case 2 :{ PORTA =8;}break; case 3 :{ PORTA =64;}break; } PORTB=t; if(c>9) { PORTB=t&0b11011111; } }

Точка у символа загорается, если с больше 9, значение на индикатор выводиться всё равно будет, т.е. будет выводиться только младший разряд, остальное всё отбрасываться (например: 19, 39 = 9. ).

В основной функции (main) МК спокойно выполняет свою работу, для вывода новой информации на дисплей ему достаточно изменить значения переменных v1,v2,v3, но изменять их следует одновременно, что бы избежать неразберихи на индикаторе.

Скачать исходник вольтметра

Alex_EXE | 01.12.2011 | Микроконтроллеры |

Источник: https://alex-exe.ru/radio/microcontrollers/dynamic-7seg-indication/

Семи сегментный индикатор и AVR. Динамическая индикация. Программа на Си. Шаг №5

Обновлено 3.04.15. Всем привет. В прошлой статье мы с Вами рассмотрели алгоритм общения с ЖКИ, а также вывод информациина нее, и протестировали в симуляторе.

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

Для отображения букв используются более сложные много сегментные и матричные индикаторы. Но здесь речь пойдет о семи сегментных… Также рассмотрим что такое динамическая индикация, как способ мгновенного отображения измеряемой величины. Для этого в программе рассмотрим использование прерываний.


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

Если индикаторов несколько, следовательно и управляются катоды несколькими ножками МК. !!! Но всегда используйте транзисторы, т.к. порты ввода-вывода могут сгореть из-за относительно большого тока. Я использовал обычные 315 транзисторы.

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

для отображения информации на сегментах 8 ножек (7 +точка) и по одной ножки на каждый индикатор для его управления, у меня их три, поэтому и ножки управления тоже три. Ниже я привел и описал программу. Для управления сегментами  будем использовать пины одного порта, что б не путаться.

Писал под микроконтроллер ATmega8. Если Вы хотите отвязаться от “камня” то это не проблема, например в разбиваем код на библиотеки, где без проблем можно изменить настройки под другой “камень”, в основном это номера пинов и портов. Там же описаны общие правила универсальности и переноса.

Рисунок подключения транзистора к МК и индикатору.

Перейдем к программе. В этой небольшой программе (на Си) я привел пример включения трех элементов индикатора и вывод числа с запятой. Использование таймера и прерывания для вывода на индикатор.

В ходе написания программы мы должны определиться какой пин порта должен соответствовать сегменту на индикаторе. Сам элемент индикатора приведен на рисунке ниже. Сбоку описание подключения выводов к сегментам элемента индикатора(пин порта – номер ножки элемента (рис.

выше) – буква сегмента – число в массиве, отвечающее за включение сегментов на элементе).

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

 #include

 #include

 #include

 /*Определим каждому пину порта элемент семи сегментника (риунок выше)*/

 #define a 128

 #define b 32

 #define c 8

 #define d 2

 #define e 1

 #define f 64

 #define g 16

 #define dp 4

 /*Эти макросы содержат числа, соответствующие двойке, возведенной в степень, равной номеру    “ножки” того порта, к которому подключен сегмент индикатора с одноименным макросу названием.*/

 short unsigned int j, k = 0;  /*переменные исп-ся в макросе прерывания*/

 float i = 0;    /*Переменная для вывода на индикатор*/

short unsigned int w = 0; /*Переменная индикатор для включения точки*/

unsigned char Slot[11];  /*Массив в котором хранятся числа, которые нужно

вывести через порт на индикатор, чтобы он показал цифру, равную номеру

  элемента массива. Числа зависят только от макросов.*/

 void Slot_init ()  /*Функция инициализации индикатора*/

 {

         Slot[0] = (a+b+c+d+e+f);

         Slot[1] = (b+c); 

         Slot[2] = (a+b+g+e+d);

         Slot[3] = (a+b+g+c+d);

         Slot[4] = (f+g+b+c);  /*Имена макросов соответствуют именам сегментов индик*/

         Slot[5] = (a+f+g+c+d);

         Slot[6] = (a+f+g+c+d+e);

         Slot[7] = (a+b+c);

         Slot[8] = (a+b+c+d+e+f+g);

         Slot[9] = (a+b+c+d+f+g);

         Slot[10] = dp;   /*Точка*/

 }

/*В этих переменных хранятся цифры, которые нужно отобразить*/

 char Elem1, Elem2, Elem3; 

 /* Функция выделяет цифры из трехзначного числа Number*/

 void Display (float Number)

 {

        float N1, N2; /*Переменные для функции modf*/

        N1 = modf (Number, &N2); /*Разбиваем число на целую и дробную части,                                                                                                             N1  = дробной N2 = целой*/

        if (N1 != 0) /*Еслине равно нулю то присутствует дробь*/ 

       {

                  Number= Number*10; /*тогда умножаем число на 10, для обычного вывода                                                                                                  на  индикатор трехзначного дробного числа*/

                  w = 1; /* переменная индикатор которая используется в цикле ниже,                                                 чтобы  включать точку*/

        }

        short unsigned int Num1, Num2, Num3;

        Num1=Num2=0;

        while (Number >= 100) /*Сотни*/ 

       {

                Number -= 100;

                Num1++;

       }

       while (Number >= 10) /*Десятки*/ 

      {

               Number -= 10;

               Num2++;

      }

       Num3 = Number; /*Еденицы*/ 

       Elem1 = Slot[Num1];

       if (w == 1) /*Условие дя включения точки на втором элементе*/

       {

                Elem2 = (Slot[Num2]|0×04); /*логическое сложение с пином отвечающим за                                                                                                        точку*/

                w = 0;    /*Выключаем точку*/

        }

        else

                Elem2 = Slot[Num2];

        Elem3 = Slot[Num3];

       }

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 (); /*Разрешить общее прерыввание*/

        /*Инициализация таймера Т0*/

       TIMSK = (1

Источник: http://www.ap-impulse.ru/podklyuchaem-semisegmentnyj-indikator-i-pishem-programmu-shag-5/

Еще раз о динамической индикации на LED-индикаторах

В этой статье пойдет речь о некоторых, на мой взгляд, немаловажных аспектах организации динамической индикации (далее ДИ) на 7-сегментных LED индикаторах для микроконтроллерных систем. Ее можно рассматривать как продолжение и дополнение ранее опубликованной моей статьи.

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

В этой простейшей схеме реализована индикация стилизованной буквы «С» таким образом, что через нижний сегмент (“d”) проходит постоянный ток 1 мА, далее снизу вверх: через сегмент “e” протекает ток 2 мА со скважностью 2, через сегмент “f” – ток 4 мА со скважностью 4 и, наконец, через сегмент “a” – ток 8 мА со скважностью 8. В итоге, имеем средний ток через каждый сегмент в 1 мА, но при разных скважностях от 1 до 8. Во вложении прилагается модель Proteus, в котором, при помощи логического анализатора, можно убедиться, что сигнал подается вышеописанным способом. Резисторы подобраны так, что обеспечиваются указанные токи (с учетом того, что падение напряжения на светодиоде при токах 1-4 мА примерно равно 1.8 В, а при 8мА – около 1.9 В). Ниже приведены фотографии свечения индикатора, как для указанных токов, так и для примерно в два раза меньших при напряжении питания 3.3 Вольт.

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

Исходя из этого эксперимента, утверждаю, что не правы как те, кто утверждает о субъективном снижении яркости, так и те, кто говорит о ее возрастании. ПРИ ОДНОМ И ТОМ ЖЕ СРЕДНЕМ ТОКЕ ЧЕРЕЗ СЕГМЕНТ ЯРКОСТЬ ПРИМЕРНО ОДИНАКОВА КАК ДЛЯ СТАТИЧЕСКОЙ ИНДИКАЦИИ, ТАК И ДЛЯ ДИНАМИЧЕСКОЙ ПРИ СКВАЖНОСТИ ОТ 1 ДО 8 .

 На том и закончим с этим вопросом.

Современные светодиодные индикаторы, особенно типов “Super Red” и “Hi Red”, начинают светиться вполне достаточно для помещений уже при токах от 0.5 мА. С учетом этого фактора возникает соблазн организовать ДИ без применения дополнительных ключей, управляя разрядами непосредственно с портов МК, например, как на нижеприведенной схеме.

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

Тут следует отметить, что хотя существуют разного рода доводы о допустимости превышения выходного тока на «разрядных» выходах ввиду большой скважности протекающего через них тока, я сторонник того, чтобы придерживаться Datasheet производителей, а в них (по крайней мере у Microchip) об этом ничего не сказано, для PIC – это максимум 25 мА.

Исходя из этого, скажем так «правильные разработчики» выбирают номинал токоограничительного резистора таким, чтобы ток сегмента был не более 3мА (тогда 8 сегментов, включая точку, в сумме дадут 24 мА). При этом, обычно пользуются

формулой (1)   R=(Upp-Uled)/I,

где Upp – напряжение питания, Uled – падение напряжения на сегменте индикатора, I – ток через сегмент. По ней для Upp=5V и принимая для индикатора красного цвета свечения Uled=1.8V, получают R=(5-1.8)/3=1.067кОм, ближайший из ряда – 1.1кОм.

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

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

К сожалению, я не нашел в Datasheet для PIC среднего семейства точной величины выходного сопротивления порта.

Косвенные вычисления, исходя из сведений из Datasheet, а так же прямые измерения на конкретных чипах, дают результат примерно: при напряжении питания 5V – 20 Ом для состояния порта «0» и 60 Ом для состояния «1», при напряжении питания 3V – соответственно 30 Ом и 80 Ом. В дальнейших выкладках будем ориентироваться на эти значения.

С учетом сопротивлений выходных каналов имеем для расчета резистора для требуемого тока сегмента 

формулу (2)  R = (Upp – UledI*N*Rout) / I – Rseg,   где N – число включенных разрядов, Rout– выходное “разрядное” сопротивление, Rseg – выходное “сегментное” сопротивление.

Из этой формулы для вычисления тока сегмента для данного ограничительного сопротивления получим

формулу (3)  I = (Upp – Uled) / (R + N*Rout+Rseg).

Вычисляя требуемый для тока 3мА резистор по формуле (2), получим: 846 Ом (ближайший – 820 Ом) для индикатора с ОК и 576 Ом (ближайший 560 Ом) для индикатора с ОА. Согласитесь, было бы обидно установить ток сегмента на 30 – 40 % меньше возможного, когда «каждый миллиампер на счету».

Для более низких напряжений питания эта разница еще больше. Так для питания в 3 Вольта для сегментного тока в 3мА по формуле (2) даже для индикатора с ОК имеем R=(3-1.8-8*30*0.003)/0.003-80=80 Ом, тогда как по упрощенной формуле (1) мы бы имели 400 Ом, то есть ток был бы 1.67 мА вместо допустимых 3 мА!!

Полученное значение R=80 Ом и формула (3) говорят о том, что для низких питающих напряжений максимальные токи определяются уже в большей степени Rout, чем R.

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

Например, вычислим для Upp=3V и R=80 Om ток через один сегмент для цифр 1 (светятся два сегмента) и 8 с точкой (8 сегментов) для индикатора с ОК по формуле (3):

I(1) = (3-1.8)/(80+2*30+80) = 5.5 mA

I(8.)= (3-1.8)/(80+8*30+80) = 3 mA

Как видим, разница почти в два раза – это будет довольно заметно, но в некоторых случаях приемлемо. Для уменьшения неравномерности придется уменьшить ток сегмента или же увеличить напряжение питания хотя бы до 3.3 В (разница в токах примерно в 1.5 раза).

Для наблюдения разницы яркости при токах через сегмент в 1, 2 и 4 мА, соответствующие выводы резисторов с выходов PIC12F629 были переключены непосредственно на плюсовую шину.

В заключении, коснемся еще одного вопроса, также нередко обсуждаемого на просторах Интернета – схем, где индикатор подключен к микроконтроллеру вообще без токоограничивающих резисторов, напрямую как сегменты, так и разряды. Исходя из формулы (3), кажется, что это в принципе возможно для малых питающих напряжений. Действительно, для Upp=3V и R=0 имеем:

I(1)=(3-1.9)/(2*30+80)=7.9 mA,  I(8.)=(3-1.8)/(8*30+80)=3.8 mA для индикатора с ОК.

I(1)=(3-1.9)/(2*80+30)=5.8 mA, I(8.)=(3-1.8)/(8*80+30)=1.8 mA для ОА.

Из формул видно, что для индикатора с ОК суммарный ток разрядов превышает допустимый 3.8*8=30.4 мА, но разность яркости 1 и 8 всего в 2 раза. Для ОА ток вполне в пределах нормы, но вот разница в токах сегментов для цифр 1 и 8 слишком велика – в 3 раза, а значит, визуально 1 будет светиться существенно ярче, чем 8, 9 или 6. Вывод: все таки, резисторы нужны при любом напряжении питания.

Надеюсь, изложенные в статье соображения будут кому-то полезными при разработке систем с ДИ.

В приложении кроме упомянутой модели имеется прошивка для тестовой схемы и код в MikroC.

Список радиоэлементов

Скачать список элементов (PDF)

Прикрепленные файлы:

Источник: http://cxem.gq/mc/mc356.php

Ссылка на основную публикацию
Adblock
detector
",css:{backgroundColor:"#000",opacity:.6}},container:{block:void 0,tpl:"
"},wrap:void 0,body:void 0,errors:{tpl:"
",autoclose_delay:2e3,ajax_unsuccessful_load:"Error"},openEffect:{type:"fade",speed:400},closeEffect:{type:"fade",speed:400},beforeOpen:n.noop,afterOpen:n.noop,beforeClose:n.noop,afterClose:n.noop,afterLoading:n.noop,afterLoadingOnShow:n.noop,errorLoading:n.noop},o=0,p=n([]),h={isEventOut:function(a,b){var c=!0;return n(a).each(function(){n(b.target).get(0)==n(this).get(0)&&(c=!1),0==n(b.target).closest("HTML",n(this).get(0)).length&&(c=!1)}),c}},q={getParentEl:function(a){var b=n(a);return b.data("arcticmodal")?b:(b=n(a).closest(".arcticmodal-container").data("arcticmodalParentEl"),!!b&&b)},transition:function(a,b,c,d){switch(d=null==d?n.noop:d,c.type){case"fade":"show"==b?a.fadeIn(c.speed,d):a.fadeOut(c.speed,d);break;case"none":"show"==b?a.show():a.hide(),d();}},prepare_body:function(a,b){n(".arcticmodal-close",a.body).unbind("click.arcticmodal").bind("click.arcticmodal",function(){return b.arcticmodal("close"),!1})},init_el:function(d,a){var b=d.data("arcticmodal");if(!b){if(b=a,o++,b.modalID=o,b.overlay.block=n(b.overlay.tpl),b.overlay.block.css(b.overlay.css),b.container.block=n(b.container.tpl),b.body=n(".arcticmodal-container_i2",b.container.block),a.clone?b.body.html(d.clone(!0)):(d.before("
"),b.body.html(d)),q.prepare_body(b,d),b.closeOnOverlayClick&&b.overlay.block.add(b.container.block).click(function(a){h.isEventOut(n(">*",b.body),a)&&d.arcticmodal("close")}),b.container.block.data("arcticmodalParentEl",d),d.data("arcticmodal",b),p=n.merge(p,d),n.proxy(e.show,d)(),"html"==b.type)return d;if(null!=b.ajax.beforeSend){var c=b.ajax.beforeSend;delete b.ajax.beforeSend}if(null!=b.ajax.success){var f=b.ajax.success;delete b.ajax.success}if(null!=b.ajax.error){var g=b.ajax.error;delete b.ajax.error}var j=n.extend(!0,{url:b.url,beforeSend:function(){null==c?b.body.html("
"):c(b,d)},success:function(c){d.trigger("afterLoading"),b.afterLoading(b,d,c),null==f?b.body.html(c):f(b,d,c),q.prepare_body(b,d),d.trigger("afterLoadingOnShow"),b.afterLoadingOnShow(b,d,c)},error:function(){d.trigger("errorLoading"),b.errorLoading(b,d),null==g?(b.body.html(b.errors.tpl),n(".arcticmodal-error",b.body).html(b.errors.ajax_unsuccessful_load),n(".arcticmodal-close",b.body).click(function(){return d.arcticmodal("close"),!1}),b.errors.autoclose_delay&&setTimeout(function(){d.arcticmodal("close")},b.errors.autoclose_delay)):g(b,d)}},b.ajax);b.ajax_request=n.ajax(j),d.data("arcticmodal",b)}},init:function(b){if(b=n.extend(!0,{},a,b),!n.isFunction(this))return this.each(function(){q.init_el(n(this),n.extend(!0,{},b))});if(null==b)return void n.error("jquery.arcticmodal: Uncorrect parameters");if(""==b.type)return void n.error("jquery.arcticmodal: Don't set parameter \"type\"");switch(b.type){case"html":if(""==b.content)return void n.error("jquery.arcticmodal: Don't set parameter \"content\"");var e=b.content;return b.content="",q.init_el(n(e),b);case"ajax":return""==b.url?void n.error("jquery.arcticmodal: Don't set parameter \"url\""):q.init_el(n("
"),b);}}},e={show:function(){var a=q.getParentEl(this);if(!1===a)return void n.error("jquery.arcticmodal: Uncorrect call");var b=a.data("arcticmodal");if(b.overlay.block.hide(),b.container.block.hide(),n("BODY").append(b.overlay.block),n("BODY").append(b.container.block),b.beforeOpen(b,a),a.trigger("beforeOpen"),"hidden"!=b.wrap.css("overflow")){b.wrap.data("arcticmodalOverflow",b.wrap.css("overflow"));var c=b.wrap.outerWidth(!0);b.wrap.css("overflow","hidden");var d=b.wrap.outerWidth(!0);d!=c&&b.wrap.css("marginRight",d-c+"px")}return p.not(a).each(function(){var a=n(this).data("arcticmodal");a.overlay.block.hide()}),q.transition(b.overlay.block,"show",1*")),b.overlay.block.remove(),b.container.block.remove(),a.data("arcticmodal",null),n(".arcticmodal-container").length||(b.wrap.data("arcticmodalOverflow")&&b.wrap.css("overflow",b.wrap.data("arcticmodalOverflow")),b.wrap.css("marginRight",0))}),"ajax"==b.type&&b.ajax_request.abort(),p=p.not(a))})},setDefault:function(b){n.extend(!0,a,b)}};n(function(){a.wrap=n(document.all&&!document.querySelector?"html":"body")}),n(document).bind("keyup.arcticmodal",function(d){var a=p.last();if(a.length){var b=a.data("arcticmodal");b.closeOnEsc&&27===d.keyCode&&a.arcticmodal("close")}}),n.arcticmodal=n.fn.arcticmodal=function(a){return e[a]?e[a].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof a&&a?void n.error("jquery.arcticmodal: Method "+a+" does not exist"):q.init.apply(this,arguments)}}(jQuery)}var debugMode="undefined"!=typeof debugFlatPM&&debugFlatPM,duplicateMode="undefined"!=typeof duplicateFlatPM&&duplicateFlatPM,countMode="undefined"!=typeof countFlatPM&&countFlatPM;document["wri"+"te"]=function(a){let b=document.createElement("div");jQuery(document.currentScript).after(b),flatPM_setHTML(b,a),jQuery(b).contents().unwrap()};function flatPM_sticky(c,d,e=0){function f(){if(null==a){let b=getComputedStyle(g,""),c="";for(let a=0;a=b.top-h?b.top-h{const d=c.split("=");return d[0]===a?decodeURIComponent(d[1]):b},""),c=""==b?void 0:b;return c}function flatPM_testCookie(){let a="test_56445";try{return localStorage.setItem(a,a),localStorage.removeItem(a),!0}catch(a){return!1}}function flatPM_grep(a,b,c){return jQuery.grep(a,(a,d)=>c?d==b:0==(d+1)%b)}function flatPM_random(a,b){return Math.floor(Math.random()*(b-a+1))+a}