CUSTOMELECTRONICS.RU
Информационно-учебный блог о разработке электроники
Эл. почта: info@customelectronics.ru

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

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

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

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

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

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

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

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

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

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

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

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

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

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

В качестве заготовки лучше использовать последний пример из статьи о статической индикации. Вам достаточно будет заменить в нем функции main() и hardware_init() на вот этот код:

void hardware_init(void) {
    DDRD |= ((1<<DIG1_PD4)|(1<<DIG2_PD5)|(1<<A_PD6)|(1<<B_PD7));
    PORTD |= ((1<<DIG1_PD4)|(1<<DIG2_PD5)|(1<<A_PD6)|(1<<B_PD7));
    DDRB |= ((1<<C_PB0)|(1<<D_PB1)|(1<<E_PB2)|(1<<F_PB3)|(1<<G_PB4));
    PORTB |= ((1<<C_PB0)|(1<<D_PB1)|(1<<E_PB2)|(1<<F_PB3)|(1<<G_PB4));
}

int main(void) {
    hardware_init();
    while(1) {
        PORTD &= ~(1<<DIG1_PD4);
        show(3);
        _delay_ms(DELAY_MS);
        clean();
        PORTD |= (1<<DIG1_PD4);
        PORTD &= ~(1<<DIG2_PD5);
        show(4);
        _delay_ms(DELAY_MS);
        clean();
        PORTD |= (1<<DIG2_PD5);
    }
}

В прошлой статье в функции hardware_init() мы перманентно включали второй разряд и никогда это не изменяли. В новой функции оба разряда изначально выключены.
Сама программа довольно прозрачна. Мы поочередно подаем питающее напряжение то на один разряд индикатора, то на другой и выводим числа "3" и "4". Каждая из цифр горит по одной секунде. Если уменьшить значение DELAY_MS, то разряды будут мерцать чаще. Считается, что мерцание с частотой 50Гц и выше не воспринимаются человеческим глазом. То есть если установить константу DELAY_MS равной 10мс, то будет казаться, что число "34" светится на дисплее непрерывно. Сделайте это.

Упрощение работы с индикатором

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

void display_show(int data) {
    int dig1 = 0;
    int dig2 = 0;
    if (data < 100) {
        while (data >= 10) {
            data -= 10;
            dig1++;
        }
    }
    dig2 = data;
    PORTD &= ~(1<<DIG1_PD4);
    show(dig1);
    _delay_ms(DELAY_MS);
    clean();
    PORTD |= (1<<DIG1_PD4);
    PORTD &= ~(1<<DIG2_PD5);
    show(dig2);
    _delay_ms(DELAY_MS);
    clean();
    PORTD |= (1<<DIG2_PD5);
}

int main(void) {
    hardware_init();
    while(1) {
        display_show(34);
    }
}

Теперь работа с индикатором выглядит предельно просто. Можно, например, использовать ее для создания вольтметра, который будет читать данные из АЦП и выводить их на дисплей.
Разберем подробно работу функции display_show(). На вход она принимает значение, которое нужно вывести. Храниться значения разрядов будут в переменных dig1 и dig2. Далее запускается цикл со счетчиком, в котором с шагом в "10" декрементируется переменная data. Цикл работает до тех пор, пока значение десятичного разряда не будет записано в переменную dig1. Затем остаток переменной data присваивается переменной dig2. То есть значение "34" будет разобрано на символы "3" и "4". После эти символы как обычно выводятся на индикаторе.

Заключение

Приведенный способ работы с индикатором не самый удобный, так как большую часть времени контроллер работает с индикатором. То есть он применим только в тех случаях, когда остальная часть программы выполняется в прерываниях, о которых мы поговорим чуть позже. Это означает, что не получится теперь использовать задержки, или долго выполняемые операции в основном цикле.
Однако мы все-таки запустим счетчик и выведем цифры бегущие от "0" до "99".
Для этого просто замените функцию main().

int main(void) {
    hardware_init();
    int i = 0;
    int value = 0;
    while(1) {
        i++;
        if (i == 7) {
            i = 0;
            value ++;
            if (value == 100) value = 0;
        }
        display_show(value);
    }
}

Переменная i в этой программе фактически считает количество циклов работы дисплея. Когда это значение доходит до "7", то на единицу увеличивается переменная value и сбрасывается в "0" переменная i. Когда value доходит до ста она тоже обнуляется.
Вот как это выглядит:

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

  1. Если в старшем разряде 0, то его нет смысла показывать. Доработайте программу так, чтобы старший разряд был погашен, если нужно показать число меньше 10
  2. Сделайте так, чтобы если функции display_show() передано число больше 99 на дисплее отображалось -0 (overflow, переполнение)

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

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

Метки: , , , Просмотров: 6635