• Ардуино: динамическая индикация. Семисегментный индикатор Динамическая индикация на семисегментных индикаторах

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


    Для отображения четырехразрядного числа необходимо завести одну общую переменную в которой будет лежать число которое хотим вывести (переменная W ), четыре переменные в которых будут храниться данные для каждого знака (N ) и еще четыре переменные для промежуточных преобразований (M ), чтобы не трогать главную переменную. Переменная должна соответствовать тому значению, которое будет в ней хранитс я. Так для переменной W достаточным будет тип integer , так как переменная такого типа способна хр анить значения от -32768 до +32767 (или word если не планируется использование отрицательных чисел). В переменных N будут лежать числа от 0 до 9 поэтому достаточным будет использование переменной типа byte
    . А в переменных M будут находиться те же значения что и в переменной W , поэтому ставим тип integer .

    Dim W As Integer
    Dim N1 As Byte
    Dim N2 As Byte
    Dim N3 As Byte
    Dim N4 As Byte
    Dim M1 As Integer
    Dim M2 As Integer
    Dim M3 As Integer
    Dim M4 As Integer


    После объявления переменных настраиваем порты на выход которые будут использоваться для подключения индикатора:

    DDRC = &B11111111
    DDRD = &B11111111


    DDRC =& B 00001111 и DDRD = & B 01111111 (четыре первых ноги порта С под аноды и шесть первых порта D под сегменты).

    Затем присваиваем переменной W то значение, которое собираемся вывести на индикатор:

    W = 1234

    "Arial","sans-serif""> В основном цикле программы присваиваем переменным М значение переменной W , я делаю так:

    M1 = W
    M2 = M1
    M3 = M1
    M4 = M1


    "Arial","sans-serif""> Это не паранойя)), это сделано с той целью, чтобы в во всех переменных М лежало одно и тоже число, так как во время операции присваивания легко может ворваться прерывание (если такое имеется и не отключено), в обработчике которого переменная W может измениться. И в случае если присваивание шло таким образом: М1= W , M 2= W , M 3= W , M 4= W в переменных М будут лежать разные значения что приведет к каше в показаниях.

    После присвоения переменным значения начинаем работать с
    каждой из них, преобразуя таким образом, чтобы в переменную N попало то значение, которое будет
    отображаться на индикаторе: в переменной
    N 1 должна оказаться «1», в N 2 – «2», в N 3 – «3», а в N 4 – «4».

    M1 = M1 / 1000 " M1 = 1234/1000 = 1,234
    N1 = Abs (m1) " N1 = Abs (1,234) = 1

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

    Для присвоения двойки переменной N 2 операция будет немного сложнее:

    M2= M2 Mod 1000 " M2 =1234 Mod 1000 = 234
    M2 = M2 / 100 " M2 = 234 / 100 = 2,34
    N2= Abs (m2) " N2 = Abs (2,34) = 2

    "Arial","sans-serif""> Для начала функцией Mod мы возвращаем переменной первые три
    цифры числа (остаток от деления на 1000), а дальше все как в первом случае.

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

    M3 = M3 Mod100
    M3 = M3 / 10
    N3 = Abs (m3)

    M4 = M4 Mod 10
    N4= Abs (m4)


    Теперь в наших переменных лежат те значения, которые мы хотим отобразить, самое время микроконтроллеру подрыгать ногами и вывести эти значения на индикатор, для этого вызываем подпрограмму обработки индикации:

    "Arial","sans-serif"">

    Gosub Led

    "Arial","sans-serif"">Процессор перепрыгнет на подпрограмму с меткой Led :

    Led:

    Portc = &B00001000

    "Arial","sans-serif""> Здесь подаем высокий уровень на PORTC .3 , к этой ноге у нас подсоединен анод первого разряда. Затем выбираем, какие сегменты необходимо зажечь, чтобы отобразить значение первой переменной. Она у нас единица поэтому ноль будет на ногах Portd .1и Portd .2, что соответствует сегментам B и С индикатора.

    Select Case N1









    End Select
    Waitms 5

    "Arial","sans-serif""> После того как зажгли нужные сегменты ждем 5 мс и переходим к отображению следующих чисел:

    Portc = &B00000100
    Select Case N2
    Case 0 : Portd = &B11000000
    Case 1 : Portd = &B11111001
    Case 2 : Portd = &B10100100
    Case 3 : Portd = &B10110000
    Case 4 : Portd = &B10011001
    Case 5 : Portd = &B10010010
    Case 6 : Portd = &B10000010
    Case 7 : Portd = &B11111000
    Case 8 : Portd = &B10000000
    Case 9 : Portd = &B10010000
    End Select

    Waitms 5

    Portc = &B00000010

    Select Case N3
    Case 0 : Portd = &B11000000
    Case 1 : Portd = &B11111001
    Case 2 : Portd = &B10100100
    Case 3 : Portd = &B10110000
    Case 4 : Portd = &B10011001
    Case 5 : Portd = &B10010010
    Case 6 : Portd = &B10000010
    Case 7 : Portd = &B11111000
    Case 8 : Portd = &B10000000
    Case 9 : Portd = &B10010000
    End Select

    Waitms 5

    Portc = &B00000001

    Select Case N4
    Case 0 : Portd = &B11000000
    Case 1 : Portd = &B11111001
    Case 2 : Portd = &B10100100
    Case 3 : Portd = &B10110000
    Case 4 : Portd = &B10011001
    Case 5 : Portd = &B10010010
    Case 6 : Portd = &B10000010
    Case 7 : Portd = &B11111000
    Case 8 : Portd = &B10000000
    Case 9 : Portd = &B10010000
    End Select

    Waitms 5

    "Arial","sans-serif""> После отображения информации на индикаторе необходимо возвратится в основной цикл программы, где нужно завершить цикл и обозначить конец программы.

    "Arial","sans-serif"">Вот что получим в итоге:

    "Arial","sans-serif"">

    "Arial","sans-serif""> За счет маленькой задержки переключения не будут заметны человеческому глазу и мы увидим целое число 1234.

    Скачать исходник и проект в протеусе можно ниже: "Arial","sans-serif"">

    Обновлено 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; /*Массив в котором хранятся числа, которые нужно
    вывести через порт на индикатор, чтобы он показал цифру, равную номеру
    элемента массива. Числа зависят только от макросов.*/
    void Slot_init () /*Функция инициализации индикатора*/
    {
    Slot = (a+b+c+d+e+f);
    Slot = (b+c);
    Slot = (a+b+g+e+d);
    Slot = (a+b+g+c+d); .
    Slot = (f+g+b+c); /*Имена макросов соответствуют именам сегментов индик*/
    Slot = (a+f+g+c+d);
    Slot = (a+f+g+c+d+e);
    Slot = (a+b+c);
    Slot = (a+b+c+d+e+f+g);
    Slot = (a+b+c+d+f+g);
    Slot = 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;
    if (w == 1) /*Условие дя включения точки на втором элементе*/
    {
    Elem2 = (Slot|0×04); /*логическое сложение с пином отвечающим за точку*/
    w = 0; /*Выключаем точку*/
    }
    else
    Elem2 = Slot;
    Elem3 = Slot;
    }
    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</*Флаг разрешенияя по переполнению таймера счетчика Т0*/
    TCCR0 = (0</* 1000000/8 = 125000= 125000/256 = 488,28 гц */
    while (1) /*Бесконечный цикл, выводим переменную на индикатор*/
    {
    _delay_ms (1000);
    i= i+0.1;
    if (i == 99.9)
    i = 0.0;
    Display (i);
    } /*Закрывающая скобка бесконечного цикла*/
    } /*Закрывающая скобка основной программы*/

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

    ISR (TIMER0_OVF_vect)
    {
    PORTB &= 0x3e; //Очистка PB7, PB6, PB0
    _for (j = 0; j<=30; j++) { } // Задержка для выключения транзистора
    (k == 3) ? k = 0: k++; /*Переменная, которая отвечает за очередность загорания трехэлементного индикатора, 0,1 и 2. При определенной цифре, на определенной ножке усатнавливается 1, далее открывается транзистор и загорается сегменты индикатора, соответсвующие переменной Elemn */
    switch (k)
    {
    case 0: PORTB |= (1 << PINB7); // Единицы
    PORTD = Elem3;
    break;
    case 1: PORTB |= (1 << PINB6); // Десятки
    PORTD = Elem2;
    break;
    case 2: PORTB |= (1 << PINB0); // Сотни
    PORTD = Elem1;
    }
    }

    Выше приведенная программа испытана в железе и в симуляторе. Ниже выложены рисунки соответственно. В железе я все спаял навесом, на быструю руку. Как видите три элемента индикатора соответственно три транзистора (обведено кружочком) . В симуляторе(Proteus) транзисторы нам не нужны. Так же одно существенное отличие в программе, а именно в прерывании, где происходит з адержка для выключения транзистора - в симуляторе пропишите 50 тактов. Все должно работать.

    По ходу публикации постов, программа для индикатора у нас немного изменилась, а именно добавился четвертый элемент, вывод на него знака минус, символов “H” и “C", формат вывода времени и объединение всех режимов . Так что читайте, анализируйте и экспериментируйте.

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

    (Скачали: 795 чел.)

    На этом все. В следущей статье я опишу подключение датчиков температуры и выведем инфорацию на индикатор. До скорой встречи!

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

    Тогда нам понадобится уже 14, 21, 28 ножек, а ножек итак мало… Тут нам на помощь приходит динамическая индикация. Основная задача динамической индикации — снизить количество используемых ножек микроконтроллера. Обратите внимание на схеме задействовано 9, а не 14 ножек. Ножки управления все подключены параллельно.

    В общем смысле работает данная конструкция следующим образом: вначале выводится конфигурация первого числа на общую шину и включаем PB1. Первый индикатор загорается, с нужным числом. Затем его гасим, выводим конфигурацию второго числа на шину данных, зажигаем второй индикатор, выключаем.

    Более детально. В первый момент времени все выключено PORTB=0x00; PORTD=0xFF; так как схема с общим «+», анодом. Далее на PORTD посылается конфигурация первого числа, например «0». Из статической индикации мы помним:

    case 0 : { PORTD= 0xC0 ; break ; }

    case 0: { PORTD=0xC0; break; }

    Но обратите внимание, «+» подключен к PORTB.1, т.е. чтобы зажечь сегмент нужно включить ножку PORTB.1=1;

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

    При высоких частотах, человеческий глаз не способен разглядеть эти переключения, и кажется что индикатор горит постоянно. Рекомендуется не использовать частоты кратные 50Гц. В своем тестовом проекте я использовал 120Гц. Таймер настроен на частоту 1МГц. Код обрабатывается в прерывании таймера1. Прерывание вызывается 240 раз в секунду, потому что индикаторов два, поэтому 1000 000/240=4166 или 0x1046 пихаем в регистр сравнения. Протеус подружить с динамическим индикатором не удалось, зато на железе заработало сразу.

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

    Для схемы с общим анодом

    Для схемы с общим катодом

    В качестве тестовой прошивки использовал таймер из предыдущего проекта.

    Видео работы прошивки

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



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

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

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

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

    На этой схеме выводы порта РВ (РВ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<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 -> PortD мы подаем напряжение на второй разряд индикатора. При следующем прерывании произойдет еще один сдвиг влево (#b 0000 0100) и будет подключен третий разряд индикатора.
    С помощью команды R20.3=1 записанной в овале, мы проверяем — достигла ли логическая единица при сдвигах третьего разряда регистра, и если — да, то записываем в R20 единицу (начинается новый круг).
    Командой R21 -> PortB мы выводим двоичный код соответствующей цифры на подключенный разряд индикатора.
    Командой R20 -> PortDigits — мы сохраняем текущее значение в переменной (последний зажженный разряд индикатора).

    Практическая работа №2

    Тема : Разработка схемы динамической индикации.

    Цель : Получить практические навыки проектирования элементов индикации цифровых устройств.

    Задание : Разработать электрическую принципиальную схему цифрового семисегментного светодиодного дисплея на основе микроконтроллера в соответствии с техническим заданием.

    Краткие теоретические сведения

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

    Светодиодный семисегментный индикатор представляет собой восемь светодиодов с соединенными катодами или анодами. Сегменты обозначаются буквами A,B,C,D,E,F,G,H как показано на рисунке 1.

    Рисунок 1

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

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

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

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

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

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

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

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

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

    При частоте «мерцания» 50Гц период импульсов равен 20мс.

    Рисунок 2

    Рисунок 3 – Электрическая схема динамической индикации

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

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

    Амплитуда импульса тока в цепи выбора индикатора должна быть в 8 раз (по числу сегментов) больше амплитуды тока в сегменте.

    На рис. 2 представлена схема динамического четырехразрядного дисплея, выполненного на семисегментных цифровых индикаторах.

    Шина сегментов SA-SH образована выводами порта Р2 микроконтроллера, а четыре младших разряда порта Р1 образуют шину выбора индикаторов (SELI-SEL4). Дисплей обрабатывается программным модулем следующим образом. В порт Р2 загружается семисегментный код символа правого индикатора (HG4). Усиленный элементом DD2 этот ток поступает на шину сегментов а,Ь,с... Затем в младшую тетраду порта Р1 загружается код выбора (включения) индикатора HG4: SEL1=0 , SEL2 -SEL4=1 (шестнадцатиричное значение Е). Ток логического нуля, усиленный элементом DD2, по проводу 11 протекает через резистор R7 и открывает транзистор VT4. Остальные транзисторы выключены. Напряжение питания +5В поступает через открытый транзистор на общий анод индикатора HG4, вызывая индикацию символа. Такое состояние сохраняется в течение времени 5мс. По окончании этого временного интервала МК выдает на разряд порта SEL1 высокий уровень, транзистор VT4 закрывается и ключ VT3 и индицируется символ в этом разряде свечение разряда прекращается. Затем в порт Р2 выдается семисегментный код символа индикатора HG3, а в состояние низкого уровня устанавливается разряд Р1.1. Тем самым включается дисплея и т.д.

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

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

    Таблица 2 – Семисегментные коды

    Байт данных A B C D E F G H НЕХ -код символа
    $9F
    $25
    $D
    $99
    $49
    $41
    $1F

    Задание

    1. Разработать электрическую принципиальную схему динамического цифрового семисегментного дисплея.

    2. Выполнить чертеж схемы электрической принципиальной согласно ГОСТ ЕСКД.

    3. Обосновать выбор схемотехнических решений.

    4. Исходные данные для проектирования представлены в таблице вариантов 2. Для расширения разрядности портов параллельного ввода-вывода микроконтроллера использовать микросхемы сдвиговых регистров. Для управления линиями выбора индикатора использовать двоично-десятичный индикатор. Для усиления сигналов выбора разряда индикации использовать транзисторные ключи.

    Таблица 2 – Исходные данные

    Вариант № Тип микроконтроллера Тип индикатора Количество сегментов
    ATmega8 BL-S56A-11
    ATmega16 BC56-11SRWA
    ATtiny13 BL-D56A-21
    ATtiny2313 BL-S56B-11
    ATmega8 BA56-11GWA
    ATmega16 BL-D56B-21
    ATtiny13 BL-D56A-21
    ATtiny2313 BL-D56A-21
    ATmega16 BL-S56B-11
    ATtiny13 BL-D56B-21