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

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

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

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

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

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

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

Схема включения многоразрядного индикатора

На этой схеме выводы порта РВ (РВ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
- вызов прерывания по переполнению счетчика таймера

Вот так настройка таймера выглядит в программе:
Программирование таймера в Algorithm BuilderГде:
- 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<3) мы проверяем какая цифра записана в регистре R20 - если меньше трех (0,1 или 2), то переходим по стрелке, а если равно трем, то обнуляем регистр R20 и данные теперь берем из переменной Data0.
Далее записываем содержимое R20 в переменную DataIndex.
Следующей командой @Data -> 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).
Следующей командой <<R20 мы производим сдвиг содержимого регистра R20 на один разряд влево (получаем #b 0000 0010).
Следующей командой R20 -> PortD мы подаем напряжение на второй разряд индикатора. При следующем прерывании произойдет еще один сдвиг влево (#b 0000 0100) и будет подключен третий разряд индикатора.
С помощью команды R20.3=1 записанной в овале, мы проверяем - достигла ли логическая единица при сдвигах третьего разряда регистра, и если - да, то записываем в R20 единицу (начинается новый круг).
Командой R21 -> PortB мы выводим двоичный код соответствующей цифры на подключенный разряд индикатора.
Командой R20 -> PortDigits - мы сохраняем текущее значение в переменной (последний зажженный разряд индикатора).

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

Общий вид программы в Algorithm Builder

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


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


(16 голосов, оценка: 4,88 из 5)

Загрузка...


Подключение многоразрядного семисегментного индикатора, организация динамической индикации, алгоритм работы программы, программа индикации на многоразрядном семисегментном индикаторе
Published by: Мир микроконтроллеров
Date Published: 04/20/2015



Комментарии

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

  1. Здравствуйте. А без прерываний многоразрядную индикацию никак не организовать?

  2. Выставили сегменты в разряде 1. Подождали;
    Переключили на разряд 2 (но горят сегменты разряда 1!);
    Выставили сегменты в разряде 2;
    ...
    Хоть сегменты "не того разряда" горят и долю секунды, но все равно неприятно выглядит такое мерцание. Это дилетанство. Нужно перед переключением гасить все сегменты полностью.

    • Здравствуйте Макс!
      Можно, конечно, и гасить сегменты перед переходом на новый разряд.
      Но когда устанавливать нужные сегменты? Получается - после перехода к новому разряду.
      Следуя Вашей логике получается следующее:
      - высвечиваем 1-й разряд
      - в конце гасим сегменты
      - переходим ко 2-му разряду
      - зажигаем нужные сегменты
      И что получается? В два раза хуже - два временных интервала будут с погашенными сегментами - до перехода к новому разряду и после перехода до установки нужных сегментов
      Оптимальный вариант - устанавливать нужные сегменты после перехода к новому разряду.
      Кстати, если устанавливать сегменты (не гася их) до перехода к новому разряду - будет заметно мерцание.
      С уважением, Admin.

  3. Благодарю, добрые человеки!! Эту тему и дс18б20 ещё не освоил, но с такими доходчиво разъяснениями - думаю дело стронется!
    Будьте Здравы!

  4. Добрый день!
    Спасибо за объяснения.В опциях проекта - компилятор - регистр Z установлен как двойной регистр. В мануле в разделе непосредственное размещение данных в памяти программ приведен пример. Согласно примера строка @D0_9*2 ->z ,представлена как
    D0_9*2 -> z. Если убрать значок "@",ошибки не выдает. В вашем примере этот значок присутствует.Может это опечатка? Спасибо.

  5. Добрый день! В принципе алгоритм понятен.Только при компилировании в строке @D0_9*2в Z, выдает ошибку,неизвестное имя @D0_9. Подскажите пожалуйста,что я делаю не так.Спасибо.

    • Доброго дня Александр!
      Я тоже когда-то нарвался на такую штуку и долго мучился, пока внимательно не прочел инструкцию.
      Дело в том, что "Z" имеет два назначения:
      1. Двойной регистр Z
      2. Флаг Z регистра SREG
      По умолчанию в АБ Z подразумевается как флаг регистра SREG (поэтому и выдается ошибка).
      Есть два пути устранения ошибки:
      1. В меню ОПЦИИ -> ОПЦИИ ПРОЕКТА -> КОМПИЛЯТОР поменять "Интерпритацию шаблона"
      2. Выделить Z жирным шрифтом нажав клавишу F2, и тогда Z будет интерпритироваться как двойной регистр Z.
      С уважением, Admin.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *